chiark / gitweb /
Initial revision
authormdw <mdw>
Wed, 17 Jun 1998 19:07:45 +0000 (19:07 +0000)
committermdw <mdw>
Wed, 17 Jun 1998 19:07:45 +0000 (19:07 +0000)
903 files changed:
StraySrc/!DLLs/!Boot,feb [new file with mode: 0644]
StraySrc/!DLLs/!Run,feb [new file with mode: 0644]
StraySrc/!DLLs/!Sprites,ff9 [new file with mode: 0644]
StraySrc/!DLLs/!Sprites22,ff9 [new file with mode: 0644]
StraySrc/Announce [new file with mode: 0644]
StraySrc/BuildTools [new file with mode: 0644]
StraySrc/COPYING [new file with mode: 0644]
StraySrc/Dynamite/Makefile,fe1 [new file with mode: 0644]
StraySrc/Dynamite/apcs/Makefile,fe1 [new file with mode: 0644]
StraySrc/Dynamite/apcs/h/dynamite [new file with mode: 0644]
StraySrc/Dynamite/apcs/s/dyn_apcs [new file with mode: 0644]
StraySrc/Dynamite/dynamite/Makefile,fe1 [new file with mode: 0644]
StraySrc/Dynamite/dynamite/rsc/messages [new file with mode: 0644]
StraySrc/Dynamite/dynamite/s/dynAnchor [new file with mode: 0644]
StraySrc/Dynamite/dynamite/s/dynArea [new file with mode: 0644]
StraySrc/Dynamite/dynamite/s/dynHeap [new file with mode: 0644]
StraySrc/Dynamite/dynamite/s/dynTask [new file with mode: 0644]
StraySrc/Dynamite/dynamite/s/dynamite [new file with mode: 0644]
StraySrc/Dynamite/dynamite/s/fastMove [new file with mode: 0644]
StraySrc/Dynamite/dynamite/sh/dynAnchor [new file with mode: 0644]
StraySrc/Dynamite/dynamite/sh/dynArea [new file with mode: 0644]
StraySrc/Dynamite/dynamite/sh/dynHeap [new file with mode: 0644]
StraySrc/Dynamite/dynamite/sh/dynTask [new file with mode: 0644]
StraySrc/Dynamite/dynamite/sh/messages [new file with mode: 0644]
StraySrc/Dynamite/dynamite/sh/wSpace [new file with mode: 0644]
StraySrc/Glass/!Glass/!Boot,feb [new file with mode: 0644]
StraySrc/Glass/!Glass/!Help [new file with mode: 0644]
StraySrc/Glass/!Glass/!Run,feb [new file with mode: 0644]
StraySrc/Glass/!Glass/!Sprites,ff9 [new file with mode: 0644]
StraySrc/Glass/!Glass/Choices [new file with mode: 0644]
StraySrc/Glass/!Glass/Defaults/Templates,fec [new file with mode: 0644]
StraySrc/Glass/!Glass/Makefile,fe1 [new file with mode: 0644]
StraySrc/Glass/!Glass/Resources/LoadSpr,ff9 [new file with mode: 0644]
StraySrc/Glass/!Glass/Resources/LoadTpl,fec [new file with mode: 0644]
StraySrc/Glass/!Glass/Resources/Messages [new file with mode: 0644]
StraySrc/Glass/!Glass/Resources/Sprites,ff9 [new file with mode: 0644]
StraySrc/Glass/!Glass/Resources/Templates,fec [new file with mode: 0644]
StraySrc/Glass/!Glass/c/align [new file with mode: 0644]
StraySrc/Glass/!Glass/c/colSelect [new file with mode: 0644]
StraySrc/Glass/!Glass/c/editIcon [new file with mode: 0644]
StraySrc/Glass/!Glass/c/editWin [new file with mode: 0644]
StraySrc/Glass/!Glass/c/gPrefs [new file with mode: 0644]
StraySrc/Glass/!Glass/c/gSprite [new file with mode: 0644]
StraySrc/Glass/!Glass/c/glass [new file with mode: 0644]
StraySrc/Glass/!Glass/c/iconData [new file with mode: 0644]
StraySrc/Glass/!Glass/c/indir [new file with mode: 0644]
StraySrc/Glass/!Glass/c/intMsgs [new file with mode: 0644]
StraySrc/Glass/!Glass/c/tearEdit [new file with mode: 0644]
StraySrc/Glass/!Glass/c/tfile [new file with mode: 0644]
StraySrc/Glass/!Glass/c/toolbox [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wDragging [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wGrab [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wGraph [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wIcons [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wMenus [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wMousePtr [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wPalette [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wRedraw [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wSelect [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wToolbars [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wWinEvent [new file with mode: 0644]
StraySrc/Glass/!Glass/c/wWindows [new file with mode: 0644]
StraySrc/Glass/!Glass/c/window [new file with mode: 0644]
StraySrc/Glass/!Glass/h/_window [new file with mode: 0644]
StraySrc/Glass/!Glass/h/align [new file with mode: 0644]
StraySrc/Glass/!Glass/h/colSelect [new file with mode: 0644]
StraySrc/Glass/!Glass/h/editIcon [new file with mode: 0644]
StraySrc/Glass/!Glass/h/editWin [new file with mode: 0644]
StraySrc/Glass/!Glass/h/gIcons [new file with mode: 0644]
StraySrc/Glass/!Glass/h/gMenus [new file with mode: 0644]
StraySrc/Glass/!Glass/h/gPrefs [new file with mode: 0644]
StraySrc/Glass/!Glass/h/gSprite [new file with mode: 0644]
StraySrc/Glass/!Glass/h/gStruct [new file with mode: 0644]
StraySrc/Glass/!Glass/h/glass [new file with mode: 0644]
StraySrc/Glass/!Glass/h/iconData [new file with mode: 0644]
StraySrc/Glass/!Glass/h/indir [new file with mode: 0644]
StraySrc/Glass/!Glass/h/intMsgs [new file with mode: 0644]
StraySrc/Glass/!Glass/h/tearEdit [new file with mode: 0644]
StraySrc/Glass/!Glass/h/tfile [new file with mode: 0644]
StraySrc/Glass/!Glass/h/toolbox [new file with mode: 0644]
StraySrc/Glass/!Glass/h/window [new file with mode: 0644]
StraySrc/Glass/!Glass/s/toolSupprt [new file with mode: 0644]
StraySrc/Hammer/Makefile,fe1 [new file with mode: 0644]
StraySrc/Hammer/s/armEmul [new file with mode: 0644]
StraySrc/Hammer/s/asm [new file with mode: 0644]
StraySrc/Hammer/s/brkpt [new file with mode: 0644]
StraySrc/Hammer/s/diss [new file with mode: 0644]
StraySrc/Hammer/s/driver [new file with mode: 0644]
StraySrc/Hammer/s/hammer [new file with mode: 0644]
StraySrc/Hammer/sh/armEmul [new file with mode: 0644]
StraySrc/Hammer/sh/asm [new file with mode: 0644]
StraySrc/Hammer/sh/brkpt [new file with mode: 0644]
StraySrc/Hammer/sh/diss [new file with mode: 0644]
StraySrc/Hammer/sh/driver [new file with mode: 0644]
StraySrc/Hammer/sh/hammer [new file with mode: 0644]
StraySrc/Libraries/BAS/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/BAS/exports [new file with mode: 0644]
StraySrc/Libraries/BAS/src/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/BAS/src/README [new file with mode: 0644]
StraySrc/Libraries/BAS/src/b/bas,ffb [new file with mode: 0644]
StraySrc/Libraries/BAS/src/rsc/messages [new file with mode: 0644]
StraySrc/Libraries/BAS/src/s/aofGen [new file with mode: 0644]
StraySrc/Libraries/BAS/src/s/bas [new file with mode: 0644]
StraySrc/Libraries/BAS/src/s/basTalk [new file with mode: 0644]
StraySrc/Libraries/BAS/src/s/fastMove [new file with mode: 0644]
StraySrc/Libraries/BAS/src/s/flex [new file with mode: 0644]
StraySrc/Libraries/BAS/src/s/get [new file with mode: 0644]
StraySrc/Libraries/BAS/src/s/insert [new file with mode: 0644]
StraySrc/Libraries/BAS/src/s/lit [new file with mode: 0644]
StraySrc/Libraries/BAS/src/s/string [new file with mode: 0644]
StraySrc/Libraries/BAS/src/s/vars [new file with mode: 0644]
StraySrc/Libraries/BAS/src/scripts/crunchit,feb [new file with mode: 0644]
StraySrc/Libraries/BAS/src/scripts/execit,ffe [new file with mode: 0644]
StraySrc/Libraries/BAS/src/scripts/exports [new file with mode: 0644]
StraySrc/Libraries/BAS/src/scripts/preproc [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/aofGen [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/bas [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/basTalk [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/basicEnv [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/fastMove [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/flex [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/get [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/insert [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/lit [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/messages [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/string [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/vars [new file with mode: 0644]
StraySrc/Libraries/BAS/src/sh/workspace [new file with mode: 0644]
StraySrc/Libraries/Core/AOF/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/Core/AOF/README [new file with mode: 0644]
StraySrc/Libraries/Core/AOF/c/aof [new file with mode: 0644]
StraySrc/Libraries/Core/AOF/h/alf [new file with mode: 0644]
StraySrc/Libraries/Core/AOF/h/aof [new file with mode: 0644]
StraySrc/Libraries/Core/AOF/h/chunk [new file with mode: 0644]
StraySrc/Libraries/Core/EmbTemp/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/Core/EmbTemp/README [new file with mode: 0644]
StraySrc/Libraries/Core/EmbTemp/s/embTemp [new file with mode: 0644]
StraySrc/Libraries/Core/EmbTemp/sh/embTemp [new file with mode: 0644]
StraySrc/Libraries/Core/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/Core/TearSupt/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/Core/TearSupt/README [new file with mode: 0644]
StraySrc/Libraries/Core/TearSupt/UnLoad,ffb [new file with mode: 0644]
StraySrc/Libraries/Core/TearSupt/bs/tearSupt,ffb [new file with mode: 0644]
StraySrc/Libraries/Core/TearSupt/h/tearSupt [new file with mode: 0644]
StraySrc/Libraries/Core/TearSupt/s/tt [new file with mode: 0644]
StraySrc/Libraries/Core/TearSupt/sh/tearSupt [new file with mode: 0644]
StraySrc/Libraries/Core/dump [new file with mode: 0644]
StraySrc/Libraries/Core/h/_time [new file with mode: 0644]
StraySrc/Libraries/Core/h/swis [new file with mode: 0644]
StraySrc/Libraries/Core/h/swiv [new file with mode: 0644]
StraySrc/Libraries/Core/header [new file with mode: 0644]
StraySrc/Libraries/Core/s/fastMove [new file with mode: 0644]
StraySrc/Libraries/Core/s/flex [new file with mode: 0644]
StraySrc/Libraries/Core/s/heap [new file with mode: 0644]
StraySrc/Libraries/Core/s/oxswi [new file with mode: 0644]
StraySrc/Libraries/Core/s/rdump [new file with mode: 0644]
StraySrc/Libraries/Core/s/swihack [new file with mode: 0644]
StraySrc/Libraries/Core/s/swiv [new file with mode: 0644]
StraySrc/Libraries/Core/s/xapp [new file with mode: 0644]
StraySrc/Libraries/Core/s/xcommon [new file with mode: 0644]
StraySrc/Libraries/Core/s/xdata [new file with mode: 0644]
StraySrc/Libraries/Core/s/xdll [new file with mode: 0644]
StraySrc/Libraries/Core/s/xentry [new file with mode: 0644]
StraySrc/Libraries/Core/s/xentry_swi [new file with mode: 0644]
StraySrc/Libraries/Core/s/xmodule [new file with mode: 0644]
StraySrc/Libraries/Core/s/xsmall [new file with mode: 0644]
StraySrc/Libraries/Core/s/xsmall_swi [new file with mode: 0644]
StraySrc/Libraries/Core/s/xswi [new file with mode: 0644]
StraySrc/Libraries/Core/sh/fastMove [new file with mode: 0644]
StraySrc/Libraries/Core/sh/flex [new file with mode: 0644]
StraySrc/Libraries/Core/sh/flexws [new file with mode: 0644]
StraySrc/Libraries/Core/sh/heapws [new file with mode: 0644]
StraySrc/Libraries/Core/stream [new file with mode: 0644]
StraySrc/Libraries/Core/swis [new file with mode: 0644]
StraySrc/Libraries/DLLLib/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/DLLLib/h/ctype [new file with mode: 0644]
StraySrc/Libraries/DLLLib/h/dll [new file with mode: 0644]
StraySrc/Libraries/DLLLib/h/errno [new file with mode: 0644]
StraySrc/Libraries/DLLLib/h/math [new file with mode: 0644]
StraySrc/Libraries/DLLLib/h/stdio [new file with mode: 0644]
StraySrc/Libraries/DLLLib/h/swiv [new file with mode: 0644]
StraySrc/Libraries/DLLLib/s/appEntry [new file with mode: 0644]
StraySrc/Libraries/DLLLib/s/clib [new file with mode: 0644]
StraySrc/Libraries/DLLLib/s/dpoll [new file with mode: 0644]
StraySrc/Libraries/DLLLib/s/dsetjmp [new file with mode: 0644]
StraySrc/Libraries/DLLLib/s/extEntry [new file with mode: 0644]
StraySrc/Libraries/DLLLib/s/findAll [new file with mode: 0644]
StraySrc/Libraries/DLLLib/s/iface [new file with mode: 0644]
StraySrc/Libraries/DLLLib/s/loadLocal [new file with mode: 0644]
StraySrc/Libraries/DLLLib/s/oscli [new file with mode: 0644]
StraySrc/Libraries/DLLLib/s/wSpace [new file with mode: 0644]
StraySrc/Libraries/DLLLib/sh/dllswis [new file with mode: 0644]
StraySrc/Libraries/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/Quartz/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/Quartz/s/fastMove [new file with mode: 0644]
StraySrc/Libraries/Quartz/s/kernel [new file with mode: 0644]
StraySrc/Libraries/Quartz/s/screen [new file with mode: 0644]
StraySrc/Libraries/Quartz/s/string [new file with mode: 0644]
StraySrc/Libraries/Quartz/sh/!FilerConf,050 [new file with mode: 0644]
StraySrc/Libraries/Quartz/sh/fastMove [new file with mode: 0644]
StraySrc/Libraries/Quartz/sh/quartz [new file with mode: 0644]
StraySrc/Libraries/Quartz/sh/screen [new file with mode: 0644]
StraySrc/Libraries/Quartz/sh/string [new file with mode: 0644]
StraySrc/Libraries/Sapphire/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/Sapphire/Modules/Docs/Sprinkle [new file with mode: 0644]
StraySrc/Libraries/Sapphire/Modules/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/Sapphire/Modules/s/constrain [new file with mode: 0644]
StraySrc/Libraries/Sapphire/Modules/s/sprinkle [new file with mode: 0644]
StraySrc/Libraries/Sapphire/README [new file with mode: 0644]
StraySrc/Libraries/Sapphire/bs/fixedPt,ffb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/bsh/banner,ffb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/bsh/dbx,ffb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/bsh/flex,ffb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/bsh/libOpts,ffb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/bsh/menuDefs,ffb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/bsh/options,ffb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/bsh/stdDbox,ffb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/choices/s/choices [new file with mode: 0644]
StraySrc/Libraries/Sapphire/choices/s/options [new file with mode: 0644]
StraySrc/Libraries/Sapphire/choices/s/prefs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/colSelect/s/colSelect [new file with mode: 0644]
StraySrc/Libraries/Sapphire/colSelect/s/hsv [new file with mode: 0644]
StraySrc/Libraries/Sapphire/colSelect/s/rgb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/akbd [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/alloc [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/banner [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/buttons [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/choices/choices [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/choices/options [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/choices/prefs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/chunk [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/cmdLine [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/coRoutine [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/colSelect [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/colourBox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/dbox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/dbx/arrow [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/dbx/colourPot [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/dbx/dbx [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/dbx/fileIcon [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/dbx/numWrite [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/dbx/slider [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/dbx/stringSet [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/defHandler [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/divide [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/drag [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/draw [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/dynPtr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/errorBox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/event [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/except [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/fastMove [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/fixedPt [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/flex [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/fontmenu [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/gallery [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/heap [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/help [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/hour [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/ibicon [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/idle [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/intKeys [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/keyMap [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/keyString [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/libOpts [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/listbox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/llistMan [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/mbox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/mem [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/menu [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/menuDefs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/msgs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/nopoll [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/note [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/pane [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/progInfo [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/ptr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/rand [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/repeater [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/report [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/res [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/resources [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/resspr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/roVersion [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/sapphire [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/saveWarn [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/screen [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/seh [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/sprite [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/sqrt [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/string [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/subAlloc [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/template [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/thread [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/tms [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/transWin [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/tspr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/viewer [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/warning [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/wimp [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/win [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/winUtils [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/writable [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/xfer/load [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/xfer/save [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/xfer/saveAs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/xfer/xload [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/h/xfer/xsave [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/s/cmath [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/s/crout [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/s/crts [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/s/csapph [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/s/csetjmp [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/s/cstart [new file with mode: 0644]
StraySrc/Libraries/Sapphire/csapph/s/ctype [new file with mode: 0644]
StraySrc/Libraries/Sapphire/dbx/s/arrow [new file with mode: 0644]
StraySrc/Libraries/Sapphire/dbx/s/colourPot [new file with mode: 0644]
StraySrc/Libraries/Sapphire/dbx/s/dbx [new file with mode: 0644]
StraySrc/Libraries/Sapphire/dbx/s/fileIcon [new file with mode: 0644]
StraySrc/Libraries/Sapphire/dbx/s/numWrite [new file with mode: 0644]
StraySrc/Libraries/Sapphire/dbx/s/slider [new file with mode: 0644]
StraySrc/Libraries/Sapphire/dbx/s/stringSet [new file with mode: 0644]
StraySrc/Libraries/Sapphire/def/csapph [new file with mode: 0644]
StraySrc/Libraries/Sapphire/def/list [new file with mode: 0644]
StraySrc/Libraries/Sapphire/def/resources [new file with mode: 0644]
StraySrc/Libraries/Sapphire/def/tearoff [new file with mode: 0644]
StraySrc/Libraries/Sapphire/def/thread [new file with mode: 0644]
StraySrc/Libraries/Sapphire/rsc/ColourSel,fec [new file with mode: 0644]
StraySrc/Libraries/Sapphire/rsc/Messages [new file with mode: 0644]
StraySrc/Libraries/Sapphire/rsc/Sprites,ff9 [new file with mode: 0644]
StraySrc/Libraries/Sapphire/rsc/Templates,fec [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/akbd [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/alloc [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/banner [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/bnrStub [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/buttons [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/chunk [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/cmdLine [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/coRoutine [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/colourBox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/dBanner [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/dKernel [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/dbox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/defHandler [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/divide [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/drag [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/draw [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/dynPtr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/errorBox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/event [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/except [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/fastMove [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/flex [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/fontMenu [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/gallery [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/heap [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/help [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/hour [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/ibicon [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/idle [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/kernel [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/keyString [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/libOpts [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/listbox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/llistMan [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/llistStub [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/mbox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/mem [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/menu [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/msgs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/nopoll [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/note [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/pane [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/progInfo [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/ptr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/rand [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/repeater [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/report [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/res [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/resources [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/resspr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/roVersion [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/sapphRes [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/saveWarn [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/screen [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/seh [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/sprite [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/sqrt [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/string [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/stub [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/subAlloc [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/template [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/thread [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/transWin [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/tspr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/viewer [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/warning [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/wimp [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/win [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/winUtils [new file with mode: 0644]
StraySrc/Libraries/Sapphire/s/writable [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/Changes [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/SAILInfo [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/ctrl [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/driver [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/error [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/express [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/getToken [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/interp [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/strBucket [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/stracc [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/termScript [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/termite [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/tokenise [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/tree [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/value [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_s/var [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/anchor [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/ctrl [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/divide [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/errNum [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/errTable [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/error [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/express [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/getToken [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/interp [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/mem [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/strBucket [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/stracc [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/termScript [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/termite [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/tokClasses [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/tokNames [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/tokTable [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/tokenise [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/tokens [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/tree [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/upcalls [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/value [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/_sh/var [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/errgen,ffb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/ctrl [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/driver [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/env [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/error [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/express [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/getToken [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/interp [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/mem [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/sail [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/strBucket [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/stracc [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/termScript [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/termite [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/tokenise [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/tree [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/value [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/s/var [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/anchor [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/ctrl [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/divide [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/errNum [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/errTable [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/error [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/express [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/getToken [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/interp [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/mem [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/strBucket [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/stracc [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/termScript [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/termite [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/tokClasses [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/tokNames [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/tokTable [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/tokenise [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/tokens [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/tree [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/upcalls [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/value [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/sh/var [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sail/tableGen,ffb [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/_colSelect/kernel [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/_colSelect/models [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/_colSelect/vars [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/_tms/tmsCreate [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/_tms/tmsGlobal [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/_tms/tmsGlue [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/_tms/tmsMain [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/akbd [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/alloc [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/banner [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/buttons [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/choices/choices [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/choices/options [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/choices/prefs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/chunk [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/cmdLine [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/coRoutine [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/colSelect [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/colourBox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/dbox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/dbx/_dbxMacs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/dbx/arrow [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/dbx/colourPot [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/dbx/dbx [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/dbx/fileIcon [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/dbx/numWrite [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/dbx/slider [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/dbx/stringSet [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/defHandler [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/divide [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/drag [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/draw [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/dynPtr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/errorBox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/event [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/except [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/fastMove [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/fixedPt [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/flex [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/fontmenu [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/gallery [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/heap [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/help [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/hour [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/ibicon [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/idle [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/intKeys [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/keyMap [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/keyString [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/libOpts [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/listbox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/llistMan [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/mbox [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/mem [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/menu [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/menuDefs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/msgs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/ncs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/nopoll [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/note [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/pane [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/progInfo [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/ptr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/rand [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/repeater [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/report [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/res [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/resources [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/resspr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/roVersion [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/sapphire [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/saveWarn [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/screen [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/seh [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/sprite [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/sqrt [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/string [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/subAlloc [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/template [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/thread [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/tms [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/transWin [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/tspr [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/viewer [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/warning [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/wimp [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/win [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/winUtils [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/writable [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/xfer/load [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/xfer/save [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/xfer/saveAs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/xfer/xload [new file with mode: 0644]
StraySrc/Libraries/Sapphire/sh/xfer/xsave [new file with mode: 0644]
StraySrc/Libraries/Sapphire/tms/s/tmsCreate [new file with mode: 0644]
StraySrc/Libraries/Sapphire/tms/s/tmsGlue [new file with mode: 0644]
StraySrc/Libraries/Sapphire/tms/s/tmsMain [new file with mode: 0644]
StraySrc/Libraries/Sapphire/xfer/s/load [new file with mode: 0644]
StraySrc/Libraries/Sapphire/xfer/s/save [new file with mode: 0644]
StraySrc/Libraries/Sapphire/xfer/s/saveAs [new file with mode: 0644]
StraySrc/Libraries/Sapphire/xfer/s/xload [new file with mode: 0644]
StraySrc/Libraries/Sapphire/xfer/s/xsave [new file with mode: 0644]
StraySrc/Libraries/Steel/Makefile,fe1 [new file with mode: 0644]
StraySrc/Libraries/Steel/Messages [new file with mode: 0644]
StraySrc/Libraries/Steel/c/akbd [new file with mode: 0644]
StraySrc/Libraries/Steel/c/alarm [new file with mode: 0644]
StraySrc/Libraries/Steel/c/baricon [new file with mode: 0644]
StraySrc/Libraries/Steel/c/blinkC [new file with mode: 0644]
StraySrc/Libraries/Steel/c/buffer [new file with mode: 0644]
StraySrc/Libraries/Steel/c/buttons [new file with mode: 0644]
StraySrc/Libraries/Steel/c/caretptr [new file with mode: 0644]
StraySrc/Libraries/Steel/c/choices [new file with mode: 0644]
StraySrc/Libraries/Steel/c/crc [new file with mode: 0644]
StraySrc/Libraries/Steel/c/creator [new file with mode: 0644]
StraySrc/Libraries/Steel/c/dbox [new file with mode: 0644]
StraySrc/Libraries/Steel/c/event [new file with mode: 0644]
StraySrc/Libraries/Steel/c/exception [new file with mode: 0644]
StraySrc/Libraries/Steel/c/fileicon [new file with mode: 0644]
StraySrc/Libraries/Steel/c/font [new file with mode: 0644]
StraySrc/Libraries/Steel/c/fontMenu [new file with mode: 0644]
StraySrc/Libraries/Steel/c/help [new file with mode: 0644]
StraySrc/Libraries/Steel/c/ibicon [new file with mode: 0644]
StraySrc/Libraries/Steel/c/interface [new file with mode: 0644]
StraySrc/Libraries/Steel/c/keyString [new file with mode: 0644]
StraySrc/Libraries/Steel/c/listbox [new file with mode: 0644]
StraySrc/Libraries/Steel/c/mem [new file with mode: 0644]
StraySrc/Libraries/Steel/c/menu [new file with mode: 0644]
StraySrc/Libraries/Steel/c/msgs [new file with mode: 0644]
StraySrc/Libraries/Steel/c/nopoll [new file with mode: 0644]
StraySrc/Libraries/Steel/c/pane [new file with mode: 0644]
StraySrc/Libraries/Steel/c/pointer [new file with mode: 0644]
StraySrc/Libraries/Steel/c/prefs [new file with mode: 0644]
StraySrc/Libraries/Steel/c/print [new file with mode: 0644]
StraySrc/Libraries/Steel/c/res [new file with mode: 0644]
StraySrc/Libraries/Steel/c/resspr [new file with mode: 0644]
StraySrc/Libraries/Steel/c/saveas [new file with mode: 0644]
StraySrc/Libraries/Steel/c/scroller [new file with mode: 0644]
StraySrc/Libraries/Steel/c/sprite [new file with mode: 0644]
StraySrc/Libraries/Steel/c/stddbox [new file with mode: 0644]
StraySrc/Libraries/Steel/c/tcol [new file with mode: 0644]
StraySrc/Libraries/Steel/c/tearoff [new file with mode: 0644]
StraySrc/Libraries/Steel/c/template [new file with mode: 0644]
StraySrc/Libraries/Steel/c/utils [new file with mode: 0644]
StraySrc/Libraries/Steel/c/viewer [new file with mode: 0644]
StraySrc/Libraries/Steel/c/visdelay [new file with mode: 0644]
StraySrc/Libraries/Steel/c/vsscanf [new file with mode: 0644]
StraySrc/Libraries/Steel/c/werr [new file with mode: 0644]
StraySrc/Libraries/Steel/c/wimpt [new file with mode: 0644]
StraySrc/Libraries/Steel/c/win [new file with mode: 0644]
StraySrc/Libraries/Steel/c/xferrecv [new file with mode: 0644]
StraySrc/Libraries/Steel/c/xfersend [new file with mode: 0644]
StraySrc/Libraries/Steel/c/xproginfo [new file with mode: 0644]
StraySrc/Libraries/Steel/def/steel [new file with mode: 0644]
StraySrc/Libraries/Steel/h/akbd [new file with mode: 0644]
StraySrc/Libraries/Steel/h/alarm [new file with mode: 0644]
StraySrc/Libraries/Steel/h/baricon [new file with mode: 0644]
StraySrc/Libraries/Steel/h/bbc [new file with mode: 0644]
StraySrc/Libraries/Steel/h/blinkC [new file with mode: 0644]
StraySrc/Libraries/Steel/h/buffer [new file with mode: 0644]
StraySrc/Libraries/Steel/h/buttons [new file with mode: 0644]
StraySrc/Libraries/Steel/h/calltrace [new file with mode: 0644]
StraySrc/Libraries/Steel/h/caretptr [new file with mode: 0644]
StraySrc/Libraries/Steel/h/choices [new file with mode: 0644]
StraySrc/Libraries/Steel/h/colourtran [new file with mode: 0644]
StraySrc/Libraries/Steel/h/coords [new file with mode: 0644]
StraySrc/Libraries/Steel/h/crc [new file with mode: 0644]
StraySrc/Libraries/Steel/h/crc32 [new file with mode: 0644]
StraySrc/Libraries/Steel/h/dbox [new file with mode: 0644]
StraySrc/Libraries/Steel/h/event [new file with mode: 0644]
StraySrc/Libraries/Steel/h/exception [new file with mode: 0644]
StraySrc/Libraries/Steel/h/fileicon [new file with mode: 0644]
StraySrc/Libraries/Steel/h/flex [new file with mode: 0644]
StraySrc/Libraries/Steel/h/font [new file with mode: 0644]
StraySrc/Libraries/Steel/h/fontMenu [new file with mode: 0644]
StraySrc/Libraries/Steel/h/heap [new file with mode: 0644]
StraySrc/Libraries/Steel/h/help [new file with mode: 0644]
StraySrc/Libraries/Steel/h/ibicon [new file with mode: 0644]
StraySrc/Libraries/Steel/h/interface [new file with mode: 0644]
StraySrc/Libraries/Steel/h/keyString [new file with mode: 0644]
StraySrc/Libraries/Steel/h/listbox [new file with mode: 0644]
StraySrc/Libraries/Steel/h/mem [new file with mode: 0644]
StraySrc/Libraries/Steel/h/menu [new file with mode: 0644]
StraySrc/Libraries/Steel/h/menuExt [new file with mode: 0644]
StraySrc/Libraries/Steel/h/msgs [new file with mode: 0644]
StraySrc/Libraries/Steel/h/nopoll [new file with mode: 0644]
StraySrc/Libraries/Steel/h/os [new file with mode: 0644]
StraySrc/Libraries/Steel/h/pane [new file with mode: 0644]
StraySrc/Libraries/Steel/h/pointer [new file with mode: 0644]
StraySrc/Libraries/Steel/h/prefs [new file with mode: 0644]
StraySrc/Libraries/Steel/h/res [new file with mode: 0644]
StraySrc/Libraries/Steel/h/resspr [new file with mode: 0644]
StraySrc/Libraries/Steel/h/saveas [new file with mode: 0644]
StraySrc/Libraries/Steel/h/scroller [new file with mode: 0644]
StraySrc/Libraries/Steel/h/sculptrix [new file with mode: 0644]
StraySrc/Libraries/Steel/h/sprite [new file with mode: 0644]
StraySrc/Libraries/Steel/h/stddbox [new file with mode: 0644]
StraySrc/Libraries/Steel/h/steel [new file with mode: 0644]
StraySrc/Libraries/Steel/h/tcol [new file with mode: 0644]
StraySrc/Libraries/Steel/h/tearoff [new file with mode: 0644]
StraySrc/Libraries/Steel/h/template [new file with mode: 0644]
StraySrc/Libraries/Steel/h/utils [new file with mode: 0644]
StraySrc/Libraries/Steel/h/viewer [new file with mode: 0644]
StraySrc/Libraries/Steel/h/visdelay [new file with mode: 0644]
StraySrc/Libraries/Steel/h/vsscanf [new file with mode: 0644]
StraySrc/Libraries/Steel/h/werr [new file with mode: 0644]
StraySrc/Libraries/Steel/h/wimp [new file with mode: 0644]
StraySrc/Libraries/Steel/h/wimpext [new file with mode: 0644]
StraySrc/Libraries/Steel/h/wimpstruct [new file with mode: 0644]
StraySrc/Libraries/Steel/h/wimpt [new file with mode: 0644]
StraySrc/Libraries/Steel/h/win [new file with mode: 0644]
StraySrc/Libraries/Steel/h/xferrecv [new file with mode: 0644]
StraySrc/Libraries/Steel/h/xfersend [new file with mode: 0644]
StraySrc/Libraries/Steel/h/xproginfo [new file with mode: 0644]
StraySrc/Libraries/Steel/h/xtearoff [new file with mode: 0644]
StraySrc/Libraries/Steel/s/bbc [new file with mode: 0644]
StraySrc/Libraries/Steel/s/calltrace [new file with mode: 0644]
StraySrc/Libraries/Steel/s/colourtran [new file with mode: 0644]
StraySrc/Libraries/Steel/s/coords [new file with mode: 0644]
StraySrc/Libraries/Steel/s/crc32 [new file with mode: 0644]
StraySrc/Libraries/Steel/s/fastMove [new file with mode: 0644]
StraySrc/Libraries/Steel/s/flex_dll [new file with mode: 0644]
StraySrc/Libraries/Steel/s/flex_stat [new file with mode: 0644]
StraySrc/Libraries/Steel/s/heap_dll [new file with mode: 0644]
StraySrc/Libraries/Steel/s/heap_stat [new file with mode: 0644]
StraySrc/Libraries/Steel/s/os [new file with mode: 0644]
StraySrc/Libraries/Steel/s/sculptrix [new file with mode: 0644]
StraySrc/Libraries/Steel/s/wimpExt [new file with mode: 0644]
StraySrc/Libraries/Steel/s/wimp_dll [new file with mode: 0644]
StraySrc/Libraries/Steel/s/wimp_main [new file with mode: 0644]
StraySrc/Libraries/Steel/s/wimp_stat [new file with mode: 0644]
StraySrc/Makefile,fe1 [new file with mode: 0644]
StraySrc/MiscToys/CheckSD/Makefile,fe1 [new file with mode: 0644]
StraySrc/MiscToys/CheckSD/README [new file with mode: 0644]
StraySrc/MiscToys/CheckSD/rsc/Templates,fec [new file with mode: 0644]
StraySrc/MiscToys/CheckSD/s/CheckSD [new file with mode: 0644]
StraySrc/MiscToys/CurrDir/Makefile,fe1 [new file with mode: 0644]
StraySrc/MiscToys/CurrDir/README [new file with mode: 0644]
StraySrc/MiscToys/CurrDir/s/currDir [new file with mode: 0644]
StraySrc/MiscToys/Makefile,fe1 [new file with mode: 0644]
StraySrc/MiscToys/PlainError/Makefile,fe1 [new file with mode: 0644]
StraySrc/MiscToys/PlainError/ReadMe [new file with mode: 0644]
StraySrc/MiscToys/PlainError/b/plainError,ffb [new file with mode: 0644]
StraySrc/MiscToys/PlainError/testit,ffb [new file with mode: 0644]
StraySrc/README [new file with mode: 0644]
StraySrc/SDLS/!DLLMerge/!Help [new file with mode: 0644]
StraySrc/SDLS/!DLLMerge/!Run,feb [new file with mode: 0644]
StraySrc/SDLS/!DLLMerge/!Sprites,ff9 [new file with mode: 0644]
StraySrc/SDLS/!DLLMerge/Makefile,fe1 [new file with mode: 0644]
StraySrc/SDLS/!DLLMerge/rsc/messages [new file with mode: 0644]
StraySrc/SDLS/!DLLMerge/rsc/templates,fec [new file with mode: 0644]
StraySrc/SDLS/!DLLMerge/s/dllmerge [new file with mode: 0644]
StraySrc/SDLS/!DLLMerge/sh/messages [new file with mode: 0644]
StraySrc/SDLS/!DLLMerge/sh/templates [new file with mode: 0644]
StraySrc/SDLS/DLLManager/Makefile,fe1 [new file with mode: 0644]
StraySrc/SDLS/DLLManager/rsc/messages [new file with mode: 0644]
StraySrc/SDLS/DLLManager/s/app [new file with mode: 0644]
StraySrc/SDLS/DLLManager/s/dheader [new file with mode: 0644]
StraySrc/SDLS/DLLManager/s/dll [new file with mode: 0644]
StraySrc/SDLS/DLLManager/s/dllmdump [new file with mode: 0644]
StraySrc/SDLS/DLLManager/s/misc [new file with mode: 0644]
StraySrc/SDLS/DLLManager/s/suballoc [new file with mode: 0644]
StraySrc/SDLS/DLLManager/sh/app [new file with mode: 0644]
StraySrc/SDLS/DLLManager/sh/appblock [new file with mode: 0644]
StraySrc/SDLS/DLLManager/sh/dll [new file with mode: 0644]
StraySrc/SDLS/DLLManager/sh/dllblock [new file with mode: 0644]
StraySrc/SDLS/DLLManager/sh/linkblock [new file with mode: 0644]
StraySrc/SDLS/DLLManager/sh/messages [new file with mode: 0644]
StraySrc/SDLS/DLLManager/sh/misc [new file with mode: 0644]
StraySrc/SDLS/DLLManager/sh/suballoc [new file with mode: 0644]
StraySrc/SDLS/DLLManager/sh/wSpace [new file with mode: 0644]
StraySrc/SDLS/Makefile,fe1 [new file with mode: 0644]
StraySrc/SDLS/cdll/Makefile,fe1 [new file with mode: 0644]
StraySrc/SDLS/cdll/c/binding [new file with mode: 0644]
StraySrc/SDLS/cdll/c/cstub [new file with mode: 0644]
StraySrc/SDLS/cdll/c/decode [new file with mode: 0644]
StraySrc/SDLS/cdll/c/dissect [new file with mode: 0644]
StraySrc/SDLS/cdll/c/dllbinder [new file with mode: 0644]
StraySrc/SDLS/cdll/c/error [new file with mode: 0644]
StraySrc/SDLS/cdll/c/extentry [new file with mode: 0644]
StraySrc/SDLS/cdll/c/hashtable [new file with mode: 0644]
StraySrc/SDLS/cdll/c/readdef [new file with mode: 0644]
StraySrc/SDLS/cdll/h/binding [new file with mode: 0644]
StraySrc/SDLS/cdll/h/crc32 [new file with mode: 0644]
StraySrc/SDLS/cdll/h/cstub [new file with mode: 0644]
StraySrc/SDLS/cdll/h/decode [new file with mode: 0644]
StraySrc/SDLS/cdll/h/error [new file with mode: 0644]
StraySrc/SDLS/cdll/h/extentry [new file with mode: 0644]
StraySrc/SDLS/cdll/h/hashtable [new file with mode: 0644]
StraySrc/SDLS/cdll/h/readdef [new file with mode: 0644]
StraySrc/SDLS/cdll/ordinal [new file with mode: 0644]
StraySrc/SDLS/cdll/s/crc32 [new file with mode: 0644]
StraySrc/SapphToys/!CApp/!Run,feb [new file with mode: 0644]
StraySrc/SapphToys/!CApp/Makefile,fe1 [new file with mode: 0644]
StraySrc/SapphToys/!CApp/UK [new file with mode: 0644]
StraySrc/SapphToys/!CApp/c/capp [new file with mode: 0644]
StraySrc/SapphToys/!ColDemo/!Run,feb [new file with mode: 0644]
StraySrc/SapphToys/!ColDemo/Resources/Messages [new file with mode: 0644]
StraySrc/SapphToys/!ColDemo/Resources/Sprites,ff9 [new file with mode: 0644]
StraySrc/SapphToys/!ColDemo/Resources/Templates,fec [new file with mode: 0644]
StraySrc/SapphToys/!ColDemo/_Makefile,fe1 [new file with mode: 0644]
StraySrc/SapphToys/!ColDemo/s/colSelect [new file with mode: 0644]
StraySrc/SapphToys/!ColDemo/s/hsv [new file with mode: 0644]
StraySrc/SapphToys/!ColDemo/s/rgb [new file with mode: 0644]
StraySrc/SapphToys/!DrawX/!Boot,feb [new file with mode: 0644]
StraySrc/SapphToys/!DrawX/!Help [new file with mode: 0644]
StraySrc/SapphToys/!DrawX/!Run,feb [new file with mode: 0644]
StraySrc/SapphToys/!DrawX/!Sprites,ff9 [new file with mode: 0644]
StraySrc/SapphToys/!DrawX/Choices [new file with mode: 0644]
StraySrc/SapphToys/!DrawX/Makefile,fe1 [new file with mode: 0644]
StraySrc/SapphToys/!DrawX/Resources/Messages [new file with mode: 0644]
StraySrc/SapphToys/!DrawX/Resources/Sprites,ff9 [new file with mode: 0644]
StraySrc/SapphToys/!DrawX/Resources/Templates,fec [new file with mode: 0644]
StraySrc/SapphToys/!DrawX/s/drawX [new file with mode: 0644]
StraySrc/SapphToys/!SWIlist/!Help [new file with mode: 0644]
StraySrc/SapphToys/!SWIlist/!Run,feb [new file with mode: 0644]
StraySrc/SapphToys/!SWIlist/!Sprites,ff9 [new file with mode: 0644]
StraySrc/SapphToys/!SWIlist/Format [new file with mode: 0644]
StraySrc/SapphToys/!SWIlist/Makefile,fe1 [new file with mode: 0644]
StraySrc/SapphToys/!SWIlist/UK [new file with mode: 0644]
StraySrc/SapphToys/!SWIlist/bs/swiList,ffb [new file with mode: 0644]
StraySrc/SapphToys/Makefile,fe1 [new file with mode: 0644]
StraySrc/Sculptrix/!SConfig/!Run,feb [new file with mode: 0644]
StraySrc/Sculptrix/!SConfig/Makefile,fe1 [new file with mode: 0644]
StraySrc/Sculptrix/!SConfig/s/loadConfig [new file with mode: 0644]
StraySrc/Sculptrix/!Setrix/!Help [new file with mode: 0644]
StraySrc/Sculptrix/!Setrix/!Run,feb [new file with mode: 0644]
StraySrc/Sculptrix/!Setrix/!Sprites,ff9 [new file with mode: 0644]
StraySrc/Sculptrix/!Setrix/Makefile,fe1 [new file with mode: 0644]
StraySrc/Sculptrix/!Setrix/Resources/Messages [new file with mode: 0644]
StraySrc/Sculptrix/!Setrix/Resources/Sprites,ff9 [new file with mode: 0644]
StraySrc/Sculptrix/!Setrix/Resources/Templates,fec [new file with mode: 0644]
StraySrc/Sculptrix/!Setrix/s/setrix [new file with mode: 0644]
StraySrc/Sculptrix/Changes [new file with mode: 0644]
StraySrc/Sculptrix/Makefile,fe1 [new file with mode: 0644]
StraySrc/Sculptrix/NewVersion [new file with mode: 0644]
StraySrc/Sculptrix/README [new file with mode: 0644]
StraySrc/Sculptrix/apcs/Makefile,fe1 [new file with mode: 0644]
StraySrc/Sculptrix/apcs/h/sculptrix [new file with mode: 0644]
StraySrc/Sculptrix/apcs/s/scp_apcs [new file with mode: 0644]
StraySrc/Sculptrix/old-vsn/README [new file with mode: 0644]
StraySrc/Sculptrix/old-vsn/s/sculptrix [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/Makefile,fe1 [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/rsc/messages [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/bbox [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/border [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/colours [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/config [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/plot [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/redraw [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/rules [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/sculptrix [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/slab [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/utils [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/s/vString [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/bbox [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/border [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/colours [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/config [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/messages [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/plot [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/redraw [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/rules [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/slab [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/utils [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/vString [new file with mode: 0644]
StraySrc/Sculptrix/sculptrix/sh/wSpace [new file with mode: 0644]
StraySrc/Utilities/Makefile,fe1 [new file with mode: 0644]
StraySrc/Utilities/b/buildstub,ffb [new file with mode: 0644]
StraySrc/Utilities/b/fixlink,ffb [new file with mode: 0644]
StraySrc/Utilities/b/msgaof,ffb [new file with mode: 0644]
StraySrc/Utilities/b/resgen,ffb [new file with mode: 0644]
StraySrc/Utilities/b/templaof,ffb [new file with mode: 0644]
StraySrc/Utilities/buildstub,ffb [new file with mode: 0644]
StraySrc/Utilities/c/alloc [new file with mode: 0644]
StraySrc/Utilities/c/chdrgen [new file with mode: 0644]
StraySrc/Utilities/c/cmdr [new file with mode: 0644]
StraySrc/Utilities/c/each [new file with mode: 0644]
StraySrc/Utilities/c/gf [new file with mode: 0644]
StraySrc/Utilities/c/glob [new file with mode: 0644]
StraySrc/Utilities/c/headerGen [new file with mode: 0644]
StraySrc/Utilities/c/inst [new file with mode: 0644]
StraySrc/Utilities/c/setdate [new file with mode: 0644]
StraySrc/Utilities/c/ssrclean [new file with mode: 0644]
StraySrc/Utilities/c/submake [new file with mode: 0644]
StraySrc/Utilities/ex/buildstub [new file with mode: 0644]
StraySrc/Utilities/ex/msgaof [new file with mode: 0644]
StraySrc/Utilities/ex/resgen [new file with mode: 0644]
StraySrc/Utilities/ex/templaof [new file with mode: 0644]
StraySrc/Utilities/fixlink,ffb [new file with mode: 0644]
StraySrc/Utilities/h/alloc [new file with mode: 0644]
StraySrc/Utilities/h/cmdr [new file with mode: 0644]
StraySrc/Utilities/h/gf [new file with mode: 0644]
StraySrc/Utilities/h/glob [new file with mode: 0644]
StraySrc/Utilities/msgaof,ffb [new file with mode: 0644]
StraySrc/Utilities/resgen,ffb [new file with mode: 0644]
StraySrc/Utilities/s/enumerate [new file with mode: 0644]
StraySrc/Utilities/s/hour [new file with mode: 0644]
StraySrc/Utilities/s/pathUtil [new file with mode: 0644]
StraySrc/Utilities/s/path_util [new file with mode: 0644]
StraySrc/Utilities/s/setSlot [new file with mode: 0644]
StraySrc/Utilities/s/test [new file with mode: 0644]
StraySrc/Utilities/sh/pathUtil [new file with mode: 0644]
StraySrc/Utilities/templaof,ffb [new file with mode: 0644]
StraySrc/dist/Core [new file with mode: 0644]
StraySrc/dist/Dynamite [new file with mode: 0644]
StraySrc/dist/Hammer [new file with mode: 0644]
StraySrc/dist/MiscToys [new file with mode: 0644]
StraySrc/dist/Quartz [new file with mode: 0644]
StraySrc/dist/SDLS [new file with mode: 0644]
StraySrc/dist/Sapphire [new file with mode: 0644]
StraySrc/dist/Sculptrix [new file with mode: 0644]
StraySrc/dist/dist [new file with mode: 0644]
StraySrc/dist/makeDist,feb [new file with mode: 0644]
StraySrc/gplnote/Makefile,fe1 [new file with mode: 0644]
StraySrc/gplnote/asm [new file with mode: 0644]
StraySrc/gplnote/basic,ffb [new file with mode: 0644]
StraySrc/gplnote/c [new file with mode: 0644]
StraySrc/ssr-init,feb [new file with mode: 0644]
StraySrc/ssr-order [new file with mode: 0644]
dist/README [new file with mode: 0644]

diff --git a/StraySrc/!DLLs/!Boot,feb b/StraySrc/!DLLs/!Boot,feb
new file mode 100644 (file)
index 0000000..68c2aac
--- /dev/null
@@ -0,0 +1,9 @@
+|
+| DLL repository !Boot file
+|
+| © 1994 Straylight
+|  Distribute as required
+|
+
+IconSprites <Obey$Dir>.!Sprites
+If "<DLL$Dir>"="" Then Run <Obey$Dir>.!Run
\ No newline at end of file
diff --git a/StraySrc/!DLLs/!Run,feb b/StraySrc/!DLLs/!Run,feb
new file mode 100644 (file)
index 0000000..7aa2c6a
--- /dev/null
@@ -0,0 +1,23 @@
+|
+| DLL repository !Run file
+|
+| © 1994 Straylight
+|  Distribute as required
+|
+
+| --- Allow slightly nicer access to our utilities ---
+
+Set DLL$Dir <Obey$Dir>
+Set Alias$_util /<DLL$Dir>.%%0 %%*1
+
+| --- Add the directories to our path ---
+
+_util hour -on
+IconSprites <DLL$Dir>.!Sprites
+Unset DLL$Path
+_util enumerate -nofiles <DLL$Dir> "_util pathUtil -create DLL$Path %%0."
+_util hour -off
+
+| --- Clear alias now we've finished ---
+
+Unset Alias$_util
diff --git a/StraySrc/!DLLs/!Sprites,ff9 b/StraySrc/!DLLs/!Sprites,ff9
new file mode 100644 (file)
index 0000000..e3cb75b
Binary files /dev/null and b/StraySrc/!DLLs/!Sprites,ff9 differ
diff --git a/StraySrc/!DLLs/!Sprites22,ff9 b/StraySrc/!DLLs/!Sprites22,ff9
new file mode 100644 (file)
index 0000000..8ff2ea0
Binary files /dev/null and b/StraySrc/!DLLs/!Sprites22,ff9 differ
diff --git a/StraySrc/Announce b/StraySrc/Announce
new file mode 100644 (file)
index 0000000..fe3c4a2
--- /dev/null
@@ -0,0 +1,152 @@
+The Straylight Source Distribution
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+For a long while now, I've been pontificating in comp.sys.acorn.programmer
+about how clever I am, and how I know how to do things properly.  Most
+of the regular readers should now be thinking something along the lines
+of `This [mdw] chap seems to know what he's doing, although I've never
+seen any of his work.  He's been going on about these libraries and
+things but we've never seen them or seen any software which uses them.
+It all seems a bit fishy.'  Well, now's my time to put my money where my
+mouth is.  Straylight is releasing all of its source code.  Well, the
+interesting bits.
+
+The next question ought to be `why?'  Why am I doing this?  Well, there
+are two reasons, although they're both associated with Linux.  The first
+reason is that I've `seen the light' of Free software, and want to do
+something about my heretical past as a Software Hoarder.  I want to give
+my small contribution to the world, as Freely as the GNU and Linux teams
+are doing.  And I want to show off a bit, too.  The second reason is
+that I'm not doing much Acorn work at all any more.  Akasha (my RiscPC)
+spends most of her time turned off now, in favour of Excessus (my Linux
+PC), and I don't have the time or the inclination to maintain this
+rather large chunk of source code any more, so I'm giving it all to the
+community which inspired it.  It feels slightly like a sort of a swan
+song as I leave the Acorn world.
+
+I'll be releasing the code in dribs and drabs over the coming weeks,
+hopefully in a sensible order, so that all the software can be built
+with the parts already available.  Unfortunately, most of it was never
+designed to be source distributed, so there's no guarantees against
+mutual dependencies.  We'll work it out as we go along, hopefully.  The
+main components are:
+
+  * Some simple header files and libraries for assembling the code, and
+    some trivial utilities used in the build processes.
+
+  * BAS -- the Basic Assembler Supplement, which allows Basic programs
+    to generate AOF object code.  This is required for some of the other
+    build tools.
+
+  * SDLS -- the Straylight Dynamic Linking System.  This is already well
+    known, but not well used, I think.  Maybe the sources will be
+    interesting to someone.
+
+  * Dynamite -- our dynamic-area heap manager module.  Again, well known
+    software, so maybe the sources will provide some interest.
+
+  * Sculptrix -- Straylight's 3D border rendering module.  I'm very
+    proud of this code.  Provided also is the source to version 1, which
+    was a horrible hack made worse by poor modifications.  Version 2
+    does more, at the same speed, in less space, and more maintainably.
+
+  * STEEL -- the Straylight Extensive Event-driven Library.  This is a
+    grandiose name for a RISC_OSLib more-or-less rewrite.  There are
+    Issues involved here, which I'll try to resolve -- some of the
+    source files aren't `pure' Straylight code, which could cause
+    problems.  I recommend against anyone using STEEL -- it's just
+    needed by Glass, which is a jolly good piece of software.
+
+  * Glass -- Straylight's template editor.  It's actually the second
+    template editor I've written, although I'm thoroughly ashamed of the
+    first one.  It's been around for ages, quietly circulating around a
+    slowly increasing coterie of friends.  I suspect many readers
+    already have copies of Glass they shouldn't have.  Well, as of this
+    announcement, those copies become legal.  I'd be interested in
+    hearing how far this informal distribution had reached.
+
+  * A pile of silly utilities.  There's a mouse speed changer which
+    tries to read the current speed using underhand methods (i.e.,
+    peeking around OS workspace).  There's a rudimentary debugger Tim
+    wrote which might be the start of something useful.
+
+  * Sprinkle -- a little module exactly 256 bytes long which supports
+    linked lists of sprite areas.
+
+  * Constrain -- constrain the mouse pointer to a circle.  This is used
+    in one of Sapphire's custom controls.
+
+  * Sapphire -- not an acronym, but a weak pun on STEEL.  This is
+    STEEL's successor.  It's a comprehensive (I think) run-time support
+    system and RISC OS library for applications written in assembler.
+
+    There are a number of bits of Sapphire which are incomplete:
+
+      -- There's a scripting language, SAIL, which is based on the work
+         Straylight did on the Termite language.  There may be
+         complications on this code.
+
+      -- There's an interface for C programs, but it's very messy.  Many
+         bits of Sapphire require more expressive syntax for declaring
+         data structures than C provides.
+
+      -- There was going to be a wonderful colour selector, but it never
+         really got finished.  The good bits in the current version are
+         the RGB selector window (which is fully functional -- the
+         RGB colour square custom control is my favourite bit) and the
+         HSV colour circle, with its circular mouse constraint.
+
+      -- The threading code needs to be rewritten, and the rest of the
+         library ought to be properly multithreaded or locked.
+
+    My favourite innovations are:
+
+      -- The way filters work in the event manager.  We never needed to
+         change the way events got dispatched, because we got it right
+         the first time.
+
+      -- Custom controls in the dialogue box system.  This one was my
+         idea.
+
+      -- The menu system.  I like the way the same menu blocks can be
+         used for normal and tearoff menus.  (We designed the system
+         together over a pub lunch, but Tim did all the implementation
+         so lots of kudos for him.)
+
+      -- The viewer code, and the background-redrawing gallery stuff.
+         This was mine, although Tim had already done the listbox code
+         on which it was based.
+
+    There are a lot of good ideas in here (in my expert opinion) and
+    some clever tricks too.  I think that anyone maintaining a RISC OS
+    library should look in here.  It is, I hope, like Glass: an example
+    of the benefits of the Second System Effect.
+
+  * Sapphire example programs.  There's a small number of these, to show
+    how we expected people to write Sapphire programs.  They're all
+    lovingly crafted and perfectly formed.  Oh, yes.
+
+Documentation for all of these is going to be patchy at best.  The
+libraries are sort-of documented by their header files, and by the
+examples provided.
+
+That's all there'll be.
+
+On the matter of licensing: I'll apply the GNU Library General Public
+License to as much as I can, and the full General Public License to
+everything else.  Software which is already OFFICIALLY available under a
+different licence may continue to be licenced under those terms;
+however, the existing licences only cover unmodified binaries, so if you
+make modifications to the software, you're bound by all the restrictions
+of the GPL.
+
+Well, thanks for taking the time to read all of this.  It's been great
+working with RISC OS, but I think I've been doing it for too long.  I'll
+still hang around Acorn newsgroups and flame people whom I think are
+being stupid.  I will keep porting to RISC OS in mind as I continue to
+write, but as far as developing specifically for Acorn is concerned,
+that's all you get.
+
+It's 10:30 at night, I'm cold, and I've been typing this for too long.
+Goodbye.  It's been great.
diff --git a/StraySrc/BuildTools b/StraySrc/BuildTools
new file mode 100644 (file)
index 0000000..43c09eb
--- /dev/null
@@ -0,0 +1,49 @@
+Build tools
+~~~~~~~~~~~
+
+Apart from the tools provided, you'll need the following programs to
+build the Straylight Source Release:
+
+cc             Acorn's C compiler
+objasm         Acorn's ARM assembler
+link           Acorn's linker
+libfile                Acorn's archiver
+squeeze                Acorn's executable compresser
+amu            Acorn's rather nasty make utility
+ccrunch                A BASIC cruncher
+sed            GNU's stream editor
+
+I recommend using the C5 versions of these tools; some of the source
+files may require C5 versions, but I'm not sure.
+
+A few pieces of code were deliberately built using the C4 versions of
+various tools, to ensure compatibility with people developing for RISC
+OS 2.  For this reason, some of the Makefiles assume the presence of
+programs `o-cc', `o-objasm', `o-link' and `o-libfile'; these are assumed
+to be the earlier versions.  If you only have one version of the
+compiler, assembler and tools, you can set aliases to make the
+`o-'-prefixed versions run the non-prefixed ones.
+
+The STEEL library may require bits of RISC_OSLib.  You won't be able to
+build STEEL or the programs which use it without RISC_OSLib.
+
+Everything else ought to be provided in the package.  There are a
+collection of strange tools we've created to help build our programs,
+and a few more written specially for this source release:
+
+buildstub      Builds Sapphire extension stubs
+enumerate      Run a *command for each file in a directory
+fixlink                Patches partially linked AOF files because link 4.00 is
+                       buggy
+hour           Hourglass control from Obey files
+inst           Install programs once they've been built
+msgaof         Compile a message file to linkable AOF
+pathutil       Manipulate path variables properly
+resgen         Tool for building DLLs containing shared resources
+setdate                Stamp the current date into an AOF file
+setslot                A replacement for *WimpSlot which understands flex
+ssrclean       Delete a lot of files at once
+submake                Tool for making recursive makes work
+templaof       Convert a template file into an embedded templates
+test           Test conditions in Obey files
+
diff --git a/StraySrc/COPYING b/StraySrc/COPYING
new file mode 100644 (file)
index 0000000..916d1f0
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/StraySrc/Dynamite/Makefile,fe1 b/StraySrc/Dynamite/Makefile,fe1
new file mode 100644 (file)
index 0000000..e362d22
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all:
+       submake *.Makefile
+
+install:
+       submake *.Makefile -- install
+
+clean:
+       submake *.Makefile -- clean
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/Dynamite/apcs/Makefile,fe1 b/StraySrc/Dynamite/apcs/Makefile,fe1
new file mode 100644 (file)
index 0000000..d557229
--- /dev/null
@@ -0,0 +1,105 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: o.dynamite
+
+o.dynamite: o.dyn_apcs
+       $(AR) -c o.dynamite o.dyn_apcs
+
+install: o.dynamite
+
+clean:
+       -$(RM) o.*
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.dyn_apcs: s.dyn_apcs
+o.dyn_apcs: libs:header
+o.dyn_apcs: libs:swis
+o.dyn_apcs: libs:stream
diff --git a/StraySrc/Dynamite/apcs/h/dynamite b/StraySrc/Dynamite/apcs/h/dynamite
new file mode 100644 (file)
index 0000000..7eb8c1a
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * dynamite.h
+ *
+ * Interface to Dynamite SWIs
+ *
+ * © 1997 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamite
+ *
+ * Dynamite is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Dynamite is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Dynamite.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __dynamite_h
+#define __dynamite_h
+
+/*----- Notes -------------------------------------------------------------*
+ *
+ * The interfaces to Dynamite have been written in assembler.  This has the
+ * benefit of making them very small and minimising procedure call overhead.
+ * It also has the disadvantage of not setting _kernel_last_oserror()
+ * properly.  If this is important, you should use _kernel_swi() directly.
+ *
+ * The SWI interface routines are safe to call from SVC mode (e.g. in a
+ * C module).
+ */
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*------ Important types --------------------------------------------------*/
+
+/* --- dynamite_anchor --- *
+ *
+ * This is the type of a Dynamite anchor.  It should only be used within
+ * these declarations, since it exists to keep the compiler happy and make
+ * the declarations look neat.  Your actual anchors will have various types
+ * depending on what you want to store in your Dynamite blocks.
+ *
+ * To avoid casts, we cheat horridly, and in the knowledge that we will only
+ * be dealing with the *address* of an anchor we macro dynamite_anchor to
+ * void, so that its address is a void *.
+ */
+
+#define dynamite_anchor void
+
+/* --- dynamite_error --- *
+ *
+ * This is the type of error which Dynamite SWIs return.  Depending on
+ * whether you're using RISC_OSLib or not, you may want these to return
+ * os_errors or _kernel_oserrors, or its own special type.  All these error
+ * structures have the same format and member names -- it's just a matter of
+ * naming the structure.
+ *
+ * The way we sort all this out is by allowing the client to set up a macro
+ * to tell us what to do.
+ */
+
+#if defined(dynamite_USE_OS_ERROR)
+
+  #ifndef __os_h
+    #include "os.h"
+  #endif
+
+  typedef os_error dynamite_error;
+
+#elif defined(dynamite_USE_KERNEL_OSERROR)
+
+  #ifndef __kernel_h
+    #include "kernel.h"
+  #endif
+
+  typedef _kernel_oserror dynamite_error;
+
+#elif !defined(dynamite_error)
+
+  typedef struct dynamite_error
+  {
+    int errnum;                         /* Error number */
+    char errmess[252];                  /* Error message text */
+  }
+  dynamite_error;
+
+#endif
+
+/* --- dynstr_blockInfo --- *
+ *
+ * This structure contains the information dynamite_blockInfo() returns.
+ */
+
+typedef struct dynstr_blockInfo
+{
+  int size;                             /* Block size in bytes */
+  int blockID;                          /* Block's ID number */
+}
+dynstr_blockInfo;
+
+/* --- dynstr_describe --- *
+ *
+ * This structure contains the information dynamite_describe() returns.
+ */
+
+typedef struct dynstr_describe
+{
+  int area;                             /* Dynamic area handle, or -1 */
+  int size;                             /* Total size of Dynamite area */
+  int unused;                           /* Space unused in Dynamite area */
+}
+dynstr_describe;
+
+/*----- Interface functions -----------------------------------------------*
+ *
+ * Most of these return a pointer to a dynamite_error structure.  If the
+ * call was successful, this pointer will be null.
+ *
+ * However, where errors are unlikely and a value return is more natural,
+ * this is not the case.
+ *
+ * To check for the existance of Dynamite you should check the return value
+ * of dynamite_describe() for an error.
+ */
+
+/* --- dynamite_alloc --- *
+ *
+ * Arguments:   anchor == address of the anchor to use
+ *              size == the size to allocate, in bytes
+ *              id == the id value to give to the block
+ *
+ * Returns:     Pointer to possible error
+ *
+ * Use:         Allocates memory from the Dynamite heap.  If successful,
+ *              *anchor on exit contains the address of the block allocated.
+ *              Note that the anchor must *not* be in application space --
+ *              use dynamite_claimAnchor to get one from the RMA if you
+ *              don't have other RMA data.
+ */
+
+extern dynamite_error *dynamite_alloc(dynamite_anchor */*anchor*/,
+                                      int /*size*/,
+                                      int /*id*/);
+
+/* --- dynamite_free --- *
+ *
+ * Arguments:   anchor == the address of block's anchor
+ *
+ * Returns:     Pointer to possible error
+ *
+ * Use:         Frees memory in the Dynamite heap.  The memory is marked
+ *              as being free, but no blocks are moved -- this makes freeing
+ *              lots of blocks very fast.
+ */
+
+extern dynamite_error *dynamite_free(dynamite_anchor */*anchor*/);
+
+/* --- dynamite_freeWithID --- *
+ *
+ * Arguments:   id == the ID of the blocks to free
+ *
+ * Returns:     Pointer to possible error
+ *
+ * Use:         Frees all blocks with the given ID value.  This allows
+ *              applications and modules to free all their allocated blocks
+ *              when they close down.
+ */
+
+extern dynamite_error *dynamite_freeWithID(int /*id*/);
+
+/* --- dynamite_blockInfo --- *
+ *
+ * Arguments:   anchor == address of block's anchor
+ *              info == address of structure to fill in
+ *
+ * Returns:     Pointer to possible error
+ *
+ * Use:         Returns information about a Dynamite block.
+ */
+
+extern dynamite_error *dynamite_blockInfo(dynamite_anchor */*anchor*/,
+                                          dynstr_blockInfo */*info*/);
+
+/* --- dynamite_changeID --- *
+ *
+ * Arguments:   anchor == address of block's anchor, or 0 for all blocks
+ *              newID == new ID to set for block or blocks
+ *              oldID == optional old ID of blocks to change, if anchor == 0
+ *
+ * Returns:     Pointer to possible error
+ *
+ * Use:         Changes the ID of a block or blocks.  If you specify a single
+ *              block by passing a nonzero anchor, you don't have to specify
+ *              an oldID value.
+ */
+
+extern dynamite_error *dynamite_changeID(dynamite_anchor */*anchor*/,
+                                         int /*newID*/,...
+                                      /* int oldID */);
+
+/* --- dynamite_resize --- *
+ *
+ * Arguments:   anchor == address of block's anchor
+ *              size == new size to make block
+ *
+ * Returns:     Pointer to possible error
+ *
+ * Use:         Changes a block's size.  If you make the block larger, the
+ *              data will be unchanged.  If you reduce the size, data at the
+ *              end will be deleted.  The block will usually move as a
+ *              result of this operation.
+ */
+
+extern dynamite_error *dynamite_resize(dynamite_anchor */*anchor*/,
+                                       int /*size*/);
+
+/* --- dynamite_midExtend --- *
+ *
+ * Arguments:   anchor == address of block's anchor
+ *              at == offset within block at which to insert or remove bytes
+ *              by == (signed) number of bytes to insert
+ *
+ * Returns:     Pointer to possible error
+ *
+ * Use:         Inserts or removes bytes in a block at a given offset.
+ *              See the manual for a complete description of this call.
+ */
+
+extern dynamite_error *dynamite_midExtend(dynamite_anchor */*anchor*/,
+                                          int /*at*/,
+                                          int /*by*/);
+
+/* --- dynamite_save --- *
+ *
+ * Arguments:   value == value to save on the relocation stack
+ *
+ * Returns:     Pointer to possible error
+ *
+ * Use:         Saves a value on the Dynamite relocation stack.  You can
+ *              only save one value at a time through this interface.
+ */
+
+extern dynamite_error *dynamite_save(void */*value*/);
+
+/* --- dynamite_load --- *
+ *
+ * Arguments:   --
+ *
+ * Returns:     The value from the top of the relocation stack.
+ *
+ * Use:         Loads a value from Dynamite's relocation stack and returns
+ *              it.  You can only restore one value at a time through this
+ *              interface.
+ */
+
+extern void *dynamite_load(void);
+
+/* --- dynamite_reduce --- *
+ *
+ * Arguments:   --
+ *
+ * Returns:     0 if heap couldn't be compacted, non-0 if it could
+ *
+ * Use:         Performs a partial compaction of the Dynamite heap.
+ */
+
+extern int dynamite_reduce(void);
+
+/* --- dynamite_compact --- *
+ *
+ * Arguments:   --
+ *
+ * Returns:     Pointer to possible error.
+ *
+ * Use:         Fully compacts the Dynamite heap.  This is equivalent to
+ *
+ *                while (dynamite_reduce())
+ *                  ;
+ */
+
+extern dynamite_error *dynamite_compact(void);
+
+/* --- dynamite_lock --- *
+ *
+ * Arguments:   --
+ *
+ * Returns:     Pointer to a possible error
+ *
+ * Use:         Locks the heap, stopping any blocks not explicitly resized
+ *              from being moved -- this basically just disables compaction.
+ *              You *must* lock the heap while it is being used within a
+ *              callback or SWI handler.
+ */
+
+extern dynamite_error *dynamite_lock(void);
+
+/* --- dynamite_unlock --- *
+ *
+ * Arguments:   --
+ *
+ * Returns:     Pointer to a possible error
+ *
+ * Use:         Unlocks the heap, allowing compaction to take place again.
+ */
+
+extern dynamite_error *dynamite_unlock(void);
+
+/* --- dynamite_claimAnchor --- *
+ *
+ * Arguments:   ancptr == where to store the address of the anchor
+ *
+ * Returns:     Pointer to a possible error
+ *
+ * Use:         Allocates an anchor from the RMA and returns its address.
+ */
+
+extern dynamite_error *dynamite_claimAnchor(dynamite_anchor **/*ancptr*/);
+
+/* --- dynamite_releaseAnchor --- *
+ *
+ * Arguments:   anchor == address of anchor to release
+ *
+ * Returns:     Pointer to possible error
+ *
+ * Use:         Frees an anchor allocated by dynamite_claimAnchor.
+ */
+
+extern dynamite_error *dynamite_releaseAnchor(dynamite_anchor */*anchor*/);
+
+/* --- dynamite_readSpriteSize --- *
+ *
+ * Arguments:   --
+ *
+ * Returns:     Actual size of sprite area in bytes
+ *
+ * Use:         Returns the real size of the sprite area -- before RISC OS
+ *              3.5, Dynamite has to fake the return value from
+ *              OS_ReadDynamicArea so that you can no longer work out how
+ *              much memory is free in the system.  This call allows you
+ *              to find the real sprite area size.
+ */
+
+extern int dynamite_readSpriteSize(void);
+
+/* --- dynamite_describe --- *
+ *
+ * Arguments:   desc == address of structure to fill in, or 0
+ *
+ * Returns:     Pointer to possible error
+ *
+ * Use:         If desc is nonzero, this call will read some useful
+ *              information about the Dynamite heap.  If desc is 0, it will
+ *              return an error if Dynamite is not loaded -- you can
+ *              therefore test for Dynamite's presence.
+ */
+
+extern dynamite_error *dynamite_describe(dynstr_describe */*desc*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/StraySrc/Dynamite/apcs/s/dyn_apcs b/StraySrc/Dynamite/apcs/s/dyn_apcs
new file mode 100644 (file)
index 0000000..02021d5
--- /dev/null
@@ -0,0 +1,282 @@
+;
+; dyn_apcs.s
+;
+; APCS interface to Dynamite SWIs
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamite
+;
+; Dynamite is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Dynamite is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Dynamite.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |C$$Code|,CODE,READONLY
+
+; --- dynamite_alloc ---
+;
+; On entry:    a1 == address of anchor
+;              a2 == size of block, in bytes
+;              a3 == block ID
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_alloc
+dynamite_alloc
+               MOV     ip,lr
+               SWI     XDynamite_Alloc
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_free ---
+;
+; On entry:    a1 == address of anchor
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_free
+dynamite_free
+               MOV     ip,lr
+               SWI     XDynamite_Free
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_freeWithID ---
+;
+; On entry:    a1 == block ID (must be non-zero)
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_freeWithID
+dynamite_freeWithID
+               MOV     ip,lr
+               SWI     XDynamite_FreeWithID
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_blockInfo ---
+;
+; On entry:    a1 == address of block anchor
+;              a2 == address of structure to fill in
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_blockInfo
+dynamite_blockInfo
+               STMFD   sp!,{lr}
+               MOV     ip,a2
+               SWI     XDynamite_BlockInfo
+               STMVCIA ip,{a3,a4}
+               MOVVC   a1,#0
+               LDMFD   sp!,{pc}^
+
+; --- dynamite_changeID ---
+;
+; On entry:    a1 == address of anchor, or 0
+;              a2 == new ID
+;              a3 == (optional) old ID
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_changeID
+dynamite_changeID
+               MOV     ip,lr
+               SWI     XDynamite_ChangeID
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_resize ---
+;
+; On entry:    a1 == address of anchor
+;              a2 == new size, in bytes
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_resize
+dynamite_resize
+               MOV     ip,lr
+               SWI     XDynamite_Resize
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_midExtend ---
+;
+; On entry:    a1 == address of anchor
+;              a2 == offset at which to extend
+;              a3 == number of bytes to add
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_midExtend
+dynamite_midExtend
+               MOV     ip,lr
+               SWI     XDynamite_MidExtend
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_save ---
+;
+; On entry:    a1 == value to save
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_save
+dynamite_save
+               MOV     ip,lr
+               MOV     a2,a1
+               MOV     a1,#2
+               SWI     XDynamite_Save
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_load ---
+;
+; On entry:    --
+;
+; On exit:     a1 == value loaded from relocation stack
+
+               EXPORT  dynamite_load
+dynamite_load
+               MOV     ip,lr
+               MOV     a1,#1
+               SWI     XDynamite_Load
+               MOVS    pc,ip
+
+; --- dynamite_reduce ---
+;
+; On entry:    --
+;
+; On exit:     a1 == 0 if compaction not performed, nonzero otherwise
+
+               EXPORT  dynamite_reduce
+dynamite_reduce
+               MOV     ip,lr
+               SWI     XDynamite_Reduce
+               MOVCC   a1,#1
+               MOVCS   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_compact ---
+;
+; On entry:    --
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_compact
+dynamite_compact
+               MOV     ip,lr
+               SWI     XDynamite_Compact
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_lock ---
+;
+; On entry:    --
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_lock
+dynamite_lock
+               MOV     ip,lr
+               SWI     XDynamite_Lock
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_unlock ---
+;
+; On entry:    --
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_unlock
+dynamite_unlock
+               MOV     ip,lr
+               SWI     XDynamite_Unlock
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_claimAnchor ---
+;
+; On entry:    a1 == address of where to store anchor
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_claimAnchor
+dynamite_claimAnchor
+               MOV     ip,lr
+               MOV     a2,a1
+               SWI     XDynamite_ClaimAnchor
+               STRVC   a1,[a2,#0]
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_releaseAnchor ---
+;
+; On entry:    a1 == address of anchor
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_releaseAnchor
+dynamite_releaseAnchor
+               MOV     ip,lr
+               SWI     XDynamite_ReleaseAnchor
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_readSpriteSize ---
+;
+; On entry:    a1 == where to store the sprite size
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_readSpriteSize
+dynamite_readSpriteSize
+               MOV     ip,lr
+               MOV     a2,a1
+               SWI     XDynamite_ReadSpriteSize
+               STRVC   a1,[a2,#0]
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; --- dynamite_describe ---
+;
+; On entry:    a1 == address of a structure to fill in
+;
+; On exit:     a1 == 0 or pointer to error
+
+               EXPORT  dynamite_describe
+dynamite_describe
+               MOV     ip,lr
+               MOV     a4,a1
+               SWI     XDynamite_Describe
+               MOVVS   pc,ip
+               CMP     a4,#0
+               STMNEIA a4,{a1-a3}
+               MOV     a1,#0
+               MOVS    pc,ip
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/Makefile,fe1 b/StraySrc/Dynamite/dynamite/Makefile,fe1
new file mode 100644 (file)
index 0000000..7f5d72d
--- /dev/null
@@ -0,0 +1,183 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+OBJS = \
+       o.dynamite \
+       o.dynAnchor o.dynArea o.dynHeap o.dynTask o.fastMove \
+       o.messages
+
+#----- Compiling things -----------------------------------------------------
+
+all: Dynamite
+
+Dynamite: $(OBJS)
+       $(SETDATE) o.version version="Dynamite\t1.21 ($(MODDATE)) $(CRIGHT)"
+       $(LD_MOD) $(OBJS) o.version
+       $(SET_MOD)
+
+o.messages: rsc.messages
+       msgaof rsc.messages o.messages sh.messages
+
+install: Dynamite
+       $(INSTALL) Dynamite <SSR$ModDir>
+
+clean:
+       -$(RM) o.* Dynamite
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.dynamite: s.dynamite
+o.dynamite: libs:header
+o.dynamite: libs:swis
+o.dynamite: libs:stream
+o.dynamite: sh.dynAnchor
+o.dynamite: sh.dynArea
+o.dynamite: sh.dynHeap
+o.dynamite: sh.dynTask
+o.dynamite: sh.wSpace
+o.dynamite: sh.messages
+o.dynamite: s.dynamite
+o.dynamite: libs:header
+o.dynamite: libs:swis
+o.dynamite: libs:stream
+o.dynamite: sh.dynAnchor
+o.dynamite: sh.dynArea
+o.dynamite: sh.dynHeap
+o.dynamite: sh.dynTask
+o.dynamite: sh.wSpace
+o.dynamite: sh.messages
+o.dynamite: s.dynamite
+o.dynamite: libs:header
+o.dynamite: libs:swis
+o.dynamite: libs:stream
+o.dynamite: sh.dynAnchor
+o.dynamite: sh.dynArea
+o.dynamite: sh.dynHeap
+o.dynamite: sh.dynTask
+o.dynamite: sh.wSpace
+o.dynamite: sh.messages
+o.dynamite: s.dynamite
+o.dynamite: libs:header
+o.dynamite: libs:swis
+o.dynamite: libs:stream
+o.dynamite: sh.dynAnchor
+o.dynamite: sh.dynArea
+o.dynamite: sh.dynHeap
+o.dynamite: sh.dynTask
+o.dynamite: sh.wSpace
+o.dynamite: sh.messages
+o.dynAnchor: s.dynAnchor
+o.dynAnchor: libs:header
+o.dynAnchor: libs:swis
+o.dynAnchor: sh.wSpace
+o.dynArea: s.dynArea
+o.dynArea: libs:header
+o.dynArea: libs:swis
+o.dynArea: libs:stream
+o.dynArea: sh.wSpace
+o.dynHeap: s.dynHeap
+o.dynHeap: libs:header
+o.dynHeap: libs:swis
+o.dynHeap: libs:stream
+o.dynHeap: libs:sh.fastMove
+o.dynHeap: sh.dynArea
+o.dynHeap: sh.dynTask
+o.dynHeap: sh.wSpace
+o.dynHeap: sh.messages
+o.dynTask: s.dynTask
+o.dynTask: libs:header
+o.dynTask: libs:swis
+o.dynTask: libs:stream
+o.dynTask: sh.dynHeap
+o.dynTask: sh.wSpace
+o.dynTask: sh.messages
+o.fastMove: s.fastMove
+o.fastMove: libs:s.fastMove
+o.fastMove: libs:header
+o.fastMove: libs:swis
diff --git a/StraySrc/Dynamite/dynamite/rsc/messages b/StraySrc/Dynamite/dynamite/rsc/messages
new file mode 100644 (file)
index 0000000..3bfa575
--- /dev/null
@@ -0,0 +1,82 @@
+;
+; Dynamite messages
+;
+; © 1995 Straylight
+;
+
+;----- Miscellaneous messages -----------------------------------------------
+
+; --- Heap dump messages ---
+
+dumpHpBase: Heap base: &
+dumpHpSize: Heap size: &
+dumpHpArSz: Area size: &
+
+dumpBlkAddr:Block address: &
+dumpBlkSize:Block size   : &
+dumpBlkId:  Block ID     : &
+dumpBlkAnch:Block anchor : &
+dumpBlkFree:Block is free<&0D><&0A>
+
+;----- Error messages -------------------------------------------------------
+
+; --- Finalisation errors ---
+
+errInUse:[1]Dynamite is in use and cannot close down
+errRelease:[1]Dynamite cannot close down (couldn't release vector)
+
+; --- ChangeDynamicArea patch errors ---
+
+errTooBig:[&1C1]Unable to move memory
+
+; --- SWI handling errors ---
+
+errBadSWI:[&1E6]Unknown Dynamite operation
+
+; --- Page manager errors ---
+
+errNoPages:[1]No pages left
+
+; --- Heap manager errors ---
+
+errBadFreeAll:[&80D310]Can't free all blocks with ID 0
+errBadAnchor:[&80D301]Bad anchor passed to Dynamite
+errNoMem:[&80D300]Couldn't allocate memory
+errBadMid:[&80D302]Bad arguments passed to Dynamite_(Mid)Extend
+
+; --- Heap integrity errors ---
+
+errBadHeap1:[&80D312]Dynamite area corrupt: anchor or anchor address corrupted
+errBadHeap2:[&80D312]Dynamite area corrupt: block length corrupted
+errBadHeap3:[&80D312]Dynamite area corrupt: anchor address corrupted
+
+; --- Compactor task errors ---
+
+errDesk:[1]Use *Desktop to start the Dynamite compactor
+
+;----- Command help and syntax strings --------------------------------------
+
+clear:{
+  *Dynamite_Clear will empty the Dynamite heap, releasing all the \
+  memory it was using.
+  Warning: No confirmation is requested; if applications are using \
+  Dynaite, they will almost certainly crash.
+  |
+  Syntax: *Dynamite_Clear\
+}
+
+compactor:{
+  The DynamiteCompactor task performs background compaction on the \
+  Dynamite heap, reducing the amount of memory the area uses.
+  Do not use *Desktop_DynamiteCompactor; use *Desktop instead.
+  |
+  Syntax: *Desktop_DynamiteCompactor\
+}
+
+heapDump:{
+  *Dynamite_HeapDump displays diagnostic information about the state of \
+  Dynamite's memory area.  This information may be of use to programmers \
+  debugging applications which use Dynamite.
+  |
+  Syntax: *Dynamite_HeapDump\
+}
diff --git a/StraySrc/Dynamite/dynamite/s/dynAnchor b/StraySrc/Dynamite/dynamite/s/dynAnchor
new file mode 100644 (file)
index 0000000..e429dbe
--- /dev/null
@@ -0,0 +1,146 @@
+;
+; dynAnchor.s
+;
+; Useful handle RMA allocation for dynamite
+;
+; © 1994-1998 Straylight
+;
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamite
+;
+; Dynamite is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Dynamite is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Dynamite.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.wSpace
+
+;----- Constants ------------------------------------------------------------
+
+danc__chunk    EQU     16                      ;Number of handles to get
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Dynamite$$Code|,CODE,READONLY
+
+; --- danc_alloc ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to block allocated, or V set and pointer to
+;                    error
+;
+; Use:         Allocates an anchor to use with dynamite from the RMA,
+;              in a very quick way indeed.
+
+               EXPORT  danc_alloc
+danc_alloc     ROUT
+
+               STMFD   R13!,{R1-R3,R14}
+
+               ; --- Are there any free blocks? ---
+
+               LDR     R2,dyn_ancTable         ;Get the free list offset
+               CMP     R2,#0                   ;Are there any free blocks?
+               BEQ     %01danc_alloc           ;No -- better allocate some
+
+               ; --- Mess about with the free list and return ---
+
+00danc_alloc   LDR     R3,[R2]                 ;Get next pointer from block
+               STR     R3,dyn_ancTable         ;This is now first free block
+               MOV     R0,R2                   ;Point to the block
+               LDMFD   R13!,{R1-R3,PC}^        ;Restore registers and return
+
+               ; --- Create a big block ---
+
+01danc_alloc   MOV     R0,#6                   ;Allocate memory please
+               MOV     R3,#danc__chunk*4+4     ;Get the chunk size
+               SWI     XOS_Module              ;Allocate the big block then
+               LDMVSFD R13!,{R1-R3,PC}         ;If it failed, return error
+
+               LDR     R14,dyn_ancList         ;Load current list head
+               STR     R2,dyn_ancList          ;Save this as new list head
+               STR     R14,[R2],#4             ;And save old list head
+
+               ; --- Now set up the links for the free list ---
+
+               MOV     R0,#0                   ;Next free pointer start at 0
+               SUB     R3,R3,#8                ;Offset to next field of sub
+02danc_alloc   STR     R0,[R2,R3]              ;Store in next field
+               ADD     R0,R2,R3                ;Point to that block
+               SUBS    R3,R3,#4                ;Point to previous block
+               BGE     %02danc_alloc           ;If more to do, continue...
+
+               ; --- The links are set up -- now take off a block ---
+
+               B       %00danc_alloc           ;Then allocate as normal
+
+               LTORG
+
+; --- danc_free ---
+;
+; On entry:    R0 == pointer to block
+;
+; On exit:     Registers preserved
+;
+; Use:         Frees an anchor allocated using danc_alloc.
+
+               EXPORT  danc_free
+danc_free      ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Preserve registers
+
+               ; --- Mess about with the list ---
+
+               LDR     R1,dyn_ancTable         ;Get current first block
+               STR     R1,[R0]                 ;Store in newly freed block
+               STR     R0,dyn_ancTable         ;And insert new block in list
+               LDMFD   R13!,{R0,R1,PC}^        ;Oh, and return to caller
+
+               LTORG
+
+; --- danc_quit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Frees everyone's anchors nicely when the module quits.
+
+               EXPORT  danc_quit
+danc_quit      ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               LDR     R2,dyn_ancList          ;Load the list head
+               CMP     R2,#0                   ;Is there anything to do?
+               LDMEQFD R13!,{R0-R2,PC}^        ;No -- return then
+               MOV     R0,#7                   ;Free RMA block
+00danc_quit    LDR     R1,[R2,#0]              ;Load the next pointer
+               SWI     XOS_Module              ;Free the block
+               MOVS    R2,R1                   ;Point to next one
+               BNE     %00danc_quit            ;And loop round for more
+               LDMFD   R13!,{R0-R2,PC}^        ;Return when all done
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/s/dynArea b/StraySrc/Dynamite/dynamite/s/dynArea
new file mode 100644 (file)
index 0000000..3eaf733
--- /dev/null
@@ -0,0 +1,325 @@
+;
+; dynArea.s
+;
+; The handling of the dynamic area itself
+;
+; © 1994-1998 Straylight
+;
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamite
+;
+; Dynamite is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Dynamite is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Dynamite.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.wSpace
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Dynamite$$Code|,CODE,READONLY
+
+; --- da_findPage ---
+;
+; On entry:    R2 == address of the page
+;
+; On exit:     R0 == page number
+;
+; Use:         Finds the page number of the page with the address given.
+
+               EXPORT  da_findPage
+da_findPage    ROUT
+
+               STMFD   R13!,{R1,R7-R9,R14}     ;Stack the link
+               LDR     R14,dyn_machine         ;Load the machine type
+               CMP     R14,#&A3                ;RISC OS 3?
+               BCS     %10da_findPage          ;Yes -- jump ahead then
+
+               LDR     R9,dyn_pageCount        ;Load number of pages-1
+               MOV     R14,#&164               ;Find CAM map (RO 2 and 3!)
+               ADD     R9,R14,R9,LSL #2        ;Last valid entry
+               MOV     R8,R2,LSL #4            ;The address of interest << 4
+               SUB     R7,R14,#4               ;We're pre-indexing
+00da_findPage  CMP     R7,R9                   ;Have we finished?
+               LDRNE   R1,[R7,#4]!             ;Load out the entry
+               TEQNE   R8,R1,LSL #4            ;Is this a match?
+               BNE     %00da_findPage          ;No -- keep on looking
+               TEQ     R8,R1,LSL #4            ;Was that a match?
+               SUBEQ   R7,R7,R14               ;Yes -- get offset from base
+               MOVEQ   R0,R7,LSR #2            ;And turn into page number
+               MOVNE   R0,#-1                  ;Otherwise return -1
+               LDMFD   R13!,{R1,R7-R9,PC}^     ;Return to caller
+
+               ; --- We are on RISC OS 3 ---
+
+10da_findPage  MOV     R1,#0                   ;Start at this page
+               MOV     R14,#-1                 ;Get a terminator
+               STMDB   R13!,{R1,R2,R3,R14}     ;Store that in block
+               MOV     R0,R13                  ;Point to the block
+               SWI     OS_FindMemMapEntries    ;Find the page number
+               LDR     R0,[R13],#16            ;Load the page number
+               LDMFD   R13!,{R1,R7-R9,PC}^     ;Return to caller
+
+               LTORG
+
+; --- da_addPages ---
+;
+; On entry:    R0 == number of pages to add
+;              R12 == workspace address
+;
+; On exit:     Possible error returned
+;
+; Use:         Increases the size of the dynamic area by the number of
+;              pages given in R0
+
+               EXPORT  da_addPages
+da_addPages    ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Save some registers
+
+               LDR     R9,dyn_machine          ;What machine are we on?
+               CMP     R9,#&A5                 ;Is it a RISC PC?
+               BGE     %50da_addPages          ;Yes -- do things differently
+
+               MOVS    R9,R0                   ;Remember this value
+               BEQ     %10da_addPages          ;Nothing to do -- return
+               LDR     R14,dyn_sprSize         ;Get address of spr area size
+               LDR     R14,[R14]               ;Get the size out
+               LDR     R1,dyn_areaSize         ;Find our area size
+               SUB     R4,R14,R1               ;Find top of system sprites
+               ADD     R2,R4,#&01400000        ;Top of sprite area
+
+               LDR     R3,dyn_log2PageSize     ;Find page size of machine
+               MOV     R5,R9,LSL R3            ;Find size in bytes
+               LDR     R3,dyn_pageSize         ;Find real page size
+               MOV     R1,R5                   ;We want this in R1 too
+               MOV     R0,#3                   ;Change sprite area size
+               SWI     XOS_ChangeDynamicArea   ;Yes... do it now!
+               BVS     %99da_addPages          ;Error -- return
+
+               ; --- Make sure system sprite size remains the same ---
+
+               MOV     R14,#&01400000          ;Get address of sprite area
+               STR     R4,[R14,#0]             ;Get system sprite size
+
+               ; --- Work out how big dynamite area is now ---
+
+               LDR     R14,dyn_areaSize        ;Get the previous size
+               RSB     R8,R14,#&01800000       ;Put new blocks here
+               ADD     R14,R14,R5              ;The new size
+               STR     R14,dyn_areaSize        ;Save this size back
+
+               ; --- Now we need to map up the area ---
+
+               SUB     R13,R13,#16             ;Get me a mem map block
+               MOV     R14,#0                  ;A nice 0 thing
+               STR     R14,[R13,#8]            ;Protection level
+               MOV     R14,#-1                 ;The terminator
+               STR     R14,[R13,#12]           ;Put that in the block
+00da_addPages  SUB     R8,R8,R3                ;Next page goes here
+               BL      da_findPage             ;Find page number of R2
+               STR     R0,[R13,#0]             ;Store the page number
+               STR     R8,[R13,#4]             ;Put that page here please
+               MOV     R0,R13                  ;Point to the block
+               SWI     XOS_SetMemMapEntries    ;Set mem map entries
+               SUBS    R9,R9,#1                ;Reduce page count
+               ADD     R2,R2,R3                ;Now move next page
+               BGT     %00da_addPages          ;Keep doing that then
+               ADD     R13,R13,#16             ;Get the block back
+
+               ; --- Phew! -- almost there ---
+
+               CMP     R4,#0                   ;Is there a sprite area?
+               MOVNE   R4,#&01400000           ;Yes -- get its address
+               MOV     R14,#&1000              ;VDU driver workspace
+               STR     R4,[R14,#1364]          ;And store as sprite area ptr
+
+10da_addPages  LDMFD   R13!,{R0-R9,PC}^        ;Return to caller
+
+               ; --- We are on a RISC PC ---
+
+50da_addPages  LDR     R1,dyn_log2PageSize     ;Get the log 2 page size
+               MOV     R1,R0,LSL R1            ;Work out increment
+               LDR     R0,dyn_areaHandle       ;Load the area handle
+               SWI     XOS_ChangeDynamicArea   ;And increase appropriately
+               LDRVC   R14,dyn_areaSize        ;Load the old area size
+               ADDVC   R14,R14,R1              ;Apply our increment to it
+               STRVC   R14,dyn_areaSize        ;And save it back again
+               LDMVCFD R13!,{R0-R9,PC}^        ;Return to caller
+
+99da_addPages  LDMFD   R13!,{R0-R9,R14}        ;Load back registers
+               ADR     R0,da__noMem            ;Point to error
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+da__noMem      DCD     1
+               DCB     "No pages left",0
+
+; --- da_removePages ---
+;
+; On entry:    R0 == number of pages to remove
+;
+; On exit:     --
+;
+; Use:         Removes the given number of pages from the dynamite
+;              area. If the number of pages to remove is greater than
+;              the actual number of pages allocated, as many as possible
+;              are removed
+
+               EXPORT  da_removePages
+da_removePages ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Stack some registers
+
+               LDR     R9,dyn_machine          ;What machine are we on?
+               CMP     R9,#&A5                 ;Is it a RISC PC?
+               BGE     %50da_removePages       ;Yes -- do things differently
+
+               MOV     R9,R0                   ;Remember this value
+               LDR     R8,dyn_areaSize         ;Get my area size
+               RSB     R2,R8,#&01800000        ;The lowest page
+
+               LDR     R5,dyn_log2PageSize     ;Get the page size
+               MOV     R7,R8,LSR R5            ;Number of dynamite pages
+               CMP     R9,R7                   ;Are we in range?
+               MOVGT   R9,R7                   ;No -- we are now
+               CMP     R9,#0                   ;Are we removing 0 pages?
+               BEQ     %99da_removePages       ;Yes -- return now
+
+               LDR     R14,dyn_sprSize         ;Get address of spr area size
+               LDR     R14,[R14]               ;Get the size out
+               LDR     R1,dyn_areaSize         ;Find our area size
+               SUB     R10,R14,R1              ;Find top of system sprites
+               ADD     R6,R10,#&01400000       ;Top of sprite area
+
+               SUB     R14,R8,R9,LSL R5        ;The new dynamite size
+               STR     R14,dyn_areaSize        ;Store this away nicely
+
+               ; --- Now we need to map down the area ---
+
+               LDR     R3,dyn_pageSize         ;Get the page size
+               MOV     R4,R9                   ;Look after the page count
+               SUB     R13,R13,#16             ;Get me a mem map block
+               MOV     R14,#0                  ;A nice 0 thing
+               STR     R14,[R13,#8]            ;Protection level
+               MOV     R14,#-1                 ;The terminator
+               STR     R14,[R13,#12]           ;Put that in the block
+00             BL      da_findPage             ;Find page number of R2
+               STR     R0,[R13,#0]             ;Store the page number
+               STR     R6,[R13,#4]             ;Put that page here please
+               MOV     R0,R13                  ;Point to the block
+               SWI     XOS_SetMemMapEntries    ;Set mem map entries
+               ADD     R2,R2,R3                ;Now move next page
+               ADD     R6,R6,R3                ;Put the next one here
+               SUBS    R9,R9,#1                ;Reduce page count
+               BGT     %00da_removePages       ;Keep doing that then
+               ADD     R13,R13,#16             ;Get the block back
+
+               CMP     R10,#0                  ;Was there an area before
+               BNE     %10da_removePages       ;Yes -- all ok then
+               LDR     R6,dyn_sprSize          ;Get address of spr area size
+               LDR     R6,[R6]                 ;Get the size out
+               MOV     R7,#0                   ;Sprite area header
+               MOV     R8,#16
+               MOV     R9,#16
+               MOV     R2,#&1400000            ;Point to sprite area
+               STMIA   R2,{R6-R9}              ;Store the header
+
+10             MOV     R1,R4,LSL R5            ;We reduce by this amount
+               RSB     R1,R1,#0                ;Make it negative
+               MOV     R0,#3                   ;Change sprite area size
+               SWI     XOS_ChangeDynamicArea   ;Remove those damn pages
+               B       %99da_removePages       ;Return to caller
+
+               ; --- We're on a RISC PC ---
+
+50             LDR     R1,dyn_log2PageSize     ;Get the log 2 page size
+               MOV     R1,R0,LSL R1            ;Work out increment
+               RSB     R1,R1,#0                ;Negate it nicely
+               LDR     R0,dyn_areaHandle       ;Load the area handle
+               SWI     XOS_ChangeDynamicArea   ;And increase appropriately
+               LDR     R14,dyn_areaSize        ;Load the current size
+               SUB     R14,R14,R1              ;How much was it altered by?
+               STR     R14,dyn_areaSize        ;And save that back
+
+99             LDMFD   R13!,{R0-R10,PC}^       ;Return to caller
+
+               LTORG
+
+
+; --- da_readSize ---
+;
+; On entry:    --
+;
+; On exit:     R0 == size of area
+;
+; Use:         Returns the size of the sprite area (including the
+;              dynamite area).
+
+               EXPORT  da_readSize
+da_readSize    ROUT
+
+               LDR     R0,dyn_machine          ;What machine are we on?
+               CMP     R0,#&A5                 ;Is it a RISC PC?
+               BGE     %50da_readSize          ;Yes -- do other things
+
+               LDR     R0,dyn_sprSize          ;Get spr area size pointer
+               LDR     R0,[R0,#0]              ;Load out the size
+               MOVS    PC,R14                  ;And return to caller
+
+               ; --- We're on a RISC PC ---
+
+50da_readSize  STMFD   R13!,{R1,R14}           ;Stack some registers
+               MOV     R0,#3                   ;Read size of sprite area
+               SWI     XOS_ReadDynamicArea     ;Read things out then
+               MOV     R0,R1                   ;Put size in R0
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- da_describe ---
+;
+; On entry:    --
+;
+; On exit:     R0 == dynamic area number (3 == sprite area)
+;              R1 == size of area
+;              R2 == total free in area
+;
+; Use:         Gives back som information on the dynamite area.
+
+               EXPORT  da_describe
+da_describe    ROUT
+
+               LDR     R0,dyn_machine          ;Load out the machine type
+               CMP     R0,#&A5                 ;Is it a RISC PC?
+               LDRGE   R0,dyn_areaHandle       ;Yes -- load dynamic area hnd
+               MOVLT   R0,#-1                  ;No -- return a silly value
+               LDR     R1,dyn_areaSize         ;Put area size in R1
+               LDR     R2,dyn_heapSize         ;And heap size in R2
+               SUB     R2,R1,R2                ;Get size of unused area
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/s/dynHeap b/StraySrc/Dynamite/dynamite/s/dynHeap
new file mode 100644 (file)
index 0000000..50e6e5f
--- /dev/null
@@ -0,0 +1,1198 @@
+;
+; dynHeap.s
+;
+; New heap management for Dynamite
+;
+; © 1994-1998 Straylight
+;
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamite
+;
+; Dynamite is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Dynamite is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Dynamite.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     libs:sh.fastMove
+
+               GET     sh.dynArea
+               GET     sh.dynTask
+               GET     sh.wSpace
+
+               GET     sh.messages
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         DIR     $reg
+$label         LDR     $reg,dyn_machine        ;Get the machine type
+               CMP     $reg,#&A5               ;Is it a RISC PC?
+               MEND
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Dynamite$$Code|,CODE,READONLY
+
+; --- dh_alloc ---
+;
+; On entry:    R0 == pointer to anchor
+;              R1 == size to allocate in bytes
+;              R2 == ID value to store
+;
+; On exit:     R0 and R1 preserved
+;              R2 == address of block allocated
+;
+; Use:         Allocates a block from the Dynamite heap.
+
+               EXPORT  dh_alloc
+dh_alloc       ROUT
+
+               STMFD   R13!,{R0,R1,R3,R14}     ;Save some registers
+               MOV     R3,R0                   ;Keep anchor pointer
+               ADD     R0,R1,#blk__oHead+15    ;Put size in R0...
+               BIC     R0,R0,#15               ;...after mangling suitably
+               BL      dh__ensure              ;Ensure the memory's there
+               BVS     %90dh_alloc             ;If not there, return error
+               STR     R1,[R0,#blk__size]      ;Save the size in there
+               STR     R3,[R0,#blk__anchor]    ;And the anchor address
+               STR     R2,[R0,#blk__id]        ;Oh, and the ID value
+               ADD     R2,R0,#blk__oHead       ;Return correct address
+               STR     R2,[R3,#0]              ;And save address in anchor
+               LDMFD   R13!,{R0,R1,R3,PC}^     ;And return to caller
+
+90dh_alloc     ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1,R3,R14}        ;Unstack some registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- dh_free ---
+;
+; On entry:    R0 == pointer to anchor of block to free
+;
+; On exit:     --
+;
+; Use:         Frees a Dynamite block.
+
+               EXPORT  dh_free
+dh_free                ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               BL      dh__checkAnchor         ;Make sure the anchor's OK
+               MOVVC   R14,#0                  ;If so, clear block's anchor
+               STRVC   R14,[R1,#blk__anchor]   ;Zero the anchor (R14==0 !!)
+               BLVC    dh__unCompact           ;Say the heap is uncompact
+               LDMFD   R13!,{R1,PC}            ;Return to caller
+
+               LTORG
+
+; --- dh_freeWithID ---
+;
+; On entry:    R0 == ID of all blocks to free
+;
+; On exit:     --
+;
+; Use:         Frees all allocated blocks with a given ID number.
+
+               EXPORT  dh_freeWithID
+dh_freeWithID  ROUT
+
+               CMP     R0,#0                   ;Is he trying to free ID 0?
+               ADREQL  R0,msg_errBadFreeAll    ;Yes -- that's an error
+               ORREQS  PC,R14,#V_flag          ;So return it to him
+
+               ; --- Do the freeing job ---
+               ;
+               ; We just tonk a 0 anchor over all blocks with a matching ID.
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               LDR     R2,dyn_heapSize         ;Load the current heap size
+               DIR     R14                     ;Is it RISC PC?
+               LDRGE   R1,dyn_areaBase         ;Yes -- load the area base
+               RSBLT   R1,R2,#&01800000        ;No -- find the base anyway
+               ADD     R2,R2,R1                ;Find the heap end address
+               MOV     R3,#0                   ;Haven't freed anything yet
+
+00dh_freeWithID        CMP     R1,R2                   ;Have we reached the end?
+               BGE     %10dh_freeWithID        ;Yes -- return then
+               LDR     R14,[R1,#blk__id]       ;Get the block's ID
+               SUBS    R14,R14,R0              ;Is it a match? (=> R14==0)
+               STREQ   R14,[R1,#blk__anchor]   ;Yes -- blank out the anchor
+               MOVEQ   R3,#1                   ;And remember we done this
+               LDR     R14,[R1,#blk__size]     ;Load this block's size
+               ADD     R14,R14,#blk__oHead+15  ;Add on the overhead size
+               BIC     R14,R14,#15             ;And align to granularity
+               ADD     R1,R1,R14               ;Move on to next block
+               B       %00dh_freeWithID        ;And go round again
+
+               ; --- We finished -- tidy up and return ---
+
+10dh_freeWithID        CMP     R3,#0                   ;Did we free anything?
+               BLNE    dh__unCompact           ;Yes -- then heap isn't tidy
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+; --- dh_blockInfo ---
+;
+; On entry:    R0 == address of block anchor
+;
+; On exit:     R0 preserved
+;              R1 == address of block
+;              R2 == size of block
+;              R3 == block ID
+;
+; Use:         Returns information about a Dynamite block
+
+               EXPORT  dh_blockInfo
+dh_blockInfo   ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+               BL      dh__checkAnchor         ;Make sure anchor is kosher
+               LDMVCIB R1,{R2,R3}              ;Yes -- load size and ID
+               ADDVC   R1,R1,#blk__oHead       ;Point to the block
+               LDMFD   R13!,{PC}               ;And return to caller
+
+               LTORG
+
+; --- dh_changeID ---
+;
+; On entry:    R0 == address of anchor block, or 0 for all
+;              R1 == new ID
+;              R2 == old ID (if R0 == 0)
+;
+; On exit:     --
+;
+; Use:         This call is use to change the ID of either an individual
+;              block (R0 == address of anchor), or the ID of all the
+;              blocks with the ID passed in R2 (if R0 == 0).
+
+               EXPORT  dh_changeID
+dh_changeID    ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+               CMP     R0,#0                   ;Just one block to change?
+               BEQ     %50dh_changeID          ;No -- jump ahead
+
+               ; --- Change the ID of a specific block ---
+
+               MOV     R2,R1                   ;Preserve the new ID
+               BL      dh__checkAnchor         ;Check the anchor
+               BVS     %99dh_changeID          ;It's garbish -- return error
+               STR     R2,[R1,#blk__id]        ;Store the new id
+               B       %98dh_changeID          ;And return to caller
+
+               ; --- Change the ID of all blocks with ID R2 ---
+
+50dh_changeID  LDR     R3,dyn_heapSize         ;Load the current heap size
+               DIR     R14                     ;Is it RISC PC?
+               LDRGE   R0,dyn_areaBase         ;Yes -- load the area base
+               RSBLT   R0,R3,#&01800000        ;No -- find the base anyway
+               ADD     R3,R3,R0                ;Find the heap end address
+
+60dh_changeID  CMP     R0,R3                   ;Have we reached the end?
+               BGE     %98dh_changeID          ;Yes -- return then
+               LDR     R14,[R0,#blk__id]       ;Get the id of this block
+               CMP     R14,R2                  ;Do we want to change it?
+               STREQ   R1,[R0,#blk__id]        ;Yes -- make it so then
+               LDR     R14,[R0,#blk__size]     ;Get the block size
+               ADD     R14,R14,#blk__oHead+15  ;Add on the block size
+               BIC     R14,R14,#15             ;And word align
+               ADD     R0,R0,R14               ;Point to the next block
+               B       %60dh_changeID          ;Keep on looking for blocks
+
+98dh_changeID  LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+99dh_changeID  ADD     R13,R13,#4              ;Don't unstack R0
+               LDMFD   R13!,{R1-R3,R14}        ;Get back registers
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- dh__checkAnchor ---
+;
+; On entry:    R0 == address of anchor to check
+;
+; On exit:     R1 == address of block descriptor
+;
+; Use:         Ensures that a given anchor is valid.
+
+dh__checkAnchor        ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+               LDR     R1,[R0,#0]              ;Load the block address
+               SUB     R1,R1,#blk__oHead       ;Point to our information
+               LDR     R14,[R1,#blk__anchor]   ;Load the block's anchor
+               CMP     R0,R14                  ;Do they match up?
+               ADRNEL  R0,msg_errBadAnchor     ;No -- point to error message
+               LDMFD   R13!,{R14}              ;Restore registers
+               BICEQS  PC,R14,#V_flag          ;Anchor OK -- clear V on exit
+               ORRNES  PC,R14,#V_flag          ;Anchor duff -- return error
+
+               LTORG
+
+; --- dh__ensure ---
+;
+; On entry:    R0 == number of bytes required (multiple of 16)
+;
+; On exit:     R0 == pointer to base of area allocated
+;
+; Use:         Ensures that there are R0 bytes available in the heap.  If
+;              there aren't R0 bytes available, it goes out of its way to
+;              ensure that there *are* by getting more.  If there still
+;              isn't enough, it compacts the heap and tries some more.
+
+dh__ensure     ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+               MOV     R1,R0                   ;Keep the size I want
+
+               ; --- Try to find some space among the free blocks ---
+
+               LDR     R3,dyn_heapSize         ;Load the current heap size
+               DIR     R14                     ;Is it RISC PC?
+               LDRGE   R2,dyn_areaBase         ;Yes -- load the area base
+               RSBLT   R2,R3,#&01800000        ;No -- find the base anyway
+               ADD     R3,R3,R2                ;Find the heap end address
+               MOV     R5,#0                   ;No bytes found yet
+
+00dh__ensure   CMP     R2,R3                   ;Is there more to go?
+               BGE     %05dh__ensure           ;No -- then extend the heap
+
+               LDR     R0,[R2,#blk__size]      ;Load this block's size
+               ADD     R0,R0,#blk__oHead+15    ;Add on the overhead size
+               BIC     R0,R0,#15               ;And align to granularity
+               LDR     R14,[R2,#blk__anchor]   ;Is the block free?
+               ADD     R2,R2,R0                ;Bump on block pointer
+               CMP     R14,#0                  ;If so, anchor==0
+               MOVNE   R5,#0                   ;If not, clear free size
+               BNE     %00dh__ensure           ;And loop round again
+
+               ; --- Found a free block ---
+
+               CMP     R5,#0                   ;Is there a free block size?
+               SUBEQ   R4,R2,R0                ;No -- this is the start then
+               ADD     R5,R5,R0                ;Add on the size of this blk
+               SUBS    R14,R5,R1               ;Is this big enough?
+               BLT     %00dh__ensure           ;No -- keep on round
+
+               ; --- Found a big enough space ---
+
+               BEQ     %03dh__ensure           ;If no leftover, skip on
+               ADD     R3,R4,R1                ;Point to bit left over
+               MOV     R0,#0                   ;This block is free
+               SUB     R2,R14,#blk__oHead      ;Subtract info overhead
+               STMIA   R3,{R0,R2}              ;Save this in the block
+
+               ; --- Return address of this memory ---
+
+03dh__ensure   MOV     R0,R4                   ;Point to the free block
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack registers
+               BICS    PC,R14,#V_flag          ;And clear error indicator
+
+               ; --- Main size ensuring loop ---
+
+05dh__ensure   LDR     R14,dyn_areaSize        ;Get the dynamic area size
+               LDR     R2,dyn_heapSize         ;And the size we're using
+               SUB     R3,R14,R2               ;How much do we have?
+               SUBS    R3,R1,R3                ;And is it enough?
+               BLE     %10dh__ensure           ;Yes -- skip onwards
+
+               ; --- Try to get some more pages ---
+
+               LDR     R14,dyn_pageSize        ;Load machine page size
+               SUB     R14,R14,#1              ;Subtract one -- round up
+               ADD     R3,R3,R14               ;Add it on for rounding
+               LDR     R4,dyn_log2PageSize     ;Load the page size log
+               MOV     R0,R3,LSR R4            ;How many do I need?
+               BL      da_addPages             ;Get some more
+               BVC     %10dh__ensure           ;It worked -- skip onwards
+
+               ; --- Hmm... -- try compacting the heap ---
+
+               BL      dh_compact              ;Try to compact the heap
+               BCC     %05dh__ensure           ;If it did, try again
+
+               ADRL    R0,msg_errNoMem         ;Point to the error
+               LDMFD   R13!,{R1-R5,R14}        ;Restore the registers
+               ORRS    PC,R14,#V_flag          ;And return to caller
+
+               ; --- Extend the heap and return the base address ---
+
+10dh__ensure   ADD     R14,R2,R1               ;Work out the new heap size
+               STR     R14,dyn_heapSize        ;Save this away for later
+               DIR     R0                      ;Get the heap's direcection
+               LDRGE   R0,dyn_areaBase         ;Yes -- load the area base
+               ADDGE   R0,R0,R2                ;And add the old heap size
+               RSBLT   R0,R14,#&01800000       ;Otherwise find the heap base
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack registers
+               BICS    PC,R14,#V_flag          ;And clear error indicator
+
+               LTORG
+
+; --- dh_reduce ---
+;
+; On entry:    --
+;
+; On exit:     CS if there was nothing we could do
+;
+; Use:         Tries to shunt the free space in the heap off the end and
+;              back into the operating system's free pool.  It does it a
+;              little bit and then stops, rather like those workmen on the
+;              M40.
+
+               EXPORT  dh_reduce
+dh_reduce      ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+               LDR     R14,dyn_hpFlags         ;Load the heap's flags
+               TST     R14,#hpFlag_tidy        ;Is the heap tidy?
+               LDREQ   R14,dyn_lockCount       ;No -- then load lock count
+               CMPEQ   R14,#0                  ;Is the heap locked?
+               BNE     %91dh_reduce            ;Yes -- then return CS now
+
+               ; --- Do search for free blocks ---
+
+               STMFD   R13!,{R0-R9}            ;Save some more registers
+               LDR     R1,dyn_heapSize         ;Load the current heap size
+               DIR     R14                     ;Is it RISC PC?
+               LDRGE   R5,dyn_areaBase         ;Yes -- load the area base
+               RSBLT   R5,R1,#&01800000        ;No -- find the base anyway
+               ADD     R1,R1,R5                ;Find the heap end address
+               MOV     R9,R5                   ;Remember heap base address
+
+               ; --- Find a free block ---
+
+               MOV     R7,#0                   ;No previous block
+00dh_reduce    CMP     R5,R1                   ;Are we at the end yet?
+               BGE     %04dh_reduce            ;Yes -- jump ahead a little
+
+               LDR     R2,[R5,#blk__anchor]    ;Get the block's anchor addr
+               CMP     R2,#0                   ;Is the block free?
+               LDR     R2,[R5,#blk__size]      ;Get the block size
+               ADD     R2,R2,#blk__oHead+15    ;Add on the overhead bytes
+               BIC     R2,R2,#15               ;And word align the size
+               MOVNE   R7,R5                   ;No -- remember where it is
+               ADDNE   R5,R5,R2                ;...move on to next one
+               BNE     %00dh_reduce            ;...go round for another one
+
+               ; --- We've found a free block ---
+
+01dh_reduce    ADD     R6,R5,R2                ;Point to the next block
+               CMP     R6,R1                   ;Is that the end of the heap?
+               MOVGE   R8,R7                   ;Yes -- set up prev pointer
+               SUBGE   R2,R2,#blk__oHead       ;...take off overhead
+               STRGE   R2,[R5,#blk__size]      ;...store overall block size
+               BGE     %04dh_reduce            ;...and jump ahead a little
+
+               ; --- Check for two free blocks together ---
+
+               LDR     R0,[R6,#blk__anchor]    ;Does this have an anchor?
+               CMP     R0,#0                   ;Check if it's free
+               SUBNE   R2,R2,#blk__oHead       ;Not -- take off overhead
+               STRNE   R2,[R5,#blk__size]      ;...store overall block size
+               BNE     %02dh_reduce            ;...jump ahead a little
+
+               ; --- Join two adjacent free blocks together ---
+
+               LDR     R0,[R6,#blk__size]      ;Yes -- get its size
+               ADD     R2,R0,R2                ;Concatenate the two blocks
+               ADD     R2,R2,#blk__oHead+15    ;Add on the overhead bytes
+               BIC     R2,R2,#15               ;And word align the size
+               B       %01dh_reduce            ;And check again...
+
+               ; --- We may be searching for the last block ---
+
+02dh_reduce
+               DIR     R14                     ;Get the heap direction
+               MOVLT   R5,R6                   ;Down -- point to next block
+               MOVLT   R8,R7                   ;...remember last block pos.
+               BLT     %00dh_reduce            ;...and keep on searching
+
+               ; --- There's a block to bring down ---
+
+               LDR     R4,[R6,#blk__size]      ;Get size of block to move
+               ADD     R4,R4,#blk__oHead+15    ;Add the flex overhead
+               BIC     R4,R4,#15               ;And word align the size
+               MOVS    R2,R4                   ;This is the size to move
+               MOV     R0,R5                   ;Where to move it to
+               MOV     R1,R6                   ;Where it is right now
+               BLNE    dh__move                ;Copy it down PDQ
+               ADD     R0,R5,R4                ;Point after block we moved
+               MOV     R1,#0                   ;Block doesn't have an anchor
+               STR     R1,[R0,#blk__anchor]    ;Store that away for later
+               SUB     R1,R6,R5                ;Find the difference here
+               SUB     R1,R1,#blk__oHead       ;Don't count this size here
+               STR     R1,[R0,#blk__size]      ;Store the old size in free
+
+               ; --- We need to fix up the block we moved ---
+
+               LDR     R0,[R5,#blk__anchor]    ;Get the anchor pointer
+               ADD     R1,R5,#blk__oHead       ;Point to the real data
+               STR     R1,[R0]                 ;Store client's new anchor
+
+               ; --- That's it -- return to caller ---
+
+               B       %10dh_reduce    ;Return to caller
+
+               ; --- We've reached the end of the heap ---
+               ;
+               ; Now things get a little more complicated:
+               ;
+               ; If the heap goes upwards, then there may be a free block
+               ; on the end that we can free (R5 < R1), otherwise the heap
+               ; is compacted.
+               ;
+               ; If the heap goes downwards, then R8 points to the block
+               ; immediately before the last free one. If R8 is 0, then
+               ; either the heap is compacted (the first block is not free)
+               ; or there is only on free block, and it's at the lower
+               ; end of the heap.
+
+04dh_reduce
+               DIR     R14                     ;Get the heap direction
+               BGE     %05dh_reduce            ;Upwards --  jump ahead
+
+               CMP     R8,#0                   ;Was there a previous block?
+               BNE     %07dh_reduce            ;Yes -- compact heap then
+
+               LDR     R14,[R9,#blk__anchor]   ;Get previous block anchor
+               CMP     R14,#0                  ;Is the first block free?
+               BNE     %90dh_reduce            ;No -- the heap is compacted
+
+               LDR     R14,[R9,#blk__size]     ;Get the size of the free blk
+               ADD     R14,R14,#blk__oHead+15  ;Add on the overhead
+               BIC     R14,R14,#15             ;And correctly align
+               ADD     R7,R9,R14               ;Point past the free block
+
+               LDR     R0,dyn_areaSize         ;Get the area size
+               RSB     R14,R0,#&01800000       ;Find the base address
+               SUB     R5,R7,R14               ;Get size of unsused area
+               SUB     R14,R0,R5               ;Get the area size left
+               STR     R14,dyn_heapSize        ;Store it away nicely
+               LDR     R14,dyn_log2PageSize    ;Get the log page size
+               MOVS    R0,R5,LSR R14           ;How many pages can we free?
+               BLNE    da_removePages          ;More than 0 -- free them
+               B       %20dh_reduce            ;Return to caller
+
+               ; --- Merge the last block with the free area ---
+
+05dh_reduce    CMP     R5,R1                   ;Had we reached the end?
+               BGE     %90dh_reduce            ;Yes -- heaps compact then
+
+               SUB     R14,R5,R9               ;Get the used area size
+               STR     R14,dyn_heapSize        ;And store it away
+               LDR     R0,dyn_pageSize         ;Get the machine page size
+               SUB     R0,R0,#1                ;Turn into a bitmask
+               ADD     R5,R5,R0                ;Align this to page boundary
+               BIC     R0,R5,R0                ;And finish off the align
+               LDR     R1,dyn_areaSize         ;Get the dyn area size
+               ADD     R1,R1,R9                ;Point to end of area
+               SUBS    R0,R1,R0                ;Are these different?
+               BEQ     %10dh_reduce            ;No -- return
+               LDR     R14,dyn_log2PageSize    ;Get the log page size
+               MOVS    R0,R0,LSR R14           ;How many pages can we free?
+               BLNE    da_removePages          ;More than 0 -- free them
+               B       %20dh_reduce            ;Return to caller
+
+               ; --- Move a block in a downwards heap ---
+
+07dh_reduce    LDR     R2,[R8,#blk__size]      ;Get size of block to move
+               ADD     R2,R2,#blk__oHead+15    ;Add the flex overhead
+               BIC     R2,R2,#15               ;And word align the size
+               ADD     R0,R8,R2                ;Point to the free block
+               LDR     R4,[R0,#blk__size]      ;Load out it's size
+               ADD     R14,R4,#blk__oHead+15   ;Add the flex overhead
+               BIC     R14,R14,#15             ;And word align the size
+               ADD     R0,R0,R14               ;Point to the end of the blk
+               SUB     R0,R0,R2                ;Copy the block to here
+               MOV     R1,R8                   ;Where it is right now
+               BLNE    dh__move                ;Copy it down PDQ
+               MOV     R1,#0                   ;Block doesn't have an anchor
+               STR     R1,[R8,#blk__anchor]    ;Store that away for later
+               STR     R4,[R8,#blk__size]      ;Store the old size in free
+
+               ; --- We need to fix up the block we moved ---
+
+               LDR     R14,[R0,#blk__anchor]   ;Get the anchor pointer
+               ADD     R0,R0,#blk__oHead       ;Point to the real data
+               STR     R0,[R14]                ;Store client's new anchor
+
+               ; --- That's it -- return ---
+
+10dh_reduce    LDMFD   R13!,{R0-R9,R14}        ;Load back registers
+               BICS    PC,R14,#C_flag          ;Return with C clear
+
+               ; --- There wasn't anything to do -- we're compacted ---
+
+20dh_reduce    LDR     R0,dyn_hpFlags          ;Load my flags
+               ORR     R0,R0,#hpFlag_tidy      ;We're compacted
+               STR     R0,dyn_hpFlags          ;Store back the flags
+               LDMFD   R13!,{R0-R9,R14}        ;Load back registers
+               BICS    PC,R14,#C_flag          ;Return with C clear
+
+               ; --- Nothing could be done ---
+
+90dh_reduce    LDMFD   R13!,{R0-R9}            ;Load back registers
+91dh_reduce    LDMFD   R13!,{R14}              ;And the link too
+               ORRS    PC,R14,#C_flag          ;Return with C set
+
+               LTORG
+
+; --- dh_compact ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Does a full compaction of the heap.
+
+               EXPORT  dh_compact
+dh_compact     ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               BL      dh_reduce               ;Try to reduce the heap
+               LDMCSFD R13!,{PC}               ;If it couldn't, return CS
+00dh_compact   BL      dh_reduce               ;Try to reduce the heap
+               BCC     %00dh_compact           ;Did something -- try again
+               LDMFD   R13!,{R14}              ;Return to caller...
+               BICS    PC,R14,#C_flag          ;... saying we did something
+
+               LTORG
+
+; --- dh__unCompact ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Marks the heap as being uncompact.
+
+dh__unCompact  ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               LDR     R14,dyn_hpFlags         ;Load the flags word
+               TST     R14,#hpFlag_tidy        ;Is the tidy bit on?
+               BICNE   R14,R14,#hpFlag_tidy    ;Clear the 'is tidy' bit
+               STRNE   R14,dyn_hpFlags         ;Store back the flags
+               BLNE    dt_message              ;Yes -- prod compactor
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- dh_lock ---
+;
+; On entry:    --
+;
+; On exit:     R10 corrupted (SWIs don't care about this)
+;
+; Use:         Locks the heap, so that compaction entirely fails to happen.
+
+               EXPORT  dh_lock
+dh_lock                ROUT
+
+               LDR     R10,dyn_lockCount       ;Load the old lock count
+               ADD     R10,R10,#1              ;Bump the counter a little
+               STR     R10,dyn_lockCount       ;Store the counter back
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- dh_unlock ---
+;
+; On entry:    --
+;
+; On exit:     R10 corrupted (SWIs don't care about this)
+;
+; Use:         Unlocks the heap, so that compaction can happen again, maybe.
+
+               EXPORT  dh_unlock
+dh_unlock      ROUT
+
+               LDR     R10,dyn_lockCount       ;Load the old lock count
+               SUBS    R10,R10,#1              ;Knock the counter down
+               STRGE   R10,dyn_lockCount       ;Store the counter back
+               BEQ     dt_message              ;If now enabled, signal task
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- dh_save ---
+;
+; On entry:    R0 == mask of registers to save
+;
+; On exit:     R10, R11 corrupted
+;
+; Use:         Saves a load of registers on the Dynamite relocation stack.
+;              The mask in R0 contains a bit set for each register to save:
+;              bit 3 set means save R3 etc.  Since this is a SWI, only
+;              R1-R9 can be saved on the stack.
+
+               EXPORT  dh_save
+dh_save                ROUT
+
+               ; --- StrongARM friendly version 1st October 1996 [mdw] ---
+
+               LDR     R10,dyn_stackPtr        ;Load the stack pointer
+
+               TST     R0,#&03F
+               BEQ     %f05
+               MOVS    R11,R0,LSL #31
+               STRCS   R1,[R10],#4
+               TST     R0,#&3FC
+               BEQ     %f00
+               MOVS    R11,R0,LSL #29
+               STRMI   R2,[R10],#4
+               STRCS   R3,[R10],#4
+               TST     R0,#&3F0
+               BEQ     %f00
+               MOVS    R11,R0,LSL #27
+               STRMI   R4,[R10],#4
+               STRCS   R5,[R10],#4
+               TST     R0,#&3C0
+               BEQ     %f00
+05             MOVS    R11,R0,LSL #25
+               STRMI   R6,[R10],#4
+               STRCS   R7,[R10],#4
+               MOVS    R11,R0,LSL #23
+               STRMI   R8,[R10],#4
+               STRCS   R9,[R10],#4
+00
+               STR     R10,dyn_stackPtr        ;Save stack pointer back
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- dh_load ---
+;
+; On entry:    R0 == mask of registers to load
+;
+; On exit:     R10, R11 corrupted
+;
+; Use:         Loads a load of registers on the Dynamite relocation stack.
+;              The mask in R0 contains a bit set for each register to load:
+;              bit 3 set means load R3 etc.  Since this is a SWI, only
+;              R1-R9 can be read from the stack.
+
+               EXPORT  dh_load
+dh_load                ROUT
+
+               ; --- StrongARM friendly version 1st October 1996 [mdw] ---
+
+               LDR     R10,dyn_stackPtr        ;Load the stack pointer
+
+               TST     R0,#&3F0
+               BEQ     %f05
+               MOVS    R11,R0,LSL #23
+               LDRCS   R9,[R10,#-4]!
+               LDRMI   R8,[R10,#-4]!
+               TST     R0,#&0FF
+               BEQ     %f00
+               MOVS    R11,R0,LSL #25
+               LDRCS   R7,[R10,#-4]!
+               LDRMI   R6,[R10,#-4]!
+               TST     R0,#&03F
+               BEQ     %f00
+               MOVS    R11,R0,LSL #27
+               LDRCS   R5,[R10,#-4]!
+               LDRMI   R4,[R10,#-4]!
+               TST     R0,#&00F
+               BEQ     %f00
+05             MOVS    R11,R0,LSL #29
+               LDRCS   R3,[R10,#-4]!
+               LDRMI   R2,[R10,#-4]!
+               MOVS    R11,R0,LSL #31
+               LDRCS   R1,[R10,#4]!
+00
+               STR     R10,dyn_stackPtr        ;Save stack pointer back
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- dh_extend ---
+;
+; On entry:    R0 == address of block anchor
+;              R1 == new size for block
+;
+; On exit:     R0 preserved
+;              R1 == address of block, may have moved
+;
+; Use:         Changes the size of a block.
+
+               EXPORT  dh_extend
+dh_extend      ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,R1                   ;Keep the size safe a while
+               BL      dh__checkAnchor         ;Make sure anchor's kosher
+               LDRVC   R1,[R1,#blk__size]      ;Load the size word nicely
+               SUBVC   R2,R2,R1                ;Get the `by' value I need
+               BLVC    dh_midExtend            ;Do the messing about
+               LDMFD   R13!,{R2,PC}            ;Return to caller
+
+               LTORG
+
+; --- dh_midExtend ---
+;
+; On entry:    R0 == address of block anchor
+;              R1 == byte offset from block start
+;              R2 == number of bytes to insert
+;
+; On exit:     R0 preserved
+;              R1 == address of block, may have moved
+;
+; Use:         Inserts or removes bytes at a given offset into a Dynamite
+;              heap block.
+
+               EXPORT  dh_midExtend
+dh_midExtend   ROUT
+
+               STMFD   R13!,{R0,R2-R9,R14}     ;Save some registers
+               MOV     R5,R0                   ;Keep the anchor address
+               MOV     R6,R1                   ;And the byte offset
+               MOV     R7,R2                   ;And the size to insert
+
+               ; --- To start with, some sanity checks ---
+
+               BL      dh__checkAnchor         ;Make sure anchor is OK
+               BVS     %90dh_midExtend         ;If not, return error
+               CMP     R7,#0                   ;Are we growing the block?
+               ADDLT   R14,R6,R7               ;No -- get lowest byte access
+               MOVGE   R14,R6                  ;Yes -- similarly
+               CMP     R14,#0                  ;Is this off the end?
+               ADRLTL  R0,msg_errBadMid        ;Yes -- point to error
+               BLT     %90dh_midExtend         ;And return to caller
+               LDR     R4,[R1,#blk__size]      ;Get the block's size
+               CMP     R6,R4                   ;Are we going too far here?
+               ADRGTL  R0,msg_errBadMid        ;Yes -- point to error
+               BGT     %90dh_midExtend         ;And return to caller
+
+               ; --- Now do the correct extend job ---
+
+               CMP     R7,#0                   ;Are we growing the block?
+               BEQ     %85dh_midExtend         ;Not changing -- return
+               BLT     %50dh_midExtend         ;Shrinking -- skip to do that
+
+               ; --- Make a block bigger ---
+               ;
+               ; We do this in 3 stages:
+               ;
+               ; * Get the amount of dead space at the end of the block, and
+               ;   see if this is enough.
+               ;
+               ; * If not, gather together the free blocks immediately
+               ;   following the block and add this to the dead space.
+               ;
+               ; * If we still don't have enough, we ensure a block of the
+               ;   required size (plus block descriptor) and copy the data
+               ;   into there.
+               ;
+               ; Registers will be used as follows:
+               ;
+               ; R5-R7 are original arguments
+               ; R4 == current size of block
+               ; R3 == size of area we have found
+               ; R2 == base address of extension area
+               ; R1 == base address of block
+
+               ADD     R2,R1,R4                ;Find the end of the block
+               ADD     R3,R4,#blk__oHead+15    ;Align block size to gran.
+               BIC     R0,R3,#15               ;To get dead space too
+               SUB     R3,R0,#blk__oHead       ;But don't have the overhead
+               SUB     R3,R3,R4                ;Get size of the dead space
+               CMP     R3,R7                   ;Is there enough for us?
+               BGE     %30dh_midExtend         ;Yes -- use it then
+
+               ; --- Now we must gather free blocks together nicely ---
+
+               STMFD   R13!,{R8-R10}           ;Save some more registers
+               ADD     R8,R1,R0                ;Find start of next block
+               DIR     R14                     ;Which way is the heap going?
+               LDRGE   R14,dyn_areaBase        ;Upwards -- get base address
+               LDRGE   R10,dyn_heapSize        ;And the heap's size
+               ADDGE   R10,R14,R10             ;To get the top of the heap
+               MOVLT   R10,#&01800000          ;Downwards -- get heap top
+
+05dh_midExtend CMP     R8,R10                  ;Are we there yet?
+               BGE     %10dh_midExtend         ;Yes -- stop there then
+               LDR     R14,[R8,#blk__anchor]   ;Get the block's anchor
+               CMP     R14,#0                  ;Is it a free block?
+               BNE     %10dh_midExtend         ;No -- stop here then
+               LDR     R9,[R8,#blk__size]      ;Get the block's size
+               ADD     R9,R9,#blk__oHead+15    ;Add information overhead
+               BIC     R9,R9,#15               ;And align size nicely
+               ADD     R8,R8,R9                ;Move on to next block
+               ADD     R3,R3,R9                ;And increase available space
+               CMP     R3,R7                   ;Do we have enough yet?
+               BLT     %05dh_midExtend         ;No -- go round again
+
+               LDMFD   R13!,{R8-R10}           ;Restore the stack pointer
+               B       %30dh_midExtend         ;And do the extend op
+
+               ; --- Not enough space in free blocks ---
+               ;
+               ; We dh__ensure enough space in the heap, and copy the whole
+               ; lot.
+
+10dh_midExtend LDMFD   R13!,{R8-R10}           ;Restore the stack pointer
+               ADD     R0,R4,R7                ;Get the required size
+               ADD     R0,R0,#blk__oHead+15    ;Add information overhead
+               BIC     R0,R0,#15               ;And align size nicely
+               BL      dh__ensure              ;Make the space available
+               BVS     %90dh_midExtend         ;If it failed, return error
+               LDR     R1,[R5,#0]              ;Reload anchor -- may move
+               SUB     R1,R1,#blk__oHead       ;And find real block base
+               ADD     R2,R4,#blk__oHead       ;Add on the info overhead
+               BL      dh__move                ;Copy the data over
+               ADD     R14,R0,#blk__oHead      ;Point to the usable area
+               STR     R14,[R5,#0]             ;Save client's new anchor
+               MOV     R14,#0                  ;Get a zero word
+               STR     R14,[R1,#blk__anchor]   ;To mark old block as free
+               BL      dh__unCompact           ;The heap is not compact now
+
+               ; --- Set up registers for the resize op ---
+
+               MOV     R1,R0                   ;Point at the new block base
+               ADD     R2,R1,R4                ;Find area to extend from
+               MOV     R3,R7                   ;And the size we have found
+
+               ; --- Perform the block resize ---
+
+30dh_midExtend ADD     R14,R4,R7               ;Get the new block size
+               STR     R14,[R1,#blk__size]     ;And save it away
+               ADD     R3,R3,R4                ;Get the total area size
+               ADD     R14,R14,#blk__oHead+15  ;Add overhead to new size
+               BIC     R14,R14,#15             ;And align nicely
+
+               ; --- Increase the heap size if we need to ---
+
+               ADD     R0,R1,R14               ;Find the end of the area
+               LDR     R9,dyn_heapSize         ;Load the current heap size
+               DIR     R8                      ;Is it RISC PC?
+               LDRGE   R8,dyn_areaBase         ;Yes -- load the area base
+               RSBLT   R8,R9,#&01800000        ;No -- find the base anyway
+               ADD     R9,R9,R8                ;Find the heap end address
+               CMP     R0,R9                   ;Is end too high?
+               SUBGT   R0,R0,R8                ;Yes -- get the heap size
+               STRGT   R0,dyn_heapSize         ;...and store it back again
+
+               ADD     R3,R3,#blk__oHead+15    ;Do the same for the whole...
+               BIC     R3,R3,#15               ;... area size
+               SUBS    R3,R3,R14               ;Get the space left at end
+               BLE     %35dh_midExtend         ;Perfect fit -- skip on
+
+               ; --- Insert a free block here ---
+
+               ADD     R0,R1,R14               ;Find the end of the area
+               MOV     R2,#0                   ;No anchor -- it's free
+               SUB     R3,R3,#blk__oHead       ;Subtract overhead size
+               STMIA   R0,{R2,R3}              ;Save in descriptor block
+
+               ; --- Now split the block as required ---
+
+35dh_midExtend ADD     R1,R1,#blk__oHead       ;Point at usable part of blk
+               ADD     R1,R1,R6                ;Find the split offset
+               ADD     R0,R1,R7                ;Find where to move to
+               SUBS    R2,R4,R6                ;How much we have to move
+               BLNE    dh__move                ;Do the split op
+               B       %85dh_midExtend         ;And return happily to caller
+
+               ; --- We have to reduce a block ---
+
+50dh_midExtend ADD     R14,R4,R7               ;Get the new size
+               STR     R14,[R1,#blk__size]     ;This is the new size
+               ADD     R1,R1,#blk__oHead       ;Point at usable part of blk
+               ADD     R1,R1,R6                ;Find the split offset
+               ADD     R0,R1,R7                ;Find where to move to
+               SUBS    R2,R4,R6                ;How much we have to move
+               BLNE    dh__move                ;Do the split op
+
+               ; --- Now update the size and insert free block ---
+
+               ADD     R3,R4,R7                ;Find the new size
+               ADD     R4,R4,#blk__oHead+15    ;Add overhead to new size
+               BIC     R4,R4,#15               ;And align nicely
+               ADD     R3,R3,#blk__oHead+15    ;Do the same for the whole...
+               BIC     R3,R3,#15               ;... area size
+               SUBS    R14,R4,R3               ;Get the space left at end
+               BEQ     %85dh_midExtend         ;Perfect fit -- skip onwards
+
+               ; --- Insert a free block here ---
+
+               LDR     R1,[R5,#0]              ;Load the block address
+               SUB     R1,R1,#blk__oHead       ;Point to the block descr.
+               ADD     R0,R1,R3                ;Find the end of the area
+               MOV     R2,#0                   ;No anchor -- it's free
+               SUB     R3,R14,#blk__oHead      ;Subtract overhead size
+               STMIA   R0,{R2,R3}              ;Save in descriptor block
+               BL      dh__unCompact           ;The heap is not compact now
+
+               ; --- Now everything is great ---
+
+85dh_midExtend LDR     R1,[R5,#0]              ;Load the block address
+               LDMFD   R13!,{R0,R2-R9,R14}     ;Unstack registers
+               BICS    PC,R14,#V_flag          ;And return to caller
+
+               ; --- We failed miserably ---
+
+90dh_midExtend ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R2-R9,R14}        ;Unstack registers
+               ORRS    PC,R14,#V_flag          ;And return to caller
+
+               LTORG
+
+; --- dh__move ---
+;
+; On entry:    R0 == destination of movement
+;              R1 == base of block to move
+;              R2 == size of block to move
+;
+; On exit:     --
+;
+; Use:         Shunts memory around in the heap, relocating everything that
+;              needs relocation.
+
+dh__move       ROUT
+
+               STMFD   R13!,{R3,R4,R14}        ;Save some registers
+               BL      fastMove                ;Do the memory movement
+
+               ; --- Now relocate entries on the stack ---
+
+10dh__move     LDR     R4,dyn_stackPtr         ;Find the stack pointer now
+               ADR     R3,dyn_stack            ;Point to the stack base
+15dh__move     CMP     R3,R4                   ;Have we finished yet?
+               BGE     %20dh__move             ;Yes -- return then
+               LDR     R14,[R3],#4             ;Load next entry from stack
+               SUB     R14,R14,R1              ;Subtract source address
+               CMP     R14,R2                  ;Is it in the block?
+               ADDLO   R14,R14,R0              ;Yes -- relocate
+               STRLO   R14,[R3,#-4]            ;And store back in stack
+               B       %15dh__move             ;And carry on relocating
+
+20dh__move     LDMFD   R13!,{R3,R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- dh_checkHeap ---
+;
+; On entry:    --
+;
+; On exit:     May return an error
+;
+; Use:         Checks the current internal format of the heap to make
+;              sure that it hasn't been corrupted in any way.
+;              If the integrity check fails then an error is returned.
+
+               EXPORT  dh_checkHeap
+dh_checkHeap   ROUT
+
+               STMFD   R13!,{R0-R7,R14}        ;Save some registers
+
+               ; --- Start going throught the blocks ---
+
+               LDR     R6,dyn_heapSize         ;Load the current heap size
+               DIR     R14                     ;Is it RISC PC?
+               LDRGE   R5,dyn_areaBase         ;Yes -- load the area base
+               RSBLT   R5,R6,#&01800000        ;No -- find the base anyway
+               ADD     R6,R6,R5                ;Find the heap end address
+               MOV     R9,R5                   ;Remember heap base address
+
+               ; --- Find a block ---
+
+               MOV     R7,R5                   ;Previous block
+00dh_checkHeap CMP     R5,R6                   ;Are we at the end yet?
+               ADRGTL  R0,msg_errBadHeap2      ;Oops -- must have a bad len
+               BGT     %90dh_checkHeap         ;Gone past -- oops
+               BEQ     %50dh_checkHeap         ;Yes -- jump ahead a little
+
+               MOV     R0,R5                   ;Get the base of area to chk
+               ADD     R1,R0,#blk__oHead       ;Get the overhead size
+               SWI     OS_ValidateAddress      ;Make sure this is kosher
+               ADRCSL  R0,msg_errBadHeap2      ;No -- must have a bad len
+               BCS     %90dh_checkHeap         ;If not, moan at client
+               LDR     R2,[R5,#blk__anchor]    ;Get the block's anchor addr
+               CMP     R2,#0                   ;Is the block free?
+               BEQ     %10dh_checkHeap         ;Yes -- jump ahead
+
+               ; --- Make sure the anchor checks OK ---
+
+               MOV     R7,R5                   ;This block could be wrong
+               MOV     R0,R2                   ;Get the base of area to chk
+               ADD     R1,R0,#4                ;Just check one word
+               SWI     OS_ValidateAddress      ;Make sure this is kosher
+               ADRCSL  R0,msg_errBadHeap3      ;Address must be dead then
+               BCS     %90dh_checkHeap         ;If not, moan at client
+
+               LDR     R0,[R2,#0]              ;Load the anchors value
+               ADD     R14,R5,#blk__oHead      ;This is what R0 should be
+               CMP     R0,R14                  ;Do they match?
+               ADRNEL  R0,msg_errBadHeap1      ;No -- point to the error
+               BNE     %90dh_checkHeap         ;And return it joyfully
+
+               ; --- Go round for more then ---
+
+10dh_checkHeap LDR     R3,[R5,#blk__size]      ;Get the block size
+               ADD     R3,R3,#blk__oHead+15    ;Add on the overhead bytes
+               BIC     R3,R3,#15               ;And word align the size
+               ADD     R5,R5,R3                ;Yes -- move on to next one
+               B       %00dh_checkHeap         ;...go round for another one
+
+50dh_checkHeap LDMFD   R13!,{R0-R7,R14}        ;Load registers back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+90dh_checkHeap ADD     R13,R13,#4
+               STR     R7,[R0,#0]              ;Store as the error number!
+               LDMFD   R13!,{R1-R7,R14}        ;Load registers back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- dh_changeAnchor ---
+;
+; On entry:    R0 == pointer to anchor for block
+;              R1 == address of new anchor
+;
+; On exit:     --
+;
+; Use:         Adjusts a block's anchor, in case it moves.
+
+               EXPORT  dh_changeAnchor
+dh_changeAnchor        ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save a register
+               MOV     R2,R1                   ;Remember this value
+               BL      dh__checkAnchor         ;Make sure the anchor's OK
+               STRVC   R2,[R1,#blk__anchor]    ;Save the new anchor pointer
+               ADDVC   R14,R1,#blk__oHead      ;Skip onto the actual data
+               STRVC   R14,[R2,#0]             ;And set the new anchor up
+               LDMFD   R13!,{R2,PC}            ;Return to caller
+
+               LTORG
+
+; --- dh_dump ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Outputs a textual description of the dynamite heap, giving
+;              details of each block within it.
+
+dh__preDump    LDR     R12,[R12]
+
+               EXPORT  dh_dump
+dh_dump                ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+
+               LDR     R4,dyn_heapSize         ;Get the current heap size
+               DIR     R14                     ;Which direction does it go?
+               LDRGE   R2,dyn_areaBase         ;Up -- find the base then
+               RSBLT   R2,R4,#&1800000         ;Down -- start below the RMA
+               ADD     R3,R2,R4                ;Find the heap limit address
+
+               ; --- Display information about the heap in general ---
+
+               ADRL    R0,msg_dumpHpBase       ;Find the message
+               MOV     R1,R2                   ;Get the heap base address
+               BL      dh__writeHex            ;And display it
+
+               MOV     R1,R4                   ;Get the heap size
+               ADRL    R0,msg_dumpHpSize       ;Find the message
+               BL      dh__writeHex            ;And display it
+
+               LDR     R1,dyn_areaSize         ;Get the dynamic area size
+               ADRL    R0,msg_dumpHpArSz       ;Find the message
+               BL      dh__writeHex            ;And display it
+
+               ; --- Now start on the loop ---
+
+00             CMP     R2,R3                   ;Have we finished yet?
+               LDMCSFD R13!,{R0-R4,PC}^        ;Yes -- then return
+
+               SWI     OS_NewLine              ;Start a new line here
+
+               ADRL    R0,msg_dumpBlkAddr      ;Point to the message
+               ADD     R1,R2,#blk__oHead       ;Point to the current block
+               BL      dh__writeHex            ;Display it
+
+               ADRL    R0,msg_dumpBlkSize      ;Point at the message
+               MOV     R0,R0                   ;No-op to prevent objasm bug!
+               LDR     R1,[R2,#blk__size]      ;Get the block's size
+               BL      dh__writeHex            ;Display it
+
+               LDR     R1,[R2,#blk__id]        ;Load the magic ID
+               ADRL    R0,msg_dumpBlkId        ;Point at the message
+               BL      dh__writeHex            ;Display it nicely
+
+               LDR     R1,[R2,#blk__anchor]    ;Find the anchor address
+               CMP     R1,#0                   ;Is the block free?
+               ADREQL  R0,msg_dumpBlkFree      ;Yes -- point to the message
+               SWIEQ   XOS_Write0              ;And display it on screen
+               ADRNEL  R0,msg_dumpBlkAnch      ;Otherwise show anchor addr
+               BLNE    dh__writeHex            ;And move on to next block
+
+               LDR     R14,[R2,#blk__size]     ;Load the block size again
+               ADD     R14,R14,#blk__oHead+15  ;Add overhead and align
+               BIC     R14,R14,#15             ;To find the next block
+               ADD     R2,R2,R14               ;Move onto the next block
+               B       %b00                    ;And skip back into the loop
+
+dh__writeHex   STMFD   R13!,{R2,R14}           ;Save some registers
+               SWI     XOS_Write0              ;Display the string
+               SUB     R13,R13,#12             ;Make a small buffer
+               MOV     R0,R1                   ;Get the number to display
+               MOV     R1,R13                  ;Point to the buffer
+               MOV     R2,#12                  ;The buffer size, sir
+               SWI     XOS_ConvertHex8         ;Convert it into ASCII
+               SWI     XOS_Write0              ;Display that too
+               SWI     XOS_NewLine             ;Move on to a new line
+               ADD     R13,R13,#12             ;Restore the stack pointer
+               LDMFD   R13!,{R2,PC}^           ;And return to caller
+
+               LTORG
+
+;----- * Commands -----------------------------------------------------------
+
+               AREA    |Dynamite$$Commands|,CODE,READONLY
+
+               DCB     "Dynamite_HeapDump",0
+               DCD     dh__preDump
+               DCD     0
+               DCD     synt_heapDump
+               DCD     help_heapDump
+
+;----- Data structures ------------------------------------------------------
+
+; --- Block descriptors ---
+
+               ^       0
+blk__anchor    #       4                       ;Address of block's anchor
+blk__size      #       4                       ;Block's size, as allocated
+blk__id                #       4                       ;Client's magic ID number
+blk__oHead     #       0                       ;Overhead on allocated blocks
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/s/dynTask b/StraySrc/Dynamite/dynamite/s/dynTask
new file mode 100644 (file)
index 0000000..6d3e5e3
--- /dev/null
@@ -0,0 +1,305 @@
+;
+; dynTask.s
+;
+; The background compacting WIMP task
+;
+; © 1994-1998 Straylight
+;
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamite
+;
+; Dynamite is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Dynamite is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Dynamite.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.dynHeap
+               GET     sh.wSpace
+
+               GET     sh.messages
+
+               IMPORT  dyn_base
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Dynamite$$Code|,CODE,READONLY
+
+; --- dt_service ---
+;
+; On entry:    R1 == service call number
+;              Other registers depend on R1
+;
+; On exit:     Depends on service call
+;
+; Use:         Handles service calls for Dynamite
+
+               EXPORT  dt_service
+dt_service     ROUT
+
+               ; --- Get rid of unwanted services quickly ---
+
+               CMP     R1,#&4A
+               CMPNE   R1,#&27
+               CMPNE   R1,#&49
+               MOVNES  PC,R14
+
+               ; --- Now dispatch wanted services ---
+
+               LDR     R12,[R12,#0]            ;Get my workspace pointer
+               STMFD   R13!,{R14}              ;Save some useful registers
+
+               CMP     R1,#&27                 ;Service_Reset...
+               BEQ     %20dt_service
+
+               CMP     R1,#&4A                 ;Service_StartedWimp
+               BEQ     %10dt_service
+
+               ; --- Service_StartWimp ---
+
+               LDR     R14,dyn_taskHandle      ;Get my task handle
+               CMP     R14,#0                  ;Am I already running?
+               MOVEQ   R14,#-1                 ;I'm trying to start up
+               STREQ   R14,dyn_taskHandle      ;Store as my task handle
+               ADREQL  R0,dt__commands         ;Point to the command string
+               MOVEQ   R1,#0                   ;Claim the service call
+               LDMFD   R13!,{PC}^              ;Return to RISC OS
+
+               ; --- Service_StartedWimp ---
+
+10dt_service   LDR     R14,dyn_taskHandle      ;Get my task handle
+               CMP     R14,#-1                 ;Am I already running?
+               MOVEQ   R14,#0                  ;No -- blank out task handle
+               STREQ   R14,dyn_taskHandle      ;Store it over the old one
+               LDMFD   R13!,{PC}^              ;Return happily
+
+               ; --- Service_Reset ---
+
+20dt_service   MOV     R14,#0                  ;Blank out my task handle
+               STR     R14,dyn_taskHandle      ;Store it over the old one
+               LDMFD   R13!,{PC}^              ;Return to RISC OS now
+
+               LTORG
+
+; --- dt__startTask ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Starts up the Dynamite application from a *Command.
+
+dt__startTask  ROUT
+
+               LDR     R12,[R12]               ;Load my workspace address
+               LDR     R0,dyn_taskHandle       ;Get my task handle variable
+               CMP     R0,#-1                  ;Am I waiting to start?
+               ADRNEL  R0,msg_errDesk          ;No -- moan at stupid user
+               ORRNES  PC,R14,#V_flag          ;And return the error
+               MOV     R0,#1                   ;We're launching the app
+               STR     R0,dyn_launch           ;So set the launch flag
+               STMFD   R13!,{R14}              ;Save a register nicely
+               MOV     R0,#2                   ;Start my module up
+               ADR     R1,dt__myName           ;Point to the module name
+               SWI     XOS_Module              ;Start up the task proper
+               LDMFD   R13!,{PC}               ;And return to caller
+
+dt__myName     DCB     "Dynamite",0
+
+               LTORG
+
+; --- dt_quit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Closes down Dynamite's WIMP task (used for background
+;              compaction of the heap).
+
+               EXPORT  dt_quit
+dt_quit                ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R0,dyn_taskHandle       ;Find my task handle
+               LDR     R1,=&4B534154           ;The magic number thing
+               SWI     XWimp_CloseDown         ;Close down the application
+               MOV     R14,#0                  ;Now we don't have a task
+               STR     R14,dyn_taskHandle      ;So zap my task handle
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+; --- dt_run ---
+;
+; On entry:    R12 == address of module private word
+;
+; On exit:     Via OS_Exit
+;
+; Use:         Runs the Dynamite WIMP task.
+
+               EXPORT  dt_run
+dt_run         ROUT
+
+               LDR     R12,[R12]               ;Find my workspace address
+               ADR     R13,dyn_pollBlk+256     ;Make a microstack
+
+               ; --- Is it worth doing anything? ---
+
+               MOV     R0,#0                   ;How many Wimp tasks?
+               SWI     Wimp_ReadSysInfo        ;Read the number back
+               CMP     R0,#0                   ;Are there any running?
+               SWIEQ   OS_Exit                 ;Nope: then don't bother
+
+               ; --- Handle the ultra-weird launch sequence ---
+
+               LDR     R14,dyn_launch          ;Load the launch flag
+               CMP     R14,#0                  ;Are we launching?
+               BEQ     %50dt_run               ;No -- launch then
+
+               ; --- Start up the WIMP thing ---
+
+               MOV     R0,#200                 ;Make it run under RISC OS 2
+               LDR     R1,=&4B534154           ;Get the magic number thing
+               ADR     R2,dt__taskName         ;Point to the task name
+               SWI     Wimp_Initialise         ;Start up the WindowManager
+               STR     R1,dyn_taskHandle       ;Save the task handle
+
+               ; --- Remove my name from the Switcher's list ---
+
+               ADR     R1,dyn_pollBlk          ;Point to the poll block
+               MOV     R0,#20                  ;Minimum message size
+               STR     R0,[R1,#0]              ;Save in position 0
+               MOV     R2,#0                   ;This is not a reply
+               MOV     R3,#&40000              ;The TaskCloseDown message
+               ORR     R3,R3,#&000C3           ;It comes in two episodes
+               ADD     R0,R1,#12               ;Point to bit of message blk
+               STMIA   R0,{R2,R3}              ;Build the message in there
+               MOV     R0,#17                  ;Don't get a reply
+               MOV     R2,#0                   ;Give everyone a shot at it
+               SWI     XWimp_SendMessage       ;Send it the message
+
+               ; --- Now do the main loop ---
+
+00dt_run       LDR     R14,dyn_hpFlags         ;Load the heap's flags
+               TST     R14,#hpFlag_tidy        ;Is the heap tidy?
+               LDREQ   R14,dyn_lockCount       ;No -- then load lock count
+               CMPEQ   R14,#0                  ;Is the heap locked?
+               MOVNE   R0,#1                   ;Tidy or locked, so be nice
+               MOVEQ   R0,#0                   ;Otherwise use idles
+               ADR     R1,dyn_pollBlk          ;Point to my pollblock
+               ADD     R13,R1,#256             ;Make a bogus stack
+               SWI     Wimp_Poll               ;Do the poll thing
+               CMP     R0,#0                   ;Is it an idle event?
+               SWIEQ   Dynamite_Reduce         ;Yes -- then reduce the heap
+               CMP     R0,#17                  ;Is it a message
+               CMPNE   R0,#18                  ;Of either type
+               LDREQ   R0,[R1,#16]             ;Get the message type
+               CMPEQ   R0,#0                   ;Is it a Message_Quit
+               LDRNE   R14,dyn_hpFlags         ;No -- load the flags
+               BICNE   R14,R14,#hpFlag_mSent   ;...clear the message sent
+               STRNE   R14,dyn_hpFlags         ;...save the flags back
+               BNE     %00dt_run               ;...loop round again
+
+               ; --- I've been told to quit ---
+               ;
+               ; Seeing as I've viciously and nastily removed myself from
+               ; the TaskManager's task table, I know this must have been
+               ; a broadcast quit, so I hari-kiri with wanton abandon.
+
+               SWI     Wimp_CloseDown          ;Close down the task
+               MOV     R0,#0                   ;No task handle any more
+               STR     R0,dyn_taskHandle       ;So zero it then
+               SWI     OS_Exit                 ;Farewell, cruel world
+
+dt__taskName   DCB     "DynamiteCompactor",0
+
+               ; --- Launch the Compactor task ---
+
+50dt_run       MOV     R0,#200                 ;Make it run under RISC OS 2
+               LDR     R1,=&4B534154           ;Get the magic number thing
+               ADR     R2,dt__launchName       ;Point to the task name
+               SWI     Wimp_Initialise         ;Start up the WindowManager
+
+               MOV     R0,#-1                  ;Fake a startup sequence
+               STR     R0,dyn_taskHandle       ;Save this as my task handle
+               LDR     R0,=dt__commands        ;Point to my main command
+               BL      dyn_base                ;Find the module base
+               ADD     R0,R14,R0               ;Relocate the address
+               SWI     Wimp_StartTask          ;Start it up nicely
+
+               SWI     Wimp_CloseDown          ;Tell WIMP to get knotted
+               SWI     OS_Exit                 ;And kill self evilly
+
+dt__launchName DCB     "DynamiteLauncher",0
+
+               LTORG
+
+; --- dt_message ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sends a silly message to the Compactor task so that it gets
+;              control again if it disabled idle events.
+
+               EXPORT  dt_message
+dt_message     ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               LDR     R14,dyn_taskHandle      ;Load my task handle
+               CMP     R14,#0                  ;Is it vaguely sensible?
+               LDMLEFD R13!,{R0-R3,PC}^        ;No -- don't bother then
+               LDR     R14,dyn_hpFlags         ;Load the flags
+               TST     R14,#hpFlag_mSent       ;Has a message been sent?
+               LDMNEFD R13!,{R0-R3,PC}^        ;Yes -- then return
+               ORR     R14,R14,#hpFlag_mSent   ;Set the flag
+               STR     R14,dyn_hpFlags         ;And save the flags back
+               ADR     R1,dyn_pollBlk          ;Point to the poll block
+               MOV     R0,#20                  ;Minimum message size
+               STR     R0,[R1,#0]              ;Save in position 0
+               MOV     R2,#0                   ;This is not a reply
+               MOV     R3,#&4A000              ;A bogus message number
+               ORR     R3,R3,#&003C0           ;(My SWI chunk base)
+               ADD     R0,R1,#12               ;Point to bit of message blk
+               STMIA   R0,{R2,R3}              ;Build the message in there
+               MOV     R0,#17                  ;Don't get a reply
+               MOV     R2,R14                  ;Get my task handle
+               SWI     XWimp_SendMessage       ;Send it the message
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+               ; --- *Commands ---
+
+               AREA    |Dynamite$$Commands|,CODE,READONLY
+
+dt__commands   DCB     "Desktop_DynamiteCompactor",0
+               DCD     dt__startTask
+               DCD     0
+               DCD     synt_compactor
+               DCD     help_compactor
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/s/dynamite b/StraySrc/Dynamite/dynamite/s/dynamite
new file mode 100644 (file)
index 0000000..2024e17
--- /dev/null
@@ -0,0 +1,608 @@
+;
+; dynamite.s
+;
+; Memory management in a dynamic area
+;
+; © 1994-1998 Straylight
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamite
+;
+; Dynamite is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Dynamite is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Dynamite.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.dynAnchor
+               GET     sh.dynArea
+               GET     sh.dynHeap
+               GET     sh.dynTask
+               GET     sh.wSpace
+
+               GET     sh.messages
+
+               IMPORT  version
+               IMPORT  |Dynamite$$Commands$$Base|
+
+;----- Module header --------------------------------------------------------
+
+               AREA    |!!!Module$$Header|,CODE,READONLY
+
+dyn__base      DCD     dt_run                  ;Application code
+               DCD     dyn__init               ;Initialisation
+               DCD     dyn__quit               ;Finalisation
+               DCD     dt_service              ;Service call handling
+               DCD     dyn__name               ;Module title string
+               DCD     version                 ;Module help string
+               DCD     |Dynamite$$Commands$$Base| ;Command table
+               DCD     &4A3C0                  ;SWI chunk number
+               DCD     dyn__swis               ;SWI handler code
+               DCD     dyn__swiNames           ;SWI name table
+               DCD     0                       ;SWI name-number code
+
+dyn__name      DCB     "Dynamite",0
+
+;----- Main module code -----------------------------------------------------
+
+               AREA    |Dynamite$$Code|,CODE,READONLY
+
+; --- dyn_base ---
+;
+; On entry:    --
+;
+; On exit:     R14 == base address of module
+;
+; Use:         Finds the base address of the module.
+
+               EXPORT  dyn_base
+dyn_base       ROUT
+
+               STMFD   R13!,{R14}
+               ADR     R14,dyn__base
+               LDMFD   R13!,{PC}^
+
+               LTORG
+
+; --- dyn__init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Claims some memory, and intercepts OS_ChangeDynamicArea.
+
+dyn__init      ROUT
+
+               STMFD   R13!,{R7,R8,R14}        ;Save some registers
+
+               ; --- Allocate module workspace ---
+
+               MOV     R0,#6                   ;Claim RMA workspace
+               LDR     R3,=dyn_wSize           ;Get my workspace size
+               SWI     XOS_Module              ;Allocate the workspace
+               LDMVSFD R13!,{R7,R8,PC}         ;If it failed, return error
+               STR     R2,[R12,#0]             ;Save workspace address
+               MOV     R12,R2                  ;Point to workspace nicely
+               STR     R12,dyn__wsAddr         ;Store for my patch code
+
+               MOV     R0,#0                   ;Initialise some workspace
+               STR     R0,dyn_areaSize         ;Dynamic area not created yet
+               STR     R0,dyn_heapSize         ;No data in the heap
+               STR     R0,dyn_lockCount        ;And clear the lock counter
+               STR     R0,dyn_launch           ;Make RMRun do clever stuff
+               STR     R0,dyn_taskHandle       ;And make the task handle 0
+               STR     R0,dyn_ancTable         ;Clear the free anchor table
+               STR     R0,dyn_ancList          ;And the anchor block list
+               MOV     R0,#hpFlag_tidy         ;We are compacted now
+               STR     R0,dyn_hpFlags          ;So make a note of this
+
+               ADR     R14,dyn_stack           ;Point to reloc stack base
+               STR     R14,dyn_stackPtr        ;Save as the stack pointer
+
+               ; --- Claim OS_ChangeDynamicArea ---
+               ;
+               ; We trap this in the kernel branch table, rather than at
+               ; the SWI vector, because it's so much easier.
+
+               SWI     XOS_ReadMemMapInfo      ;Read nice things
+               STR     R0,dyn_pageSize         ;Save the page size
+               SUB     R1,R1,#1                ;Chop one off for da_findPage
+               STR     R1,dyn_pageCount        ;And the number of them
+               MOV     R14,#0                  ;Log 2 of page size
+00dyn__init    TST     R0,#1                   ;Is bottom bit set yet?
+               MOVEQ   R0,R0,LSR#1             ;No -- shift along a bit
+               ADDEQ   R14,R14,#1              ;Add to the log
+               BEQ     %00dyn__init            ;And keep on going
+               STR     R14,dyn_log2PageSize    ;And store this away
+
+               MOV     R0,#129                 ;The OS_Byte number
+               MOV     R1,#0                   ;Lovely...
+               MOV     R2,#255                 ;...jubbly!
+               SWI     XOS_Byte                ;Get OS Version number
+               STR     R1,dyn_machine          ;Store this away
+               CMP     R1,#&A5                 ;Is this a RISC PC?
+               BGE     %50dyn__init            ;Yes -- jump ahead then
+               CMP     R1,#&A3                 ;Is it RISC OS 2?
+               LDRLT   R0,=&ABC                ;Yes --- this is sprarea size
+               LDRGE   R0,=&ACC                ;No -- this is then
+               STR     R0,dyn_sprSize          ;Save in the workspace
+
+               MOV     R6,PC                   ;Get the current status
+               TST     R6,#IRQ_disable         ;Are IRQs enabled?
+               TEQEQP  R6,#IRQ_disable         ;Yes -- disable them then
+
+               LDR     R0,=&01F033FC           ;Find the kernel dispatcher
+               LDR     R14,[R0,#OS_ChangeDynamicArea*4]
+               STR     R14,dyn_oldChnArea      ;Save this in my workspace
+               ADR     R14,dyn__patch          ;Point to my patch routine
+               STR     R14,[R0,#OS_ChangeDynamicArea*4]
+
+               LDR     R14,[R0,#OS_ReadDynamicArea*4]
+               STR     R14,dyn_oldReadArea     ;Save this in my workspace
+               ADR     R14,dyn__readPatch      ;Point to my patch routine
+               STR     R14,[R0,#OS_ReadDynamicArea*4]
+
+               LDR     R14,[R0,#OS_ValidateAddress*4]
+               STR     R14,dyn_oldValidate     ;Save this in my workspace
+               ADR     R14,dyn__valPatch       ;Point to my patch routine
+               STR     R14,[R0,#OS_ValidateAddress*4]
+               TEQP    R6,#0                   ;Restore interrupt status
+               MOV     R0,R0                   ;Shut the assembler up
+
+               ; --- Find the TaskManager and WindowManager addresses ---
+
+               ADR     R6,dyn_switchBase       ;Point to bit of workspace
+               MOV     R0,#18                  ;Look up modules by name
+               ADR     R1,dyn__switcher        ;Point to the Switcher's name
+               SWI     XOS_Module              ;Try and find its address
+               MOVVS   R3,#0                   ;If not there, dummy address
+               MOVVS   R4,#0                   ;For that and the end
+               LDRVC   R4,[R3,#-4]             ;Otherwise load module length
+               STMIA   R6!,{R3,R4}             ;Save them in workspace
+
+               ADR     R1,dyn__wimp            ;Point to the Wimp's name
+               SWI     XOS_Module              ;Try and find its address
+               MOVVS   R3,#0                   ;If not there, dummy address
+               MOVVS   R4,#0                   ;For that and the end
+               LDRVC   R4,[R3,#-4]             ;Otherwise load module length
+               STMIA   R6!,{R3,R4}             ;Save them in workspace
+               LDMFD   R13!,{R7,R8,PC}^        ;Return to caller
+
+               ; --- The machine is a RISC PC -- lucky sod! ---
+
+50dyn__init    MOV     R0,#0                   ;Create dynamic area
+               MOV     R1,#-1                  ;No particular number
+               MOV     R2,#0                   ;Initial size of area
+               MOV     R3,#-1                  ;No particular base address
+               MOV     R4,#&80                 ;The area flags
+               MOV     R5,#-1                  ;No maximum size please
+               MOV     R6,#0                   ;No handler needed
+               MOV     R7,#0                   ;Workspace to pass to handler
+               ADR     R8,dyn__areaName        ;Dynamic area name
+               SWI     XOS_DynamicArea         ;Create the area
+               STRVC   R1,dyn_areaHandle       ;Store the handle
+               STRVC   R3,dyn_areaBase         ;And the base address
+
+               LDMFD   R13!,{R7,R8,PC}         ;Return to caller
+
+dyn__switcher  DCB     "TaskManager",0
+dyn__wimp      DCB     "WindowManager",0
+dyn__areaName  DCB     "Dynamite",0
+
+               LTORG
+
+dyn__wsAddr    DCD     0                       ;Yuk -- address of workspace
+
+; --- dyn__quit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Tries to close Dynamite down.
+
+dyn__quit      ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save a register
+               LDR     R12,[R12]               ;Find my workspace address
+
+               ; --- Make sure we're not needed ---
+
+               BL      dh_compact              ;Compact the heap first
+               LDR     R14,dyn_areaSize        ;How much space are we using?
+               CMP     R14,#0                  ;Is it 0?
+               BNE     %45dyn__quit            ;No -- people might want them
+               LDR     R14,dyn_stackPtr        ;Load the stack pointer
+               ADR     R0,dyn_stack            ;Point to the stack base
+               CMP     R14,R0                  ;Are these equal?
+               BNE     %45dyn__quit            ;No -- we're still used then
+
+               ; --- Close down the compactor ---
+
+               LDR     R14,dyn_taskHandle      ;Get the task handle
+               CMP     R14,#0                  ;Is it a sensible one?
+               BLGT    dt_quit                 ;Yes -- kill the task then
+               BL      danc_quit               ;Free all anchor blocks
+
+               ; --- Get rid of all used pages ---
+
+               LDR     R0,dyn_areaSize         ;Get the area size
+               LDR     R1,dyn_log2PageSize     ;And log 2 of page size
+               MOV     R0,R0,LSR R1            ;Number of pages in area
+               BL      da_removePages          ;Remove pages
+
+               LDR     R0,dyn_machine          ;Get the machine type
+               CMP     R0,#&A5                 ;Is it a RISC PC?
+               BGE     %60dyn__quit            ;Yes -- jump ahead
+
+               ; --- First, try to release OS_ChangeDynamicArea ---
+
+               LDR     R0,=&01F033FC           ;Find the kernel dispatcher
+               LDR     R1,[R0,#OS_ChangeDynamicArea*4]
+               ADR     R14,dyn__patch          ;Point to my patch routine
+               CMP     R1,R14                  ;Can I release it safely?
+               BNE     %50dyn__quit            ;No -- report an error
+
+               LDR     R1,[R0,#OS_ReadDynamicArea*4]
+               ADR     R14,dyn__readPatch      ;Point to my patch routine
+               CMP     R1,R14                  ;Can I release it safely?
+               BNE     %50dyn__quit            ;No -- report an error
+
+               LDR     R1,[R0,#OS_ValidateAddress*4]
+               ADR     R14,dyn__valPatch       ;Point to my patch routine
+               CMP     R1,R14                  ;Can I release it safely?
+               BNE     %50dyn__quit            ;No -- report an error
+
+               LDR     R14,dyn_oldChnArea      ;Load the previous value
+               STR     R14,[R0,#OS_ChangeDynamicArea*4]
+               LDR     R14,dyn_oldReadArea     ;Load the previous value
+               STR     R14,[R0,#OS_ReadDynamicArea*4]
+               LDR     R14,dyn_oldValidate     ;Load the previous value
+               STR     R14,[R0,#OS_ValidateAddress*4]
+
+               ; --- Free the workspace I claimed ---
+
+40dyn__quit    MOV     R0,#7                   ;Free RMA workspace
+               MOV     R2,R12                  ;Point to my workspace
+               SWI     XOS_Module              ;Try to free it nicely
+               LDR     R0,[R13],#4             ;Load private word address
+               MOV     R14,#0                  ;Clear private word value
+               STR     R14,[R0,#0]             ;To stop OS doing this too...
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               ; --- We have handles or relocation entries ---
+
+45dyn__quit    ADRL    R0,msg_errInUse         ;Point to error message
+               LDMFD   R13!,{R12,R14}          ;Unstack some registers
+               ORRS    PC,R14,#V_flag          ;Return to caller with error
+
+               ; --- We couldn't release OS_ChangeDynamicArea ---
+
+50dyn__quit    ADRL    R0,msg_errRelease       ;Point to error message
+               LDMFD   R13!,{R12,R14}          ;Unstack some registers
+               ORRS    PC,R14,#V_flag          ;Return to caller with error
+
+               ; --- We're on a RISC PC ---
+
+60dyn__quit    MOV     R0,#1                   ;Remove dynamic area
+               LDR     R1,dyn_areaHandle       ;Get the area handle
+               SWI     XOS_DynamicArea         ;Remove it then
+               B       %40dyn__quit            ;Now free workspace etc.
+
+               LTORG
+
+; --- dyn__patch ---
+;
+; On entry:    As for ChangeDynamicArea
+;
+; On exit:     Ditto
+;
+; Use:         Mangles ChangeDynamicArea when being used on the system
+;              sprite area.
+
+dyn__patch     ROUT
+
+               LDR     R12,dyn__wsAddr         ;Find my workspace address
+               CMP     R0,#3                   ;Is it the sprite area?
+               LDRNE   PC,dyn_oldChnArea       ;No -- continue as normal
+
+               ; --- Mangle the `remembered' size of the sprite area ---
+
+               STMFD   R13!,{R14}              ;Save another register
+               LDR     R11,dyn_sprSize         ;Find the size word
+               LDR     R14,[R11,#0]            ;Load total sprite area size
+               ADD     R10,R14,R1              ;How much does he want?
+               CMP     R10,#4*1024*1024        ;More than 4 megs?
+               BGT     %90dyn__patch           ;Yes -- that's an error
+               LDR     R10,dyn_areaSize        ;Load my area's size
+               SUB     R14,R14,R10             ;Get the size of the sprites
+               STR     R14,[R11,#0]            ;Save that for the duration
+
+               ; --- This is nasty and complicated ---
+               ;
+               ; Post processing on kernel SWIs is not something normally
+               ; to be enjoyed.  The way things will have to be done is as
+               ; follows:
+               ;
+               ; * We save R14 and the value &2002A (XOS_ChangeDynamicArea)
+               ;   on the stack.  The SWI value is so that we regain control
+               ;   if something went sadly amiss.
+               ;
+               ; * We call the previous OS_ChangeDynamicArea routine, having
+               ;   set a suitably bogus return address.
+               ;
+               ; * We mangle the system sprite area in a manner in keeping
+               ;   with the aim of the program.
+               ;
+               ; * Then we examine the status returned to us, and if V was
+               ;   set AND the X bit of the R11 saved on the stack before
+               ;   we were entered at the top was clear we call
+               ;   OS_GenerateError.
+
+               MOV     R11,#OS_ChangeDynamicArea ;Get the SWI number
+               ORR     R11,R11,#&20000         ;Set the X bit nicely
+               STMFD   R13!,{R10-R12}          ;Save other registers here
+               STMFD   R13!,{R11}              ;And the obviously bogus R11
+               MOV     R14,PC                  ;Set up a return address
+               LDR     PC,dyn_oldChnArea       ;And let it rip...
+
+               ; --- We have now done a ChangeDynamicArea ---
+                ;
+                ; R14 saved above is on the stack, along with the caller's
+                ; R10-R12 from the OS SWI dispatcher.
+
+               LDR     R11,dyn_sprSize         ;Find the size word
+               LDR     R14,[R11,#0]            ;Load the new area size
+               ADD     R14,R14,R10             ;Add the old difference
+               STR     R14,[R11,#0]            ;And save it back again
+
+50dyn__patch   LDMFD   R13!,{R14}              ;Get his return address
+               LDMFD   R13!,{R11}              ;Get the SWI number too
+               LDMVCFD R13!,{R10-R12}          ;Restore his registers
+               BICVCS  PC,R14,#V_flag          ;And return control to him
+
+               TST     R11,#&20000             ;Was the X bit set?
+               SWIEQ   OS_GenerateError        ;No -- do error like things
+
+               LDMFD   R13!,{R10-R12}          ;Restore his registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               ; --- He wanted too much memory ---
+
+90dyn__patch   ADRL    R0,msg_errTooBig        ;Point to the error
+               CMP     R0,#&80000000           ;Create an overflow
+               B       %50dyn__patch           ;Make it look like it came
+                                               ;from ChangeDynamicArea
+               LTORG
+
+; --- dyn__readPatch ---
+;
+; On entry:    R0 == dynamic area to read, and flags etc.
+;
+; On exit:     R1 == size of dynamic area, R2 == optional maximum size
+;
+; Use:         Reads the size of a dynamic area.  If the caller is
+;              interested in the sprite area AND they're not either the
+;              TaskManager or the WindowManager, we mangle the result so
+;              they think that the sprite area doesn't contain our clever
+;              heap.
+
+dyn__readPatch ROUT
+
+               LDR     R12,dyn__wsAddr         ;Find my workspace address
+               BIC     R10,R0,#&80             ;Clear the clever flag bit
+               CMP     R10,#3                  ;Is it the sprite area?
+               LDRNE   PC,dyn_oldReadArea      ;No -- continue as normal
+
+               ; --- Do all the work then ---
+               ;
+               ; Seeing as we know all there is to know about the sprite
+               ; area, we can do all this here without the yukkiness of
+               ; postprocessing.
+
+               STMFD   R13!,{R2,R14}           ;Save the link register
+               ADR     R11,dyn_switchBase      ;Find module addresses
+               BIC     R10,R14,#&FC000003      ;Find caller's address
+               LDMIA   R11!,{R1,R2}            ;Load switcher base/size
+               SUB     R14,R10,R1              ;Subtract switcher base
+               CMP     R14,R2                  ;Is it within switcher?
+               LDMHSIA R11!,{R1,R2}            ;No -- load wimp base/size
+               SUBHS   R14,R10,R1              ;Subtract wimp base
+               CMPHS   R14,R2                  ;Is it within wimp?
+               LDMFD   R13!,{R2,R14}           ;Unstack registers again
+
+               LDR     R1,dyn_sprSize          ;Find sprite area size word
+               LDR     R1,[R1,#0]              ;Load current sprite size
+               LDRHS   R10,dyn_areaSize        ;If caller is pleb, mangle it
+               SUBHS   R1,R1,R10               ;By subtracting our heap size
+               TST     R0,#&80                 ;Does he want max size?
+               MOVNE   R2,#4*1024*1024         ;Yes -- that's 4MB
+               MOV     R0,#&01400000           ;Point to sprite area start
+
+               ADD     R13,R13,#4              ;Skip past stacked R11
+               LDMFD   R13!,{R10-R12}          ;Unstack caller's registers
+               BICS    PC,R14,#V_flag          ;And return to caller
+
+               LTORG
+
+; --- dyn__valPatch ---
+;
+; On entry:    As for OS_ValidateAddress
+;
+; On exit:     As for OS_ValidateAddress
+;
+; Use:         Mangles OS_ValidateAddress so that it gets our somewhat
+;              rearranged sprite area correct.  This is necessary due to
+;              braindead implementation of OS_ValidateAddress.  I'd like to
+;              be able to do the job properly by hacking the CAM map, but
+;              the Mysterious Background Address Validator assumes that the
+;              SWI works in the way Acorn wrote it, so that's put the
+;              kybosh on that plan.
+
+dyn__valPatch  ROUT
+
+               LDR     R12,dyn__wsAddr         ;Find my workspace address
+
+               STMFD   R13!,{R14}              ;Save the link register
+               MOV     R10,#&01400000          ;Get base of the sprite area
+               MOV     R11,#&01800000          ;Get limit too
+               CMP     R0,R10                  ;Is it in there?
+               CMPCS   R11,R0
+               CMPCS   R1,R10
+               CMPCS   R11,R1
+               LDMCCFD R13!,{R14}              ;No -- restore link
+               LDRCC   PC,dyn_oldValidate      ;And let OS_VA do it then
+
+               ; --- Check for weird sprite area thing and Dynamite area ---
+
+               LDR     R11,dyn_sprSize         ;Get address of sprite size
+               LDR     R11,[R11,#0]            ;Load size of sprite area
+               LDR     R14,dyn_areaSize        ;Load our area size
+               ADD     R11,R10,R11             ;Find end of sprite area
+               SUB     R10,R11,R14             ;Taking our area into account
+               MOV     R11,#&01800000          ;Find top of sprite slot
+               SUB     R11,R11,R14             ;Find bottom of our area
+               CMP     R11,R0                  ;This is deep -- think about
+               CMPHI   R1,R10                  ;it for a while.
+               LDMFD   R13!,{R14}              ;If it isn't invalid...
+               ADD     R13,R13,#4
+               LDMFD   R13!,{R10-R12}
+               ORRHIS  PC,R14,#C_flag
+               BICLSS  PC,R14,#C_flag
+
+               LTORG
+
+; --- dyn__swis ---
+;
+; On entry:    R11 == SWI index
+;
+; On exit:     Depends on the SWI
+;
+; Use:         Dispatches SWIs to other routines
+
+dyn__swis      ROUT
+
+               LDR     R12,[R12]               ;Find my module workspace
+
+               CMP     R11,#&3F
+               BEQ     dh_dump
+
+               CMP     R11,#(%10-%00)/4        ;Is the SWI in range?
+               ADDLO   PC,PC,R11,LSL #2        ;Yes -- dispatch it then
+               B       %10dyn__swis            ;Otherwise report the error
+
+00dyn__swis    B       dh_alloc                ;Dynamite_Claim
+               B       dh_free                 ;Dynamite_Free
+               B       dh_freeWithID           ;Dynamite_FreeWithID
+               B       dh_blockInfo            ;Dynamite_BlockInfo
+               B       dh_changeID             ;Dynamite_ChangeID
+               B       dh_extend               ;Dynamite_Resize
+               B       dh_midExtend            ;Dynamite_MidExtend
+               B       dh_save                 ;Dynamite_Save
+               B       dh_load                 ;Dynamite_Load
+               B       dh_reduce               ;Dynamite_Reduce
+               B       dh_compact              ;Dynamite_Compact
+               B       dh_lock                 ;Dynamite_Lock
+               B       dh_unlock               ;Dynamite_Unlock
+               B       danc_alloc              ;Dynamite_ClaimAnchor
+               B       danc_free               ;Dynamite_ReleaseAnchor
+               B       da_readSize             ;Dynamite_ReadSpriteSize
+               B       da_describe             ;Dynamite_Describe
+               B       dh_checkHeap            ;Dynamite_IntegrityCheck
+               B       dh_changeAnchor         ;Dynamite_ChangeAnchor
+
+10dyn__swis    ADRL    R0,msg_errBadSWI        ;Point at the error
+               ORRS    PC,R14,#V_flag          ;And return it back
+
+dyn__swiNames  DCB     "Dynamite",0
+               DCB     "Alloc",0
+               DCB     "Free",0
+               DCB     "FreeWithID",0
+               DCB     "BlockInfo",0
+               DCB     "ChangeID",0
+               DCB     "Resize",0
+               DCB     "MidExtend",0
+               DCB     "Save",0
+               DCB     "Load",0
+               DCB     "Reduce",0
+               DCB     "Compact",0
+               DCB     "Lock",0
+               DCB     "Unlock",0
+               DCB     "ClaimAnchor",0
+               DCB     "ReleaseAnchor",0
+               DCB     "ReadSpriteSize",0
+               DCB     "Describe",0
+               DCB     "IntegrityCheck",0
+               DCB     "ChangeAnchor",0
+               DCB     0
+
+               LTORG
+
+; --- *Dynamite_Clear ---
+
+dyn__clear     ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R12,[R12]               ;Load the workspace address
+
+               ; --- Empty the heap ---
+
+               LDR     R0,dyn_areaSize         ;Get the area size
+               LDR     R1,dyn_log2PageSize     ;And log 2 of page size
+               MOV     R0,R0,LSR R1            ;Number of pages in area
+               BL      da_removePages          ;Remove pages
+
+               ; --- Free all the anchors ---
+
+               BL      danc_quit               ;Free all allocated anchors
+
+               ; --- Reset the heap variables ---
+
+               MOV     R0,#0                   ;Initialise some workspace
+               STR     R0,dyn_areaSize         ;Dynamic area not created yet
+               STR     R0,dyn_heapSize         ;No data in the heap
+               STR     R0,dyn_lockCount        ;And clear the lock counter
+               STR     R0,dyn_ancTable         ;Clear the free anchor table
+               STR     R0,dyn_ancList          ;And the anchor block list
+               MOV     R0,#hpFlag_tidy         ;We are compacted now
+               STR     R0,dyn_hpFlags          ;So make a note of this
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+               ; --- *Commands ---
+
+               AREA    |Dynamite$$Commands|,CODE,READONLY
+
+               DCB     "Dynamite_Clear",0
+               DCD     dyn__clear
+               DCD     0
+               DCD     synt_clear
+               DCD     help_clear
+
+               AREA    |Dynamite$$Commands_End|,CODE,READONLY
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/s/fastMove b/StraySrc/Dynamite/dynamite/s/fastMove
new file mode 100644 (file)
index 0000000..6e9b1f0
--- /dev/null
@@ -0,0 +1 @@
+               LNK     libs:s.fastMove
diff --git a/StraySrc/Dynamite/dynamite/sh/dynAnchor b/StraySrc/Dynamite/dynamite/sh/dynAnchor
new file mode 100644 (file)
index 0000000..49f1439
--- /dev/null
@@ -0,0 +1,51 @@
+;
+; dynAnchor.sh
+;
+; Useful handle RMA allocation for dynamite
+;
+; © 1994 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   danc_alloc
+;   danc_free
+;   danc_quit
+
+; --- danc_alloc ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to block allocated, or V set and pointer to
+;                    error
+;
+; Use:         Allocates an anchor to use with dynamite from the RMA,
+;              in a very quick way indeed.
+
+               IMPORT  danc_alloc
+
+; --- danc_free ---
+;
+; On entry:    R0 == pointer to block
+;
+; On exit:     Registers preserved
+;
+; Use:         Frees an anchor allocated using danc_alloc.
+
+               IMPORT  danc_free
+
+; --- danc_quit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Frees everyone's anchors nicely when the module quits.
+
+               IMPORT  danc_quit
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/sh/dynArea b/StraySrc/Dynamite/dynamite/sh/dynArea
new file mode 100644 (file)
index 0000000..3edf5a9
--- /dev/null
@@ -0,0 +1,79 @@
+;
+; dynArea.sh
+;
+; The handling of the dynamic area itself
+;
+; © 1994 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   da_findPage
+;   da_addPages
+;   da_removePages
+;   da_readSize
+;   da_describe
+
+; --- da_findPage ---
+;
+; On entry:    R2 == address of the page
+;
+; On exit:     R0 == page number
+;
+; Use:         Finds the page number of the page with the address given.
+
+               IMPORT  da_findPage
+
+; --- da_addPages ---
+;
+; On entry:    R0 == number of pages to add
+;              R12 == workspace address
+;
+; On exit:     Possible error returned
+;
+; Use:         Increases the size of the dynamic area by the number of
+;              pages given in R0
+
+               IMPORT  da_addPages
+
+; --- da_removePages ---
+;
+; On entry:    R0 == number of pages to remove
+;
+; On exit:     --
+;
+; Use:         Removes the given number of pages from the dynamite
+;              area. If the number of pages to remove is greater than
+;              the actual number of pages allocated, as many as possible
+;              are removed
+
+               IMPORT  da_removePages
+
+; --- da_readSize ---
+;
+; On entry:    --
+;
+; On exit:     R0 == size of area
+;
+; Use:         Returns the size of the sprite area (including the
+;              dynamite area).
+
+               IMPORT  da_readSize
+
+; --- da_describe ---
+;
+; On entry:    --
+;
+; On exit:     R0 == dynamic area number (3 == sprite area)
+;              R1 == size of area
+;              R2 == total free in area
+;
+; Use:         Gives back som information on the dynamite area.
+
+               IMPORT  da_describe
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/sh/dynHeap b/StraySrc/Dynamite/dynamite/sh/dynHeap
new file mode 100644 (file)
index 0000000..ac4c3b6
--- /dev/null
@@ -0,0 +1,226 @@
+;
+; dynHeap.sh
+;
+; New heap management for Dynamite
+;
+; © 1994 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  dh_alloc
+;  dh_free
+;  dh_freeWithID
+;  dh_blockInfo
+;  dh_changeID
+;  dh_reduce
+;  dh_compact
+;  dh_lock
+;  dh_unlock
+;  dh_save
+;  dh_load
+;  dh_extend
+;  dh_midExtend
+;  dh_checkHeap
+;  dh_changeAnchor
+;  dh_dump
+
+               [       :LNOT::DEF:dynHeap__dfn
+               GBLL    dynHeap__dfn
+
+; --- dh_alloc ---
+;
+; On entry:    R0 == pointer to anchor
+;              R1 == size to allocate in bytes
+;              R2 == ID value to store
+;
+; On exit:     R0 and R1 preserved
+;              R2 == address of block allocated
+;
+; Use:         Allocates a block from the Dynamite heap.
+
+               IMPORT  dh_alloc
+
+; --- dh_free ---
+;
+; On entry:    R0 == pointer to anchor of block to free
+;
+; On exit:     --
+;
+; Use:         Frees a Dynamite block.
+
+               IMPORT  dh_free
+
+; --- dh_freeWithID ---
+;
+; On entry:    R0 == ID of all blocks to free
+;
+; On exit:     --
+;
+; Use:         Frees all allocated blocks with a given ID number.
+
+               IMPORT  dh_freeWithID
+
+; --- dh_blockInfo ---
+;
+; On entry:    R0 == address of block anchor
+;
+; On exit:     R0 preserved
+;              R1 == address of block
+;              R2 == size of block
+;              R3 == block ID
+;
+; Use:         Returns information about a Dynamite block
+
+               IMPORT  dh_blockInfo
+
+; --- dh_changeID ---
+;
+; On entry:    R0 == address of anchor block, or 0 for all
+;              R1 == new ID
+;              R2 == old ID (if R0 == 0)
+;
+; On exit:     --
+;
+; Use:         This call is use to change the ID of either an individual
+;              block (R0 == address of anchor), or the ID of all the
+;              blocks with the ID passed in R2 (if R0 == 0).
+
+               IMPORT  dh_changeID
+
+; --- dh_reduce ---
+;
+; On entry:    --
+;
+; On exit:     CS if there was nothing we could do
+;
+; Use:         Tries to shunt the free space in the heap off the end and
+;              back into the operating system's free pool.  It does it a
+;              little bit and then stops, rather like those workmen on the
+;              M40.
+
+               IMPORT  dh_reduce
+
+; --- dh_compact ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Does a full compaction of the heap.
+
+               IMPORT  dh_compact
+
+; --- dh_lock ---
+;
+; On entry:    --
+;
+; On exit:     R10 corrupted (SWIs don't care about this)
+;
+; Use:         Locks the heap, so that compaction entirely fails to happen.
+
+               IMPORT  dh_lock
+
+; --- dh_unlock ---
+;
+; On entry:    --
+;
+; On exit:     R10 corrupted (SWIs don't care about this)
+;
+; Use:         Unlocks the heap, so that compaction can happen again, maybe.
+
+               IMPORT  dh_unlock
+
+; --- dh_save ---
+;
+; On entry:    R0 == mask of registers to save
+;
+; On exit:     R10, R11 corrupted
+;
+; Use:         Saves a load of registers on the Dynamite relocation stack.
+;              The mask in R0 contains a bit set for each register to save:
+;              bit 3 set means save R3 etc.  Since this is a SWI, only
+;              R1-R9 can be saved on the stack.
+
+               IMPORT  dh_save
+
+; --- dh_load ---
+;
+; On entry:    R0 == mask of registers to load
+;
+; On exit:     R10, R11 corrupted
+;
+; Use:         Loads a load of registers on the Dynamite relocation stack.
+;              The mask in R0 contains a bit set for each register to load:
+;              bit 3 set means load R3 etc.  Since this is a SWI, only
+;              R1-R9 can be read from the stack.
+
+               IMPORT  dh_load
+
+; --- dh_extend ---
+;
+; On entry:    R0 == address of block anchor
+;              R1 == new size for block
+;
+; On exit:     R0 preserved
+;              R1 == address of block, may have moved
+;
+; Use:         Changes the size of a block.
+
+               IMPORT  dh_extend
+
+; --- dh_midExtend ---
+;
+; On entry:    R0 == address of block anchor
+;              R1 == byte offset from block start
+;              R2 == number of bytes to insert
+;
+; On exit:     R0 preserved
+;              R1 == address of block, may have moved
+;
+; Use:         Inserts or removes bytes at a given offset into a Dynamite
+;              heap block.
+
+               IMPORT  dh_midExtend
+
+; --- dh_checkHeap ---
+;
+; On entry:    --
+;
+; On exit:     May return an error
+;
+; Use:         Checks the current internal format of the heap to make
+;              sure that it hasn't been corrupted in any way.
+;              If the integrity check fails then an error is returned.
+
+               IMPORT  dh_checkHeap
+
+; --- dh_changeAnchor ---
+;
+; On entry:    R0 == pointer to anchor for block
+;              R1 == address of new anchor
+;
+; On exit:     --
+;
+; Use:         Adjusts a block's anchor, in case it moves.
+
+               IMPORT  dh_changeAnchor
+
+; --- dh_dump ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Outputs a textual description of the dynamite heap, giving
+;              details of each block within it.
+
+               IMPORT  dh_dump
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/sh/dynTask b/StraySrc/Dynamite/dynamite/sh/dynTask
new file mode 100644 (file)
index 0000000..5a395a4
--- /dev/null
@@ -0,0 +1,63 @@
+;
+; dynTask.sh
+;
+; The background compacting WIMP task
+;
+; © 1994 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   dt_run
+;   dt_service
+;   dt_quit
+;   dt_message
+
+; --- dt_service ---
+;
+; On entry:    R1 == service call number
+;              Other registers depend on R1
+;
+; On exit:     Depends on service call
+;
+; Use:         Handles service calls for Dynamite
+
+               IMPORT  dt_service
+
+; --- dt_quit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Closes down Dynamite's WIMP task (used for background
+;              compaction of the heap).
+
+               IMPORT  dt_quit
+
+; --- dt_run ---
+;
+; On entry:    R12 == address of module private word
+;
+; On exit:     Via OS_Exit
+;
+; Use:         Runs the Dynamite WIMP task.
+
+               IMPORT  dt_run
+
+; --- dt_message ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sends a silly message to the Compactor task so that it gets
+;              control again if it disabled idle events.
+
+               IMPORT  dt_message
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/sh/messages b/StraySrc/Dynamite/dynamite/sh/messages
new file mode 100644 (file)
index 0000000..674b91a
--- /dev/null
@@ -0,0 +1,38 @@
+;
+; Message symbols [generated by msgAOF]
+;
+
+               [       :LNOT::DEF:msg__dfn
+               GBLL    msg__dfn
+
+               IMPORT  msg_dumpHpBase
+               IMPORT  msg_dumpHpSize
+               IMPORT  msg_dumpHpArSz
+               IMPORT  msg_dumpBlkAddr
+               IMPORT  msg_dumpBlkSize
+               IMPORT  msg_dumpBlkId
+               IMPORT  msg_dumpBlkAnch
+               IMPORT  msg_dumpBlkFree
+               IMPORT  msg_errInUse
+               IMPORT  msg_errRelease
+               IMPORT  msg_errTooBig
+               IMPORT  msg_errBadSWI
+               IMPORT  msg_errNoPages
+               IMPORT  msg_errBadFreeAll
+               IMPORT  msg_errBadAnchor
+               IMPORT  msg_errNoMem
+               IMPORT  msg_errBadMid
+               IMPORT  msg_errBadHeap1
+               IMPORT  msg_errBadHeap2
+               IMPORT  msg_errBadHeap3
+               IMPORT  msg_errDesk
+               IMPORT  help_clear
+               IMPORT  synt_clear
+               IMPORT  help_compactor
+               IMPORT  synt_compactor
+               IMPORT  help_heapDump
+               IMPORT  synt_heapDump
+
+               ]
+
+               END
diff --git a/StraySrc/Dynamite/dynamite/sh/wSpace b/StraySrc/Dynamite/dynamite/sh/wSpace
new file mode 100644 (file)
index 0000000..46c4c07
--- /dev/null
@@ -0,0 +1,66 @@
+;
+; wSpace.sh
+;
+; Dynamite workspace layout
+;
+; © 1994 Straylight
+;
+
+               ^       0,R12
+dyn__wStart    #       0
+
+               ; --- Information about the Dynamite area ---
+
+dyn_machine    #       4                       ;Machine version number
+dyn_areaHandle #       0                       ;Handle of dynamic area or...
+dyn_oldChnArea #       4                       ;Old ChangeDynArea address
+dyn_areaBase   #       0                       ;Base addr of area or...
+dyn_oldReadArea        #       4                       ;Old ReadDynArea address
+dyn_oldValidate        #       4                       ;Old ValidateAddress vector
+
+               ; --- Variables for ReadDynamicArea hackery ---
+
+dyn_switchBase #       4                       ;Base of TaskManager module
+dyn_switchSize #       4                       ;Size of TaskManager module
+dyn_wimpBase   #       4                       ;Base of WindowManager module
+dyn_wimpSize   #       4                       ;Size of WindowManager module
+
+               ; --- Low-level heap details ---
+
+dyn_areaSize   #       4                       ;Current size of area
+dyn_sprSize    #       4                       ;Address of size of spr area
+dyn_pageSize   #       4                       ;The page size of the machine
+dyn_log2PageSize #     4                       ;Make a good guess
+dyn_pageCount  #       4                       ;Number of pages
+
+               ; --- Heap variables ---
+
+dyn_heapSize   #       4                       ;Space actually used in heap
+dyn_lockCount  #       4                       ;How often we've been locked
+dyn_hpFlags    #       4                       ;Some interesting heap flags
+
+hpFlag_tidy    EQU     (1<<0)                  ;The heap is nice and tidy
+hpFlag_mSent   EQU     (1<<1)                  ;A message has been sent
+
+               ; --- Anchor allocation ---
+
+dyn_ancTable   #       4                       ;Pointer to the free handles
+dyn_ancList    #       4                       ;List of big anchor blocks
+
+               ; --- Background compactor variables ---
+
+dyn_taskHandle #       4                       ;The compactor's task handle
+dyn_launch     #       4                       ;Whether we're launching
+
+               ; --- Relocation stack ---
+
+dyn_stackPtr   #       4                       ;The stack pointer
+
+               ; --- Big buffers and stuff ---
+
+dyn_pollBlk    #       256                     ;The poll block thing
+dyn_stack      #       4*256                   ;The stack area
+
+dyn_wSize      EQU     {VAR}-dyn__wStart
+
+               END
diff --git a/StraySrc/Glass/!Glass/!Boot,feb b/StraySrc/Glass/!Glass/!Boot,feb
new file mode 100644 (file)
index 0000000..4b9569f
--- /dev/null
@@ -0,0 +1,12 @@
+|
+| Glass 1.xx !Boot file
+|
+| © 1993 Straylight
+|
+| This file version 1.00 (25 March 1993)
+|
+
+Set Glass$Dir <Obey$Dir>
+IconSprites <Glass$Dir>.!Sprites
+Set Alias$Glass Run <Glass$Dir>.!Run %%*0
+Set Alias$@RunType_FEC Run <Glass$Dir>.!Run %%*0
diff --git a/StraySrc/Glass/!Glass/!Help b/StraySrc/Glass/!Glass/!Help
new file mode 100644 (file)
index 0000000..6ed30a1
--- /dev/null
@@ -0,0 +1,132 @@
+                ____
+               /             ___   ___   ___
+              /    ___ |    /___\ (___  (___
+              \______/ |___ |   | ____) ____)
+
+             ©   1 9 9 5   S t r a y l i g h t
+___________________________________________________________
+
+    We would like Glass to be the *BEST* user interface
+  design program available.  In order to do this, we need
+ *your* comments and suggestions for new features.  Please
+  send any requests, comments or anything else about this
+ program to Straylight at the address given at the bottom
+                       of this file.
+___________________________________________________________
+
+                      Program credits
+
+Glass's executable `!RunImage' contains code from the
+following sources:
+
+  * Compiled Glass source code, written by Straylight
+  * SharedCLibrary stubs, written by Straylight
+  * Steel DLL stubs, generated by Straylight's DLL system
+  * Anything else link threw in, by ARM ltd and Acorn
+
+Most of the Glass code was compiled using Acorn ANSI C. The
+rest was assembled using Acorn ARM AOF Macro Assembler
+(objasm), or autogenerated using Straylight AOF producing
+tools.
+
+Glass application icon drawn in Paint by Straylight (but
+thanks to Mike Geller for the old one).  Other graphics by
+Straylight, with the aid of the following software:
+
+  Paint by Acorn Computers Limited
+  Snippet by 4Mation
+  ArtWorks by Computer Concepts Limited
+  ChangeFSI by Acorn Computers Limited
+
+Glass window templates designed by Straylight using
+WindowEd by Armen Software for the original set, and using
+Glass enough of it had been completed.
+
+Also included in the Glass distribution are:
+
+  * Interface, by Simon Huntingdon
+  * WimpExtension, by Jon Ribbens of DoggySoft
+  * DLLManager module and other parts of the Straylight
+    Dynamic Linking System, by Straylight
+  * The `Steel' library, by Straylight
+  * Scuptrix, by Straylight
+
+With grateful thanks.
+
+___________________________________________________________
+
+                      Special thanks
+
+Thanks to Dom Symes, for Zap, which I used for all of the
+Glass source, and large chunks of Steel.
+
+Thanks to Gary Partis at Morley, for getting my SCSI system
+going.
+
+Thanks also to Jon Ribbens (of DoggySoft) for some very
+constructive comments during test stage 1.  The orange
+buttons are done specially for you (in Zap :-) ).  Oh, and
+also for the lift down to Acorn World.
+
+Thanks to Steve Haeck for the lift back :-).
+
+Thanks to all them at Armen Software.  They know who they
+are, and why.
+
+Thanks to all of the rest of the test team, both offical
+and unofficial.
+
+Finally, I'd like to thank Acorn Computers Limited, not
+only for all the software given in the list above, but also
+for their operating system, and the hardware than runs it.
+It sometimes feels like a losing battle trying to make
+RISC OS do clever things, but there's always a way, and
+it's always worth it in the end.
+___________________________________________________________
+
+                     Revision history
+
+Version    Date         Event
+
+1.00                    Finished initial version.  Time to
+                       fix the bugs :-(
+___________________________________________________________
+
+                  Things to beware of
+
+There's a tiny problem with Simon Huntingdon's Interface
+module which you should be aware of.  If you have an icon
+which contains anti-aliased fonts and a validation string
+which contains instructions to change the background colour
+when the icon is clicked, Interface can become confused and
+mangle the font data in the mistaken belief that it's icon
+colours.  I've worked around this by forcing the font
+information back into the icon, but while it's pressed in,
+the icon may appear strange (maybe the text will disappear,
+or be in a completely different font).  Be warned.  There's
+not an awful lot I can do about this.
+
+WimpExtension doesn't have this problem (which is lucky,
+because it would be much more difficult to work around).
+
+Beware of using the Toolbox on windows that start drags
+when you click on them -- they can leave the drags
+incomplete, and the application gets very confused, usually
+terminally.  I could try sending them a User_Drag_Box
+event, but I'm not sure that won't just cause more
+problems.  Grab icon used to have this problem too, but
+I've stopped using Wimp_DragBox for that now.
+
+I may consider restricting the Toolbox to Glass's own
+windows.  This feature, while not making any strictly
+illegal calls, still does somewhat strange things, and
+applications which aren't built to stand them will behave
+in ways which are unfortunately far too predicatable.
+
+There appears to be a problem in some versions of the
+WindowManager which causes an Address exception when you
+have an icon which is both anti-aliased and word-wrapped.
+The work-around for this is fairly simple: don't have these
+sorts of icons.  This is the first Wimp bug I haven't
+managed to bodge my way around somehow.
+___________________________________________________________
diff --git a/StraySrc/Glass/!Glass/!Run,feb b/StraySrc/Glass/!Glass/!Run,feb
new file mode 100644 (file)
index 0000000..9f28c9a
--- /dev/null
@@ -0,0 +1,62 @@
+|
+| Glass 1.xx !Run file
+|
+| © 1994 Straylight
+|
+| This file version 1.00 (20 March 1994)
+|
+
+Set Glass$Dir <Obey$Dir>
+IconSprites <Glass$Dir>.!Sprites
+Set Alias$Glass Run <Glass$Dir>.!Run %%*0
+Set Alias$@RunType_FEC Run <Glass$Dir>.!Run %%*0
+
+/<Glass$Dir>.setSlot -appName Glass 320K 4K
+
+Set Alias$IfUnset If "|<%%0>"="" %%*1
+Set Alias$TrySet IfUnset %%0 Then /|<Glass$Dir>.test -file %%1 -isDir -then "Run %%1"
+
+TrySet System$Path <Boot$Dir>.Resources.!System
+TrySet System$Path $.!System
+IfUnset System$Path Then Error 0 System resources could not be found.  Please double-click a !System folder and reload.
+
+TrySet Wimp$Scrap <System$Dir>.^.!Scrap
+IfUnset Wimp$Scrap Then Error 0 Couldn't find Scrap folder.  Please double click a !Scrap folder (or !System if you don't have !Scrap) and reload.
+
+TrySet DLL$Path <System$Dir>.^.!DLLs
+IfUnset DLL$Path Then Error 0 Couldn't find Dynamic Link libraries.  Please double click a !DLLs folder and reload.
+
+Unset Alias$IfUnset
+Unset Alias$TrySet
+
+Set Alias$_RMEnsure RMEnsure %%0 0.00 RMLoad %%2 |m RMEnsure %%0 %%1
+
+_RMEnsure SharedCLibrary 3.75 System:Modules.CLib
+_RMEnsure Sculptrix 2.01 <Glass$Dir>.Modules.Sculptrix
+_RMEnsure InterfaceManager 2.00 <Glass$Dir>.Modules.Interface
+_RMEnsure WimpExtension 2.18 <Glass$Dir>.Modules.WimpExt
+_RMEnsure FPEmulator 2.80 System:Modules.FPEmulator
+_RMEnsure DLLManager 1.14 <DLL$Dir>.DLLManager
+_RMEnsure ColourTrans 0.51 System:Modules.Colours
+
+Unset Alias$_RMEnsure
+
+DLLEnsure Steel 1.00
+
+/<Glass$Dir>.setSlot -appName Glass 320K 4K
+
+Set Alias$AddCLI If "%%*0"<>"" Then Set Glass$CLI |<Glass$CLI> %%*0
+Set Alias$IfRun /<Glass$Dir>.test -file %%0 -isFile -then "Run %%*0"
+
+Set Glass$CLI ""
+Set Glass$Image <Glass$Dir>.!RunImage
+IfRun <Glass$Dir>.Setup %*0
+If "<Glass$CLI>"="" Then Set Glass$CLI "%*0"
+
+Unset Alias$IfRun
+Unset Alias$AddCLI
+
+Set Alias$_Glass Unset Alias$_Glass |m Run <Glass$Image> <Glass$CLI>
+Unset Glass$CLI
+Unset Glass$Image
+_Glass
\ No newline at end of file
diff --git a/StraySrc/Glass/!Glass/!Sprites,ff9 b/StraySrc/Glass/!Glass/!Sprites,ff9
new file mode 100644 (file)
index 0000000..39c0503
Binary files /dev/null and b/StraySrc/Glass/!Glass/!Sprites,ff9 differ
diff --git a/StraySrc/Glass/!Glass/Choices b/StraySrc/Glass/!Glass/Choices
new file mode 100644 (file)
index 0000000..24e41e3
--- /dev/null
@@ -0,0 +1,70 @@
+;
+; Glass preferences
+;
+
+Autosave_TimeUnits=minutes
+Autosave_Time=5
+Autosave_Alterations=0
+Autosave_Prompt=false
+
+Interface_DisplayBorders=false
+Interface_SlabIcons=true
+Interface_DragboxAroundBorder=true
+Interface_SlabOnMenu=false
+
+WimpExtension_DisplayBorders=false
+WimpExtension_KeyPress=true
+WimpExtension_DragboxAroundBorder=true
+
+Sculptrix_DisplayBorders=true
+Sculptrix_SlabIcons=true
+Sculptrix_DragboxAroundBorder=true
+Sculptrix_SlabOnMenu=false
+
+Sprites_LoadSprites=true
+Sprites_Load!Sprites=true
+Sprites_LoadDefaults=false
+
+Files_IconSize=small
+Files_SortBy name
+
+Grid_Display=false
+Grid_Lock=false
+Grid_Width=16
+Grid_Height=16
+Grid_DrawLines=false
+Grid_GridColour=8
+Grid_GuideColour=3
+Grid_SelectedGuideColour=3
+
+Select_DrawBorder=true
+Select_DottedBorder=true
+Select_BorderColour=3
+Select_EdgeHandles=true
+Select_HandleSize=4
+Select_HandleColour=7
+Select_SpecialColour=11
+
+Confirm_Quit=true
+Confirm_Close=true
+Confirm_DelWind=true
+Confirm_DelIcon=false
+Confirm_TestCloseEdit=false
+Confirm_Overwrite=true
+
+Toolbar_Display=true
+Toolbar_Floating=false
+Toolbar_Position=-18,0
+Toolbar_OnLeft=true
+
+Infobar_Display=true
+Infobar_Floating=false
+Infobar_Position=0,-16
+Infobar_Underneath=true
+
+Misc_DrawHatch=false
+Misc_BlinkCursor=true
+Misc_VisibleInWork=true
+Misc_CreateOnTop=true
+Misc_RenumberOnDelete=true
+Misc_ControlToEdit=false
diff --git a/StraySrc/Glass/!Glass/Defaults/Templates,fec b/StraySrc/Glass/!Glass/Defaults/Templates,fec
new file mode 100644 (file)
index 0000000..eacdf85
Binary files /dev/null and b/StraySrc/Glass/!Glass/Defaults/Templates,fec differ
diff --git a/StraySrc/Glass/!Glass/Makefile,fe1 b/StraySrc/Glass/!Glass/Makefile,fe1
new file mode 100644 (file)
index 0000000..a0105ea
--- /dev/null
@@ -0,0 +1,1188 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © 1994-%ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+OBJ = \
+       o.glass \
+       o.align o.colSelect o.toolbox \
+       o.editIcon o.editWin o.gPrefs o.tearEdit \
+       o.gSprite o.tfile \
+       o.iconData o.indir o.intMsgs o.toolSupprt \
+       o.wDragging o.wGrab o.wGraph o.wIcons o.window o.wMenus \
+               o.wMousePtr o.wPalette o.wRedraw o.wSelect o.wToolbars \
+               o.wWindows o.wWinEvent
+
+LIBS = libs:o.astubs libs:lib.steeldll libs:o.dlllib libs:o.swiv
+
+#----- Compiling things -----------------------------------------------------
+
+all: !RunImage Modules.Sculptrix setSlot test
+
+install:
+
+clean:
+       -$(RM) o.* !RunImage Modules.Sculptrix setSlot test
+
+#----- Nitty Gritty Bitties -------------------------------------------------
+
+!RunImage: $(OBJ) $(LIBS)
+       $(SETDATE) o.version date="$(DATE)" cright="$(CRIGHT)"
+       $(LD_APP) $(OBJ) o.version $(LIBS)
+       $(SQUEEZE)
+       $(SET_APP)
+
+Modules.Sculptrix: <SSR$ModDir>.Sculptrix
+       $(INSTALL) <SSR$ModDir>.Sculptrix Modules
+
+setSlot: <SSR$BinDir>.setSlot
+       $(INSTALL) <SSR$BinDir>.setSlot @
+
+test: <SSR$BinDir>.test
+       $(INSTALL) <SSR$BinDir>.test @
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.tearEdit:    c.tearEdit
+o.tearEdit:    libs:steel.h.Steel
+o.tearEdit:    libs:steel.h.wimp
+o.tearEdit:    libs:steel.h.wimpstruct
+o.tearEdit:    libs:steel.h.os
+o.tearEdit:    C:h.kernel
+o.tearEdit:    libs:steel.h.sprite
+o.tearEdit:    libs:steel.h.wimpt
+o.tearEdit:    libs:steel.h.win
+o.tearEdit:    libs:steel.h.event
+o.tearEdit:    libs:steel.h.menu
+o.tearEdit:    libs:steel.h.ibicon
+o.tearEdit:    libs:steel.h.res
+o.tearEdit:    libs:steel.h.resspr
+o.tearEdit:    libs:steel.h.template
+o.tearEdit:    libs:steel.h.dbox
+o.tearEdit:    libs:steel.h.mem
+o.tearEdit:    libs:steel.h.visdelay
+o.tearEdit:    libs:steel.h.help
+o.tearEdit:    libs:steel.h.exception
+o.tearEdit:    libs:h.dll
+o.tearEdit:    libs:steel.h.msgs
+o.tearEdit:    libs:steel.h.utils
+o.tearEdit:    libs:steel.h.stddbox
+o.tearEdit:    libs:steel.h.xfersend
+o.tearEdit:    libs:steel.h.werr
+o.tearEdit:    libs:steel.h.buttons
+o.tearEdit:    libs:steel.h.akbd
+o.tearEdit:    libs:steel.h.buffer
+o.tearEdit:    libs:steel.h.colourtran
+o.tearEdit:    libs:steel.h.font
+o.tearEdit:    C:h.drawmod
+o.tearEdit:    libs:steel.h.tearoff
+o.tearEdit:    h.gStruct
+o.tearEdit:    h.gPrefs
+o.tearEdit:    h.glass
+o.tearEdit:    libs:steel.h.viewer
+o.tearEdit:    libs:steel.h.pane
+o.tearEdit:    libs:steel.h.listbox
+o.tearEdit:    h.glass
+o.tearEdit:    h.window
+o.tearEdit:    h.tfile
+o.tearEdit:    h.indir
+o.tearEdit:    h.tearEdit
+o.tearEdit:    h.gStruct
+o.iconData:    c.iconData
+o.iconData:    libs:steel.h.Steel
+o.iconData:    libs:steel.h.wimp
+o.iconData:    libs:steel.h.wimpstruct
+o.iconData:    libs:steel.h.os
+o.iconData:    C:h.kernel
+o.iconData:    libs:steel.h.sprite
+o.iconData:    libs:steel.h.wimpt
+o.iconData:    libs:steel.h.win
+o.iconData:    libs:steel.h.event
+o.iconData:    libs:steel.h.menu
+o.iconData:    libs:steel.h.ibicon
+o.iconData:    libs:steel.h.res
+o.iconData:    libs:steel.h.resspr
+o.iconData:    libs:steel.h.template
+o.iconData:    libs:steel.h.dbox
+o.iconData:    libs:steel.h.mem
+o.iconData:    libs:steel.h.visdelay
+o.iconData:    libs:steel.h.help
+o.iconData:    libs:steel.h.exception
+o.iconData:    libs:h.dll
+o.iconData:    libs:steel.h.msgs
+o.iconData:    libs:steel.h.utils
+o.iconData:    libs:steel.h.stddbox
+o.iconData:    libs:steel.h.xfersend
+o.iconData:    libs:steel.h.werr
+o.iconData:    libs:h.swis
+o.iconData:    h.gStruct
+o.iconData:    h.gPrefs
+o.iconData:    h.glass
+o.iconData:    libs:steel.h.viewer
+o.iconData:    libs:steel.h.pane
+o.iconData:    libs:steel.h.listbox
+o.iconData:    h.glass
+o.iconData:    h.iconData
+o.iconData:    h.indir
+o.intMsgs:     c.intMsgs
+o.intMsgs:     libs:steel.h.Steel
+o.intMsgs:     libs:steel.h.wimp
+o.intMsgs:     libs:steel.h.wimpstruct
+o.intMsgs:     libs:steel.h.os
+o.intMsgs:     C:h.kernel
+o.intMsgs:     libs:steel.h.sprite
+o.intMsgs:     libs:steel.h.wimpt
+o.intMsgs:     libs:steel.h.win
+o.intMsgs:     libs:steel.h.event
+o.intMsgs:     libs:steel.h.menu
+o.intMsgs:     libs:steel.h.ibicon
+o.intMsgs:     libs:steel.h.res
+o.intMsgs:     libs:steel.h.resspr
+o.intMsgs:     libs:steel.h.template
+o.intMsgs:     libs:steel.h.dbox
+o.intMsgs:     libs:steel.h.mem
+o.intMsgs:     libs:steel.h.visdelay
+o.intMsgs:     libs:steel.h.help
+o.intMsgs:     libs:steel.h.exception
+o.intMsgs:     libs:h.dll
+o.intMsgs:     libs:steel.h.msgs
+o.intMsgs:     libs:steel.h.utils
+o.intMsgs:     libs:steel.h.stddbox
+o.intMsgs:     libs:steel.h.xfersend
+o.intMsgs:     libs:steel.h.werr
+o.intMsgs:     h.glass
+o.intMsgs:     h.intMsgs
+o.intMsgs:     h.gStruct
+o.intMsgs:     h.gPrefs
+o.intMsgs:     libs:steel.h.viewer
+o.intMsgs:     libs:steel.h.pane
+o.intMsgs:     libs:steel.h.listbox
+o.toolSupprt: s.toolSupprt
+o.toolSupprt: libs:Header
+o.toolSupprt: libs:SWIs
+o.window:      c.window
+o.window:      h.window
+o.window:      h.gStruct
+o.window:      h.gPrefs
+o.window:      h.glass
+o.window:      libs:steel.h.wimp
+o.window:      libs:steel.h.wimpstruct
+o.window:      libs:steel.h.os
+o.window:      C:h.kernel
+o.window:      libs:steel.h.sprite
+o.window:      libs:steel.h.dbox
+o.window:      libs:steel.h.event
+o.window:      libs:steel.h.menu
+o.window:      libs:steel.h.viewer
+o.window:      libs:steel.h.pane
+o.window:      libs:steel.h.listbox
+o.window:      h._window
+o.window:      h.gStruct
+o.glass:       c.glass
+o.glass:       libs:h.dll
+o.glass:       libs:h.os
+o.glass:       C:h.kernel
+o.glass:       libs:h.wimp
+o.glass:       libs:h.wimpstruct
+o.glass:       libs:h.sprite
+o.glass:       libs:steel.h.Steel
+o.glass:       libs:steel.h.wimpt
+o.glass:       libs:steel.h.win
+o.glass:       libs:steel.h.event
+o.glass:       libs:steel.h.menu
+o.glass:       libs:steel.h.ibicon
+o.glass:       libs:steel.h.res
+o.glass:       libs:steel.h.resspr
+o.glass:       libs:steel.h.template
+o.glass:       libs:steel.h.dbox
+o.glass:       libs:steel.h.mem
+o.glass:       libs:steel.h.visdelay
+o.glass:       libs:steel.h.help
+o.glass:       libs:steel.h.exception
+o.glass:       libs:steel.h.msgs
+o.glass:       libs:steel.h.utils
+o.glass:       libs:steel.h.stddbox
+o.glass:       libs:steel.h.xfersend
+o.glass:       libs:steel.h.werr
+o.glass:       libs:steel.h.xferrecv
+o.glass:       libs:steel.h.flex
+o.glass:       libs:steel.h.saveas
+o.glass:       libs:h.swis
+o.glass:       libs:steel.h.viewer
+o.glass:       libs:steel.h.mem
+o.glass:       libs:steel.h.caretptr
+o.glass:       libs:steel.h.pointer
+o.glass:       libs:steel.h.buttons
+o.glass:       libs:steel.h.sculptrix
+o.glass:       libs:steel.h.flex
+o.glass:       h.gStruct
+o.glass:       h.gPrefs
+o.glass:       h.glass
+o.glass:       libs:steel.h.pane
+o.glass:       libs:steel.h.listbox
+o.glass:       h.gIcons
+o.glass:       h.gMenus
+o.glass:       h.glass
+o.glass:       h.toolbox
+o.glass:       h.tfile
+o.glass:       h.intMsgs
+o.glass:       h.gPrefs
+o.glass:       h.gSprite
+o.glass:       h.indir
+o.glass:       h.window
+o.glass:       h.tearEdit
+o.glass:       h.gStruct
+o.align:       c.align
+o.align:       libs:steel.h.Steel
+o.align:       libs:steel.h.wimp
+o.align:       libs:steel.h.wimpstruct
+o.align:       libs:steel.h.os
+o.align:       C:h.kernel
+o.align:       libs:steel.h.sprite
+o.align:       libs:steel.h.wimpt
+o.align:       libs:steel.h.win
+o.align:       libs:steel.h.event
+o.align:       libs:steel.h.menu
+o.align:       libs:steel.h.ibicon
+o.align:       libs:steel.h.res
+o.align:       libs:steel.h.resspr
+o.align:       libs:steel.h.template
+o.align:       libs:steel.h.dbox
+o.align:       libs:steel.h.mem
+o.align:       libs:steel.h.visdelay
+o.align:       libs:steel.h.help
+o.align:       libs:steel.h.exception
+o.align:       libs:h.dll
+o.align:       libs:steel.h.msgs
+o.align:       libs:steel.h.utils
+o.align:       libs:steel.h.stddbox
+o.align:       libs:steel.h.xfersend
+o.align:       libs:steel.h.werr
+o.align:       h.gIcons
+o.align:       h.glass
+o.align:       h.window
+o.align:       h.gStruct
+o.align:       h.gPrefs
+o.align:       libs:steel.h.viewer
+o.align:       libs:steel.h.pane
+o.align:       libs:steel.h.listbox
+o.align:       h.align
+o.align:       h.tfile
+o.colSelect:   c.colSelect
+o.colSelect:   libs:steel.h.Steel
+o.colSelect:   libs:steel.h.wimp
+o.colSelect:   libs:steel.h.wimpstruct
+o.colSelect:   libs:steel.h.os
+o.colSelect:   C:h.kernel
+o.colSelect:   libs:steel.h.sprite
+o.colSelect:   libs:steel.h.wimpt
+o.colSelect:   libs:steel.h.win
+o.colSelect:   libs:steel.h.event
+o.colSelect:   libs:steel.h.menu
+o.colSelect:   libs:steel.h.ibicon
+o.colSelect:   libs:steel.h.res
+o.colSelect:   libs:steel.h.resspr
+o.colSelect:   libs:steel.h.template
+o.colSelect:   libs:steel.h.dbox
+o.colSelect:   libs:steel.h.mem
+o.colSelect:   libs:steel.h.visdelay
+o.colSelect:   libs:steel.h.help
+o.colSelect:   libs:steel.h.exception
+o.colSelect:   libs:h.dll
+o.colSelect:   libs:steel.h.msgs
+o.colSelect:   libs:steel.h.utils
+o.colSelect:   libs:steel.h.stddbox
+o.colSelect:   libs:steel.h.xfersend
+o.colSelect:   libs:steel.h.werr
+o.colSelect:   libs:steel.h.akbd
+o.colSelect:   libs:steel.h.colourtran
+o.colSelect:   libs:steel.h.font
+o.colSelect:   C:h.drawmod
+o.colSelect:   h.gIcons
+o.colSelect:   h.glass
+o.colSelect:   h.colSelect
+o.toolbox:     c.toolbox
+o.toolbox:     libs:steel.h.Steel
+o.toolbox:     libs:steel.h.wimp
+o.toolbox:     libs:steel.h.wimpstruct
+o.toolbox:     libs:steel.h.os
+o.toolbox:     C:h.kernel
+o.toolbox:     libs:steel.h.sprite
+o.toolbox:     libs:steel.h.wimpt
+o.toolbox:     libs:steel.h.win
+o.toolbox:     libs:steel.h.event
+o.toolbox:     libs:steel.h.menu
+o.toolbox:     libs:steel.h.ibicon
+o.toolbox:     libs:steel.h.res
+o.toolbox:     libs:steel.h.resspr
+o.toolbox:     libs:steel.h.template
+o.toolbox:     libs:steel.h.dbox
+o.toolbox:     libs:steel.h.mem
+o.toolbox:     libs:steel.h.visdelay
+o.toolbox:     libs:steel.h.help
+o.toolbox:     libs:steel.h.exception
+o.toolbox:     libs:h.dll
+o.toolbox:     libs:steel.h.msgs
+o.toolbox:     libs:steel.h.utils
+o.toolbox:     libs:steel.h.stddbox
+o.toolbox:     libs:steel.h.xfersend
+o.toolbox:     libs:steel.h.werr
+o.toolbox:     libs:steel.h.sculptrix
+o.toolbox:     libs:steel.h.pointer
+o.toolbox:     libs:steel.h.bbc
+o.toolbox:     h.gIcons
+o.toolbox:     h.glass
+o.toolbox:     h.toolbox
+o.editIcon:    c.editIcon
+o.editIcon:    libs:steel.h.Steel
+o.editIcon:    libs:steel.h.wimp
+o.editIcon:    libs:steel.h.wimpstruct
+o.editIcon:    libs:steel.h.os
+o.editIcon:    C:h.kernel
+o.editIcon:    libs:steel.h.sprite
+o.editIcon:    libs:steel.h.wimpt
+o.editIcon:    libs:steel.h.win
+o.editIcon:    libs:steel.h.event
+o.editIcon:    libs:steel.h.menu
+o.editIcon:    libs:steel.h.ibicon
+o.editIcon:    libs:steel.h.res
+o.editIcon:    libs:steel.h.resspr
+o.editIcon:    libs:steel.h.template
+o.editIcon:    libs:steel.h.dbox
+o.editIcon:    libs:steel.h.mem
+o.editIcon:    libs:steel.h.visdelay
+o.editIcon:    libs:steel.h.help
+o.editIcon:    libs:steel.h.exception
+o.editIcon:    libs:h.dll
+o.editIcon:    libs:steel.h.msgs
+o.editIcon:    libs:steel.h.utils
+o.editIcon:    libs:steel.h.stddbox
+o.editIcon:    libs:steel.h.xfersend
+o.editIcon:    libs:steel.h.werr
+o.editIcon:    libs:h.swis
+o.editIcon:    libs:steel.h.buttons
+o.editIcon:    libs:steel.h.fontMenu
+o.editIcon:    libs:steel.h.akbd
+o.editIcon:    libs:steel.h.bbc
+o.editIcon:    libs:steel.h.buffer
+o.editIcon:    libs:steel.h.font
+o.editIcon:    C:h.drawmod
+o.editIcon:    h.gStruct
+o.editIcon:    h.gPrefs
+o.editIcon:    h.glass
+o.editIcon:    libs:steel.h.viewer
+o.editIcon:    libs:steel.h.pane
+o.editIcon:    libs:steel.h.listbox
+o.editIcon:    h.gMenus
+o.editIcon:    h.gIcons
+o.editIcon:    h.glass
+o.editIcon:    h.tfile
+o.editIcon:    h.window
+o.editIcon:    h.intMsgs
+o.editIcon:    h.editIcon
+o.editIcon:    h.colSelect
+o.editIcon:    h.indir
+o.editIcon:    h.gPrefs
+o.editWin:     c.editWin
+o.editWin:     libs:steel.h.Steel
+o.editWin:     libs:steel.h.wimp
+o.editWin:     libs:steel.h.wimpstruct
+o.editWin:     libs:steel.h.os
+o.editWin:     C:h.kernel
+o.editWin:     libs:steel.h.sprite
+o.editWin:     libs:steel.h.wimpt
+o.editWin:     libs:steel.h.win
+o.editWin:     libs:steel.h.event
+o.editWin:     libs:steel.h.menu
+o.editWin:     libs:steel.h.ibicon
+o.editWin:     libs:steel.h.res
+o.editWin:     libs:steel.h.resspr
+o.editWin:     libs:steel.h.template
+o.editWin:     libs:steel.h.dbox
+o.editWin:     libs:steel.h.mem
+o.editWin:     libs:steel.h.visdelay
+o.editWin:     libs:steel.h.help
+o.editWin:     libs:steel.h.exception
+o.editWin:     libs:h.dll
+o.editWin:     libs:steel.h.msgs
+o.editWin:     libs:steel.h.utils
+o.editWin:     libs:steel.h.stddbox
+o.editWin:     libs:steel.h.xfersend
+o.editWin:     libs:steel.h.werr
+o.editWin:     libs:h.swis
+o.editWin:     libs:steel.h.buttons
+o.editWin:     libs:steel.h.fontMenu
+o.editWin:     libs:steel.h.akbd
+o.editWin:     libs:steel.h.buffer
+o.editWin:     libs:steel.h.font
+o.editWin:     C:h.drawmod
+o.editWin:     h.glass
+o.editWin:     h.tfile
+o.editWin:     h.gStruct
+o.editWin:     h.gPrefs
+o.editWin:     libs:steel.h.viewer
+o.editWin:     libs:steel.h.pane
+o.editWin:     libs:steel.h.listbox
+o.editWin:     h.window
+o.editWin:     h.intMsgs
+o.editWin:     h.editWin
+o.editWin:     h.colSelect
+o.editWin:     h.indir
+o.editWin:     h.gPrefs
+o.editWin:     h.gStruct
+o.editWin:     h.gMenus
+o.editWin:     h.gIcons
+o.gPrefs:      c.gPrefs
+o.gPrefs:      libs:steel.h.Steel
+o.gPrefs:      libs:steel.h.wimp
+o.gPrefs:      libs:steel.h.wimpstruct
+o.gPrefs:      libs:steel.h.os
+o.gPrefs:      C:h.kernel
+o.gPrefs:      libs:steel.h.sprite
+o.gPrefs:      libs:steel.h.wimpt
+o.gPrefs:      libs:steel.h.win
+o.gPrefs:      libs:steel.h.event
+o.gPrefs:      libs:steel.h.menu
+o.gPrefs:      libs:steel.h.ibicon
+o.gPrefs:      libs:steel.h.res
+o.gPrefs:      libs:steel.h.resspr
+o.gPrefs:      libs:steel.h.template
+o.gPrefs:      libs:steel.h.dbox
+o.gPrefs:      libs:steel.h.mem
+o.gPrefs:      libs:steel.h.visdelay
+o.gPrefs:      libs:steel.h.help
+o.gPrefs:      libs:steel.h.exception
+o.gPrefs:      libs:h.dll
+o.gPrefs:      libs:steel.h.msgs
+o.gPrefs:      libs:steel.h.utils
+o.gPrefs:      libs:steel.h.stddbox
+o.gPrefs:      libs:steel.h.xfersend
+o.gPrefs:      libs:steel.h.werr
+o.gPrefs:      libs:steel.h.prefs
+o.gPrefs:      libs:steel.h.pane
+o.gPrefs:      libs:steel.h.listbox
+o.gPrefs:      libs:steel.h.blinkC
+o.gPrefs:      libs:steel.h.buttons
+o.gPrefs:      libs:steel.h.akbd
+o.gPrefs:      h.gIcons
+o.gPrefs:      h.gMenus
+o.gPrefs:      h.glass
+o.gPrefs:      h.gPrefs
+o.gPrefs:      h.intMsgs
+o.gPrefs:      h.gStruct
+o.gPrefs:      libs:steel.h.viewer
+o.gPrefs:      h.colSelect
+o.gPrefs:      h.window
+o.gSprite:     c.gSprite
+o.gSprite:     libs:steel.h.Steel
+o.gSprite:     libs:steel.h.wimp
+o.gSprite:     libs:steel.h.wimpstruct
+o.gSprite:     libs:steel.h.os
+o.gSprite:     C:h.kernel
+o.gSprite:     libs:steel.h.sprite
+o.gSprite:     libs:steel.h.wimpt
+o.gSprite:     libs:steel.h.win
+o.gSprite:     libs:steel.h.event
+o.gSprite:     libs:steel.h.menu
+o.gSprite:     libs:steel.h.ibicon
+o.gSprite:     libs:steel.h.res
+o.gSprite:     libs:steel.h.resspr
+o.gSprite:     libs:steel.h.template
+o.gSprite:     libs:steel.h.dbox
+o.gSprite:     libs:steel.h.mem
+o.gSprite:     libs:steel.h.visdelay
+o.gSprite:     libs:steel.h.help
+o.gSprite:     libs:steel.h.exception
+o.gSprite:     libs:h.dll
+o.gSprite:     libs:steel.h.msgs
+o.gSprite:     libs:steel.h.utils
+o.gSprite:     libs:steel.h.stddbox
+o.gSprite:     libs:steel.h.xfersend
+o.gSprite:     libs:steel.h.werr
+o.gSprite:     libs:steel.h.xferrecv
+o.gSprite:     libs:steel.h.flex
+o.gSprite:     libs:steel.h.saveas
+o.gSprite:     libs:h.swis
+o.gSprite:     libs:steel.h.viewer
+o.gSprite:     libs:steel.h.flex
+o.gSprite:     libs:steel.h.akbd
+o.gSprite:     libs:steel.h.bbc
+o.gSprite:     libs:steel.h.choices
+o.gSprite:     libs:steel.h.colourtran
+o.gSprite:     libs:steel.h.font
+o.gSprite:     C:h.drawmod
+o.gSprite:     h.gStruct
+o.gSprite:     h.gPrefs
+o.gSprite:     h.glass
+o.gSprite:     libs:steel.h.pane
+o.gSprite:     libs:steel.h.listbox
+o.gSprite:     h.gMenus
+o.gSprite:     h.gIcons
+o.gSprite:     h.glass
+o.gSprite:     h.intMsgs
+o.gSprite:     h.gSprite
+o.gSprite:     h.gPrefs
+o.gSprite:     h.indir
+o.gSprite:     h.window
+o.gSprite:     h.tfile
+o.tfile:       c.tfile
+o.tfile:       libs:steel.h.Steel
+o.tfile:       libs:steel.h.wimp
+o.tfile:       libs:steel.h.wimpstruct
+o.tfile:       libs:steel.h.os
+o.tfile:       C:h.kernel
+o.tfile:       libs:steel.h.sprite
+o.tfile:       libs:steel.h.wimpt
+o.tfile:       libs:steel.h.win
+o.tfile:       libs:steel.h.event
+o.tfile:       libs:steel.h.menu
+o.tfile:       libs:steel.h.ibicon
+o.tfile:       libs:steel.h.res
+o.tfile:       libs:steel.h.resspr
+o.tfile:       libs:steel.h.template
+o.tfile:       libs:steel.h.dbox
+o.tfile:       libs:steel.h.mem
+o.tfile:       libs:steel.h.visdelay
+o.tfile:       libs:steel.h.help
+o.tfile:       libs:steel.h.exception
+o.tfile:       libs:h.dll
+o.tfile:       libs:steel.h.msgs
+o.tfile:       libs:steel.h.utils
+o.tfile:       libs:steel.h.stddbox
+o.tfile:       libs:steel.h.xfersend
+o.tfile:       libs:steel.h.werr
+o.tfile:       libs:steel.h.xferrecv
+o.tfile:       libs:steel.h.flex
+o.tfile:       libs:steel.h.saveas
+o.tfile:       libs:h.swis
+o.tfile:       libs:steel.h.viewer
+o.tfile:       libs:steel.h.mem
+o.tfile:       libs:steel.h.nopoll
+o.tfile:       libs:steel.h.flex
+o.tfile:       libs:steel.h.akbd
+o.tfile:       libs:steel.h.alarm
+o.tfile:       libs:steel.h.bbc
+o.tfile:       libs:steel.h.buffer
+o.tfile:       libs:steel.h.font
+o.tfile:       C:h.drawmod
+o.tfile:       h.gStruct
+o.tfile:       h.gPrefs
+o.tfile:       h.glass
+o.tfile:       libs:steel.h.pane
+o.tfile:       libs:steel.h.listbox
+o.tfile:       h.gIcons
+o.tfile:       h.gMenus
+o.tfile:       h.glass
+o.tfile:       h.toolbox
+o.tfile:       h.intMsgs
+o.tfile:       h.tfile
+o.tfile:       h.gPrefs
+o.tfile:       h.gSprite
+o.tfile:       h.indir
+o.tfile:       h.window
+o.tfile:       h.editWin
+o.tfile:       h.iconData
+o.indir:       c.indir
+o.indir:       libs:steel.h.Steel
+o.indir:       libs:steel.h.wimp
+o.indir:       libs:steel.h.wimpstruct
+o.indir:       libs:steel.h.os
+o.indir:       C:h.kernel
+o.indir:       libs:steel.h.sprite
+o.indir:       libs:steel.h.wimpt
+o.indir:       libs:steel.h.win
+o.indir:       libs:steel.h.event
+o.indir:       libs:steel.h.menu
+o.indir:       libs:steel.h.ibicon
+o.indir:       libs:steel.h.res
+o.indir:       libs:steel.h.resspr
+o.indir:       libs:steel.h.template
+o.indir:       libs:steel.h.dbox
+o.indir:       libs:steel.h.mem
+o.indir:       libs:steel.h.visdelay
+o.indir:       libs:steel.h.help
+o.indir:       libs:steel.h.exception
+o.indir:       libs:h.dll
+o.indir:       libs:steel.h.msgs
+o.indir:       libs:steel.h.utils
+o.indir:       libs:steel.h.stddbox
+o.indir:       libs:steel.h.xfersend
+o.indir:       libs:steel.h.werr
+o.indir:       libs:steel.h.buttons
+o.indir:       libs:steel.h.bbc
+o.indir:       h.gIcons
+o.indir:       h.glass
+o.indir:       libs:h.heap
+o.indir:       h.indir
+o.wDragging:   c.wDragging
+o.wDragging:   libs:steel.h.Steel
+o.wDragging:   libs:steel.h.wimp
+o.wDragging:   libs:steel.h.wimpstruct
+o.wDragging:   libs:steel.h.os
+o.wDragging:   C:h.kernel
+o.wDragging:   libs:steel.h.sprite
+o.wDragging:   libs:steel.h.wimpt
+o.wDragging:   libs:steel.h.win
+o.wDragging:   libs:steel.h.event
+o.wDragging:   libs:steel.h.menu
+o.wDragging:   libs:steel.h.ibicon
+o.wDragging:   libs:steel.h.res
+o.wDragging:   libs:steel.h.resspr
+o.wDragging:   libs:steel.h.template
+o.wDragging:   libs:steel.h.dbox
+o.wDragging:   libs:steel.h.mem
+o.wDragging:   libs:steel.h.visdelay
+o.wDragging:   libs:steel.h.help
+o.wDragging:   libs:steel.h.exception
+o.wDragging:   libs:h.dll
+o.wDragging:   libs:steel.h.msgs
+o.wDragging:   libs:steel.h.utils
+o.wDragging:   libs:steel.h.stddbox
+o.wDragging:   libs:steel.h.xfersend
+o.wDragging:   libs:steel.h.werr
+o.wDragging:   libs:h.swis
+o.wDragging:   libs:steel.h.akbd
+o.wDragging:   libs:steel.h.coords
+o.wDragging:   libs:steel.h.wimp
+o.wDragging:   libs:steel.h.bbc
+o.wDragging:   h.gStruct
+o.wDragging:   h.gPrefs
+o.wDragging:   h.glass
+o.wDragging:   libs:steel.h.viewer
+o.wDragging:   libs:steel.h.pane
+o.wDragging:   libs:steel.h.listbox
+o.wDragging:   h.gMenus
+o.wDragging:   h.gIcons
+o.wDragging:   h.glass
+o.wDragging:   h.gPrefs
+o.wDragging:   h.tfile
+o.wDragging:   h.window
+o.wDragging:   h._window
+o.wDragging:   h.gStruct
+o.wDragging:   h.editIcon
+o.wDragging:   h.editWin
+o.wGrab:       c.wGrab
+o.wGrab:       libs:steel.h.Steel
+o.wGrab:       libs:steel.h.wimp
+o.wGrab:       libs:steel.h.wimpstruct
+o.wGrab:       libs:steel.h.os
+o.wGrab:       C:h.kernel
+o.wGrab:       libs:steel.h.sprite
+o.wGrab:       libs:steel.h.wimpt
+o.wGrab:       libs:steel.h.win
+o.wGrab:       libs:steel.h.event
+o.wGrab:       libs:steel.h.menu
+o.wGrab:       libs:steel.h.ibicon
+o.wGrab:       libs:steel.h.res
+o.wGrab:       libs:steel.h.resspr
+o.wGrab:       libs:steel.h.template
+o.wGrab:       libs:steel.h.dbox
+o.wGrab:       libs:steel.h.mem
+o.wGrab:       libs:steel.h.visdelay
+o.wGrab:       libs:steel.h.help
+o.wGrab:       libs:steel.h.exception
+o.wGrab:       libs:h.dll
+o.wGrab:       libs:steel.h.msgs
+o.wGrab:       libs:steel.h.utils
+o.wGrab:       libs:steel.h.stddbox
+o.wGrab:       libs:steel.h.xfersend
+o.wGrab:       libs:steel.h.werr
+o.wGrab:       libs:h.swis
+o.wGrab:       libs:steel.h.pointer
+o.wGrab:       libs:steel.h.bbc
+o.wGrab:       libs:steel.h.buffer
+o.wGrab:       h.gStruct
+o.wGrab:       h.gPrefs
+o.wGrab:       h.glass
+o.wGrab:       libs:steel.h.viewer
+o.wGrab:       libs:steel.h.pane
+o.wGrab:       libs:steel.h.listbox
+o.wGrab:       h.gMenus
+o.wGrab:       h.gIcons
+o.wGrab:       h.glass
+o.wGrab:       h.gPrefs
+o.wGrab:       h.tfile
+o.wGrab:       h.window
+o.wGrab:       h._window
+o.wGrab:       h.gStruct
+o.wGrab:       h.iconData
+o.wGraph:      c.wGraph
+o.wGraph:      libs:steel.h.Steel
+o.wGraph:      libs:steel.h.wimp
+o.wGraph:      libs:steel.h.wimpstruct
+o.wGraph:      libs:steel.h.os
+o.wGraph:      C:h.kernel
+o.wGraph:      libs:steel.h.sprite
+o.wGraph:      libs:steel.h.wimpt
+o.wGraph:      libs:steel.h.win
+o.wGraph:      libs:steel.h.event
+o.wGraph:      libs:steel.h.menu
+o.wGraph:      libs:steel.h.ibicon
+o.wGraph:      libs:steel.h.res
+o.wGraph:      libs:steel.h.resspr
+o.wGraph:      libs:steel.h.template
+o.wGraph:      libs:steel.h.dbox
+o.wGraph:      libs:steel.h.mem
+o.wGraph:      libs:steel.h.visdelay
+o.wGraph:      libs:steel.h.help
+o.wGraph:      libs:steel.h.exception
+o.wGraph:      libs:h.dll
+o.wGraph:      libs:steel.h.msgs
+o.wGraph:      libs:steel.h.utils
+o.wGraph:      libs:steel.h.stddbox
+o.wGraph:      libs:steel.h.xfersend
+o.wGraph:      libs:steel.h.werr
+o.wGraph:      libs:h.swis
+o.wGraph:      libs:steel.h.bbc
+o.wGraph:      libs:steel.h.colourtran
+o.wGraph:      libs:steel.h.font
+o.wGraph:      C:h.drawmod
+o.wGraph:      h.gStruct
+o.wGraph:      h.gPrefs
+o.wGraph:      h.glass
+o.wGraph:      libs:steel.h.viewer
+o.wGraph:      libs:steel.h.pane
+o.wGraph:      libs:steel.h.listbox
+o.wGraph:      h.gMenus
+o.wGraph:      h.gIcons
+o.wGraph:      h.glass
+o.wGraph:      h.gPrefs
+o.wGraph:      h.window
+o.wGraph:      h._window
+o.wGraph:      h.gStruct
+o.wIcons:      c.wIcons
+o.wIcons:      libs:steel.h.Steel
+o.wIcons:      libs:steel.h.wimp
+o.wIcons:      libs:steel.h.wimpstruct
+o.wIcons:      libs:steel.h.os
+o.wIcons:      C:h.kernel
+o.wIcons:      libs:steel.h.sprite
+o.wIcons:      libs:steel.h.wimpt
+o.wIcons:      libs:steel.h.win
+o.wIcons:      libs:steel.h.event
+o.wIcons:      libs:steel.h.menu
+o.wIcons:      libs:steel.h.ibicon
+o.wIcons:      libs:steel.h.res
+o.wIcons:      libs:steel.h.resspr
+o.wIcons:      libs:steel.h.template
+o.wIcons:      libs:steel.h.dbox
+o.wIcons:      libs:steel.h.mem
+o.wIcons:      libs:steel.h.visdelay
+o.wIcons:      libs:steel.h.help
+o.wIcons:      libs:steel.h.exception
+o.wIcons:      libs:h.dll
+o.wIcons:      libs:steel.h.msgs
+o.wIcons:      libs:steel.h.utils
+o.wIcons:      libs:steel.h.stddbox
+o.wIcons:      libs:steel.h.xfersend
+o.wIcons:      libs:steel.h.werr
+o.wIcons:      libs:h.swis
+o.wIcons:      libs:steel.h.interface
+o.wIcons:      libs:steel.h.sculptrix
+o.wIcons:      libs:steel.h.flex
+o.wIcons:      libs:steel.h.bbc
+o.wIcons:      libs:steel.h.font
+o.wIcons:      C:h.drawmod
+o.wIcons:      h.gStruct
+o.wIcons:      h.gPrefs
+o.wIcons:      h.glass
+o.wIcons:      libs:steel.h.viewer
+o.wIcons:      libs:steel.h.pane
+o.wIcons:      libs:steel.h.listbox
+o.wIcons:      h.gMenus
+o.wIcons:      h.gIcons
+o.wIcons:      h.glass
+o.wIcons:      h.gPrefs
+o.wIcons:      h.tfile
+o.wIcons:      h.window
+o.wIcons:      h._window
+o.wIcons:      h.gStruct
+o.wIcons:      h.editIcon
+o.wIcons:      h.indir
+o.wIcons:      h.iconData
+o.wIcons:      h.tearEdit
+o.wIcons:      h.gStruct
+o.wMousePtr:   c.wMousePtr
+o.wMousePtr:   libs:steel.h.Steel
+o.wMousePtr:   libs:steel.h.wimp
+o.wMousePtr:   libs:steel.h.wimpstruct
+o.wMousePtr:   libs:steel.h.os
+o.wMousePtr:   C:h.kernel
+o.wMousePtr:   libs:steel.h.sprite
+o.wMousePtr:   libs:steel.h.wimpt
+o.wMousePtr:   libs:steel.h.win
+o.wMousePtr:   libs:steel.h.event
+o.wMousePtr:   libs:steel.h.menu
+o.wMousePtr:   libs:steel.h.ibicon
+o.wMousePtr:   libs:steel.h.res
+o.wMousePtr:   libs:steel.h.resspr
+o.wMousePtr:   libs:steel.h.template
+o.wMousePtr:   libs:steel.h.dbox
+o.wMousePtr:   libs:steel.h.mem
+o.wMousePtr:   libs:steel.h.visdelay
+o.wMousePtr:   libs:steel.h.help
+o.wMousePtr:   libs:steel.h.exception
+o.wMousePtr:   libs:h.dll
+o.wMousePtr:   libs:steel.h.msgs
+o.wMousePtr:   libs:steel.h.utils
+o.wMousePtr:   libs:steel.h.stddbox
+o.wMousePtr:   libs:steel.h.xfersend
+o.wMousePtr:   libs:steel.h.werr
+o.wMousePtr:   libs:h.swis
+o.wMousePtr:   libs:steel.h.pointer
+o.wMousePtr:   h.gStruct
+o.wMousePtr:   h.gPrefs
+o.wMousePtr:   h.glass
+o.wMousePtr:   libs:steel.h.viewer
+o.wMousePtr:   libs:steel.h.pane
+o.wMousePtr:   libs:steel.h.listbox
+o.wMousePtr:   h.gMenus
+o.wMousePtr:   h.gIcons
+o.wMousePtr:   h.glass
+o.wMousePtr:   h.gPrefs
+o.wMousePtr:   h.window
+o.wMousePtr:   h._window
+o.wMousePtr:   h.gStruct
+o.wRedraw:     c.wRedraw
+o.wRedraw:     libs:steel.h.Steel
+o.wRedraw:     libs:steel.h.wimp
+o.wRedraw:     libs:steel.h.wimpstruct
+o.wRedraw:     libs:steel.h.os
+o.wRedraw:     C:h.kernel
+o.wRedraw:     libs:steel.h.sprite
+o.wRedraw:     libs:steel.h.wimpt
+o.wRedraw:     libs:steel.h.win
+o.wRedraw:     libs:steel.h.event
+o.wRedraw:     libs:steel.h.menu
+o.wRedraw:     libs:steel.h.ibicon
+o.wRedraw:     libs:steel.h.res
+o.wRedraw:     libs:steel.h.resspr
+o.wRedraw:     libs:steel.h.template
+o.wRedraw:     libs:steel.h.dbox
+o.wRedraw:     libs:steel.h.mem
+o.wRedraw:     libs:steel.h.visdelay
+o.wRedraw:     libs:steel.h.help
+o.wRedraw:     libs:steel.h.exception
+o.wRedraw:     libs:h.dll
+o.wRedraw:     libs:steel.h.msgs
+o.wRedraw:     libs:steel.h.utils
+o.wRedraw:     libs:steel.h.stddbox
+o.wRedraw:     libs:steel.h.xfersend
+o.wRedraw:     libs:steel.h.werr
+o.wRedraw:     libs:h.swis
+o.wRedraw:     libs:steel.h.interface
+o.wRedraw:     libs:steel.h.sculptrix
+o.wRedraw:     libs:steel.h.bbc
+o.wRedraw:     libs:steel.h.coords
+o.wRedraw:     libs:steel.h.wimp
+o.wRedraw:     h.gStruct
+o.wRedraw:     h.gPrefs
+o.wRedraw:     h.glass
+o.wRedraw:     libs:steel.h.viewer
+o.wRedraw:     libs:steel.h.pane
+o.wRedraw:     libs:steel.h.listbox
+o.wRedraw:     h.gMenus
+o.wRedraw:     h.gIcons
+o.wRedraw:     h.glass
+o.wRedraw:     h.gPrefs
+o.wRedraw:     h.window
+o.wRedraw:     h._window
+o.wRedraw:     h.gStruct
+o.wRedraw:     h.tearEdit
+o.wRedraw:     h.gStruct
+o.wToolbars:   c.wToolbars
+o.wToolbars:   libs:steel.h.Steel
+o.wToolbars:   libs:steel.h.wimp
+o.wToolbars:   libs:steel.h.wimpstruct
+o.wToolbars:   libs:steel.h.os
+o.wToolbars:   C:h.kernel
+o.wToolbars:   libs:steel.h.sprite
+o.wToolbars:   libs:steel.h.wimpt
+o.wToolbars:   libs:steel.h.win
+o.wToolbars:   libs:steel.h.event
+o.wToolbars:   libs:steel.h.menu
+o.wToolbars:   libs:steel.h.ibicon
+o.wToolbars:   libs:steel.h.res
+o.wToolbars:   libs:steel.h.resspr
+o.wToolbars:   libs:steel.h.template
+o.wToolbars:   libs:steel.h.dbox
+o.wToolbars:   libs:steel.h.mem
+o.wToolbars:   libs:steel.h.visdelay
+o.wToolbars:   libs:steel.h.help
+o.wToolbars:   libs:steel.h.exception
+o.wToolbars:   libs:h.dll
+o.wToolbars:   libs:steel.h.msgs
+o.wToolbars:   libs:steel.h.utils
+o.wToolbars:   libs:steel.h.stddbox
+o.wToolbars:   libs:steel.h.xfersend
+o.wToolbars:   libs:steel.h.werr
+o.wToolbars:   libs:h.swis
+o.wToolbars:   libs:steel.h.interface
+o.wToolbars:   libs:steel.h.sculptrix
+o.wToolbars:   libs:steel.h.buttons
+o.wToolbars:   libs:steel.h.caretPtr
+o.wToolbars:   libs:steel.h.pointer
+o.wToolbars:   libs:steel.h.flex
+o.wToolbars:   libs:steel.h.akbd
+o.wToolbars:   libs:steel.h.coords
+o.wToolbars:   libs:steel.h.wimp
+o.wToolbars:   libs:steel.h.pointer
+o.wToolbars:   libs:steel.h.bbc
+o.wToolbars:   libs:steel.h.colourtran
+o.wToolbars:   libs:steel.h.font
+o.wToolbars:   C:h.drawmod
+o.wToolbars:   libs:steel.h.font
+o.wToolbars:   h.gStruct
+o.wToolbars:   h.gPrefs
+o.wToolbars:   h.glass
+o.wToolbars:   libs:steel.h.viewer
+o.wToolbars:   libs:steel.h.pane
+o.wToolbars:   libs:steel.h.listbox
+o.wToolbars:   h.gMenus
+o.wToolbars:   h.gIcons
+o.wToolbars:   h.glass
+o.wToolbars:   h.gPrefs
+o.wToolbars:   h.tfile
+o.wToolbars:   h.window
+o.wToolbars:   h._window
+o.wToolbars:   h.gStruct
+o.wToolbars:   h.intMsgs
+o.wToolbars:   h.toolbox
+o.wToolbars:   h.editIcon
+o.wToolbars:   h.editWin
+o.wToolbars:   h.indir
+o.wToolbars:   h.align
+o.wToolbars:   h.iconData
+o.wToolbars:   h.tearEdit
+o.wToolbars:   h.gStruct
+o.wWindows:    c.wWindows
+o.wWindows:    libs:steel.h.Steel
+o.wWindows:    libs:steel.h.wimp
+o.wWindows:    libs:steel.h.wimpstruct
+o.wWindows:    libs:steel.h.os
+o.wWindows:    C:h.kernel
+o.wWindows:    libs:steel.h.sprite
+o.wWindows:    libs:steel.h.wimpt
+o.wWindows:    libs:steel.h.win
+o.wWindows:    libs:steel.h.event
+o.wWindows:    libs:steel.h.menu
+o.wWindows:    libs:steel.h.ibicon
+o.wWindows:    libs:steel.h.res
+o.wWindows:    libs:steel.h.resspr
+o.wWindows:    libs:steel.h.template
+o.wWindows:    libs:steel.h.dbox
+o.wWindows:    libs:steel.h.mem
+o.wWindows:    libs:steel.h.visdelay
+o.wWindows:    libs:steel.h.help
+o.wWindows:    libs:steel.h.exception
+o.wWindows:    libs:h.dll
+o.wWindows:    libs:steel.h.msgs
+o.wWindows:    libs:steel.h.utils
+o.wWindows:    libs:steel.h.stddbox
+o.wWindows:    libs:steel.h.xfersend
+o.wWindows:    libs:steel.h.werr
+o.wWindows:    libs:h.swis
+o.wWindows:    libs:steel.h.flex
+o.wWindows:    h.gStruct
+o.wWindows:    h.gPrefs
+o.wWindows:    h.glass
+o.wWindows:    libs:steel.h.viewer
+o.wWindows:    libs:steel.h.pane
+o.wWindows:    libs:steel.h.listbox
+o.wWindows:    h.gMenus
+o.wWindows:    h.gIcons
+o.wWindows:    h.glass
+o.wWindows:    h.tfile
+o.wWindows:    h.window
+o.wWindows:    h._window
+o.wWindows:    h.gStruct
+o.wWindows:    h.editWin
+o.wWinEvent:   c.wWinEvent
+o.wWinEvent:   libs:steel.h.Steel
+o.wWinEvent:   libs:steel.h.wimp
+o.wWinEvent:   libs:steel.h.wimpstruct
+o.wWinEvent:   libs:steel.h.os
+o.wWinEvent:   C:h.kernel
+o.wWinEvent:   libs:steel.h.sprite
+o.wWinEvent:   libs:steel.h.wimpt
+o.wWinEvent:   libs:steel.h.win
+o.wWinEvent:   libs:steel.h.event
+o.wWinEvent:   libs:steel.h.menu
+o.wWinEvent:   libs:steel.h.ibicon
+o.wWinEvent:   libs:steel.h.res
+o.wWinEvent:   libs:steel.h.resspr
+o.wWinEvent:   libs:steel.h.template
+o.wWinEvent:   libs:steel.h.dbox
+o.wWinEvent:   libs:steel.h.mem
+o.wWinEvent:   libs:steel.h.visdelay
+o.wWinEvent:   libs:steel.h.help
+o.wWinEvent:   libs:steel.h.exception
+o.wWinEvent:   libs:h.dll
+o.wWinEvent:   libs:steel.h.msgs
+o.wWinEvent:   libs:steel.h.utils
+o.wWinEvent:   libs:steel.h.stddbox
+o.wWinEvent:   libs:steel.h.xfersend
+o.wWinEvent:   libs:steel.h.werr
+o.wWinEvent:   libs:h.swis
+o.wWinEvent:   libs:steel.h.interface
+o.wWinEvent:   libs:steel.h.sculptrix
+o.wWinEvent:   libs:steel.h.caretPtr
+o.wWinEvent:   libs:steel.h.pointer
+o.wWinEvent:   libs:steel.h.akbd
+o.wWinEvent:   libs:steel.h.bbc
+o.wWinEvent:   h.gStruct
+o.wWinEvent:   h.gPrefs
+o.wWinEvent:   h.glass
+o.wWinEvent:   libs:steel.h.viewer
+o.wWinEvent:   libs:steel.h.pane
+o.wWinEvent:   libs:steel.h.listbox
+o.wWinEvent:   h.gMenus
+o.wWinEvent:   h.gIcons
+o.wWinEvent:   h.glass
+o.wWinEvent:   h.gPrefs
+o.wWinEvent:   h.tfile
+o.wWinEvent:   h.window
+o.wWinEvent:   h._window
+o.wWinEvent:   h.gStruct
+o.wWinEvent:   h.intMsgs
+o.wWinEvent:   h.toolbox
+o.wWinEvent:   h.editIcon
+o.wWinEvent:   h.editWin
+o.wWinEvent:   h.tearEdit
+o.wWinEvent:   h.gStruct
+o.wMenus:      c.wMenus
+o.wMenus:      libs:steel.h.Steel
+o.wMenus:      libs:steel.h.wimp
+o.wMenus:      libs:steel.h.wimpstruct
+o.wMenus:      libs:steel.h.os
+o.wMenus:      C:h.kernel
+o.wMenus:      libs:steel.h.sprite
+o.wMenus:      libs:steel.h.wimpt
+o.wMenus:      libs:steel.h.win
+o.wMenus:      libs:steel.h.event
+o.wMenus:      libs:steel.h.menu
+o.wMenus:      libs:steel.h.ibicon
+o.wMenus:      libs:steel.h.res
+o.wMenus:      libs:steel.h.resspr
+o.wMenus:      libs:steel.h.template
+o.wMenus:      libs:steel.h.dbox
+o.wMenus:      libs:steel.h.mem
+o.wMenus:      libs:steel.h.visdelay
+o.wMenus:      libs:steel.h.help
+o.wMenus:      libs:steel.h.exception
+o.wMenus:      libs:h.dll
+o.wMenus:      libs:steel.h.msgs
+o.wMenus:      libs:steel.h.utils
+o.wMenus:      libs:steel.h.stddbox
+o.wMenus:      libs:steel.h.xfersend
+o.wMenus:      libs:steel.h.werr
+o.wMenus:      libs:h.swis
+o.wMenus:      libs:steel.h.buttons
+o.wMenus:      libs:steel.h.choices
+o.wMenus:      libs:steel.h.bbc
+o.wMenus:      libs:steel.h.buffer
+o.wMenus:      libs:steel.h.tearoff
+o.wMenus:      h.gStruct
+o.wMenus:      h.gPrefs
+o.wMenus:      h.glass
+o.wMenus:      libs:steel.h.viewer
+o.wMenus:      libs:steel.h.pane
+o.wMenus:      libs:steel.h.listbox
+o.wMenus:      h.gMenus
+o.wMenus:      h.gIcons
+o.wMenus:      h.glass
+o.wMenus:      h.gPrefs
+o.wMenus:      h.tfile
+o.wMenus:      h.window
+o.wMenus:      h._window
+o.wMenus:      h.gStruct
+o.wMenus:      h.editIcon
+o.wMenus:      h.editWin
+o.wMenus:      h.align
+o.wMenus:      h.iconData
+o.wMenus:      h.tearEdit
+o.wMenus:      h.gStruct
diff --git a/StraySrc/Glass/!Glass/Resources/LoadSpr,ff9 b/StraySrc/Glass/!Glass/Resources/LoadSpr,ff9
new file mode 100644 (file)
index 0000000..308c483
Binary files /dev/null and b/StraySrc/Glass/!Glass/Resources/LoadSpr,ff9 differ
diff --git a/StraySrc/Glass/!Glass/Resources/LoadTpl,fec b/StraySrc/Glass/!Glass/Resources/LoadTpl,fec
new file mode 100644 (file)
index 0000000..1d7e7de
Binary files /dev/null and b/StraySrc/Glass/!Glass/Resources/LoadTpl,fec differ
diff --git a/StraySrc/Glass/!Glass/Resources/Messages b/StraySrc/Glass/!Glass/Resources/Messages
new file mode 100644 (file)
index 0000000..560547b
--- /dev/null
@@ -0,0 +1,269 @@
+;
+; Glass 1.xx messages
+;
+
+;----- Main Glass messages --------------------------------------------------
+
+; --- Miscellaneous standard messages ---
+
+yes:Yes
+no:No
+
+; --- Alignment dialogue ---
+
+alNEM:Not enough memory to align icons
+alNOHC:No horizontal container icon.  The icons have not been moved horizontally.
+alNOVC:No vertical container icon.  The icons have not been moved vertically.
+
+alBATH:(align__horizCompare): Bad alignment type
+alBATV:(align__vertCompare): Bad alignment type
+
+; --- Edit window/icon dialogues ---
+
+teNEMUI/eiNEMUI:Not enough memory to update icon
+ewNEMUW:Not enough memory to update window
+
+eiNEM:Not enough memory to edit icon
+ewNEM:Not enough memory to edit window
+
+eiCFF:Couldn't find font '%s'.  The icon will not be antialiased.  Colours may appear strange.
+ewCFF:Couldn't find font '%s'.  The title will not be antialiased.
+
+eiCDIP/ewCDWP:Delete
+eiCDI:Are you sure you want to delete this icon?
+ewCDW:Are you sure you want to delete this window?
+
+eiSPRGONE:Sprite '%s' not found: can't calculate size
+
+eiFGC:Icon foreground
+eiBGC:Icon background
+
+ewTBFG:Title foreground
+ewTBBG:Title background
+ewWAFG:Work area foreground
+ewWABG:Work area background
+ewSCFG:Scroll bar foreground
+ewSCBG:Scroll bar background
+ewTBHI:Title highlight
+
+; --- Button type menus ---
+
+eiBTMT:Button type
+eiBTYPE0/ewBTYPE0:Never
+eiBTYPE1/ewBTYPE1:Always
+eiBTYPE2/ewBTYPE2:Auto-repeat
+eiBTYPE3/ewBTYPE3/ewBTYPE9:Debounced
+eiBTYPE4/ewBTYPE4:Release
+eiBTYPE5/ewBTYPE5:Double click
+eiBTYPE6/ewBTYPE6/ewBTYPE11:Click/drag
+eiBTYPE7/ewBTYPE7:Release/drag
+eiBTYPE8/ewBTYPE8:Double/drag
+eiBTYPE9:'Menu' icon
+eiBTYPE10/ewBTYPE10:Click/double/drag
+eiBTYPE11:Select/drag
+eiBTYPE12/ewBTYPE12:Type 12
+eiBTYPE13/ewBTYPE13:Type 13
+eiBTYPE14:Click/write/drag
+ewBTYPE14:Type 14
+eiBTYPE15/ewBTYPE15:Writable
+
+; --- Template file management ---
+
+tfUNT:<Untitled>
+
+; --- Initialisation messages ---
+
+wePUR:Free template editor
+weIBM:>Info...|Preferences...,Toolbox...,Heap info...|Quit
+
+weILM:Loading messages
+weILW:Loading windows
+weLDF:Loading defaults
+weIRP:Reading preferences
+weILD:Loading document
+weIFI:Initialised OK
+
+; --- Preferences messages ---
+
+prBTU:Bad time unit '%s' at line %i (must be 'hours', 'minutes' or 'seconds')
+prHR:hours
+prMI:minutes
+prSE:seconds
+prUNITT:Units
+prUNIT:Hours,Minutes,Seconds
+
+prBIS:Bad icon size '%s' at line %i (must be 'large' or 'small')
+prBST:Bad sort type '%s' at line %i (must be 'name', 'size', 'icons'  or 'noSort')
+
+prSILT:An invalid autosave time has been entered.  A default of %i has been substituted.
+
+prSILC:An invalid autosave count has been entered.  A default of %i has been substituted.
+
+prGCOL:Grid colour
+prGDCOL:Guide colour
+prSGDCOL:Selected guide colour
+prSBCOL:Select border colour
+prSHCOL:Drag handle colour
+prSSCOL:Special handle colour
+
+; --- Sprite handling ---
+
+spVT:%s sprites
+spBANR:Template file sprites window
+
+spELD:Error loading default sprites: %s
+spNEMLD:Not enough memory to load default sprites
+
+spNEMC:Not enough memory to create sprite area.  Using the WIMP sprite area for this template file.  Sprites may not appear correctly.
+
+spNEMM:Not enough memory to merge sprites
+spEMF:Error merging file: %s
+
+spSPR:Sprite
+spM:>Info...        \8bF1,+_,Select all      ^A,Clear selection ^Z,>Save...         F3,Grab sprites... ^G
+spSS:>Info...   ^F1,>Copy...    ^C,>Rename...  ^R,>Save...   \8bF3,Delete     ^X
+
+spNAE:Sprite '%s' already exists
+spNEMCPY:Not enough memory to copy sprite
+spSVSPR:Save sprites
+
+spCGS:Can't grab sprites from the background or icon bar
+spNEMGS:Not enough memory to grab sprites
+spNAUSA:This window doesn't have a user sprite area
+spGRB:Grabbed
+
+spESS:Error saving sprites: %s
+spNEMSLSV:Not enough memory to save selection
+
+; --- Internel broadcast system ---
+
+imSMT:(intMsgs_send, caller fault): Bad message number
+
+; --- Tearoff icon editor ---
+
+teNEMUI:Not enough memory to update icon
+teFG:Foreground
+teBG:Background
+
+teEIMT:Edit icon
+teEIM:Data,Appearance,Actions,Colours,>Position...,>Size...
+teEIDT:Data
+teEID:>Edit data...,>Indirected...,Text,Sprite
+teAPMT:Appearance
+teAPM:Horizontally centred,Vertically centred,Right aligned|Border,Filled background,Half-size sprite,Needs help
+teACMT:Actions
+teACM:Button type,>ESG...,Adjust toggles,Selected,Shaded
+teCMT:Colours
+teCM:>Foreground...,>Background...
+
+; --- Template file handling ---
+
+tfNEMTF:Not enough memory to create new template file.
+tfBANR:Template file window
+
+tfNEMTL:Not enough memory to load template file
+tfELF:Error loading file: %s
+tfCFF:Some fonts used in this template file could not be found.  Icons with such fonts will not be anti-aliased.
+tfUTEC:Unrecognised template entry code found.  Some information may be lost if you save this file.
+
+tfNAE:Window '%s' already exists
+
+tfNEMCRT:Not enough memory for new window
+tfFERC:Font error while creating window
+tfNEMGW:Not enough memory to grab window
+tfFERG:Font error while grabbing window: some icons may not appear correctly
+tfNEMCW:Not enough memory for copy.
+tfFERCP:Font error while copying window: some icons may not appear correctly
+
+tfTMP:Templates
+tfSVTIT:Save templates
+tfSVWTIT:Save window
+tfSVSEL/spSVSEL:Save selection
+tfSEL/spSEL:Selection
+
+tfCSID:Can't save in Glass demo
+tfNEMST:Not enough memory to save templates
+tfERT:Error saving templates: %s
+
+tfSOFP/spSOFP:Replace
+tfSOF/spSOF:File '%s' already exists.  Are you sure you want to replace it?
+
+tfCOPY/spCOPY:Copy
+tfREN/spREN:Rename
+tfDELWP:Delete
+tfDELW:Are you sure you want to delete the selected windows?
+
+tfCRT:Create
+tfGRAB:Grab
+
+tfM:>Info...        \8bF1,Display,+_,Select all      ^A,Clear selection ^Z,>Save...         F3,>Create...       ^N,>Grab window...  ^G,Show sprites    ^S
+
+tfDSPT:Display
+tfDSPM:Large icons           F5,Small icons          \8bF5|Sort by name          F6,Sort by size         \8bF6,Sort by no. of icons ^F6,Don't sort          \8b^F6
+
+tfWS:>Info...  ^F1,Edit...   ^E,>Copy...   ^C,>Rename... ^R,>Save... \8bF3,Delete    ^X
+
+tfWIN:Window
+
+tfOTQP:Quit
+tfOTQ1:%i file modified but unsaved in Glass.  Are you sure you want to quit?
+tfOTQM:%i files modified but unsaved in Glass.  Are you sure you want to quit?
+
+; --- Grabbing icons ---
+
+wdFERGI:Font error while grabbing icon.  Icon may not appear correctly.
+wdNITG:No icon to grab
+wdCGI:Can't grab icons from this window
+wdAGRB:Already in grab mode
+
+; --- Other icon manipulation ---
+
+wdNEMCI:Not enough memory to create icon
+wdFERCPY:Font error while copying icons.  Some icons may not appear correctly.
+wdNEMCP:Not enough memory for copy
+wdIIRN:Bad icon renumber: icon has not been renumbered
+
+; --- Main window menu ---
+
+wdTCRP/wdTCEP:Continue
+wdTCE:Entering test mode will cancel any currently open edit dialogues for this window.  Are you sure you want to continue?
+wdTCR:Entering renumber mode will cancel any currently open edit dialogues for this window.  Are you sure you want to continue?
+wdCDIP:Delete
+wdCDI:Are you sure you want to delete the selected icons?
+
+wdFERCI:Font error while creating icon.  Icon may not appear correctly.
+
+wdTMG:You can only create %i guides in a window
+
+wdCRTMT:New icon
+
+wdWMT:Window
+wdWM:Misc,>Save...#F3,Select,Create icon,>Edit icon,>Grid...,Guides
+
+wdMISCMT:Window
+wdMISCM:>Info...#^F1|Edit window...#^W,Test mode#^T,Remove deleted icons,Bring back icons|Close window#^F2
+
+wdSELMT:Select
+wdSELM:Select all#^A,Clear selection#^Z,Copy#^C,Delete#^X|Reorder#^R,Bring to front#\8b^F,Raise#^F,Lower#^B,Put to back#\8b^B|Pull onto grid#^P,Align...#^L|Edit...#^E,Button type
+
+wdICNMT:Create icon
+wdICNM:New icon#^N,Show palette,Grab icon#^G
+
+wdGDEMT:Guides
+wdGDEM:Select all,Clear selection,Delete selection|Create horizontal,Create vertical
+
+; --- Icon palette handling ---
+
+wdNEMIP:Not enough memory to open icon palette
+wdIPT:Icon palette
+wdERIP:Error creating icon palette: %s
+
+; --- Toolbar handling ---
+
+wdBACKG:Back
+
+;----- Help messages --------------------------------------------------------
+
+;----- STEEL messages -------------------------------------------------------
+
+;----------------------------------------------------------------------------
diff --git a/StraySrc/Glass/!Glass/Resources/Sprites,ff9 b/StraySrc/Glass/!Glass/Resources/Sprites,ff9
new file mode 100644 (file)
index 0000000..3bb4179
Binary files /dev/null and b/StraySrc/Glass/!Glass/Resources/Sprites,ff9 differ
diff --git a/StraySrc/Glass/!Glass/Resources/Templates,fec b/StraySrc/Glass/!Glass/Resources/Templates,fec
new file mode 100644 (file)
index 0000000..d6310c7
Binary files /dev/null and b/StraySrc/Glass/!Glass/Resources/Templates,fec differ
diff --git a/StraySrc/Glass/!Glass/c/align b/StraySrc/Glass/!Glass/c/align
new file mode 100644 (file)
index 0000000..4b36069
--- /dev/null
@@ -0,0 +1,810 @@
+/*
+ * align.c
+ *
+ * The alignment dialogue box
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#include "steel/Steel.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gIcons.h"
+
+#include "glass.h"
+#include "window.h"
+#include "align.h"
+#include "tfile.h"
+
+/*----- Type definitions --------------------------------------------------*/
+
+typedef struct
+{
+  wimp_box box;
+  int i;
+}
+align__iconstr;
+
+typedef enum
+{
+  align__MIN,
+  align__CENTRE,
+  align__MAX
+}
+align__order;
+
+/*----- Static global variables -------------------------------------------*/
+
+static dbox align__dbox;
+static align__order align__sortOrder;
+
+/*----- Support routines --------------------------------------------------*/
+
+/*
+ * int align__horizCompare(const void *a,const void *b)
+ *
+ * Use
+ *  Compares two icons for horizontal alignment.  Used as a compare for
+ *  qsort.
+ */
+
+static int align__horizCompare(const void *a,const void *b)
+{
+  const align__iconstr *x=a;
+  const align__iconstr *y=b;
+  int result=0;
+  switch (align__sortOrder)
+  {
+    case align__MIN:
+      result=x->box.x0-y->box.x0;
+      break;
+    case align__MAX:
+      result=x->box.x1-y->box.x1;
+      break;
+    case align__CENTRE:
+      result=x->box.x1+x->box.x0-y->box.x0-y->box.x1;
+      break;
+    default:
+      werr(TRUE,msgs_lookup("alBATH"));
+      break;
+  }
+  return (result);
+}
+
+/*
+ * int align__vertCompare(const void *a,const void *b)
+ *
+ * Use
+ *  Compares two icons for vertical alignment.  Used as a compare for
+ *  qsort.
+ */
+
+static int align__vertCompare(const void *a,const void *b)
+{
+  const align__iconstr *x=a;
+  const align__iconstr *y=b;
+  int result=0;
+  switch (align__sortOrder)
+  {
+    case align__MIN:
+      result=x->box.y0-y->box.y0;
+      break;
+    case align__MAX:
+      result=x->box.y1-y->box.y1;
+      break;
+    case align__CENTRE:
+      result=x->box.y1+x->box.y0-y->box.y0-y->box.y1;
+      break;
+    default:
+      werr(TRUE,msgs_lookup("alBATV"));
+      break;
+  }
+  return (result);
+}
+
+/*
+ * void align__doAlign(void)
+ *
+ * Use
+ *  Does an align on the currently selected icons, wherever they may be.
+ *  The settings are read from the dialogue box, and processed.
+ */
+
+static void align__doAlign(void)
+{
+  align__iconstr *a;                 /* Array of icons to align            */
+  glass_windPointer *w=window_selectionOwner(); /* Window containing icons */
+  wimp_box bound;                    /* Bounding box of the selection      */
+  int width=0;                       /* Total width of all the icons       */
+  int height=0;                      /* Total height of all the icons      */
+
+  int xcont=-1;                      /* Index/icon of horizontal container */
+  int ycont=-1;                      /* Index/icon of vertical container   */
+
+  int num;                           /* Number of selected icons           */
+
+  /* --- Loop variables --- */
+
+  int i;
+  int j;
+
+  /* --- Ensure that we have something to do --- */
+
+  if (!w)
+    return;
+  if (!w->selno)
+    return;
+
+  num=w->selno;
+
+  /* --- Put the icons into an array for sorting etc. --- *
+   *
+   * We also keep track of the bounding box of the selected icons, their
+   * total width and their total height, and which, if any, are containers.
+   */
+
+  {
+    BOOL started=FALSE;
+
+    /* --- Allocate memory for the array --- */
+
+    if (a=mem_alloc(num*sizeof(align__iconstr)),!a)
+    {
+      werr(FALSE,msgs_lookup("alNEM"));
+      return;
+    }
+
+    j=0;
+    for (i=0;i<w->def->desc.w.nicons;i++)
+    {
+      if (w->def->i[i].selected)
+      {
+        a[j].i=i;
+        window_boundingBox(w,i,&a[j].box);
+        width+=a[j].box.x1-a[j].box.x0;
+        height+=a[j].box.y1-a[j].box.y0;
+        if (!started)
+        {
+          bound=a[j].box;
+          started=TRUE;
+          xcont=ycont=j;
+        }
+        else
+        {
+          if (bound.x0>a[j].box.x0)
+          {
+            bound.x0=a[j].box.x0;
+            if (bound.x1<a[j].box.x1)
+            {
+              bound.x1=a[j].box.x1;
+              xcont=j;
+            }
+            else
+              xcont=-1;
+          }
+          else if (bound.x1<a[j].box.x1)
+          {
+            bound.x1=a[j].box.x1;
+            xcont=-1;
+          }
+
+          if (bound.y0>a[j].box.y0)
+          {
+            bound.y0=a[j].box.y0;
+            if (bound.y1<a[j].box.y1)
+            {
+              bound.y1=a[j].box.y1;
+              ycont=j;
+            }
+            else
+              ycont=-1;
+          }
+          else if (bound.y1<a[j].box.y1)
+          {
+            bound.y1=a[j].box.y1;
+            ycont=-1;
+          }
+        }
+        j++;
+      }
+    }
+
+  }
+
+  if (xcont!=-1)
+    xcont=a[xcont].i;
+  if (ycont!=-1)
+    ycont=a[ycont].i;
+
+  /* --- Now to do the job properly --- *
+   *
+   * Aligning is easy.  Just find the align position and Bob's your uncle.
+   * Distributing the icons is more difficult.  I'll come to that when
+   * it's a better time.
+   */
+
+  /* --- First do horizontal movement --- */
+
+  if (dbox_selecticon(align__dbox,glass_AHALIGN,dbox_READSTATE))
+  {
+
+    /* --- Right.  Just aligning to do.  This is really easy --- */
+
+    if (dbox_selecticon(align__dbox,glass_AHLEFT,dbox_READSTATE))
+    {
+      for (i=0;i<num;i++)
+      {
+        a[i].box.x1+=bound.x0-a[i].box.x0;
+        a[i].box.x0=bound.x0;
+      }
+    }
+    else if (dbox_selecticon(align__dbox,glass_AHRIGHT,dbox_READSTATE))
+    {
+      for (i=0;i<num;i++)
+      {
+        a[i].box.x0+=bound.x1-a[i].box.x1;
+        a[i].box.x1=bound.x1;
+      }
+    }
+    else
+    {
+      int centre;
+      int icwidth;
+
+      /* --- Centring is complicated by the two bounding boxes --- */
+
+      if (dbox_selecticon(align__dbox,glass_AHBOUND,dbox_READSTATE))
+        centre=(bound.x1+bound.x0)/2;
+      else
+      {
+        centre=w->def->desc.w.scx+
+               (w->def->desc.w.box.x1-w->def->desc.w.box.x0)/2;
+      }
+
+      for (i=0;i<num;i++)
+      {
+        icwidth=a[i].box.x1-a[i].box.x0;
+        a[i].box.x0=centre-icwidth/2;
+        a[i].box.x1=centre+icwidth/2;
+      }
+    }
+  }
+  else if (dbox_selecticon(align__dbox,glass_AHDISTRIB,dbox_READSTATE))
+  {
+
+    /* --- Hmm... right.  Got to distribute these --- *
+     *
+     * First of all, we've got to put them in some sort of order.
+     */
+
+    if (dbox_selecticon(align__dbox,glass_AHLEFT,dbox_READSTATE))
+      align__sortOrder=align__MIN;
+    else if (dbox_selecticon(align__dbox,glass_AHCENTRE,dbox_READSTATE) ||
+             dbox_selecticon(align__dbox,glass_AHWIDTH,dbox_READSTATE))
+      align__sortOrder=align__CENTRE;
+    else
+      align__sortOrder=align__MAX;
+
+    qsort(a,w->selno,sizeof(align__iconstr),align__horizCompare);
+
+    if (dbox_selecticon(align__dbox,glass_AHLEFT,dbox_READSTATE))
+    {
+      int space=a[num-1].box.x0-a[0].box.x0;
+      int anchor=a[0].box.x0;
+      int thisBit;
+
+      for (i=0;i<num;i++)
+      {
+        thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dx()-1) );
+        a[i].box.x1+=thisBit-a[i].box.x0;
+        a[i].box.x0=thisBit;
+      }
+    }
+    else if (dbox_selecticon(align__dbox,glass_AHRIGHT,dbox_READSTATE))
+    {
+      int space=a[num-1].box.x1-a[0].box.x1;
+      int anchor=a[0].box.x1;
+      int thisBit;
+
+      for (i=0;i<num;i++)
+      {
+        thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dx()-1) );
+        a[i].box.x0+=thisBit-a[i].box.x1;
+        a[i].box.x1=thisBit;
+      }
+    }
+    else if (dbox_selecticon(align__dbox,glass_AHCENTRE,dbox_READSTATE))
+    {
+      int space=(a[num-1].box.x1+a[num-1].box.x0)/2-
+                (a[0].box.x1+a[0].box.x0)/2;
+      int anchor=(a[0].box.x1+a[0].box.x0)/2;
+      int icwidth;
+      int thisBit;
+
+      for (i=0;i<num;i++)
+      {
+        thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dx()-1) );
+        icwidth=a[i].box.x1-a[i].box.x0;
+        a[i].box.x0=thisBit-icwidth/2;
+        a[i].box.x1=thisBit+icwidth/2;
+      }
+    }
+    else if (dbox_selecticon(align__dbox,glass_AHBOUND,dbox_READSTATE))
+    {
+      int space=bound.x1-bound.x0-width;
+      int icwidth;
+      int thisBit;
+      int anchor=bound.x0; /* This anchor moves, unlike the last lot */
+
+      for (i=0;i<num;i++)
+      {
+        icwidth=a[i].box.x1-a[i].box.x0;
+        thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dx()-1) );
+        a[i].box.x0=thisBit;
+        a[i].box.x1=thisBit+icwidth;
+        anchor+=icwidth;
+      }
+    }
+    else if (dbox_selecticon(align__dbox,glass_AHVISAREA,dbox_READSTATE))
+    {
+      int space=w->def->desc.w.box.x1-w->def->desc.w.box.x0-width;
+      int icwidth;
+      int thisBit;
+      int anchor=w->def->desc.w.scx; /* This anchor also moves */
+
+      for (i=0;i<num;i++)
+      {
+        icwidth=a[i].box.x1-a[i].box.x0;
+        thisBit=anchor + ( ( space*(i+1) )/(num+1) & ~(wimpt_dx()-1) );
+        a[i].box.x0=thisBit;
+        a[i].box.x1=thisBit+icwidth;
+        anchor+=icwidth;
+      }
+    }
+    else if (xcont!=-1)
+    {
+      int space=2*(bound.x1-bound.x0)-width;
+      int icwidth;
+      int thisBit;
+      int anchor=bound.x0; /* This anchor also moves */
+      int done=1;
+
+      for (i=0;i<num;i++)
+      {
+        if (a[i].i==xcont)
+          continue; /* Don't move the container icon at all */
+        icwidth=a[i].box.x1-a[i].box.x0;
+        thisBit=anchor + ( (space*done)/num & ~(wimpt_dx()-1) );
+        a[i].box.x0=thisBit;
+        a[i].box.x1=thisBit+icwidth;
+        anchor+=icwidth;
+        done++;
+      }
+    }
+    else
+    {
+      note(msgs_lookup("alNOHC"));
+    }
+  }
+
+  /* --- Now do the vertical bit (just a case'n'paste of above) --- */
+
+  if (dbox_selecticon(align__dbox,glass_AVALIGN,dbox_READSTATE))
+  {
+
+    /* --- Right.  Just aligning to do.  This is really easy --- */
+
+    if (dbox_selecticon(align__dbox,glass_AVBOTTOM,dbox_READSTATE))
+    {
+      for (i=0;i<num;i++)
+      {
+        a[i].box.y1+=bound.y0-a[i].box.y0;
+        a[i].box.y0=bound.y0;
+      }
+    }
+    else if (dbox_selecticon(align__dbox,glass_AVTOP,dbox_READSTATE))
+    {
+      for (i=0;i<num;i++)
+      {
+        a[i].box.y0+=bound.y1-a[i].box.y1;
+        a[i].box.y1=bound.y1;
+      }
+    }
+    else
+    {
+      int centre;
+      int icheight;
+
+      /* --- Centring is complicated by the two bounding boxes --- */
+
+      if (dbox_selecticon(align__dbox,glass_AVBOUND,dbox_READSTATE))
+        centre=(bound.y1+bound.y0)/2;
+      else
+      {
+        centre=w->def->desc.w.scy-
+               (w->def->desc.w.box.y1-w->def->desc.w.box.y0)/2;
+      }
+
+      for (i=0;i<num;i++)
+      {
+        icheight=a[i].box.y1-a[i].box.y0;
+        a[i].box.y0=centre-icheight/2;
+        a[i].box.y1=centre+icheight/2;
+      }
+    }
+  }
+  else if (dbox_selecticon(align__dbox,glass_AVDISTRIB,dbox_READSTATE))
+  {
+
+    /* --- Hmm... right.  Got to distribute these --- *
+     *
+     * First of all, we've got to put them in some sort of order.
+     */
+
+    if (dbox_selecticon(align__dbox,glass_AVBOTTOM,dbox_READSTATE))
+      align__sortOrder=align__MIN;
+    else if (dbox_selecticon(align__dbox,glass_AVCENTRE,dbox_READSTATE) ||
+             dbox_selecticon(align__dbox,glass_AVHEIGHT,dbox_READSTATE))
+      align__sortOrder=align__CENTRE;
+    else
+      align__sortOrder=align__MAX;
+
+    qsort(a,w->selno,sizeof(align__iconstr),align__vertCompare);
+
+    if (dbox_selecticon(align__dbox,glass_AVBOTTOM,dbox_READSTATE))
+    {
+      int space=a[num-1].box.y0-a[0].box.y0;
+      int anchor=a[0].box.y0;
+      int thisBit;
+
+      for (i=0;i<num;i++)
+      {
+        thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dy()-1) );
+        a[i].box.y1+=thisBit-a[i].box.y0;
+        a[i].box.y0=thisBit;
+      }
+    }
+    else if (dbox_selecticon(align__dbox,glass_AVTOP,dbox_READSTATE))
+    {
+      int space=a[num-1].box.y1-a[0].box.y1;
+      int anchor=a[0].box.y1;
+      int thisBit;
+
+      for (i=0;i<num;i++)
+      {
+        thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dy()-1) );
+        a[i].box.y0+=thisBit-a[i].box.y1;
+        a[i].box.y1=thisBit;
+      }
+    }
+    else if (dbox_selecticon(align__dbox,glass_AVCENTRE,dbox_READSTATE))
+    {
+      int space=(a[num-1].box.y1+a[num-1].box.y0)/2-
+                (a[0].box.y1+a[0].box.y0)/2;
+      int anchor=(a[0].box.y1+a[0].box.y0)/2;
+      int icheight;
+      int thisBit;
+
+      for (i=0;i<num;i++)
+      {
+        thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dy()-1) );
+        icheight=a[i].box.y1-a[i].box.y0;
+        a[i].box.y0=thisBit-icheight/2;
+        a[i].box.y1=thisBit+icheight/2;
+      }
+    }
+    else if (dbox_selecticon(align__dbox,glass_AVBOUND,dbox_READSTATE))
+    {
+      int space=bound.y1-bound.y0-height;
+      int icheight;
+      int thisBit;
+      int anchor=bound.y0; /* This anchor moves, unlike the last lot */
+
+      for (i=0;i<num;i++)
+      {
+        icheight=a[i].box.y1-a[i].box.y0;
+        thisBit=anchor + ( (space*i)/(num-1) & ~(wimpt_dy()-1) );
+        a[i].box.y0=thisBit;
+        a[i].box.y1=thisBit+icheight;
+        anchor+=icheight;
+      }
+    }
+    else if (dbox_selecticon(align__dbox,glass_AVVISAREA,dbox_READSTATE))
+    {
+      int space=w->def->desc.w.box.y1-w->def->desc.w.box.y0;
+      int icheight;
+      int thisBit;
+      int anchor=w->def->desc.w.scy-space; /* This anchor also moves */
+      space-=height;
+
+      for (i=0;i<num;i++)
+      {
+        icheight=a[i].box.y1-a[i].box.y0;
+        thisBit=anchor + ( ( space*(i+1) )/(num+1) & ~(wimpt_dy()-1) );
+        a[i].box.y0=thisBit;
+        a[i].box.y1=thisBit+icheight;
+        anchor+=icheight;
+      }
+    }
+    else if (ycont!=-1)
+    {
+      int space=2*(bound.y1-bound.y0)-height;
+      int icheight;
+      int thisBit;
+      int anchor=bound.y0; /* This anchor also moves */
+      int done=1;
+
+      for (i=0;i<num;i++)
+      {
+        if (a[i].i==ycont)
+          continue; /* Don't move the container icon at all */
+        icheight=a[i].box.y1-a[i].box.y0;
+        thisBit=anchor + ( (space*done)/num & ~(wimpt_dy()-1) );
+        a[i].box.y0=thisBit;
+        a[i].box.y1=thisBit+icheight;
+        anchor+=icheight;
+        done++;
+      }
+    }
+    else
+    {
+      note(msgs_lookup("alNOVC"));
+    }
+  }
+
+  tfile_markAsAltered(w->t);
+
+  for (i=0;i<w->selno;i++)
+    window_setBox(w,a[i].i,&a[i].box);
+
+  mem_free(a);
+}
+
+/*----- Event handlers ----------------------------------------------------*/
+
+/*
+ * void align__dboxHandler(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles events for the Alignment dialogue box.
+ *
+ * Parameters
+ *  dbox d == the dbox handle (align__dbox)
+ *  dbox_field f == what happened (usually a mouse click)
+ *  void *handle == a pointer (ignored)
+ */
+
+static void align__dboxHandler(dbox d,dbox_field f,void *handle)
+{
+  BOOL shadeBox;
+  unused(handle);
+  switch (f)
+  {
+    case dbox_CLOSE:
+      dbox_delete(d);
+      align__dbox=0;
+      break;
+    case glass_AOK:
+      dbox_clickicon(d,f);
+      align__doAlign();
+      if (!dbox_wasAdjustClick())
+        dbox_hide(d);
+      dbox_unclick();
+      if (!dbox_wasAdjustClick())
+      {
+        dbox_delete(d);
+        align__dbox=0;
+      }
+      break;
+    case glass_ACANCEL:
+      dbox_clickicon(d,f);
+      dbox_hide(d);
+      dbox_unclick();
+      dbox_delete(d);
+      align__dbox=0;
+      break;
+    case glass_AHNONE:
+      dbox_clickicon(d,f);
+      dbox_shadeicon(d,glass_AHLEFT,TRUE);
+      dbox_shadeicon(d,glass_AHRIGHT,TRUE);
+      dbox_shadeicon(d,glass_AHCENTRE,TRUE);
+      dbox_shadeicon(d,glass_AHWIDTH,TRUE);
+      dbox_shadeicon(d,glass_AHBOUND,TRUE);
+      dbox_shadeicon(d,glass_AHVISAREA,TRUE);
+      dbox_shadeicon(d,glass_AHCONTAIN,TRUE);
+      dbox_unclick();
+      break;
+    case glass_AHALIGN:
+      dbox_clickicon(d,f);
+      dbox_shadeicon(d,glass_AHLEFT,FALSE);
+      dbox_shadeicon(d,glass_AHRIGHT,FALSE);
+      dbox_shadeicon(d,glass_AHCENTRE,FALSE);
+      dbox_shadeicon(d,glass_AHWIDTH,TRUE);
+      if (dbox_selecticon(d,glass_AHWIDTH,dbox_READSTATE))
+      {
+        dbox_selecticon(d,glass_AHWIDTH,FALSE);
+        dbox_selecticon(d,glass_AHCENTRE,TRUE);
+      }
+      shadeBox=!dbox_selecticon(d,glass_AHCENTRE,dbox_READSTATE);
+      dbox_shadeicon(d,glass_AHBOUND,shadeBox);
+      dbox_shadeicon(d,glass_AHVISAREA,shadeBox);
+      dbox_shadeicon(d,glass_AHCONTAIN,TRUE);
+      if (dbox_selecticon(d,glass_AHCONTAIN,dbox_READSTATE))
+      {
+        dbox_selecticon(d,glass_AHCONTAIN,FALSE);
+        dbox_selecticon(d,glass_AHBOUND,TRUE);
+      }
+      dbox_unclick();
+      break;
+    case glass_AHDISTRIB:
+      dbox_clickicon(d,f);
+      dbox_shadeicon(d,glass_AHLEFT,FALSE);
+      dbox_shadeicon(d,glass_AHRIGHT,FALSE);
+      dbox_shadeicon(d,glass_AHCENTRE,FALSE);
+      dbox_shadeicon(d,glass_AHWIDTH,FALSE);
+      shadeBox=!dbox_selecticon(d,glass_AHWIDTH,dbox_READSTATE);
+      dbox_shadeicon(d,glass_AHBOUND,shadeBox);
+      dbox_shadeicon(d,glass_AHVISAREA,shadeBox);
+      dbox_shadeicon(d,glass_AHCONTAIN,shadeBox);
+      dbox_unclick();
+      break;
+    case glass_AVNONE:
+      dbox_clickicon(d,f);
+      dbox_shadeicon(d,glass_AVTOP,TRUE);
+      dbox_shadeicon(d,glass_AVBOTTOM,TRUE);
+      dbox_shadeicon(d,glass_AVCENTRE,TRUE);
+      dbox_shadeicon(d,glass_AVHEIGHT,TRUE);
+      dbox_shadeicon(d,glass_AVBOUND,TRUE);
+      dbox_shadeicon(d,glass_AVVISAREA,TRUE);
+      dbox_shadeicon(d,glass_AVCONTAIN,TRUE);
+      dbox_unclick();
+      break;
+    case glass_AVALIGN:
+      dbox_clickicon(d,f);
+      dbox_shadeicon(d,glass_AVTOP,FALSE);
+      dbox_shadeicon(d,glass_AVBOTTOM,FALSE);
+      dbox_shadeicon(d,glass_AVCENTRE,FALSE);
+      dbox_shadeicon(d,glass_AVHEIGHT,TRUE);
+      if (dbox_selecticon(d,glass_AVHEIGHT,dbox_READSTATE))
+      {
+        dbox_selecticon(d,glass_AVHEIGHT,FALSE);
+        dbox_selecticon(d,glass_AVCENTRE,TRUE);
+      }
+      shadeBox=!dbox_selecticon(d,glass_AVCENTRE,dbox_READSTATE);
+      dbox_shadeicon(d,glass_AVBOUND,shadeBox);
+      dbox_shadeicon(d,glass_AVVISAREA,shadeBox);
+      dbox_shadeicon(d,glass_AVCONTAIN,TRUE);
+      if (dbox_selecticon(d,glass_AVCONTAIN,dbox_READSTATE))
+      {
+        dbox_selecticon(d,glass_AVCONTAIN,FALSE);
+        dbox_selecticon(d,glass_AVBOUND,TRUE);
+      }
+      dbox_unclick();
+      break;
+    case glass_AVDISTRIB:
+      dbox_clickicon(d,f);
+      dbox_shadeicon(d,glass_AVTOP,FALSE);
+      dbox_shadeicon(d,glass_AVBOTTOM,FALSE);
+      dbox_shadeicon(d,glass_AVCENTRE,FALSE);
+      dbox_shadeicon(d,glass_AVHEIGHT,FALSE);
+      shadeBox=!dbox_selecticon(d,glass_AVHEIGHT,dbox_READSTATE);
+      dbox_shadeicon(d,glass_AVBOUND,shadeBox);
+      dbox_shadeicon(d,glass_AVVISAREA,shadeBox);
+      dbox_shadeicon(d,glass_AVCONTAIN,shadeBox);
+      dbox_unclick();
+      break;
+    case glass_AHLEFT:
+    case glass_AHRIGHT:
+    case glass_AHCENTRE:
+    case glass_AHWIDTH:
+    case glass_AHBOUND:
+    case glass_AHVISAREA:
+    case glass_AHCONTAIN:
+      dbox_clickicon(d,f);
+      if (dbox_selecticon(d,glass_AHALIGN,dbox_READSTATE))
+        shadeBox=!dbox_selecticon(d,glass_AHCENTRE,dbox_READSTATE);
+      else
+        shadeBox=!dbox_selecticon(d,glass_AHWIDTH,dbox_READSTATE);
+      dbox_shadeicon(d,glass_AHBOUND,shadeBox);
+      dbox_shadeicon(d,glass_AHVISAREA,shadeBox);
+      dbox_shadeicon(d,
+                     glass_AHCONTAIN,
+                     !dbox_selecticon(d,glass_AHWIDTH,dbox_READSTATE));
+      dbox_unclick();
+      break;
+    case glass_AVTOP:
+    case glass_AVBOTTOM:
+    case glass_AVCENTRE:
+    case glass_AVHEIGHT:
+    case glass_AVBOUND:
+    case glass_AVVISAREA:
+    case glass_AVCONTAIN:
+      dbox_clickicon(d,f);
+      if (dbox_selecticon(d,glass_AVALIGN,dbox_READSTATE))
+        shadeBox=!dbox_selecticon(d,glass_AVCENTRE,dbox_READSTATE);
+      else
+        shadeBox=!dbox_selecticon(d,glass_AVHEIGHT,dbox_READSTATE);
+      dbox_shadeicon(d,glass_AVBOUND,shadeBox);
+      dbox_shadeicon(d,glass_AVVISAREA,shadeBox);
+      dbox_shadeicon(d,
+                     glass_AVCONTAIN,
+                     !dbox_selecticon(d,glass_AVHEIGHT,dbox_READSTATE));
+      dbox_unclick();
+      break;
+  }
+}
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void align(void)
+ *
+ * Use
+ *  Opens the align dialogue box.  There can only be one selection, ergo
+ *  there can only be one align box.
+ */
+
+void align(void)
+{
+  if (!align__dbox)
+  {
+    align__dbox=dbox_create("align");
+    if (!align__dbox)
+      return;
+
+    dbox_shadeicon(align__dbox,glass_AHLEFT,TRUE);
+    dbox_shadeicon(align__dbox,glass_AHRIGHT,TRUE);
+    dbox_shadeicon(align__dbox,glass_AHCENTRE,TRUE);
+    dbox_shadeicon(align__dbox,glass_AHWIDTH,TRUE);
+    dbox_shadeicon(align__dbox,glass_AHBOUND,TRUE);
+    dbox_shadeicon(align__dbox,glass_AHVISAREA,TRUE);
+    dbox_shadeicon(align__dbox,glass_AHCONTAIN,TRUE);
+
+    dbox_shadeicon(align__dbox,glass_AVTOP,TRUE);
+    dbox_shadeicon(align__dbox,glass_AVBOTTOM,TRUE);
+    dbox_shadeicon(align__dbox,glass_AVCENTRE,TRUE);
+    dbox_shadeicon(align__dbox,glass_AVHEIGHT,TRUE);
+    dbox_shadeicon(align__dbox,glass_AVBOUND,TRUE);
+    dbox_shadeicon(align__dbox,glass_AVVISAREA,TRUE);
+    dbox_shadeicon(align__dbox,glass_AVCONTAIN,TRUE);
+
+    dbox_eventHandler(align__dbox,align__dboxHandler,0);
+  }
+  dbox_display(align__dbox,dbox_STATIC_LASTPOS);
+}
diff --git a/StraySrc/Glass/!Glass/c/colSelect b/StraySrc/Glass/!Glass/c/colSelect
new file mode 100644 (file)
index 0000000..1c5d6b4
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * colSelect.c
+ *
+ * Handling of a colour button
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdlib.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#include "steel/Steel.h"
+#include "steel/akbd.h"
+#include "steel/colourtran.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gIcons.h"
+
+#include "glass.h"
+#include "colSelect.h"
+
+/*----- Support routines --------------------------------------------------*/
+
+/*
+ * void colSelect__addBorder(dbox d,int colour)
+ *
+ * Use
+ *  Adds a border to an icon in the colour dbox.  It chooses the most
+ *  suitable colour for the border as being the nearest colour available in
+ *  the WIMP palette to either black or white, whichever contrasts most
+ *  with the colour to border.
+ *
+ * Parameters
+ *  dbox d == the colour dbox handle
+ *  int colour == the colour to border
+ */
+
+static void colSelect__addBorder(dbox d,int colour)
+{
+  static wimp_paletteword blacknwhite[]={0,0,0,0, 0,255,255,255,};
+  static wimp_palettestr wimppal;
+  int col;
+  wimpt_noerr(wimp_readpalette(&wimppal));
+  wimpt_noerr(colourtran_return_Oppcolourformode(wimppal.c[colour],0,
+                                                          blacknwhite,&col));
+  wimpt_noerr(colourtran_return_colourformode(blacknwhite[col],12,
+                                                            wimppal.c,&col));
+  /* --- We now have the correctly contrasting colour in col --- */
+  wimpt_noerr(wimp_set_icon_state(dbox_syshandle(d),
+                          colour+glass_CSCOLOURS,5+(col<<24),0x0f000005));
+}
+
+/*
+ * void colSelect__removeBorder(dbox d,int colour)
+ *
+ * Use
+ *  Removes the 'selected' border from the colour specified.
+ *
+ * Parameters
+ *  dbox d == the colour dbox handle
+ *  int colour == the colour to unborder
+ */
+
+static void colSelect__removeBorder(dbox d,int colour)
+{
+  wimpt_noerr(wimp_set_icon_state(dbox_syshandle(d),
+                                    colour+glass_CSCOLOURS,0,0x0f000005));
+}
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void colSelect_setColourButton(dbox d,dbox_field f,int colour)
+ *
+ * Use
+ *  Sets a colour button to show a colour
+ *
+ * Parameters
+ *  dbox d == dbox containing button
+ *  dbox_field f == the icon which is the button
+ *  int colour == colour to set the button.  255 means transparent
+ */
+
+void colSelect_setColourButton(dbox d,dbox_field f,int colour)
+{
+  if (colour==255)
+  {
+    wimpt_noerr(wimp_set_icon_state(dbox_syshandle(d),f,
+                                                     0x10000003,0xf0000003));
+  }
+  else
+  {
+    wimpt_noerr(wimp_set_icon_state(dbox_syshandle(d),f,
+                                        0x00000001+(colour<<28),0xf0000003));
+  }
+}
+
+/*
+ * BOOL colSelect__raw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles raw events (keypresses in particular) in the Glass colour box.
+ *
+ * Parameters
+ *  dbox d == the dialogue box handle in question
+ *  wimp_eventstr *e == the wimp event block
+ *  void *handle == pointer to colour value
+ *
+ * Returns
+ *  Whether the event was interesting or not.
+ */
+
+static BOOL colSelect__raw(dbox d,wimp_eventstr *e,void *handle)
+{
+  int *c = handle;
+  BOOL handled = FALSE;
+  switch (e->e)
+  {
+    case wimp_EKEY: {
+      unsigned mask = 0;
+      int offset = 0;
+      int ncol;
+      if (dbox_selecticon(d,glass_CSTRANS,dbox_READSTATE))
+        break;
+      switch (e->data.key.chcode)
+      {
+        case key_Left:
+          mask = 0xC;
+          offset = -1;
+          break;
+        case key_Right:
+          mask = 0xC;
+          offset = 1;
+          break;
+        case key_Up:
+          mask = ~0xC;
+          offset = -4;
+          break;
+        case key_Down:
+          mask = ~0xC;
+          offset = 4;
+          break;
+      }
+      if (!mask)
+        break;
+      handled = TRUE;
+      ncol = *c + offset;
+      if ((ncol ^ *c) & mask)
+        break;
+      colSelect__removeBorder(d,*c);
+      colSelect__addBorder(d,ncol);
+      *c = ncol;
+      break;
+    }
+  }
+  return (handled);
+}
+
+/*
+ * void colSelect(dbox d,dbox_field f,wimp_bbits bbits,char *editing,
+ *                          BOOL allowTrans,colSelect_proc proc,void *handle)
+ *
+ * Use
+ *  Handles mouse events on a colour button.
+ *
+ * Parameters
+ *  dbox d == the dialogue containing the colour button
+ *  dbox_field f == the icon which is the colour button
+ *  wimp_bbits bbits == button status that prompted this
+ *  char *editing == what we're editing (for dialogue)
+ *  BOOL allowTrans == whether we're allowed transparent colour
+ *  colSelect_proc proc == routine to take notice of any changes
+ *  void *handle == pointer to pass to the proc
+ */
+
+void colSelect(dbox d,dbox_field f,wimp_bbits bbits,char *editing,
+                            BOOL allowTrans,colSelect_proc proc,void *handle)
+{
+  int curcol;
+  wimp_icon ic;
+  dbox cs;
+  dbox_field cf;
+  BOOL done=FALSE;
+  wimpt_noerr(wimp_get_icon_info(dbox_syshandle(d),f,&ic));
+  curcol=(ic.flags>>28) & 15;
+  if (ic.flags & 2)
+    curcol=255;
+  switch (bbits)
+  {
+    case wimp_BLEFT:
+      switch (curcol)
+      {
+        case 255:
+          curcol=0;
+          break;
+        case 15:
+          curcol=(allowTrans ? 255 : 0);
+          break;
+        default:
+          curcol++;
+          break;
+      }
+      colSelect_setColourButton(d,f,curcol);
+      proc(d,f,curcol,handle);
+      break;
+    case wimp_BRIGHT:
+      switch (curcol)
+      {
+        case 255:
+          curcol=15;
+          break;
+        case 0:
+          curcol=(allowTrans ? 255 : 15);
+          break;
+        default:
+          curcol--;
+          break;
+      }
+      colSelect_setColourButton(d,f,curcol);
+      proc(d,f,curcol,handle);
+      break;
+    case wimp_BMID:
+      if (cs=dbox_create("colourSel"),!cs)
+        return;
+      if (!allowTrans)
+        wimpt_noerr(wimp_set_icon_state(dbox_syshandle(cs),glass_CSTRANS,
+                                                               1<<23,1<<23));
+      if (curcol==255)
+      {
+        dbox_selecticon(cs,glass_CSTRANS,TRUE);
+        curcol=7;
+      }
+      else
+      {
+        dbox_selecticon(cs,glass_CSTRANS,FALSE);
+        colSelect__addBorder(cs,curcol);
+      }
+      dbox_setfield(cs,glass_CSEDITING,"%s",editing);
+      dbox_rawEventHandler(cs,colSelect__raw,&curcol);
+      dbox_display(cs,dbox_MENU_OVERPTR);
+      {
+        wimp_caretstr c;
+        c.w = dbox_syshandle(cs);
+        c.i = -1;
+        c.x = -500;
+        c.y = 0;
+        c.height = 40;
+        c.index = -1;
+        wimp_set_caret_pos(&c);
+      }
+      while (!done)
+      {
+        cf=dbox_fillin(cs);
+        switch (cf)
+        {
+          case dbox_CLOSE:
+            dbox_delete(cs);
+            done=TRUE;
+            break;
+          case dbox_HELP:
+            help_startHelp();
+            help_addLine(msgs_lookup("cshCSDB"));
+            help_readFromIcon();
+            help_endHelp();
+            break;
+          case glass_CSCANCEL:
+            dbox_clickicon(cs,cf);
+            dbox_hide(cs);
+            dbox_unclick();
+            dbox_delete(cs);
+            done=TRUE;
+            break;
+          case glass_CSOK:
+            dbox_clickicon(cs,cf);
+            if (dbox_selecticon(cs,glass_CSTRANS,dbox_READSTATE))
+            {
+              colSelect_setColourButton(d,f,255);
+              proc(d,f,255,handle);
+            }
+            else
+            {
+              colSelect_setColourButton(d,f,curcol);
+              proc(d,f,curcol,handle);
+            }
+            if (!dbox_wasAdjustClick())
+              dbox_hide(cs);
+            dbox_unclick();
+            if (!dbox_wasAdjustClick())
+            {
+              dbox_delete(cs);
+              done=TRUE;
+            }
+            break;
+          case glass_CSTRANS:
+            if (dbox_selecticon(cs,glass_CSTRANS,dbox_READSTATE))
+              colSelect__removeBorder(cs,curcol);
+            else
+              colSelect__addBorder(cs,curcol);
+            break;
+          default:
+            cf-=glass_CSCOLOURS;
+            if (cf>=0 && cf<=15 && (cf!=curcol ||
+                        dbox_selecticon(cs,glass_CSTRANS,dbox_READSTATE)))
+            {
+              if (!dbox_selecticon(cs,glass_CSTRANS,FALSE))
+                colSelect__removeBorder(cs,curcol);
+              colSelect__addBorder(cs,cf);
+              curcol=cf;
+            }
+            break;
+        }
+      }
+      break;
+  }
+}
diff --git a/StraySrc/Glass/!Glass/c/editIcon b/StraySrc/Glass/!Glass/c/editIcon
new file mode 100644 (file)
index 0000000..74d7f83
--- /dev/null
@@ -0,0 +1,1690 @@
+/*
+ * editIcon.c
+ *
+ * Edit icon dialogue box
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/buttons.h"
+#include "steel/fontMenu.h"
+#include "steel/akbd.h"
+#include "steel/bbc.h"
+#include "steel/buffer.h"
+#include "steel/font.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "tfile.h"
+#include "window.h"
+#include "intMsgs.h"
+#include "editIcon.h"
+#include "colSelect.h"
+#include "indir.h"
+#include "gPrefs.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+static char *editIcon__panels[]=
+{
+  "iconData",
+  "iconAppear",
+  "iconActions",
+  "iconColours",
+  "iconPos",
+  "iconSize",
+};
+
+/*----- Support routines --------------------------------------------------*/
+
+#define max2(a,b) ((a)>(b) ? (a) : (b))
+#define min2(a,b) ((a)<(b) ? (a) : (b))
+
+/*
+ * void editIcon__setupPanel(glass_editIcon *ed)
+ *
+ * Use
+ *  Sets up a panel from the icon description given.
+ *
+ * Parameters
+ *  glass_editIcon *ed == the edit to handle.
+ */
+
+static void editIcon__setupPanel(glass_editIcon *ed)
+{
+  char *p;
+
+  switch (ed->e.panel)
+  {
+    case glass_EIDATA:
+      dbox_setfield(ed->e.pd,glass_EIDVALSTRING,"%s",ed->valid);
+      dbox_setfield(ed->e.pd,glass_EIDDATA,"%s",ed->data);
+      if (!(ed->idef.flags&3))
+      {
+        dbox_shadeicon(ed->e.pd,glass_EIDINDIR,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDDATA,TRUE);
+        dbox_selecticon(ed->e.pd,glass_EIDINDIR,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EIDVALID,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALID,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+        dbox_setfield(ed->e.pd,glass_EIDINDSIZE,"%i",12);
+      }
+      else if (ed->idef.flags & wimp_INDIRECT)
+      {
+        dbox_shadeicon(ed->e.pd,glass_EIDINDIR,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDDATA,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EIDINDIR,TRUE);
+        dbox_selecticon(ed->e.pd,glass_EIDVALID,ed->hasValid);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,!ed->hasValid);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALID,
+                                               !(ed->idef.flags&wimp_ITEXT));
+        dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDUP,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDPART,FALSE);
+        dbox_setfield(ed->e.pd,glass_EIDINDSIZE,"%i",ed->indLen);
+      }
+      else
+      {
+        dbox_shadeicon(ed->e.pd,glass_EIDINDIR,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDDATA,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EIDINDIR,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EIDVALID,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALID,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+        dbox_setfield(ed->e.pd,glass_EIDINDSIZE,"%i",12);
+      }
+      dbox_selecticon(ed->e.pd,glass_EIDTEXT,
+                                              !!(ed->idef.flags&wimp_ITEXT));
+      dbox_selecticon(ed->e.pd,glass_EIDSPRITE,
+                                            !!(ed->idef.flags&wimp_ISPRITE));
+      break;
+    case glass_EIAPPEARANCE:
+      dbox_setfield(ed->e.pd,glass_EIAFONTNAME,"%.%s",ed->font);
+      dbox_setfield(ed->e.pd,glass_EIAFSIZEWRITE,"%i",ed->fontSize);
+      if (ed->idef.flags & wimp_ITEXT)
+      {
+        if (ed->idef.flags & wimp_IFONT)
+        {
+          dbox_selecticon(ed->e.pd,glass_EIAFONT,TRUE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONTNAME,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONTMENU,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONT,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEUP,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEDOWN,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEWRITE,FALSE);
+        }
+        else
+        {
+          dbox_selecticon(ed->e.pd,glass_EIAFONT,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONT,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONTNAME,TRUE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONTMENU,TRUE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEUP,TRUE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEDOWN,TRUE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEWRITE,TRUE);
+        }
+      }
+      else
+      {
+        dbox_selecticon(ed->e.pd,glass_EIAFONT,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFONT,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFONTNAME,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFONTMENU,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFSIZEUP,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFSIZEDOWN,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFSIZEWRITE,TRUE);
+      }
+      dbox_selecticon(ed->e.pd,glass_EIAHCENTRE,
+                                         !!(ed->idef.flags & wimp_IHCENTRE));
+      dbox_selecticon(ed->e.pd,glass_EIAVCENTRE,
+                                         !!(ed->idef.flags & wimp_IVCENTRE));
+      dbox_selecticon(ed->e.pd,glass_EIARALIGN,
+                                           !!(ed->idef.flags & wimp_IRJUST));
+      dbox_selecticon(ed->e.pd,glass_EIABORDER,
+                                          !!(ed->idef.flags & wimp_IBORDER));
+      dbox_selecticon(ed->e.pd,glass_EIAFILL,
+                                          !!(ed->idef.flags & wimp_IFILLED));
+      if (ed->idef.flags & wimp_ISPRITE)
+      {
+        dbox_selecticon(ed->e.pd,glass_EIAHALFSIZE,
+                                     !!(ed->idef.flags & wimp_IHALVESPRITE));
+        dbox_shadeicon(ed->e.pd,glass_EIAHALFSIZE,FALSE);
+      }
+      else
+      {
+        dbox_selecticon(ed->e.pd,glass_EIAHALFSIZE,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIAHALFSIZE,TRUE);
+      }
+      dbox_selecticon(ed->e.pd,glass_EIANEEDSHELP,
+                                          !!(ed->idef.flags & wimp_IREDRAW));
+      break;
+    case glass_EIACTIONS:
+      p=buffer_find();
+      sprintf(p,"eiBTYPE%i",(ed->idef.flags>>12) & 0x0f);
+      dbox_setfield(ed->e.pd,glass_EIABTYPE,"%s",msgs_lookup(p));
+      dbox_setfield(ed->e.pd,glass_EIAESGWRITE,"%i",
+                                                (ed->idef.flags>>16) & 0x1f);
+      dbox_selecticon(ed->e.pd,glass_EIAADJUST,
+                                         !!(ed->idef.flags & wimp_IESG_NOC));
+      dbox_selecticon(ed->e.pd,glass_EIASELECT,
+                                        !!(ed->idef.flags & wimp_ISELECTED));
+      dbox_selecticon(ed->e.pd,glass_EIASHADE,
+                                        !!(ed->idef.flags & wimp_INOSELECT));
+      break;
+    case glass_EICOLOURS:
+      colSelect_setColourButton(ed->e.pd,glass_EICFORE,
+                                                  (ed->idef.flags>>24) & 15);
+      colSelect_setColourButton(ed->e.pd,glass_EICBACK,
+                                                  (ed->idef.flags>>28) & 15);
+      break;
+    case glass_EISIZE:
+      dbox_setfield(ed->e.pd,
+                    glass_EIPWRITE,
+                    "%i,%i",
+                    ed->idef.box.x1-ed->idef.box.x0,
+                    ed->idef.box.y1-ed->idef.box.y0);
+      dbox_shadeicon(ed->e.pd,glass_EIPSETSIZE,!(ed->idef.flags & 3));
+      break;
+    case glass_EIPOSITION:
+      dbox_setfield(ed->e.pd,
+                    glass_EIPWRITE,
+                    "%i,%i",
+                    ed->idef.box.x0,
+                    ed->idef.box.y0);
+      break;
+  }
+}
+
+/*
+ * BOOL editIcon__getSpriteSize(char *name,sprite_area *a,int *x,int *y)
+ *
+ * Use
+ *  Attempts to read the size of a sprite in OS units.
+ *
+ * Returns
+ *  TRUE if it really worked
+ */
+
+static BOOL editIcon__getSpriteSize(char *name,sprite_area *a,int *x,int *y)
+{
+  os_error *e;
+  os_regset r;
+
+  /* --- First look in the given area --- */
+
+  e=os_swivr(OS_SpriteOp,&r,40+256,a,name);
+
+  /* --- Now, OS version permitting, look in the WIMP area --- */
+
+  if (e && wimpt_getVersion()>=300)
+    e=os_swivr(Wimp_SpriteOp,&r,40,0,name);
+
+  /* --- If it worked, read out all the info and return it --- */
+
+  if (!e)
+  {
+    *x=r.r[3]<<bbc_modevar(r.r[6],bbc_XEigFactor);
+    *y=r.r[4]<<bbc_modevar(r.r[6],bbc_YEigFactor);
+  }
+
+  /* --- Return the success value --- */
+
+  return (!e);
+}
+
+/*
+ * void editIcon__setSize(glass_editIcon *ed)
+ *
+ * Use
+ *  Reads the size of the icon correctly from the definition, assuming
+ *  various things:
+ *
+ *  1. The icon isn't word-wrapped
+ *  2. Both selected and unselected versions of the sprite to use are the
+ *     same size
+ *  3. Size is independent of things like button type
+ */
+
+static void editIcon__setSize(glass_editIcon *ed)
+{
+  int w,h;
+  int sw,sh;
+  char sname[15];
+  static int posns[]={1,1,2,2,1,1,3,2};
+  int f;
+  char *sprname;
+
+  /* --- Read the current width and height from dbox --- */
+
+  dbox_scanfield(ed->e.pd,glass_EIPWRITE,"%d,%d",&w,&h);
+
+  /* --- Find out if this is going to be easy --- */
+
+  switch (ed->idef.flags & 3)
+  {
+    /* --- No icon data -- ignore this operation --- */
+
+    case 0:
+      break;
+
+    /* --- Only text -- work it out (assuming system font size) --- */
+
+    case 1:
+      h=48;
+      w=16*(strlen(ed->data)+1);
+      break;
+
+    /* --- Only a sprite -- use the size of the sprite --- */
+
+    case 2:
+      if (!editIcon__getSpriteSize(ed->data,ed->w->t->s,&w,&h))
+        note(msgs_lookup("eiSPRGONE"),ed->data);
+      break;
+
+    /* --- Text and sprite together --- */
+
+    case 3:
+      sprname=ed->data;
+
+      if ((ed->idef.flags & 0x100) && ed->hasValid)
+      {
+        /* --- Parse the validation string to find the sprite name --- */
+
+        int state=1;
+        char *p=ed->valid;
+        char *q=sname;
+
+        for (;*p>31 && state!=3;p++)
+        {
+          switch (*p)
+          {
+            case '\\':
+              if (p[1]>31)
+                p++;
+              if (state==1)
+                state=0;
+              else if (state==2)
+                *q++=*p;
+              break;
+            case ';':
+              if (state>1)
+              {
+                *q++=0;
+                state=3;
+              }
+              else
+                state=1;
+              break;
+            case 'S':
+            case 's':
+              if (state==1)
+                state=2;
+              else if (state==2)
+                *q++=*p;
+              break;
+            case ',':
+              switch (state)
+              {
+                case 2:
+                  *q++=0;
+                  state++;
+              }
+              break;
+            default:
+              switch (state)
+              {
+                case 1:
+                  state=0;
+                  break;
+                case 2:
+                  *q++=*p;
+                  break;
+              }
+              break;
+          }
+        }
+
+        if (state==2)
+        {
+          *q++=0;
+          state=3;
+        }
+
+        if (state==3)
+          sprname=sname;
+      }
+
+      if (editIcon__getSpriteSize(sprname,ed->w->t->s,&sw,&sh))
+      {
+        if (ed->data[0])
+        {
+          h=48;
+          w=16*(strlen(ed->data)+1);
+
+          f=posns[(tst(ed->idef.flags,3)<<2) |
+                  (tst(ed->idef.flags,4)<<1) |
+                  (tst(ed->idef.flags,9)<<0)];
+
+          if (f & 2)
+            h=max2(h,sh);
+          else
+            h+=sh;
+
+          if (f & 1)
+            w=max2(w,sw);
+          else
+            w+=sw;
+        }
+        else
+        {
+          h=sh;
+          w=sw;
+        }
+      }
+      else
+        note(msgs_lookup("eiSPRGONE"),sprname);
+      break;
+  }
+
+  dbox_setfield(ed->e.pd,glass_EIPWRITE,"%i,%i",w,h);
+}
+
+/*
+ * void editIcon__closePanel(glass_editIcon *ed)
+ *
+ * Use
+ *  Records the settings in a panel for future reference, for example when
+ *  the panel is being replaced by a different one.
+ *
+ * Parameters
+ *  glass_editIcon *ed == the edit box we're talking about
+ */
+
+#define Q dbox_READSTATE
+
+static void editIcon__closePanel(glass_editIcon *ed)
+{
+  int esg;
+  int x,y;
+  switch (ed->e.panel)
+  {
+    case glass_EIDATA:
+      dbox_getfield(ed->e.pd,glass_EIDDATA,ed->data,256);
+      dbox_getfield(ed->e.pd,glass_EIDVALSTRING,ed->valid,256);
+      dbox_scanfield(ed->e.pd,glass_EIDINDSIZE,"%d",&ed->indLen);
+      ed->hasValid=dbox_selecticon(ed->e.pd,glass_EIDVALID,Q);
+      ed->idef.flags&=~0x00000103;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIDTEXT,Q)<<0;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIDSPRITE,Q)<<1;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIDINDIR,Q)<<8;
+      break;
+    case glass_EIAPPEARANCE:
+      ed->idef.flags&=~0x00000afc;
+      dbox_scanfield(ed->e.pd,glass_EIAFSIZEWRITE,"%d",&ed->fontSize);
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIAHCENTRE,Q)<<3;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIAVCENTRE,Q)<<4;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIABORDER,Q)<<2;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIAFILL,Q)<<5;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIAFONT,Q)<<6;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIANEEDSHELP,Q)<<7;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIARALIGN,Q)<<9;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIAHALFSIZE,Q)<<11;
+      break;
+    case glass_EIACTIONS:
+      ed->idef.flags&=~0x007f0400;
+      dbox_scanfield(ed->e.pd,glass_EIAESGWRITE,"%d",&esg);
+      ed->idef.flags|=esg<<16;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIAADJUST,Q)<<10;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIASELECT,Q)<<21;
+      ed->idef.flags|=dbox_selecticon(ed->e.pd,glass_EIASHADE,Q)<<22;
+      break;
+    case glass_EISIZE:
+      dbox_scanfield(ed->e.pd,glass_EIPWRITE,"%d,%d",&x,&y);
+      ed->idef.box.x1=ed->idef.box.x0+x;
+      ed->idef.box.y1=ed->idef.box.y0+y;
+      break;
+    case glass_EIPOSITION:
+      dbox_scanfield(ed->e.pd,glass_EIPWRITE,"%d,%d",&x,&y);
+      ed->idef.box.x1+=x-ed->idef.box.x0;
+      ed->idef.box.y1+=y-ed->idef.box.y0;
+      ed->idef.box.x0=x;
+      ed->idef.box.y0=y;
+      break;
+  }
+}
+
+#undef Q
+
+/*
+ * void editIcon__setPanel(glass_editIcon *ed,dbox_field f)
+ *
+ * Use
+ *  Creates a new panel based on a radio button click or some-such.
+ *
+ * Parameters
+ *  glass_editIcon *ed == the edit window to change panel
+ *  dbox_field f == the radio button associated with the desired panel
+ */
+
+static void editIcon__panelHandler(dbox d,dbox_field f,void *handle);
+static BOOL editIcon__panelRaw(dbox d,wimp_eventstr *e,void *handle);
+
+static void editIcon__setPanel(glass_editIcon *ed,dbox_field f)
+{
+  dbox d;
+  wimp_wstate s;
+  wimp_icon i;
+  int width,height;
+  int ox,oy;
+  wimp_w behind;
+  wimp_caretstr c;
+  BOOL ownCaret=TRUE;
+  if (f==ed->e.panel)
+    return;
+  editIcon__closePanel(ed);
+  wimpt_noerr(wimp_get_wind_state(dbox_syshandle(ed->e.d),&s));
+  wimpt_noerr(wimp_get_icon_info(dbox_syshandle(ed->e.d),
+                                                        glass_EIPOSN,&i));
+  ox=s.o.box.x0-s.o.x;
+  oy=s.o.box.y1-s.o.y;
+  mem_useUser(indir_alloc,indir_free);
+  if (f==-1)
+    d=dbox_create("iconNowt");
+  else
+    d=dbox_create(editIcon__panels[f-glass_EIDATA]);
+  if (!d)
+  {
+    mem_useMalloc();
+    return;
+  }
+  dbox_eventHandler(d,editIcon__panelHandler,ed);
+  dbox_rawEventHandler(d,editIcon__panelRaw,ed);
+  if (ed->e.panel)
+  {
+    wimpt_noerr(wimp_get_caret_pos(&c));
+    ownCaret=(c.w==dbox_syshandle(ed->e.pd));
+    dbox_selecticon(ed->e.d,ed->e.panel,dbox_RESETSTATE);
+    wimpt_noerr(wimp_get_wind_state(dbox_syshandle(ed->e.pd),&s));
+    pane_removePane(ed->e.p,dbox_syshandle(ed->e.pd));
+    dbox_delete(ed->e.pd);
+  }
+  dbox_selecticon(ed->e.d,f,dbox_SETSTATE);
+  behind=s.o.behind;
+  wimpt_noerr(wimp_get_wind_state(dbox_syshandle(d),&s));
+  width=s.o.box.x1-s.o.box.x0;
+  height=s.o.box.y1-s.o.box.y0;
+  s.o.box.x0=i.box.x0+ox+wimpt_dx();
+  s.o.box.y0=i.box.y0+oy+wimpt_dy();
+  s.o.box.x1=s.o.box.x0+width;
+  s.o.box.y1=s.o.box.y0+height;
+  s.o.y=10000;
+  s.o.behind=behind;
+  ed->e.pd=d;
+  ed->e.panel=f;
+  editIcon__setupPanel(ed);
+  wimpt_noerr(wimp_open_wind(&s.o));
+  if (ownCaret)
+  {
+    c.w=dbox_syshandle(d);
+    c.i=-1;
+    c.x=-500000;
+    c.y=0;
+    c.height=0x02000000;
+    wimpt_noerr(wimp_set_caret_pos(&c));
+  }
+  pane_addPane(ed->e.p,dbox_syshandle(d));
+  mem_useMalloc();
+}
+
+/*
+ * void editIcon__recreate(glass_editIcon *ed)
+ *
+ * Use
+ *  Recreates the icon from the dialogue box settings
+ *
+ * Parameters
+ *  glass_editIcon *ed == info about the edit
+ */
+
+static void editIcon__recreate(glass_editIcon *ed)
+{
+  char *p=0;
+  char *q=0;
+  int inum;
+  int fhandle;
+  ed->w->def->i[ed->i].edit=0;   /* Delink temporarily                     */
+  window_redrawIcon(ed->w,ed->i); /* Force redraw of old icon              */
+
+  if (!(ed->idef.flags & wimp_INDIRECT))
+  {
+    ed->indLen=12;
+    ed->hasValid=FALSE;
+  }
+  if (strlen(ed->data)>=ed->indLen)
+  {
+    ed->idef.flags|=wimp_INDIRECT;
+    ed->indLen=strlen(ed->data)+1;
+  }
+  if (ed->idef.flags & wimp_INDIRECT)
+  {
+    if (p=indir_alloc(ed->indLen),!p)
+    {
+      werr(FALSE,msgs_lookup("eiNEMUI"));
+      return;
+    }
+    if (ed->hasValid && (ed->idef.flags & wimp_ITEXT))
+    {
+      if (q=indir_alloc(strlen(ed->valid)+1),!q)
+      {
+        indir_free(p);
+        werr(FALSE,msgs_lookup("eiNEMUI"));
+        return;
+      }
+      strcpy(q,ed->valid);
+      ed->w->size+=strlen(ed->valid)+1;
+    }
+    strcpy(p,ed->data);
+    ed->w->size+=ed->indLen;
+  }
+
+  if (ed->w->def->i[ed->i].i.flags & wimp_IFONT) /* Was old anti?          */
+  {
+    fhandle=(ed->w->def->i[ed->i].i.flags >> 24) & 255;
+    wimpt_noerr(font_lose(fhandle));
+    ed->w->fonts[fhandle]--;
+  }
+  if (ed->idef.flags & wimp_IFONT) /* Is new icon antialiased?             */
+  {
+    if (font_find(ed->font,ed->fontSize*16,ed->fontSize*16,0,0,&fhandle))
+    {
+      werr(FALSE,msgs_lookup("eiCFF"),ed->font);
+      ed->idef.flags&=~wimp_IFONT;
+    }
+    else
+    {
+      ed->w->antiAliased=TRUE;
+      ed->w->fonts[fhandle]++;
+      ed->idef.flags=(ed->idef.flags & 0x00ffffff) | (fhandle<<24);
+    }
+  }
+
+  if (ed->w->def->i[ed->i].i.flags & wimp_INDIRECT)
+  {
+    indir_free(ed->w->def->i[ed->i].i.data.indirecttext.buffer);
+    ed->w->size-=ed->w->def->i[ed->i].i.data.indirecttext.bufflen;
+    if ((ed->w->def->i[ed->i].i.flags & wimp_ITEXT) &&
+          (ed->w->def->i[ed->i].i.data.indirecttext.validstring!=(char *)-1))
+    {
+      utils_ctermToNterm(ed->w->def->i[ed->i].
+                         i.data.indirecttext.validstring);
+      ed->w->size-=
+              strlen(ed->w->def->i[ed->i].i.data.indirecttext.validstring)+1;
+      indir_free(ed->w->def->i[ed->i].i.data.indirecttext.validstring);
+    }
+  }
+
+  if (p)
+  {
+    ed->idef.data.indirecttext.buffer=p;
+    ed->idef.data.indirecttext.bufflen=ed->indLen;
+    if (q)
+      ed->idef.data.indirecttext.validstring=q;
+    else if (ed->idef.flags & wimp_ITEXT)
+      ed->idef.data.indirecttext.validstring=(char *)-1;
+    else
+      ed->idef.data.indirectsprite.spritearea=ed->w->t->s;
+  }
+  else
+    memcpy(ed->idef.data.text,ed->data,12);
+
+  ed->w->def->i[ed->i].i=ed->idef;
+  dbox_scanfield(ed->e.d,glass_EINUMWRITE,"%d",&inum);
+  if (!window_renumber(ed->w,ed->i,inum))
+    dbox_setfield(ed->e.d,glass_EINUMWRITE,"%i",ed->i);
+  else
+    ed->i=inum;
+
+  window_redrawIcon(ed->w,ed->i); /* Force redraw of new icon              */
+  ed->w->def->i[ed->i].edit=ed;  /* Relink again                           */
+  tfile_markAsAltered(ed->w->t);
+}
+
+/*
+ * void editIcon__nextPanel(glass_editIcon *ed,int dir)
+ *
+ * Use
+ *  Changes panel to the next one in the given direction.  Skips shaded
+ *  panels and handles everything nicely.
+ *
+ * Parameters
+ *  glass_editIcon *ed == the edit dialogue box to move about in
+ *  int dir == the direction (-1 for up, 1 for down)
+ */
+
+static void editIcon__nextPanel(glass_editIcon *ed,int dir)
+{
+  int i=ed->e.panel;
+
+  if (i==-1)
+    i=(dir==1 ? glass_EIDATA : glass_EISIZE);
+  else
+    i+=dir;
+
+  for (;i>=glass_EIDATA && i<=glass_EISIZE;i+=dir)
+  {
+    if (!dbox_shadeicon(ed->e.d,i,dbox_READSTATE))
+    {
+      editIcon__setPanel(ed,i);
+      break;
+    }
+  }
+}
+
+/*----- Event handlers ----------------------------------------------------*/
+
+/*
+ * void editIcon__dboxHandler(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles any and all events directed at the dbox.  Well, almost all...
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the event that happened
+ *  void *handle == pointer to the dialogue box control info
+ */
+
+static void editIcon__dboxHandler(dbox d,dbox_field f,void *handle)
+{
+  glass_editIcon *ed=handle;
+  buttons_simpleArrow sa={0,9999,FALSE};
+
+  switch (f)
+  {
+    case dbox_CLOSE:
+      if (ed->e.pd)
+        dbox_deleteNoUpdate(ed->e.pd);
+      pane_delete(ed->e.p);
+      dbox_delete(ed->e.d);
+      ed->w->def->i[ed->i].edit=0;
+      mem_free(ed);
+      break;
+    case dbox_HELP:
+      help_startHelp();
+      help_addLine(msgs_lookup("eihEIDB"));
+      help_readFromIcon();
+      help_endHelp();
+      break;
+    case glass_EICAN:
+      dbox_clickicon(d,f);
+      if (!dbox_wasAdjustClick())
+        pane_close(ed->e.p);
+      else
+      {
+        /* --- set up for old icon --- */
+        ed->idef=ed->w->def->i[ed->i].i;
+        editIcon_readData(ed->w,ed->i);
+        dbox_setfield(ed->e.d,glass_EINUMWRITE,"%i",ed->i);
+        editIcon__setupPanel(ed);
+      }
+      dbox_unclick();
+      if (!dbox_wasAdjustClick())
+        editIcon_close(ed->w,ed->i);
+      break;
+    case glass_EIOK:
+      dbox_clickicon(d,f);
+      editIcon__closePanel(ed);
+      if (!dbox_wasAdjustClick())
+      {
+        pane_close(ed->e.p);
+        editIcon__recreate(ed);
+        dbox_unclick();
+        editIcon_close(ed->w,ed->i);
+      }
+      else
+      {
+        editIcon__recreate(ed);
+        editIcon_readData(ed->w,ed->i);
+        editIcon__setupPanel(ed);
+        dbox_unclick();
+      }
+      break;
+    case glass_EIDELETE:
+      dbox_clickicon(d,f);
+      if (gPrefs_current()->cDelIcon)
+      {
+        if (!warning(msgs_lookup("eiCDIP"),
+           msgs_lookup("eiCDI")))
+        {
+          dbox_unclick();
+          return;
+        }
+      }
+      pane_close(ed->e.p);
+      dbox_unclick();
+      window_deleteIcon(ed->w,ed->i); /* Closes the edit for us            */
+      break;
+    case glass_EIDATA:
+    case glass_EIAPPEARANCE:
+    case glass_EIACTIONS:
+    case glass_EICOLOURS:
+    case glass_EIPOSITION:
+    case glass_EISIZE:
+      editIcon__setPanel(ed,f);
+      break;
+    case glass_EINUMUP:
+      buttons_arrow(d,f,d,glass_EINUMWRITE,0,+1,&sa);
+      break;
+    case glass_EINUMDOWN:
+      buttons_arrow(d,f,d,glass_EINUMWRITE,0,-1,&sa);
+      break;
+  }
+}
+
+/*
+ * BOOL editIcon__dboxRaw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles open window requests and things for the main Preferences dbox.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  wimp_eventstr *e == the event that happened
+ *  void *handle == a unused pointer
+ *
+ * Returns
+ *  TRUE if the event has been handled;
+ */
+
+static BOOL editIcon__dboxRaw(dbox d,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  glass_editIcon *ed=handle;
+  glass_intMsgstr *m;
+  unused(d);
+  switch (e->e)
+  {
+    case wimp_EOPEN:
+      pane_moved(ed->e.p);
+      handled=TRUE;
+      break;
+    case wimp_EKEY:
+      switch (e->data.key.chcode)
+      {
+        case akbd_UpK+akbd_Sh:
+          editIcon__nextPanel(ed,-1);
+          handled=TRUE;
+          break;
+        case akbd_DownK+akbd_Sh:
+          editIcon__nextPanel(ed,+1);
+          handled=TRUE;
+          break;
+      }
+      break;
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MINTERNAL:
+          m=intMsgs_receive(e);
+          switch(e->data.msg.data.words[0])
+          {
+            case glass_DELETEFILE:
+              if (m->df.t==ed->w->t)
+                editIcon_close(ed->w,ed->i);
+              break;
+            case glass_DELETEWINDOW:
+              if (m->dw.w==ed->w)
+                editIcon_close(ed->w,ed->i);
+              break;
+            case glass_RENAME:
+              if (m->rn.w==ed->w)
+                dbox_setfield(ed->e.d,glass_EIWINDISP,"%s",ed->w->id);
+              break;
+          }
+          break;
+      }
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * menu editIcon__fontMaker(void *handle)
+ *
+ * Use
+ *  Sets up the font menu.
+ *
+ * Parameters
+ *  void *handle == pointer to this edit
+ *
+ * Returns
+ *  A menu to display
+ */
+
+static menu editIcon__fontMaker(void *handle)
+{
+  glass_editIcon *ed=handle;
+  menu m=fontMenu_createFontMenu(FALSE);
+  fontMenu_tickGivenName(ed->font);
+  return (m);
+}
+
+/*
+ * void editIcon__fontHandler(int hit[],void *handle)
+ *
+ * Use
+ *  Gets the font chosen from the font menu.
+ *
+ * Parameters
+ *  int hit[] == the hit string
+ *  void *handle == pointer to this edit
+ */
+
+static void editIcon__fontHandler(int hit[],void *handle)
+{
+  glass_editIcon *ed=handle;
+  if (hit[0])
+  {
+    strcpy(ed->font,fontMenu_fontname(hit[0],hit[1]));
+    dbox_setfield(ed->e.pd,glass_EIAFONTNAME,"%.%s",ed->font);
+  }
+}
+
+/*
+ * void editIcon__fontHelp(int hit[],void *handle)
+ *
+ * Use
+ *  Gives help on a font menu item
+ *
+ * Parameters
+ *  int hit[] == the hit string
+ *  void *handle == pointer to this edit
+ */
+
+static void editIcon__fontHelp(int hit[],void *handle)
+{
+  unused(handle);
+  if (hit[0])
+  {
+    help_startHelp();
+    help_addLine(msgs_lookup("eimhFONT"),fontMenu_fontname(hit[0],hit[1]));
+    help_endHelp();
+  }
+}
+
+/*
+ * menu editIcon__btypeMaker(void *handle)
+ *
+ * Use
+ *  Generates and sets up a button type menu for an edit dialogue box
+ *
+ * Parameters
+ *  void *handle == pointer to the edit
+ *
+ * Returns
+ *  The menu to use
+ */
+
+static menu editIcon__btypeMaker(void *handle)
+{
+  static menu m;
+  static int ticked;
+  glass_editIcon *ed=handle;
+  int i;
+  char *buf=buffer_find();
+  if (!m)
+  {
+    m=menu_new(msgs_lookup("eiBTMT"),msgs_lookup("eiBTYPE0"));
+    for (i=1;i<=15;i++)
+    {
+      sprintf(buf,"eiBTYPE%i",i);
+      menu_extend(m,msgs_lookup(buf));
+    }
+  }
+  if (ticked)
+    menu_setflags(m,ticked,FALSE,FALSE);
+  ticked=((ed->idef.flags>>12)&0x0f)+1;
+  menu_setflags(m,ticked,TRUE,FALSE);
+  return (m);
+}
+
+/*
+ * void editIcon__btypeHandler(int hit[],void *handle)
+ *
+ * Use
+ *  Handles a click on the button type menu.
+ *
+ * Parameters
+ *  int hit[] == the mouse click info
+ *  void *handle == pointer to edit information
+ */
+
+static void editIcon__btypeHandler(int hit[],void *handle)
+{
+  glass_editIcon *ed=handle;
+  char *buf=buffer_find();
+  if (hit[0])
+  {
+    ed->idef.flags&=~0x0000f000;
+    ed->idef.flags+=(hit[0]-1)<<12;
+    sprintf(buf,"eiBTYPE%i",hit[0]-1);
+    dbox_setfield(ed->e.pd,glass_EIABTYPE,"%s",msgs_lookup(buf));
+  }
+}
+
+/*
+ * void editIcon__colProc(dbox d,dbox_field f,int colour, void *handle)
+ *
+ * Use
+ *  This routine is called when a colour is selected in the colours panel.
+ *
+ * Parameters
+ *  dbox d == the panel's handle
+ *  dbox_field f == the colour button that has changed
+ *  int colour == the new colour for the button
+ *  void *handle == pointer to this edit
+ */
+
+static void editIcon__colProc(dbox d,dbox_field f,int colour,void *handle)
+{
+  glass_editIcon *ed=handle;
+  unused(d);
+  switch (f)
+  {
+    case glass_EICFORE:
+      ed->idef.flags=(ed->idef.flags & ~0x0f000000)+(colour<<24);
+      break;
+    case glass_EICBACK:
+      ed->idef.flags=(ed->idef.flags & ~0xf0000000)+(colour<<28);
+      break;
+  }
+}
+
+/*
+ * void editIcon__btypeHelp(int hit[],void *handle)
+ *
+ * Use
+ *  Handles a help request for the button type menu.
+ *
+ * Parameters
+ *  int hit[] == the helpq info
+ *  void *handle == pointer to edit information
+ */
+
+static void editIcon__btypeHelp(int hit[],void *handle)
+{
+  char *buf=buffer_find();
+  unused(handle);
+  if (hit[0])
+  {
+    help_startHelp();
+    sprintf(buf,"eiBTYPE%i",hit[0]-1);
+    help_addLine(msgs_lookup("eimhBTYPE"),msgs_lookup(buf));
+    help_endHelp();
+  }
+}
+
+/*
+ * void editIcon__posSizeArrows(dbox d,dbox_field f,int diff,void *handle)
+ *
+ * Use
+ *  Handles a click event on one of the position or size arrow buttons in
+ *  the dialogue box.  See the structure definition below for a description
+ *  of the data structure required.
+ */
+
+typedef struct
+{
+  BOOL xOrY;
+  BOOL sizing;
+}
+editIcon__posSizeArrowstr;
+
+static void editIcon__posSizeArrows(dbox d,
+                                    dbox_field f,
+                                    int diff,
+                                    void *handle)
+{
+  editIcon__posSizeArrowstr *s=handle;
+  int x,y;
+  int *v;
+
+  dbox_scanfield(d,f,"%d,%d",&x,&y);
+  v=s->xOrY ? &x : &y;
+  *v+=diff;
+  if (s->sizing && *v<0)
+    *v=0;
+  dbox_setfield(d,f,"%i,%i",x,y);
+}
+
+/*
+ * void editIcon__panelHandler(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles simple click events for the current panel in an edit dbox
+ *
+ * Parameters
+ *  dbox d == the panel's dbox handle
+ *  dbox_field f == the icon that was clicked
+ *  void *handle == pointer to edit information
+ */
+
+static void editIcon__panelHandler(dbox d,dbox_field f,void *handle)
+{
+  glass_editIcon *ed=handle;
+  buttons_simpleArrow sa={0,9999,FALSE};
+  buttons_simpleArrow esga={0,31,FALSE};
+  editIcon__posSizeArrowstr psa={0,FALSE};
+  BOOL indon;
+
+  switch (f)
+  {
+    case dbox_CLOSE:
+    case dbox_HELP:
+    case glass_EIOK:
+    case glass_EICAN:
+      editIcon__dboxHandler(ed->e.d,f,ed);
+      return;
+      break;
+  }
+  switch (ed->e.panel)
+  {
+    case glass_EIDATA:
+      switch (f)
+      {
+        case glass_EIDINDIR:
+          if (dbox_selecticon(d,f,dbox_READSTATE))
+          {
+            if (dbox_selecticon(ed->e.pd,glass_EIDTEXT,dbox_READSTATE))
+            {
+              dbox_shadeicon(ed->e.pd,glass_EIDVALID,FALSE);
+              dbox_shadeicon(ed->e.pd,
+                             glass_EIDVALSTRING,
+                             !dbox_selecticon(ed->e.pd,
+                                              glass_EIDVALID,
+                                              dbox_READSTATE));
+            }
+            dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDUP,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDPART,FALSE);
+          }
+          else
+          {
+            dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDVALID,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+          }
+          break;
+        case glass_EIDINDUP:
+          buttons_arrow(ed->e.pd,f,ed->e.pd,glass_EIDINDSIZE,0,+1,&sa);
+          break;
+        case glass_EIDINDDOWN:
+          buttons_arrow(ed->e.pd,f,ed->e.pd,glass_EIDINDSIZE,0,-1,&sa);
+          break;
+        case glass_EIDVALID:
+          dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,dbox_TOGGLESTATE);
+          break;
+        case glass_EIDMINIMISE:
+          dbox_clickicon(d,f);
+          dbox_getfield(d,glass_EIDDATA,ed->data,256);
+          dbox_setfield(d,glass_EIDINDSIZE,"%i",strlen(ed->data)+1);
+          dbox_unclick();
+          break;
+        case glass_EIDTEXT:
+          if (dbox_selecticon(ed->e.pd,glass_EIDTEXT,dbox_READSTATE))
+          {
+            dbox_shadeicon(ed->e.pd,glass_EIDDATA,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDIR,FALSE);
+            if (dbox_selecticon(d,glass_EIDINDIR,dbox_READSTATE))
+            {
+              dbox_shadeicon(ed->e.pd,glass_EIDVALID,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,
+                !dbox_selecticon(ed->e.pd,glass_EIDVALID,dbox_READSTATE));
+              dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDUP,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDPART,FALSE);
+            }
+            else
+            {
+              dbox_shadeicon(ed->e.pd,glass_EIDVALID,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+            }
+            dbox_shadeicon(ed->e.d,glass_EICOLOURS,
+                                            !!(ed->idef.flags & wimp_IFONT));
+          }
+          else
+          {
+            dbox_shadeicon(ed->e.pd,glass_EIDVALID,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,TRUE);
+            if (dbox_selecticon(d,glass_EIDSPRITE,dbox_READSTATE))
+            {
+              dbox_shadeicon(ed->e.pd,glass_EIDDATA,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDIR,FALSE);
+              indon=dbox_selecticon(d,glass_EIDINDIR,dbox_READSTATE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,!indon);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDUP,!indon);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,!indon);
+              dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,!indon);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDPART,!indon);
+            }
+            else
+            {
+              dbox_shadeicon(ed->e.pd,glass_EIDDATA,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDIR,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+            }
+            dbox_shadeicon(ed->e.d,glass_EICOLOURS,FALSE);
+          }
+          break;
+        case glass_EIDSPRITE:
+          if (dbox_selecticon(ed->e.pd,glass_EIDSPRITE,dbox_READSTATE))
+          {
+            dbox_shadeicon(ed->e.pd,glass_EIDDATA,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDIR,FALSE);
+            indon=dbox_selecticon(d,glass_EIDINDIR,dbox_READSTATE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,!indon);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDUP,!indon);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,!indon);
+            dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,!indon);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDPART,!indon);
+          }
+         else if (!dbox_selecticon(ed->e.pd,glass_EIDTEXT,dbox_READSTATE))
+          {
+            dbox_shadeicon(ed->e.pd,glass_EIDDATA,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDIR,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+          }
+          break;
+      }
+      break;
+    case glass_EIAPPEARANCE:
+      switch (f)
+      {
+        case glass_EIAFONT:
+          if (dbox_selecticon(d,f,dbox_READSTATE) ||
+              fontMenu_createFontMenu(FALSE))
+          {
+            dbox_selecticon(d,f,dbox_TOGGLESTATE);
+            dbox_shadeicon(d,glass_EIAFONTNAME,dbox_TOGGLESTATE);
+            dbox_shadeicon(d,glass_EIAFONTMENU,dbox_TOGGLESTATE);
+            dbox_shadeicon(d,glass_EIAFSIZEUP,dbox_TOGGLESTATE);
+            dbox_shadeicon(d,glass_EIAFSIZEDOWN,dbox_TOGGLESTATE);
+            dbox_shadeicon(d,glass_EIAFSIZEWRITE,dbox_TOGGLESTATE);
+            dbox_shadeicon(ed->e.d,glass_EICOLOURS,dbox_TOGGLESTATE);
+          }
+          break;
+        case glass_EIAFSIZEUP:
+          buttons_arrow(ed->e.pd,f,ed->e.pd,glass_EIAFSIZEWRITE,0,+1,&sa);
+          break;
+        case glass_EIAFSIZEDOWN:
+          buttons_arrow(ed->e.pd,f,ed->e.pd,glass_EIAFSIZEWRITE,0,-1,&sa);
+          break;
+      }
+      break;
+    case glass_EIACTIONS:
+      switch (f)
+      {
+        case glass_EIAESGUP:
+          buttons_arrow(d,f,d,glass_EIAESGWRITE,0,+1,&esga);
+          break;
+        case glass_EIAESGDOWN:
+          buttons_arrow(d,f,d,glass_EIAESGWRITE,0,-1,&esga);
+          break;
+      }
+      break;
+    case glass_EICOLOURS:
+      /* Nothin' doing */
+      break;
+    case glass_EISIZE:
+      psa.sizing=TRUE;
+      /* Drop through */
+    case glass_EIPOSITION:
+      switch (f)
+      {
+        case glass_EIPUP:
+          psa.xOrY=FALSE;
+          buttons_arrow(d,f,d,glass_EIPWRITE,
+                        editIcon__posSizeArrows,
+                        +wimpt_dy(),
+                        &psa);
+          break;
+        case glass_EIPDOWN:
+          psa.xOrY=FALSE;
+          buttons_arrow(d,f,d,glass_EIPWRITE,
+                        editIcon__posSizeArrows,
+                        -wimpt_dy(),
+                        &psa);
+          break;
+        case glass_EIPLEFT:
+          psa.xOrY=TRUE;
+          buttons_arrow(d,f,d,glass_EIPWRITE,
+                        editIcon__posSizeArrows,
+                        -wimpt_dx(),
+                        &psa);
+          break;
+        case glass_EIPRIGHT:
+          psa.xOrY=TRUE;
+          buttons_arrow(d,f,d,glass_EIPWRITE,
+                        editIcon__posSizeArrows,
+                        +wimpt_dx(),
+                        &psa);
+          break;
+        case glass_EIPSETSIZE:
+          dbox_clickicon(d,f);
+          editIcon__setSize(ed);
+          dbox_unclick();
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * BOOL editIcon__panelRaw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles the more wierd events for a particular panel.
+ *
+ * Parameters
+ *  dbox d == the dbox handle of the panel
+ *  wimp_eventstr *e == the event to look at
+ *  void *handle == pointer to the current edit
+ *
+ * Returns
+ *  TRUE if the event is dead (long live the event...)
+ */
+
+static BOOL editIcon__panelRaw(dbox d,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  glass_editIcon *ed=handle;
+  BOOL cursor=FALSE;
+  if (e->e==wimp_EKEY)
+  {
+    switch (e->data.key.chcode)
+    {
+      case akbd_UpK+akbd_Sh:
+        editIcon__nextPanel(ed,-1);
+        handled=TRUE;
+        break;
+      case akbd_DownK+akbd_Sh:
+        editIcon__nextPanel(ed,+1);
+        handled=TRUE;
+        break;
+    }
+  }
+  if (!handled) switch (ed->e.panel)
+  {
+    case glass_EIDATA:
+      /* Nothin' doing */
+      break;
+    case glass_EIAPPEARANCE:
+      switch (e->e)
+      {
+        case wimp_EBUT:
+          switch (e->data.but.m.i)
+          {
+            case glass_EIAFONTNAME:
+              menu_make(editIcon__fontMaker,editIcon__fontHandler,
+                                                      editIcon__fontHelp,ed);
+              handled=TRUE;
+              break;
+            case glass_EIAFONTMENU:
+              dbox_clickicon(d,glass_EIAFONTMENU);
+              menu_make(editIcon__fontMaker,editIcon__fontHandler,
+                                                      editIcon__fontHelp,ed);
+              dbox_unclick();
+              handled=TRUE;
+              break;
+          }
+          break;
+      }
+      break;
+    case glass_EIACTIONS:
+      switch (e->e)
+      {
+        case wimp_EBUT:
+          switch (e->data.but.m.i)
+          {
+            case glass_EIABTYPE:
+              menu_make(editIcon__btypeMaker,editIcon__btypeHandler,
+                                                     editIcon__btypeHelp,ed);
+              handled=TRUE;
+              break;
+            case glass_EIABTMENU:
+              dbox_clickicon(d,glass_EIABTMENU);
+              menu_make(editIcon__btypeMaker,editIcon__btypeHandler,
+                                                     editIcon__btypeHelp,ed);
+              dbox_unclick();
+              handled=TRUE;
+              break;
+          }
+          break;
+        case wimp_EKEY:
+          switch (e->data.key.c.i)
+          {
+            case glass_EIAESGWRITE:
+              switch (e->data.key.chcode)
+              {
+                case akbd_DownK:
+                case akbd_UpK:
+                case akbd_TabK:
+                case akbd_TabK+akbd_Sh:
+                case akbd_UpK+akbd_Ctl:
+                case akbd_DownK+akbd_Ctl:
+                  cursor=TRUE;
+                  break;
+              }
+              handled=buttons_insertChar(d,e->data.key.chcode,'0','9');
+              if (handled || cursor)
+                buttons_arrowClick(d,glass_EIAESGWRITE,0,31,0,FALSE);
+              break;
+          }
+          break;
+      }
+      break;
+    case glass_EICOLOURS:
+      switch (e->e)
+      {
+        case wimp_EBUT:
+          switch (e->data.but.m.i)
+          {
+            case glass_EICFORE:
+              colSelect(ed->e.pd,glass_EICFORE,e->data.but.m.bbits,
+                                  msgs_lookup("eiFGC"),FALSE,
+                                                       editIcon__colProc,ed);
+              break;
+            case glass_EICBACK:
+              colSelect(ed->e.pd,glass_EICBACK,e->data.but.m.bbits,
+                                  msgs_lookup("eiBGC"),FALSE,
+                                                       editIcon__colProc,ed);
+              break;
+          }
+          break;
+      }
+      break;
+    case glass_EISIZE:
+    case glass_EIPOSITION:
+      /* Nothin' doin' */
+      break;
+  }
+  return (FALSE);
+}
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void editIcon_renumber(glass_windPointer *w,int icon,int new)
+ *
+ * Use
+ *  Informs an edit dialogue that an icon has been renumbered.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number
+ *  int new == the new number for the icon
+ */
+
+void editIcon_renumber(glass_windPointer *w,int icon,int new)
+{
+  glass_editIcon *ed=w->def->i[icon].edit;
+  if (!ed)
+    return;
+  ed->i=new;
+  dbox_setfield(ed->e.d,glass_EINUMWRITE,"%i",new);
+}
+
+/*
+ * void editIcon_iconMoved(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Informs an edit dialogue that an icon has been moved.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number.  This may not be the same during the edit...
+ */
+
+void editIcon_iconMoved(glass_windPointer *w,int icon)
+{
+  glass_editIcon *ed=w->def->i[icon].edit;
+  if (!ed)
+    return;
+  ed->idef.box=ed->w->def->i[ed->i].i.box;
+  if (ed->e.panel==glass_EIPOSITION || ed->e.panel==glass_EISIZE)
+    editIcon__setupPanel(ed);
+}
+
+/*
+ * void editIcon_readData(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Forces a re-read of the icon data for the given icon edit
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number.  This may not be the same during the edit...
+ */
+
+void editIcon_readData(glass_windPointer *w,int icon)
+{
+  glass_editIcon *ed=w->def->i[icon].edit;
+  if (!ed)
+    return;
+  ed->idef.data=ed->w->def->i[ed->i].i.data;
+  if (ed->idef.flags & wimp_INDIRECT)
+  {
+    utils_ctermToNterm(ed->idef.data.indirecttext.buffer);
+    strcpy(ed->data,ed->idef.data.indirecttext.buffer);
+    ed->indLen=ed->idef.data.indirecttext.bufflen;
+    if (ed->idef.flags & wimp_ITEXT &&
+                          ed->idef.data.indirecttext.validstring!=(char *)-1)
+    {
+      utils_ctermToNterm(ed->idef.data.indirecttext.validstring);
+      strcpy(ed->valid,ed->idef.data.indirecttext.validstring);
+      ed->hasValid=TRUE;
+    }
+    else
+    {
+      ed->valid[0]=0;
+      ed->hasValid=FALSE;
+    }
+  }
+  else
+  {
+    ed->data[12]=0;
+    memcpy(ed->data,ed->idef.data.text,12);
+    utils_ctermToNterm(ed->data);
+    ed->valid[0]=0;
+    ed->indLen=12;
+  }
+  if (ed->e.panel==glass_EIDATA)
+    editIcon__setupPanel(ed);
+  if (ed->idef.flags & wimp_IFONT)
+  {
+    if (ed->e.panel==glass_EICOLOURS)
+      editIcon__setPanel(ed,-1);
+    dbox_shadeicon(ed->e.d,glass_EICOLOURS,TRUE);
+  }
+  else
+    dbox_shadeicon(ed->e.d,glass_EICOLOURS,FALSE);
+}
+
+/*
+ * void editIcon_close(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Closes an edit window
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number.  This may not be the same during the edit...
+ */
+
+void editIcon_close(glass_windPointer *w,int icon)
+{
+  glass_editIcon *ed=w->def->i[icon].edit;
+  if (ed)
+  {
+    if (ed->e.pd)
+      dbox_deleteNoUpdate(ed->e.pd);
+    pane_delete(ed->e.p);
+    dbox_deleteNoUpdate(ed->e.d);
+    ed->w->def->i[ed->i].edit=0;
+    mem_free(ed);
+  }
+}
+
+/*
+ * void editIcon(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Edits the given icon in a dialogue box.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number.  This may not be the same during the edit...
+ */
+
+void editIcon(glass_windPointer *w,int icon)
+{
+  glass_editIcon *ed;
+  os_regset r;
+  if (w->def->i[icon].edit)
+  {
+    dbox_display(w->def->i[icon].edit->e.d,TRUE);
+    pane_front(w->def->i[icon].edit->e.p);
+    return;
+  }
+  mem_useUser(indir_alloc,indir_free);
+  ed=mem_alloc(sizeof(glass_editIcon));
+  if (!ed)
+  {
+    werr(FALSE,msgs_lookup("eiNEM"));
+    mem_useMalloc();
+    return;
+  }
+  if (ed->e.d=dbox_create("editIcon"),!ed->e.d)
+  {
+    mem_free(ed);
+    mem_useMalloc();
+    return;
+  }
+  if (ed->e.p=pane_create(dbox_syshandle(ed->e.d)),!ed->e.p)
+  {
+    dbox_delete(ed->e.d);
+    mem_free(ed);
+    mem_useMalloc();
+    return;
+  }
+  mem_useMalloc();
+  ed->w=w;
+  ed->i=icon;
+  ed->idef=w->def->i[icon].i;
+  w->def->i[icon].edit=ed;
+  ed->e.panel=0;
+
+  /* --- Set up icon data now --- */
+  editIcon_readData(w,icon);
+  if (ed->idef.flags & wimp_IFONT)
+  {
+    r.r[0]=ed->idef.flags >> 24;
+    r.r[1]=(int)(ed->font);
+    wimpt_noerr(os_swix(XFont_ReadDefn,&r));
+    utils_ctermToNterm(ed->font);
+    ed->fontSize=r.r[2]/16;
+    dbox_shadeicon(ed->e.d,glass_EICOLOURS,TRUE);
+  }
+  else
+  {
+    strcpy(ed->font,"Homerton.Medium");
+    ed->fontSize=12;
+    dbox_shadeicon(ed->e.d,glass_EICOLOURS,FALSE);
+  }
+
+  /* --- Now do handlers, and final setting up --- */
+  dbox_setfield(ed->e.d,glass_EINUMWRITE,"%i",icon);
+  dbox_setfield(ed->e.d,glass_EIWINDISP,"%s",w->id);
+  dbox_eventHandler(ed->e.d,editIcon__dboxHandler,ed);
+  dbox_rawEventHandler(ed->e.d,editIcon__dboxRaw,ed);
+  dbox_openDisplaced(ed->e.d);
+  editIcon__setPanel(ed,glass_EIDATA);
+}
diff --git a/StraySrc/Glass/!Glass/c/editWin b/StraySrc/Glass/!Glass/c/editWin
new file mode 100644 (file)
index 0000000..835bd8e
--- /dev/null
@@ -0,0 +1,1934 @@
+/*
+ * editWindow.c
+ *
+ * Edit window dialogue box
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/buttons.h"
+#include "steel/fontMenu.h"
+#include "steel/akbd.h"
+#include "steel/buffer.h"
+#include "steel/font.h"
+
+/*
+ * Glass headers
+ */
+
+#include "glass.h"
+#include "tfile.h"
+#include "window.h"
+#include "intMsgs.h"
+#include "editWin.h"
+#include "colSelect.h"
+#include "indir.h"
+#include "gPrefs.h"
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+static char *editWindow__panels[]=
+{
+  "windChars",
+  "windGadgets",
+  "windButton",
+  "iconData",
+  "iconAppear",
+  "windColours",
+  "windSize",
+};
+
+#define editWindow__ICAPPHEIGHT -504
+
+/*----- New RISC OS 3 window flags ----------------------------------------*/
+
+#define wimp_WONSCREEN (1<<13)
+#define wimp_WRUBBERH (1<<14)
+#define wimp_WRUBBERV (1<<15)
+
+/*----- Support routines --------------------------------------------------*/
+
+#define max2(a,b) ((a)>(b) ? (a) : (b))
+#define min2(a,b) ((a)<(b) ? (a) : (b))
+
+/*
+ * void editWindow__checkExtents(glass_editWindow *ed,BOOL redraw,
+ *                                                                 BOOL read)
+ *
+ * Use
+ *  Ensures that the window extents are correctly set according to window
+ *  size etc.
+ *
+ * Parameters
+ *  glass_editWindow *ed == the edit
+ *  BOOL rbl == whether to redraw the bottom left setting
+ *  BOOL rtr == whether to redraw the top right setting
+ *  BOOL read == whether to read settings from dbox
+ */
+
+static void editWindow__checkExtents(glass_editWindow *ed,BOOL rbl,
+                                                          BOOL rtr,BOOL read)
+{
+  BOOL bl=rbl;
+  BOOL tr=rtr;
+  int x,y;
+  if (ed->e.panel==glass_EWWORKAREA && read)
+  {
+    dbox_scanfield(ed->e.pd,
+                   glass_EWSBOTTOMLEFT,
+                   "%d,%d",
+                   &ed->wdef.ex.x0,
+                   &ed->wdef.ex.y0);
+    dbox_scanfield(ed->e.pd,
+                   glass_EWSTOPRIGHT,
+                   "%d,%d",
+                   &ed->wdef.ex.x1,
+                   &ed->wdef.ex.y1);
+  }
+  if (ed->e.panel==glass_EWWORKAREA)
+  {
+    dbox_scanfield(ed->e.pd,glass_EWSMINWIDTH,"%d",&x);
+    dbox_scanfield(ed->e.pd,glass_EWSMINHEIGHT,"%d",&y);
+  }
+  else
+  {
+    x=ed->wdef.minsize & 0xffff;
+    y=(ed->wdef.minsize>>16) & 0xffff;
+  }
+
+  if (gPrefs_current()->mVisInWork)
+  {
+    if (ed->wdef.ex.x0>ed->w->def->desc.w.scx)
+    {
+      ed->wdef.ex.x0=ed->w->def->desc.w.scx;
+      bl=TRUE;
+    }
+    if (ed->wdef.ex.y0>ed->w->def->desc.w.scy+
+                       ed->w->def->desc.w.box.y0-
+                       ed->w->def->desc.w.box.y1)
+    {
+      ed->wdef.ex.y0=ed->w->def->desc.w.scy+
+                     ed->w->def->desc.w.box.y0-
+                     ed->w->def->desc.w.box.y1;
+      bl=TRUE;
+    }
+    if (ed->wdef.ex.x1<ed->w->def->desc.w.scx+
+                       ed->w->def->desc.w.box.x1-
+                       ed->w->def->desc.w.box.x0)
+    {
+      ed->wdef.ex.x1=ed->w->def->desc.w.scx+
+                     ed->w->def->desc.w.box.x1-
+                     ed->w->def->desc.w.box.x0;
+      tr=TRUE;
+    }
+    if (ed->wdef.ex.y1<ed->w->def->desc.w.scy)
+    {
+      ed->wdef.ex.y1=ed->w->def->desc.w.scy;
+      tr=TRUE;
+    }
+  }
+  if (bl && ed->e.panel==glass_EWWORKAREA)
+  {
+    dbox_setfield(ed->e.pd,
+                  glass_EWSBOTTOMLEFT,
+                  "%i,%i",
+                  ed->wdef.ex.x0,
+                  ed->wdef.ex.y0);
+  }
+  if (tr && ed->e.panel==glass_EWWORKAREA)
+  {
+    dbox_setfield(ed->e.pd,
+                  glass_EWSTOPRIGHT,
+                  "%i,%i",
+                  ed->wdef.ex.x1,
+                  ed->wdef.ex.y1);
+  }
+  bl=rbl;
+  tr=rtr;
+  if (gPrefs_current()->mVisInWork)
+  {
+    if (x>ed->w->def->desc.w.box.x1-ed->w->def->desc.w.box.x0)
+    {
+      x=ed->w->def->desc.w.box.x1-ed->w->def->desc.w.box.x0;
+      bl=TRUE;
+    }
+    if (y>ed->w->def->desc.w.box.y1-ed->w->def->desc.w.box.y0)
+    {
+      y=ed->w->def->desc.w.box.y1-ed->w->def->desc.w.box.y0;
+      tr=TRUE;
+    }
+  }
+  else
+  {
+    if (x>ed->wdef.ex.x1-ed->wdef.ex.x0)
+    {
+      x=ed->wdef.ex.x1-ed->wdef.ex.x0;
+      bl=TRUE;
+    }
+    if (y>ed->wdef.ex.y1-ed->wdef.ex.y0)
+    {
+      y=ed->wdef.ex.y1-ed->wdef.ex.y0;
+      tr=TRUE;
+    }
+  }
+  ed->wdef.minsize=x+(y<<16);
+  if (bl && ed->e.panel==glass_EWWORKAREA)
+    dbox_setfield(ed->e.pd,glass_EWSMINWIDTH,"%i",x);
+  if (tr && ed->e.panel==glass_EWWORKAREA)
+    dbox_setfield(ed->e.pd,glass_EWSMINHEIGHT,"%i",y);
+}
+
+/*
+ * void editWindow__setupPanel(glass_editWindow *ed)
+ *
+ * Use
+ *  Sets up a panel from the icon description given.
+ *
+ * Parameters
+ *  glass_editWindow *ed == the edit to handle.
+ */
+
+static void editWindow__setupPanel(glass_editWindow *ed)
+{
+  char *buf=buffer_find();
+
+  switch (ed->e.panel)
+  {
+    case glass_EWCHARS:
+      dbox_selecticon(ed->e.pd,
+                      glass_EWCMOVE,
+                      !!(ed->wdef.flags & wimp_WMOVEABLE));
+      dbox_selecticon(ed->e.pd,
+                      glass_EWCREDRAW,
+                      !!(ed->wdef.flags & wimp_REDRAW_OK));
+      dbox_selecticon(ed->e.pd,
+                      glass_EWCPANE,
+                      !!(ed->wdef.flags & wimp_WPANE));
+      dbox_selecticon(ed->e.pd,
+                      glass_EWCNOBOUNDS,
+                      !!(ed->wdef.flags & wimp_WTRESPASS));
+      dbox_selecticon(ed->e.pd,
+                      glass_EWCONSCREEN,
+                      !!(ed->wdef.flags & wimp_WONSCREEN));
+      if (ed->wdef.flags & wimp_WSCROLL_R1)
+      {
+        dbox_selecticon(ed->e.pd,glass_EWCSCRLREP,TRUE);
+        dbox_selecticon(ed->e.pd,glass_EWCSCRLDEB,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EWCSCRLQ,FALSE);
+      }
+      else if (ed->wdef.flags & wimp_SCROLL_R2)
+      {
+        dbox_selecticon(ed->e.pd,glass_EWCSCRLREP,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EWCSCRLDEB,TRUE);
+        dbox_selecticon(ed->e.pd,glass_EWCSCRLQ,FALSE);
+      }
+      else
+      {
+        dbox_selecticon(ed->e.pd,glass_EWCSCRLREP,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EWCSCRLDEB,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EWCSCRLQ,TRUE);
+      }
+      dbox_selecticon(ed->e.pd,
+                      glass_EWCGCOL,
+                      !!(ed->wdef.flags & wimp_REAL_COLOURS));
+      dbox_selecticon(ed->e.pd,
+                      glass_EWCBACK,
+                      !!(ed->wdef.flags & wimp_BACK_WINDOW));
+      dbox_selecticon(ed->e.pd,
+                      glass_EWCHOTKEYS,
+                      !!(ed->wdef.flags & wimp_HOT_KEYS));
+      break;
+    case glass_EWGADGETS:
+      if (tst(ed->wdef.flags,31))
+      {
+        dbox_shadeicon(ed->e.pd,glass_EWGOTITLE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EWGOCLOSEBACK,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EWGOHORIZ,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EWGOVERT,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EWGNTITLE,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EWGNHORIZ,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EWGNVERT,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EWGNEW,TRUE);
+        dbox_selecticon(ed->e.pd,glass_EWGOLD,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EWGOTITLE,tst(ed->wdef.flags,26));
+        dbox_selecticon(ed->e.pd,
+                        glass_EWGOCLOSEBACK,
+                        tst(ed->wdef.flags,24) || tst(ed->wdef.flags,25));
+        dbox_selecticon(ed->e.pd,glass_EWGOHORIZ,tst(ed->wdef.flags,30));
+        dbox_selecticon(ed->e.pd,glass_EWGOVERT,tst(ed->wdef.flags,28));
+        dbox_selecticon(ed->e.pd,glass_EWGNTITLE,tst(ed->wdef.flags,26));
+        dbox_selecticon(ed->e.pd,glass_EWGNCLOSE,tst(ed->wdef.flags,25));
+        dbox_shadeicon(ed->e.pd,glass_EWGNCLOSE,!tst(ed->wdef.flags,26));
+        dbox_selecticon(ed->e.pd,glass_EWGNRESIZE,tst(ed->wdef.flags,29));
+        dbox_shadeicon(ed->e.pd,
+                       glass_EWGNRESIZE,
+                       !(tst(ed->wdef.flags,28) || tst(ed->wdef.flags,30)));
+        dbox_selecticon(ed->e.pd,glass_EWGNBACK,tst(ed->wdef.flags,24));
+        dbox_shadeicon(ed->e.pd,glass_EWGNBACK,!tst(ed->wdef.flags,26));
+        dbox_selecticon(ed->e.pd,glass_EWGNTOGGLE,tst(ed->wdef.flags,27));
+        dbox_shadeicon(ed->e.pd,
+                       glass_EWGNTOGGLE,
+                       !(tst(ed->wdef.flags,26) || tst(ed->wdef.flags,28)));
+        dbox_selecticon(ed->e.pd,glass_EWGNHORIZ,tst(ed->wdef.flags,30));
+        dbox_selecticon(ed->e.pd,glass_EWGNVERT,tst(ed->wdef.flags,28));
+      }
+      else
+      {
+        dbox_shadeicon(ed->e.pd,glass_EWGOTITLE,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EWGOHORIZ,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EWGOVERT,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EWGNTITLE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EWGNCLOSE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EWGNRESIZE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EWGNBACK,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EWGNTOGGLE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EWGNHORIZ,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EWGNVERT,TRUE);
+        dbox_selecticon(ed->e.pd,glass_EWGNEW,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EWGOLD,TRUE);
+        dbox_selecticon(ed->e.pd,glass_EWGOTITLE,tst(ed->wdef.flags,0));
+        dbox_selecticon(ed->e.pd,
+                        glass_EWGOCLOSEBACK,
+                        !tst(ed->wdef.flags,7));
+        dbox_shadeicon(ed->e.pd,
+                       glass_EWGOCLOSEBACK,
+                       !tst(ed->wdef.flags,0));
+        dbox_selecticon(ed->e.pd,glass_EWGOHORIZ,tst(ed->wdef.flags,3));
+        dbox_selecticon(ed->e.pd,glass_EWGOVERT,tst(ed->wdef.flags,2));
+        dbox_selecticon(ed->e.pd,glass_EWGNTITLE,tst(ed->wdef.flags,0));
+        dbox_selecticon(ed->e.pd,glass_EWGNCLOSE,!tst(ed->wdef.flags,7));
+        dbox_selecticon(ed->e.pd,
+                        glass_EWGNRESIZE,
+                        tst(ed->wdef.flags,2) || tst(ed->wdef.flags,3));
+        dbox_selecticon(ed->e.pd,glass_EWGNBACK,!tst(ed->wdef.flags,7));
+        dbox_selecticon(ed->e.pd,glass_EWGNTOGGLE,tst(ed->wdef.flags,2));
+        dbox_selecticon(ed->e.pd,glass_EWGNHORIZ,tst(ed->wdef.flags,3));
+        dbox_selecticon(ed->e.pd,glass_EWGNVERT,tst(ed->wdef.flags,2));
+      }
+      break;
+    case glass_EWBTYPE:
+      sprintf(buf,"ewBTYPE%i",(ed->wdef.workflags>>12) & 0x0f);
+      dbox_setfield(ed->e.pd,glass_EWBBTDISP,"%s",msgs_lookup(buf));
+      break;
+    case glass_EWTDATA:
+      dbox_setfield(ed->e.pd,glass_EIDVALSTRING,"%s",ed->valid);
+      dbox_setfield(ed->e.pd,glass_EIDDATA,"%s",ed->data);
+      if (!(ed->wdef.titleflags & 3))
+      {
+        dbox_shadeicon(ed->e.pd,glass_EIDINDIR,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDDATA,TRUE);
+        dbox_selecticon(ed->e.pd,glass_EIDINDIR,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EIDVALID,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALID,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+        dbox_setfield(ed->e.pd,glass_EIDINDSIZE,"%i",12);
+      }
+      else if (ed->wdef.titleflags & wimp_INDIRECT)
+      {
+        dbox_shadeicon(ed->e.pd,glass_EIDINDIR,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDDATA,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EIDINDIR,TRUE);
+        dbox_selecticon(ed->e.pd,glass_EIDVALID,ed->hasValid);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,!ed->hasValid);
+        dbox_shadeicon(ed->e.pd,
+                       glass_EIDVALID,
+                       !(ed->wdef.titleflags&wimp_ITEXT));
+        dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDUP,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDPART,FALSE);
+        dbox_setfield(ed->e.pd,glass_EIDINDSIZE,"%i",ed->indLen);
+      }
+      else
+      {
+        dbox_shadeicon(ed->e.pd,glass_EIDINDIR,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDDATA,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EIDINDIR,FALSE);
+        dbox_selecticon(ed->e.pd,glass_EIDVALID,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDVALID,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+        dbox_setfield(ed->e.pd,glass_EIDINDSIZE,"%i",12);
+      }
+      dbox_selecticon(ed->e.pd,
+                      glass_EIDTEXT,
+                      !!(ed->wdef.titleflags&wimp_ITEXT));
+      dbox_selecticon(ed->e.pd,
+                      glass_EIDSPRITE,
+                      !!(ed->wdef.titleflags&wimp_ISPRITE));
+      break;
+    case glass_EWTAPPEAR:
+      dbox_setfield(ed->e.pd,glass_EIAFONTNAME,"%.%s",ed->font);
+      dbox_setfield(ed->e.pd,glass_EIAFSIZEWRITE,"%i",ed->fontSize);
+      if (ed->wdef.titleflags & wimp_ITEXT)
+      {
+        if (ed->wdef.titleflags & wimp_IFONT)
+        {
+          dbox_selecticon(ed->e.pd,glass_EIAFONT,TRUE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONTNAME,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONTMENU,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONT,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEUP,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEDOWN,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEWRITE,FALSE);
+        }
+        else
+        {
+          dbox_selecticon(ed->e.pd,glass_EIAFONT,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONT,FALSE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONTNAME,TRUE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFONTMENU,TRUE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEUP,TRUE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEDOWN,TRUE);
+          dbox_shadeicon(ed->e.pd,glass_EIAFSIZEWRITE,TRUE);
+        }
+      }
+      else
+      {
+        dbox_selecticon(ed->e.pd,glass_EIAFONT,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFONT,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFONTNAME,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFONTMENU,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFSIZEUP,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFSIZEDOWN,TRUE);
+        dbox_shadeicon(ed->e.pd,glass_EIAFSIZEWRITE,TRUE);
+      }
+      dbox_selecticon(ed->e.pd,
+                      glass_EIAHCENTRE,
+                      !!(ed->wdef.titleflags & wimp_IHCENTRE));
+      dbox_selecticon(ed->e.pd,
+                      glass_EIAVCENTRE,
+                      !!(ed->wdef.titleflags & wimp_IVCENTRE));
+      dbox_selecticon(ed->e.pd,
+                      glass_EIARALIGN,
+                      !!(ed->wdef.titleflags & wimp_IRJUST));
+      if (ed->wdef.titleflags & wimp_ISPRITE)
+      {
+        dbox_selecticon(ed->e.pd,
+                        glass_EIAHALFSIZE,
+                        !!(ed->wdef.titleflags & wimp_IHALVESPRITE));
+        dbox_shadeicon(ed->e.pd,glass_EIAHALFSIZE,FALSE);
+      }
+      else
+      {
+        dbox_selecticon(ed->e.pd,glass_EIAHALFSIZE,FALSE);
+        dbox_shadeicon(ed->e.pd,glass_EIAHALFSIZE,TRUE);
+      }
+      dbox_selecticon(ed->e.pd,glass_EIABORDER,FALSE);
+      dbox_selecticon(ed->e.pd,glass_EIAFILL,FALSE);
+      dbox_selecticon(ed->e.pd,glass_EIANEEDSHELP,FALSE);
+      dbox_shadeicon(ed->e.pd,glass_EIABORDER,TRUE);
+      dbox_shadeicon(ed->e.pd,glass_EIAFILL,TRUE);
+      dbox_shadeicon(ed->e.pd,glass_EIANEEDSHELP,TRUE);
+      /* The above aren't relevant to a window title */
+      break;
+    case glass_EWCOLOURS:
+      colSelect_setColourButton(ed->e.pd,
+                                glass_EWCTBFORE,
+                                ed->wdef.colours[0]);
+      colSelect_setColourButton(ed->e.pd,
+                                glass_EWCTBBACK,
+                                ed->wdef.colours[1]);
+      colSelect_setColourButton(ed->e.pd,
+                                glass_EWCWAFORE,
+                                ed->wdef.colours[2]);
+      colSelect_setColourButton(ed->e.pd,
+                                glass_EWCWABACK,
+                                ed->wdef.colours[3]);
+      colSelect_setColourButton(ed->e.pd,
+                                glass_EWCSCFORE,
+                                ed->wdef.colours[5]);
+      colSelect_setColourButton(ed->e.pd,
+                                glass_EWCSCBACK,
+                                ed->wdef.colours[4]);
+      colSelect_setColourButton(ed->e.pd,
+                                glass_EWCHIGH,
+                                ed->wdef.colours[6]);
+      break;
+    case glass_EWWORKAREA:
+      dbox_setfield(ed->e.pd,
+                    glass_EWSMINWIDTH,
+                    "%i",
+                    ed->wdef.minsize & 0xffff);
+      dbox_setfield(ed->e.pd,
+                    glass_EWSMINHEIGHT,
+                    "%i",
+                    (ed->wdef.minsize>>16) & 0xffff);
+      editWindow__checkExtents(ed,TRUE,TRUE,FALSE);
+      dbox_selecticon(ed->e.pd,
+                      glass_EWSRUBBERH,
+                      !!(ed->wdef.flags & wimp_WRUBBERH));
+      dbox_selecticon(ed->e.pd,
+                      glass_EWSRUBBERV,
+                      !!(ed->wdef.flags & wimp_WRUBBERV));
+      break;
+  }
+}
+
+/*
+ * void editWindow__closePanel(glass_editWindow *ed)
+ *
+ * Use
+ *  Records the settings in a panel for future reference, for example when
+ *  the panel is being replaced by a different one.
+ *
+ * Parameters
+ *  glass_editWindow *ed == the edit box we're talking about
+ */
+
+#define Q dbox_READSTATE
+
+static void editWindow__closePanel(glass_editWindow *ed)
+{
+  switch (ed->e.panel)
+  {
+    case glass_EWCHARS:
+      ed->wdef.flags&=~0x00003f72;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWCMOVE,Q)<<1;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWCREDRAW,Q)<<4;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWCPANE,Q)<<5;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWCNOBOUNDS,Q)<<6;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWCONSCREEN,Q)<<13;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWCSCRLREP,Q)<<8;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWCSCRLDEB,Q)<<9;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWCGCOL,Q)<<10;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWCBACK,Q)<<11;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWCHOTKEYS,Q)<<12;
+      break;
+    case glass_EWGADGETS:
+      ed->wdef.flags&=~0xff00008d;
+      if (dbox_selecticon(ed->e.pd,glass_EWGOLD,Q))
+      {
+        ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWGOTITLE,Q)<<0;
+        ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWGOVERT,Q)<<2;
+        ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWGOHORIZ,Q)<<3;
+        ed->wdef.flags|=(!dbox_selecticon(ed->e.pd,
+                                          glass_EWGOCLOSEBACK,
+                                          Q))<<7;
+      }
+      else
+      {
+        ed->wdef.flags|=wimp_WNEW;
+        ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWGNBACK,Q)<<24;
+        ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWGNCLOSE,Q)<<25;
+        ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWGNTITLE,Q)<<26;
+        ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWGNTOGGLE,Q)<<27;
+        ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWGNVERT,Q)<<28;
+        ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWGNRESIZE,Q)<<29;
+        ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWGNHORIZ,Q)<<30;
+      }
+      break;
+    case glass_EWTDATA:
+      dbox_getfield(ed->e.pd,glass_EIDDATA,ed->data,256);
+      dbox_getfield(ed->e.pd,glass_EIDVALSTRING,ed->valid,256);
+      dbox_scanfield(ed->e.pd,glass_EIDINDSIZE,"%d",&ed->indLen);
+      ed->hasValid=dbox_selecticon(ed->e.pd,glass_EIDVALID,Q);
+      ed->wdef.titleflags&=~0x00000103;
+      ed->wdef.titleflags|=dbox_selecticon(ed->e.pd,glass_EIDTEXT,Q)<<0;
+      ed->wdef.titleflags|=dbox_selecticon(ed->e.pd,glass_EIDSPRITE,Q)<<1;
+      ed->wdef.titleflags|=dbox_selecticon(ed->e.pd,glass_EIDINDIR,Q)<<8;
+      break;
+    case glass_EWTAPPEAR:
+      ed->wdef.titleflags&=~0x00000afc;
+      dbox_scanfield(ed->e.pd,glass_EIAFSIZEWRITE,"%d",&ed->fontSize);
+      ed->wdef.titleflags|=dbox_selecticon(ed->e.pd,
+                                           glass_EIAHCENTRE,
+                                           Q)<<3;
+      ed->wdef.titleflags|=dbox_selecticon(ed->e.pd,glass_EIAVCENTRE,Q)<<4;
+      ed->wdef.titleflags|=dbox_selecticon(ed->e.pd,glass_EIAFONT,Q)<<6;
+      ed->wdef.titleflags|=dbox_selecticon(ed->e.pd,glass_EIARALIGN,Q)<<9;
+      ed->wdef.titleflags|=dbox_selecticon(ed->e.pd,glass_EIAHALFSIZE,Q)<<11;
+      break;
+    case glass_EWWORKAREA:
+      ed->wdef.flags&=~0x0000c000;
+      editWindow__checkExtents(ed,FALSE,FALSE,TRUE);
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWSRUBBERH,Q)<<14;
+      ed->wdef.flags|=dbox_selecticon(ed->e.pd,glass_EWSRUBBERV,Q)<<15;
+      break;
+  }
+}
+
+#undef Q
+
+/*
+ * void editWindow__setPanel(glass_editWindow *ed,dbox_field f)
+ *
+ * Use
+ *  Creates a new panel based on a radio button click or some-such.
+ *
+ * Parameters
+ *  glass_editWindow *ed == the edit window to change panel
+ *  dbox_field f == the radio button associated with the desired panel
+ */
+
+static void editWindow__panelHandler(dbox d,dbox_field f,void *handle);
+static BOOL editWindow__panelRaw(dbox d,wimp_eventstr *e,void *handle);
+
+static void editWindow__setPanel(glass_editWindow *ed,dbox_field f)
+{
+  dbox d;
+  wimp_wstate s;
+  wimp_icon i;
+  int width,height;
+  int ox,oy;
+  wimp_w behind;
+  wimp_caretstr c;
+  wimp_redrawstr r;
+  BOOL ownCaret=TRUE;
+
+  if (f==ed->e.panel)
+    return;
+  editWindow__closePanel(ed);
+  wimpt_noerr(wimp_get_wind_state(dbox_syshandle(ed->e.d),&s));
+  wimpt_noerr(wimp_get_icon_info(dbox_syshandle(ed->e.d),
+                                 glass_EWPOSN,&i));
+  ox=s.o.box.x0-s.o.x;
+  oy=s.o.box.y1-s.o.y;
+  mem_useUser(indir_alloc,indir_free);
+  if (f==-1)
+    d=dbox_create("iconNowt");
+  else
+    d=dbox_create(editWindow__panels[f-glass_EWCHARS]);
+  if (!d)
+  {
+    mem_useMalloc();
+    return;
+  }
+  dbox_eventHandler(d,editWindow__panelHandler,ed);
+  dbox_rawEventHandler(d,editWindow__panelRaw,ed);
+  if (ed->e.panel)
+  {
+    wimpt_noerr(wimp_get_caret_pos(&c));
+    ownCaret=(c.w==dbox_syshandle(ed->e.pd));
+    dbox_selecticon(ed->e.d,ed->e.panel,dbox_RESETSTATE);
+    wimpt_noerr(wimp_get_wind_state(dbox_syshandle(ed->e.pd),&s));
+    pane_removePane(ed->e.p,dbox_syshandle(ed->e.pd));
+    dbox_delete(ed->e.pd);
+  }
+  dbox_selecticon(ed->e.d,f,dbox_SETSTATE);
+  behind=s.o.behind;
+  wimpt_noerr(wimp_get_wind_state(dbox_syshandle(d),&s));
+  width=s.o.box.x1-s.o.box.x0;
+  height=s.o.box.y1-s.o.box.y0;
+  s.o.box.x0=i.box.x0+ox+wimpt_dx();
+  s.o.box.y0=i.box.y0+oy+wimpt_dy();
+  s.o.box.x1=s.o.box.x0+width;
+  s.o.box.y1=s.o.box.y0+height;
+  s.o.y=10000;
+  s.o.behind=behind;
+  ed->e.pd=d;
+  ed->e.panel=f;
+  editWindow__setupPanel(ed);
+  if (f==glass_EWTAPPEAR)
+  {
+    r.w=s.o.w;
+    r.box.x0=0;
+    r.box.x1=s.o.box.x1-s.o.box.x0;
+    r.box.y1=0;
+    r.box.y0=editWindow__ICAPPHEIGHT;
+    wimpt_noerr(wimp_set_extent(&r));
+  }
+  wimpt_noerr(wimp_open_wind(&s.o));
+  if (ownCaret)
+  {
+    c.w=dbox_syshandle(d);
+    c.i=-1;
+    c.x=-500000;
+    c.y=0;
+    c.height=0x02000000;
+    wimpt_noerr(wimp_set_caret_pos(&c));
+  }
+  pane_addPane(ed->e.p,dbox_syshandle(d));
+  mem_useMalloc();
+}
+
+/*
+ * void editWindow__recreate(glass_editWindow *ed)
+ *
+ * Use
+ *  Recreates the icon from the dialogue box settings
+ *
+ * Parameters
+ *  glass_editWindow *ed == info about the edit
+ */
+
+static void editWindow__recreate(glass_editWindow *ed)
+{
+  char *p=0;
+  char *q=0;
+  char newname[15];
+  int fhandle;
+  ed->w->edit=0;                 /* Delink temporarily                     */
+
+  editWindow__checkExtents(ed,FALSE,FALSE,TRUE);
+  if (!(ed->wdef.titleflags & wimp_INDIRECT))
+  {
+    ed->indLen=12;
+    ed->hasValid=FALSE;
+  }
+  if (strlen(ed->data)>=ed->indLen)
+  {
+    ed->wdef.titleflags|=wimp_INDIRECT;
+    ed->indLen=strlen(ed->data)+1;
+  }
+  if (ed->wdef.titleflags & wimp_INDIRECT)
+  {
+    if (p=indir_alloc(ed->indLen),!p)
+    {
+      werr(FALSE,msgs_lookup("ewNEMUW"));
+      return;
+    }
+    if (ed->hasValid && (ed->wdef.titleflags & wimp_ITEXT))
+    {
+      if (q=indir_alloc(strlen(ed->valid)+1),!q)
+      {
+        indir_free(p);
+        werr(FALSE,
+             msgs_lookup("ewNEMUW"));
+        return;
+      }
+      strcpy(q,ed->valid);
+      ed->w->size+=strlen(ed->valid)+1;
+    }
+    strcpy(p,ed->data);
+    ed->w->size+=ed->indLen;
+  }
+
+  if (ed->w->def->desc.w.titleflags & wimp_IFONT) /* Was old antialiased?  */
+  {
+    fhandle=(ed->w->def->desc.w.titleflags >> 24) & 255;
+    wimpt_noerr(font_lose(fhandle));
+    ed->w->fonts[fhandle]--;
+  }
+  if (ed->wdef.titleflags & wimp_IFONT) /* Is new title antialiased?       */
+  {
+    if (font_find(ed->font,ed->fontSize*16,ed->fontSize*16,0,0,&fhandle))
+    {
+      werr(FALSE,msgs_lookup("ewCFF"),ed->font);
+      ed->wdef.titleflags&=~wimp_IFONT;
+    }
+    else
+    {
+      ed->w->antiAliased=TRUE;
+      ed->w->fonts[fhandle]++;
+      ed->wdef.titleflags=(ed->wdef.titleflags & 0x00ffffff) | (fhandle<<24);
+    }
+  }
+
+  if (ed->w->def->desc.w.titleflags & wimp_INDIRECT)
+  {
+    indir_free(ed->w->def->desc.w.title.indirecttext.buffer);
+    ed->w->size-=ed->w->def->desc.w.title.indirecttext.bufflen;
+    if ((ed->w->def->desc.w.titleflags & wimp_ITEXT) &&
+        (ed->w->def->desc.w.title.indirecttext.validstring!=(char *)-1))
+    {
+      ed->w->size-=
+              strlen(ed->w->def->desc.w.title.indirecttext.validstring)+1;
+      indir_free(ed->w->def->desc.w.title.indirecttext.validstring);
+    }
+  }
+
+  if (p)
+  {
+    ed->wdef.title.indirecttext.buffer=p;
+    ed->wdef.title.indirecttext.bufflen=ed->indLen;
+    if (q)
+      ed->wdef.title.indirecttext.validstring=q;
+    else if (ed->wdef.titleflags & wimp_ITEXT)
+      ed->wdef.title.indirecttext.validstring=(char *)-1;
+    else
+      ed->wdef.title.indirectsprite.spritearea=ed->w->t->s;
+  }
+  else
+    memcpy(ed->wdef.title.text,ed->data,12);
+
+  ed->wdef.box=ed->w->def->desc.w.box;
+  ed->wdef.scx=ed->w->def->desc.w.scx;
+  ed->wdef.scy=ed->w->def->desc.w.scy;
+  ed->wdef.behind=ed->w->def->desc.w.behind;
+  ed->wdef.nicons=ed->w->def->desc.w.nicons;
+  ed->w->def->desc.w=ed->wdef;
+  dbox_getfield(ed->e.d,glass_EWIDWRITE,newname,15);
+  tfile_rename(newname,ed->w);
+  dbox_setfield(ed->e.d,glass_EWIDWRITE,"%s",ed->w->id);
+
+  ed->w->edit=ed;                /* Relink again                           */
+  window_recreate(ed->w);
+  tfile_markAsAltered(ed->w->t);
+}
+
+/*
+ * void editWindow__nextPanel(glass_editWindow *ed,int dir)
+ *
+ * Use
+ *  Changes panel to the next one in the given direction.  Skips shaded
+ *  panels and handles everything nicely.
+ *
+ * Parameters
+ *  glass_editWindow *ed == the edit dialogue box to move about in
+ *  int dir == the direction (-1 for up, 1 for down)
+ */
+
+static void editWindow__nextPanel(glass_editWindow *ed,int dir)
+{
+  int i=ed->e.panel;
+
+  if (i==-1)
+    i=(dir==1 ? glass_EWCHARS : glass_EWWORKAREA);
+  else
+    i+=dir;
+
+  for (;i>=glass_EWCHARS && i<=glass_EWWORKAREA;i+=dir)
+  {
+    if (!dbox_shadeicon(ed->e.d,i,dbox_READSTATE))
+    {
+      editWindow__setPanel(ed,i);
+      break;
+    }
+  }
+}
+
+/*----- Event handlers ----------------------------------------------------*/
+
+/*
+ * void editWindow__dboxHandler(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles any and all events directed at the dbox.  Well, almost all...
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the event that happened
+ *  void *handle == pointer to the dialogue box control info
+ */
+
+static void editWindow__dboxHandler(dbox d,dbox_field f,void *handle)
+{
+  glass_editWindow *ed=handle;
+  switch (f)
+  {
+    case dbox_CLOSE:
+      editWindow_close(ed->w);
+      break;
+    case dbox_HELP:
+      help_startHelp();
+      help_addLine(msgs_lookup("ewhEIDB"));
+      help_readFromIcon();
+      help_endHelp();
+      break;
+    case glass_EWCAN:
+      dbox_clickicon(d,f);
+      if (!dbox_wasAdjustClick())
+        pane_close(ed->e.p);
+      else
+      {
+        /* --- set up for old window --- */
+        ed->wdef=ed->w->def->desc.w;
+        editWindow_readData(ed->w);
+        dbox_setfield(ed->e.d,glass_EWIDWRITE,"%s",ed->w->id);
+        editWindow__setupPanel(ed);
+      }
+      dbox_unclick();
+      if (!dbox_wasAdjustClick())
+        editWindow_close(ed->w);
+      break;
+    case glass_EWOK:
+      dbox_clickicon(d,f);
+      editWindow__closePanel(ed);
+      if (!dbox_wasAdjustClick())
+      {
+        pane_close(ed->e.p);
+        editWindow__recreate(ed);
+        dbox_unclick();
+        editWindow_close(ed->w);
+      }
+      else
+      {
+        editWindow__recreate(ed);
+        editWindow_readData(ed->w);
+        editWindow__setupPanel(ed);
+        dbox_unclick();
+      }
+      break;
+    case glass_EWDEL:
+      dbox_clickicon(d,f);
+      if (gPrefs_current()->cDelWind)
+      {
+        if (!warning(msgs_lookup("ewCDWP"),
+                     msgs_lookup("ewCDW")))
+        {
+          dbox_unclick();
+          return;
+        }
+      }
+      pane_close(ed->e.p);
+      dbox_unclick();
+      tfile_markAsAltered(ed->w->t);
+      tfile_deleteWindow(ed->w->i,ed->w); /* This causes a close for us    */
+      break;
+    case glass_EWSAVE:
+      dbox_clickicon(d,f);
+      dbox_unclick();
+      tfile_saveWindow(ed->w);
+      break;
+    case glass_EWCHARS:
+    case glass_EWGADGETS:
+    case glass_EWBTYPE:
+    case glass_EWTDATA:
+    case glass_EWTAPPEAR:
+    case glass_EWCOLOURS:
+    case glass_EWWORKAREA:
+      editWindow__setPanel(ed,f);
+      break;
+  }
+}
+
+/*
+ * BOOL editWindow__dboxRaw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles open window requests and things for the main Preferences dbox.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  wimp_eventstr *e == the event that happened
+ *  void *handle == a unused pointer
+ *
+ * Returns
+ *  TRUE if the event has been handled;
+ */
+
+static BOOL editWindow__dboxRaw(dbox d,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  glass_editWindow *ed=handle;
+  glass_intMsgstr *m;
+  unused(d);
+  switch (e->e)
+  {
+    case wimp_EOPEN:
+      pane_moved(ed->e.p);
+      handled=TRUE;
+      break;
+    case wimp_EKEY:
+      switch (e->data.key.chcode)
+      {
+        case akbd_UpK+akbd_Sh:
+          editWindow__nextPanel(ed,-1);
+          handled=TRUE;
+          break;
+        case akbd_DownK+akbd_Sh:
+          editWindow__nextPanel(ed,+1);
+          handled=TRUE;
+          break;
+      }
+      break;
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MINTERNAL:
+          m=intMsgs_receive(e);
+          switch(e->data.msg.data.words[0])
+          {
+            case glass_DELETEFILE:
+              if (m->df.t==ed->w->t)
+                editWindow_close(ed->w);
+              break;
+            case glass_SAVEFILE:
+              if (m->df.t==ed->w->t)
+                dbox_setfield(ed->e.d,glass_EWFILEDISP,"%.%s",
+                                                         ed->w->t->filename);
+              break;
+            case glass_DELETEWINDOW:
+              if (m->dw.w==ed->w)
+                editWindow_close(ed->w);
+              break;
+            case glass_RENAME:
+              if (m->rn.w==ed->w)
+                dbox_setfield(ed->e.d,glass_EWIDWRITE,"%s",ed->w->id);
+              break;
+          }
+          break;
+      }
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * menu editWindow__fontMaker(void *handle)
+ *
+ * Use
+ *  Sets up the font menu.
+ *
+ * Parameters
+ *  void *handle == pointer to this edit
+ *
+ * Returns
+ *  A menu to display
+ */
+
+static menu editWindow__fontMaker(void *handle)
+{
+  glass_editWindow *ed=handle;
+  menu m=fontMenu_createFontMenu(FALSE);
+  fontMenu_tickGivenName(ed->font);
+  return (m);
+}
+
+/*
+ * void editWindow__fontHandler(int hit[],void *handle)
+ *
+ * Use
+ *  Gets the font chosen from the font menu.
+ *
+ * Parameters
+ *  int hit[] == the hit string
+ *  void *handle == pointer to this edit
+ */
+
+static void editWindow__fontHandler(int hit[],void *handle)
+{
+  glass_editWindow *ed=handle;
+  if (hit[0])
+  {
+    strcpy(ed->font,fontMenu_fontname(hit[0],hit[1]));
+    dbox_setfield(ed->e.pd,glass_EIAFONTNAME,"%.%s",ed->font);
+  }
+}
+
+/*
+ * void editWindow__fontHelp(int hit[],void *handle)
+ *
+ * Use
+ *  Gives help on a font menu item
+ *
+ * Parameters
+ *  int hit[] == the hit string
+ *  void *handle == pointer to this edit
+ */
+
+static void editWindow__fontHelp(int hit[],void *handle)
+{
+  unused(handle);
+  if (hit[0])
+  {
+    help_startHelp();
+    help_addLine(msgs_lookup("ewmhFONT"),fontMenu_fontname(hit[0],hit[1]));
+    help_endHelp();
+  }
+}
+
+/*
+ * menu editWindow__btypeMaker(void *handle)
+ *
+ * Use
+ *  Generates and sets up a button type menu for an edit dialogue box
+ *
+ * Parameters
+ *  void *handle == pointer to the edit
+ *
+ * Returns
+ *  The menu to use
+ */
+
+static menu editWindow__btypeMaker(void *handle)
+{
+  static menu m;
+  static int ticked;
+  glass_editWindow *ed=handle;
+  int i;
+  char *buf=buffer_find();
+
+  if (!m)
+  {
+    m=menu_new(msgs_lookup("eiBTMT"),msgs_lookup("ewBTYPE0"));
+    for (i=1;i<=15;i++)
+    {
+      sprintf(buf,"ewBTYPE%i",i);
+      menu_extend(m,msgs_lookup(buf));
+    }
+  }
+  if (ticked)
+    menu_setflags(m,ticked,FALSE,FALSE);
+  ticked=((ed->wdef.workflags>>12)&0x0f)+1;
+  menu_setflags(m,ticked,TRUE,FALSE);
+  return (m);
+}
+
+/*
+ * void editWindow__btypeHandler(int hit[],void *handle)
+ *
+ * Use
+ *  Handles a click on the button type menu.
+ *
+ * Parameters
+ *  int hit[] == the mouse click info
+ *  void *handle == pointer to edit information
+ */
+
+static void editWindow__btypeHandler(int hit[],void *handle)
+{
+  glass_editWindow *ed=handle;
+  char *buf=buffer_find();
+
+  if (hit[0])
+  {
+    ed->wdef.workflags&=~0x0000f000;
+    ed->wdef.workflags+=(hit[0]-1)<<12;
+    sprintf(buf,"ewBTYPE%i",hit[0]-1);
+    dbox_setfield(ed->e.pd,glass_EIABTYPE,"%s",msgs_lookup(buf));
+  }
+}
+
+/*
+ * void editWindow__colProc(dbox d,dbox_field f,int colour, void *handle)
+ *
+ * Use
+ *  This routine is called when a colour is selected in the colours panel.
+ *
+ * Parameters
+ *  dbox d == the panel's handle
+ *  dbox_field f == the colour button that has changed
+ *  int colour == the new colour for the button
+ *  void *handle == pointer to this edit
+ */
+
+static void editWindow__colProc(dbox d,dbox_field f,int colour,void *handle)
+{
+  glass_editWindow *ed=handle;
+  unused(d);
+  switch (f)
+  {
+    case glass_EWCTBFORE:
+      ed->wdef.colours[0]=colour;
+      dbox_shadeicon(ed->e.d,glass_EWGADGETS,colour==255);
+      if ((tst(ed->wdef.flags,31) && tst(ed->wdef.flags,26))
+       || (!tst(ed->wdef.flags,31) && tst(ed->wdef.flags,0)))
+      {
+        dbox_shadeicon(ed->e.d,glass_EWTDATA,colour==255);
+        dbox_shadeicon(ed->e.d,glass_EWTAPPEAR,colour==255);
+      }
+      break;
+    case glass_EWCTBBACK:
+      ed->wdef.colours[1]=colour;
+      break;
+    case glass_EWCWAFORE:
+      ed->wdef.colours[2]=colour;
+      break;
+    case glass_EWCWABACK:
+      ed->wdef.colours[3]=colour;
+      break;
+    case glass_EWCSCFORE:
+      ed->wdef.colours[5]=colour;
+      break;
+    case glass_EWCSCBACK:
+      ed->wdef.colours[4]=colour;
+      break;
+    case glass_EWCHIGH:
+      ed->wdef.colours[6]=colour;
+      break;
+  }
+}
+
+/*
+ * void editWindow__btypeHelp(int hit[],void *handle)
+ *
+ * Use
+ *  Handles a help request for the button type menu.
+ *
+ * Parameters
+ *  int hit[] == the helpq info
+ *  void *handle == pointer to edit information
+ */
+
+static void editWindow__btypeHelp(int hit[],void *handle)
+{
+  char *buf=buffer_find();
+  unused(handle);
+  if (hit[0])
+  {
+    help_startHelp();
+    sprintf(buf,"ewBTYPE%i",hit[0]-1);
+    help_addLine(msgs_lookup("ewmhBTYPE"),msgs_lookup(buf));
+    help_endHelp();
+  }
+}
+
+/*
+ * void editWindow__extArrows(dbox d,dbox_field f,int diff,void *handle)
+ *
+ * Use
+ *  Handles a click on one of the (many!) arrow buttons in the extends panel.
+ */
+
+typedef struct
+{
+  BOOL xOrY;
+  BOOL topOrBottom;
+  glass_editWindow *ed;
+}
+editWindow__extArrowstr;
+
+static void editWindow__extArrows(dbox d,dbox_field f,int diff,void *handle)
+{
+  editWindow__extArrowstr *a=handle;
+  wimp_box *b=&a->ed->wdef.ex;
+  int *v;
+  unused(f);
+
+  if (a->xOrY)
+    v=(a->topOrBottom ? &b->x1 : &b->x0);
+  else
+    v=(a->topOrBottom ? &b->y1 : &b->y0);
+
+  dbox_scanfield(d,glass_EWSBOTTOMLEFT,"%d,%d",&b->x0,&b->y0);
+  dbox_scanfield(d,glass_EWSTOPRIGHT,"%d,%d",&b->x1,&b->y1);
+
+  *v+=diff;
+
+  editWindow__checkExtents(a->ed,!a->topOrBottom,a->topOrBottom,FALSE);
+}
+
+/*
+ * void editWindow__panelHandler(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles simple click events for the current panel in an edit dbox
+ *
+ * Parameters
+ *  dbox d == the panel's dbox handle
+ *  dbox_field f == the icon that was clicked
+ *  void *handle == pointer to edit information
+ */
+
+static void editWindow__panelHandler(dbox d,dbox_field f,void *handle)
+{
+  glass_editWindow *ed=handle;
+  int on;
+  buttons_simpleArrow sa={0,9999,FALSE};
+  editWindow__extArrowstr eas;
+  BOOL indon;
+
+  switch (f)
+  {
+    case dbox_CLOSE:
+    case dbox_HELP:
+    case glass_EIOK:
+    case glass_EICAN:
+      editWindow__dboxHandler(ed->e.d,f,ed);
+      return;
+      break;
+  }
+  switch (ed->e.panel)
+  {
+    case glass_EWGADGETS:
+      on=!dbox_selecticon(d,f,dbox_READSTATE);
+      switch (f)
+      {
+        case glass_EWGOLD:
+          if (on)
+          {
+            dbox_selecticon(d,glass_EWGOLD,TRUE);
+            dbox_selecticon(d,glass_EWGNEW,FALSE);
+            dbox_shadeicon(d,glass_EWGOTITLE,FALSE);
+            dbox_shadeicon(d,glass_EWGOCLOSEBACK,
+                      !dbox_selecticon(d,glass_EWGOTITLE,dbox_READSTATE));
+            dbox_shadeicon(d,glass_EWGOHORIZ,FALSE);
+            dbox_shadeicon(d,glass_EWGOVERT,FALSE);
+            dbox_shadeicon(d,glass_EWGNTITLE,TRUE);
+            dbox_shadeicon(d,glass_EWGNCLOSE,TRUE);
+            dbox_shadeicon(d,glass_EWGNBACK,TRUE);
+            dbox_shadeicon(d,glass_EWGNTOGGLE,TRUE);
+            dbox_shadeicon(d,glass_EWGNRESIZE,TRUE);
+            dbox_shadeicon(d,glass_EWGNHORIZ,TRUE);
+            dbox_shadeicon(d,glass_EWGNVERT,TRUE);
+          }
+          break;
+        case glass_EWGNEW:
+          if (on)
+          {
+            dbox_selecticon(d,glass_EWGOLD,FALSE);
+            dbox_selecticon(d,glass_EWGNEW,TRUE);
+            dbox_shadeicon(d,glass_EWGOTITLE,TRUE);
+            dbox_shadeicon(d,glass_EWGOCLOSEBACK,TRUE);
+            dbox_shadeicon(d,glass_EWGOHORIZ,TRUE);
+            dbox_shadeicon(d,glass_EWGOVERT,TRUE);
+            dbox_shadeicon(d,glass_EWGNTITLE,FALSE);
+            dbox_shadeicon(d,glass_EWGNCLOSE,
+                      !dbox_selecticon(d,glass_EWGNTITLE,dbox_READSTATE));
+            dbox_shadeicon(d,glass_EWGNBACK,
+                      !dbox_selecticon(d,glass_EWGNTITLE,dbox_READSTATE));
+            dbox_shadeicon(d,glass_EWGNTOGGLE,
+                       !(dbox_selecticon(d,glass_EWGNTITLE,dbox_READSTATE)
+                    || dbox_selecticon(d,glass_EWGNVERT,dbox_READSTATE)));
+            dbox_shadeicon(d,glass_EWGNRESIZE,
+                       !(dbox_selecticon(d,glass_EWGNHORIZ,dbox_READSTATE)
+                    || dbox_selecticon(d,glass_EWGNVERT,dbox_READSTATE)));
+            dbox_shadeicon(d,glass_EWGNHORIZ,FALSE);
+            dbox_shadeicon(d,glass_EWGNVERT,FALSE);
+          }
+          break;
+        case glass_EWGOTITLE:
+          dbox_selecticon(d,f,on);
+          dbox_selecticon(d,glass_EWGNTITLE,on);
+          dbox_shadeicon(d,glass_EWGOCLOSEBACK,!on);
+          dbox_shadeicon(ed->e.d,glass_EWTDATA,!on);
+          dbox_shadeicon(ed->e.d,glass_EWTAPPEAR,!on);
+          break;
+        case glass_EWGOCLOSEBACK:
+          dbox_selecticon(d,f,on);
+          dbox_selecticon(d,glass_EWGNCLOSE,on);
+          dbox_selecticon(d,glass_EWGNBACK,on);
+          break;
+        case glass_EWGOHORIZ:
+          dbox_selecticon(d,f,on);
+          dbox_selecticon(d,glass_EWGNHORIZ,on);
+          dbox_selecticon(d,glass_EWGNRESIZE,
+                (on || dbox_selecticon(d,glass_EWGOVERT,dbox_READSTATE)));
+          break;
+        case glass_EWGOVERT:
+          dbox_selecticon(d,f,on);
+          dbox_selecticon(d,glass_EWGNVERT,on);
+          dbox_selecticon(d,glass_EWGNTOGGLE,on);
+          dbox_selecticon(d,glass_EWGNRESIZE,
+               (on || dbox_selecticon(d,glass_EWGOHORIZ,dbox_READSTATE)));
+          break;
+        case glass_EWGNTITLE:
+          dbox_selecticon(d,f,on);
+          dbox_selecticon(d,glass_EWGOTITLE,on);
+          dbox_shadeicon(d,glass_EWGNCLOSE,!on);
+          dbox_shadeicon(d,glass_EWGNBACK,!on);
+          dbox_shadeicon(d,glass_EWGNTOGGLE,
+               !(on || dbox_selecticon(d,glass_EWGNVERT,dbox_READSTATE)));
+          dbox_shadeicon(ed->e.d,glass_EWTDATA,!on);
+          dbox_shadeicon(ed->e.d,glass_EWTAPPEAR,!on);
+          break;
+        case glass_EWGNCLOSE:
+          dbox_selecticon(d,f,on);
+          dbox_selecticon(d,glass_EWGOCLOSEBACK,
+                (on || dbox_selecticon(d,glass_EWGNBACK,dbox_READSTATE)));
+          break;
+        case glass_EWGNBACK:
+          dbox_selecticon(d,f,on);
+          dbox_selecticon(d,glass_EWGOCLOSEBACK,
+               (on || dbox_selecticon(d,glass_EWGNCLOSE,dbox_READSTATE)));
+          break;
+        case glass_EWGNTOGGLE:
+        case glass_EWGNRESIZE:
+          dbox_selecticon(d,f,on);
+          break;
+        case glass_EWGNHORIZ:
+          dbox_selecticon(d,f,on);
+          dbox_selecticon(d,glass_EWGOHORIZ,on);
+          dbox_shadeicon(d,glass_EWGNRESIZE,
+               !(on || dbox_selecticon(d,glass_EWGNVERT,dbox_READSTATE)));
+          break;
+        case glass_EWGNVERT:
+          dbox_selecticon(d,f,on);
+          dbox_selecticon(d,glass_EWGOVERT,on);
+          dbox_shadeicon(d,glass_EWGNRESIZE,
+              !(on || dbox_selecticon(d,glass_EWGNHORIZ,dbox_READSTATE)));
+          dbox_shadeicon(d,glass_EWGNTOGGLE,
+              !(on || dbox_selecticon(d,glass_EWGNTITLE,dbox_READSTATE)));
+          break;
+      }
+      break;
+    case glass_EWTDATA:
+      switch (f)
+      {
+        case glass_EIDINDIR:
+          if (dbox_selecticon(d,f,dbox_READSTATE))
+          {
+            if (dbox_selecticon(ed->e.pd,glass_EIDTEXT,dbox_READSTATE))
+            {
+              dbox_shadeicon(ed->e.pd,glass_EIDVALID,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,
+                !dbox_selecticon(ed->e.pd,glass_EIDVALID,dbox_READSTATE));
+            }
+            dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDUP,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDPART,FALSE);
+          }
+          else
+          {
+            dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDVALID,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+          }
+          break;
+        case glass_EIDINDUP:
+          buttons_arrow(d,f,d,glass_EIDINDSIZE,0,+1,&sa);
+          break;
+        case glass_EIDINDDOWN:
+          buttons_arrow(d,f,d,glass_EIDINDSIZE,0,-1,&sa);
+          break;
+        case glass_EIDVALID:
+          dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,dbox_TOGGLESTATE);
+          break;
+        case glass_EIDMINIMISE:
+          dbox_clickicon(d,f);
+          dbox_getfield(d,glass_EIDDATA,ed->data,256);
+          dbox_setfield(d,glass_EIDINDSIZE,"%i",strlen(ed->data)+1);
+          dbox_unclick();
+          break;
+        case glass_EIDTEXT:
+          if (dbox_selecticon(ed->e.pd,glass_EIDTEXT,dbox_READSTATE))
+          {
+            dbox_shadeicon(ed->e.pd,glass_EIDDATA,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDIR,FALSE);
+            if (dbox_selecticon(d,glass_EIDINDIR,dbox_READSTATE))
+            {
+              dbox_shadeicon(ed->e.pd,glass_EIDVALID,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,
+                !dbox_selecticon(ed->e.pd,glass_EIDVALID,dbox_READSTATE));
+              dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDUP,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDPART,FALSE);
+            }
+            else
+            {
+              dbox_shadeicon(ed->e.pd,glass_EIDVALID,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+            }
+          }
+          else
+          {
+            dbox_shadeicon(ed->e.pd,glass_EIDVALID,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDVALSTRING,TRUE);
+            if (dbox_selecticon(d,glass_EIDSPRITE,dbox_READSTATE))
+            {
+              dbox_shadeicon(ed->e.pd,glass_EIDDATA,FALSE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDIR,FALSE);
+              indon=dbox_selecticon(d,glass_EIDINDIR,dbox_READSTATE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,!indon);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDUP,!indon);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,!indon);
+              dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,!indon);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDPART,!indon);
+            }
+            else
+            {
+              dbox_shadeicon(ed->e.pd,glass_EIDDATA,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDIR,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+              dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+            }
+          }
+          break;
+        case glass_EIDSPRITE:
+          if (dbox_selecticon(ed->e.pd,glass_EIDSPRITE,dbox_READSTATE))
+          {
+            dbox_shadeicon(ed->e.pd,glass_EIDDATA,FALSE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDIR,FALSE);
+            indon=dbox_selecticon(d,glass_EIDINDIR,dbox_READSTATE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,!indon);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDUP,!indon);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,!indon);
+            dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,!indon);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDPART,!indon);
+          }
+         else if (!dbox_selecticon(ed->e.pd,glass_EIDTEXT,dbox_READSTATE))
+          {
+            dbox_shadeicon(ed->e.pd,glass_EIDDATA,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDIR,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDSIZE,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDUP,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDDOWN,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDMINIMISE,TRUE);
+            dbox_shadeicon(ed->e.pd,glass_EIDINDPART,TRUE);
+          }
+          break;
+      }
+      break;
+    case glass_EWTAPPEAR:
+      switch (f)
+      {
+        case glass_EIAFONT:
+          if (dbox_selecticon(d,f,dbox_READSTATE) ||
+              fontMenu_createFontMenu(FALSE))
+          {
+            dbox_selecticon(d,f,dbox_TOGGLESTATE);
+            dbox_shadeicon(d,glass_EIAFONTNAME,dbox_TOGGLESTATE);
+            dbox_shadeicon(d,glass_EIAFONTMENU,dbox_TOGGLESTATE);
+            dbox_shadeicon(d,glass_EIAFSIZEUP,dbox_TOGGLESTATE);
+            dbox_shadeicon(d,glass_EIAFSIZEDOWN,dbox_TOGGLESTATE);
+            dbox_shadeicon(d,glass_EIAFSIZEWRITE,dbox_TOGGLESTATE);
+          }
+          break;
+        case glass_EIAFSIZEUP:
+          buttons_arrow(d,f,d,glass_EIAFSIZEWRITE,0,+1,&sa);
+          break;
+        case glass_EIAFSIZEDOWN:
+          buttons_arrow(d,f,d,glass_EIAFSIZEWRITE,0,-1,&sa);
+          break;
+      }
+      break;
+    case glass_EWWORKAREA:
+      eas.ed=ed;
+      switch (f)
+      {
+        case glass_EWSTOPUP:
+          eas.xOrY=FALSE;
+          eas.topOrBottom=TRUE;
+          buttons_arrow(d,f,d,0,editWindow__extArrows,+wimpt_dy(),&eas);
+          break;
+        case glass_EWSTOPDOWN:
+          eas.xOrY=FALSE;
+          eas.topOrBottom=TRUE;
+          buttons_arrow(d,f,d,0,editWindow__extArrows,-wimpt_dy(),&eas);
+          break;
+        case glass_EWSLEFTLEFT:
+          eas.xOrY=TRUE;
+          eas.topOrBottom=FALSE;
+          buttons_arrow(d,f,d,0,editWindow__extArrows,-wimpt_dx(),&eas);
+          break;
+        case glass_EWSLEFTRIGHT:
+          eas.xOrY=TRUE;
+          eas.topOrBottom=FALSE;
+          buttons_arrow(d,f,d,0,editWindow__extArrows,+wimpt_dx(),&eas);
+          break;
+        case glass_EWSRIGHTLEFT:
+          eas.xOrY=TRUE;
+          eas.topOrBottom=TRUE;
+          buttons_arrow(d,f,d,0,editWindow__extArrows,-wimpt_dx(),&eas);
+          break;
+        case glass_EWSRIGHTRIGHT:
+          eas.xOrY=TRUE;
+          eas.topOrBottom=TRUE;
+          buttons_arrow(d,f,d,0,editWindow__extArrows,+wimpt_dx(),&eas);
+          break;
+        case glass_EWSBOTTOMUP:
+          eas.xOrY=FALSE;
+          eas.topOrBottom=FALSE;
+          buttons_arrow(d,f,d,0,editWindow__extArrows,+wimpt_dy(),&eas);
+          break;
+        case glass_EWSBOTTOMDOWN:
+          eas.xOrY=FALSE;
+          eas.topOrBottom=FALSE;
+          buttons_arrow(d,f,d,0,editWindow__extArrows,-wimpt_dy(),&eas);
+          break;
+        case glass_EWSEXTLOCK:
+          dbox_clickicon(d,f);
+          ed->wdef.ex.x0=ed->w->def->desc.w.scx;
+          ed->wdef.ex.x1=ed->w->def->desc.w.scx+
+                         ed->w->def->desc.w.box.x1-ed->w->def->desc.w.box.x0;
+          ed->wdef.ex.y0=ed->w->def->desc.w.scy+
+                         ed->w->def->desc.w.box.y0-ed->w->def->desc.w.box.y1;
+          ed->wdef.ex.y1=ed->w->def->desc.w.scy;
+          editWindow__checkExtents(ed,TRUE,TRUE,FALSE);
+          dbox_unclick();
+          break;
+        case glass_EWSTLLARGE:
+          dbox_clickicon(d,f);
+          ed->wdef.ex.x0=(ed->wdef.ex.x0 - 2000) / 2000 * 2000;
+          ed->wdef.ex.y1=(ed->wdef.ex.y1 + 2000) / 2000 * 2000;
+          editWindow__checkExtents(ed,TRUE,TRUE,FALSE);
+          dbox_unclick();
+          break;
+        case glass_EWSBRLARGE:
+          dbox_clickicon(d,f);
+          ed->wdef.ex.x1=(ed->wdef.ex.x1 + 2000) / 2000 * 2000;
+          ed->wdef.ex.y0=(ed->wdef.ex.y0 - 2000) / 2000 * 2000;
+          editWindow__checkExtents(ed,TRUE,TRUE,FALSE);
+          dbox_unclick();
+          break;
+        case glass_EWSMINWSET:
+          dbox_clickicon(d,f);
+          dbox_setfield(d,glass_EWSMINWIDTH,"%i",
+                        ed->w->def->desc.w.box.x1-ed->w->def->desc.w.box.x0);
+          dbox_unclick();
+          break;
+        case glass_EWSMINHSET:
+          dbox_clickicon(d,f);
+          dbox_setfield(d,glass_EWSMINHEIGHT,"%i",
+                        ed->w->def->desc.w.box.y1-ed->w->def->desc.w.box.y0);
+          dbox_unclick();
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * BOOL editWindow__panelRaw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles the more wierd events for a particular panel.
+ *
+ * Parameters
+ *  dbox d == the dbox handle of the panel
+ *  wimp_eventstr *e == the event to look at
+ *  void *handle == pointer to the current edit
+ *
+ * Returns
+ *  TRUE if the event is dead (long live the event...)
+ */
+
+static BOOL editWindow__panelRaw(dbox d,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  glass_editWindow *ed=handle;
+  if (e->e==wimp_EKEY)
+  {
+    switch (e->data.key.chcode)
+    {
+      case akbd_UpK+akbd_Sh:
+        editWindow__nextPanel(ed,-1);
+        handled=TRUE;
+        break;
+      case akbd_DownK+akbd_Sh:
+        editWindow__nextPanel(ed,+1);
+        handled=TRUE;
+        break;
+    }
+  }
+  if (!handled) switch (ed->e.panel)
+  {
+    case glass_EWTDATA:
+      /* Nothin' doing */
+      break;
+    case glass_EWTAPPEAR:
+      switch (e->e)
+      {
+        case wimp_EBUT:
+          switch (e->data.but.m.i)
+          {
+            case glass_EIAFONTNAME:
+              menu_make(editWindow__fontMaker,editWindow__fontHandler,
+                                                    editWindow__fontHelp,ed);
+              handled=TRUE;
+              break;
+            case glass_EIAFONTMENU:
+              dbox_clickicon(d,glass_EIAFONTMENU);
+              menu_make(editWindow__fontMaker,editWindow__fontHandler,
+                                                      editWindow__fontHelp,ed);
+              dbox_unclick();
+              handled=TRUE;
+              break;
+          }
+          break;
+      }
+      break;
+    case glass_EWBTYPE:
+      switch (e->e)
+      {
+        case wimp_EBUT:
+          switch (e->data.but.m.i)
+          {
+            case glass_EWBBTDISP:
+              menu_make(editWindow__btypeMaker,editWindow__btypeHandler,
+                                                   editWindow__btypeHelp,ed);
+              handled=TRUE;
+              break;
+            case glass_EWBBTMENU:
+              dbox_clickicon(d,glass_EWBBTMENU);
+              menu_make(editWindow__btypeMaker,editWindow__btypeHandler,
+                                                   editWindow__btypeHelp,ed);
+              dbox_unclick();
+              handled=TRUE;
+              break;
+          }
+          break;
+      }
+      break;
+    case glass_EWCOLOURS:
+      switch (e->e)
+      {
+        case wimp_EBUT:
+          switch (e->data.but.m.i)
+          {
+            case glass_EWCTBFORE:
+              colSelect(ed->e.pd,glass_EWCTBFORE,e->data.but.m.bbits,
+                          msgs_lookup("ewTBFG"),TRUE,editWindow__colProc,ed);
+              break;
+            case glass_EWCTBBACK:
+              colSelect(ed->e.pd,glass_EWCTBBACK,e->data.but.m.bbits,
+                         msgs_lookup("ewTBBG"),FALSE,editWindow__colProc,ed);
+              break;
+            case glass_EWCWAFORE:
+              colSelect(ed->e.pd,glass_EWCWAFORE,e->data.but.m.bbits,
+                         msgs_lookup("ewWAFG"),FALSE,editWindow__colProc,ed);
+              break;
+            case glass_EWCWABACK:
+              colSelect(ed->e.pd,glass_EWCWABACK,e->data.but.m.bbits,
+                          msgs_lookup("ewWABG"),TRUE,editWindow__colProc,ed);
+              break;
+            case glass_EWCSCFORE:
+              colSelect(ed->e.pd,glass_EWCSCFORE,e->data.but.m.bbits,
+                         msgs_lookup("ewSCFG"),FALSE,editWindow__colProc,ed);
+              break;
+            case glass_EWCSCBACK:
+              colSelect(ed->e.pd,glass_EWCSCBACK,e->data.but.m.bbits,
+                         msgs_lookup("ewSCBG"),FALSE,editWindow__colProc,ed);
+              break;
+            case glass_EWCHIGH:
+              colSelect(ed->e.pd,glass_EWCHIGH,e->data.but.m.bbits,
+                         msgs_lookup("ewTBHI"),FALSE,editWindow__colProc,ed);
+          }
+          break;
+      }
+      break;
+  }
+  return (FALSE);
+}
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void editWindow_windowMoved(glass_windPointer *w)
+ *
+ * Use
+ *  Informs an edit dialogue that a window has been moved.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ */
+
+void editWindow_windowMoved(glass_windPointer *w)
+{
+  glass_editWindow *ed=w->edit;
+  if (!ed)
+    return;
+  editWindow__checkExtents(ed,FALSE,FALSE,TRUE);
+}
+
+/*
+ * void editWindow_readData(glass_windPointer *w)
+ *
+ * Use
+ *  Forces a re-read of the title data for the given window edit.  Since
+ *  this is called on setting up an edit and cancelling one, it also does
+ *  some
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ */
+
+void editWindow_readData(glass_windPointer *w)
+{
+  glass_editWindow *ed=w->edit;
+  if (!ed)
+    return;
+  ed->wdef.title=ed->w->def->desc.w.title;
+  if (ed->wdef.titleflags & wimp_INDIRECT)
+  {
+    utils_ctermToNterm(ed->wdef.title.indirecttext.buffer);
+    strcpy(ed->data,ed->wdef.title.indirecttext.buffer);
+    ed->indLen=ed->wdef.title.indirecttext.bufflen;
+    if (ed->wdef.titleflags & wimp_ITEXT &&
+                         ed->wdef.title.indirecttext.validstring!=(char *)-1)
+    {
+      utils_ctermToNterm(ed->wdef.title.indirecttext.validstring);
+      strcpy(ed->valid,ed->wdef.title.indirecttext.validstring);
+      ed->hasValid=TRUE;
+    }
+    else
+    {
+      ed->valid[0]=0;
+      ed->hasValid=FALSE;
+    }
+  }
+  else
+  {
+    ed->data[12]=0;
+    memcpy(ed->data,ed->wdef.title.text,12);
+    utils_ctermToNterm(ed->data);
+    ed->valid[0]=0;
+    ed->indLen=12;
+  }
+
+  if (ed->wdef.colours[0]==255)  /* If no system area                      */
+  {
+    dbox_shadeicon(ed->e.d,glass_EWTDATA,TRUE);
+    dbox_shadeicon(ed->e.d,glass_EWTAPPEAR,TRUE);
+    dbox_shadeicon(ed->e.d,glass_EWGADGETS,TRUE);
+    if (ed->e.panel==glass_EWTDATA
+     || ed->e.panel==glass_EWTAPPEAR
+     || ed->e.panel==glass_EWGADGETS)
+      editWindow__setPanel(ed,-1);
+  }
+  else if ((tst(ed->wdef.flags,31) && !tst(ed->wdef.flags,26))
+        || (!tst(ed->wdef.flags,31) && !tst(ed->wdef.flags,0)))
+  {
+    dbox_shadeicon(ed->e.d,glass_EWTDATA,TRUE);
+    dbox_shadeicon(ed->e.d,glass_EWTAPPEAR,TRUE);
+    dbox_shadeicon(ed->e.d,glass_EWGADGETS,FALSE);
+    if (ed->e.panel==glass_EWTDATA
+     || ed->e.panel==glass_EWTAPPEAR)
+      editWindow__setPanel(ed,-1);
+  }
+  else
+  {
+    dbox_shadeicon(ed->e.d,glass_EWTDATA,FALSE);
+    dbox_shadeicon(ed->e.d,glass_EWTAPPEAR,FALSE);
+    dbox_shadeicon(ed->e.d,glass_EWGADGETS,FALSE);
+  }
+
+  if (ed->e.panel==glass_EWTDATA)
+    editWindow__setupPanel(ed);
+}
+
+/*
+ * void editWindow_close(glass_windPointer *w)
+ *
+ * Use
+ *  Closes an edit window
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ */
+
+void editWindow_close(glass_windPointer *w)
+{
+  glass_editWindow *ed=w->edit;
+  if (ed)
+  {
+    if (ed->e.pd)
+      dbox_deleteNoUpdate(ed->e.pd);
+    pane_delete(ed->e.p);
+    dbox_deleteNoUpdate(ed->e.d);
+    ed->w->edit=0;
+    mem_free(ed);
+  }
+}
+
+/*
+ * void editWindow(glass_windPointer *w)
+ *
+ * Use
+ *  Edits the given window in a dialogue box.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to edit
+ */
+
+void editWindow(glass_windPointer *w)
+{
+  glass_editWindow *ed;
+  os_regset r;
+  if (w->edit)
+  {
+    dbox_display(w->edit->e.d,TRUE);
+    pane_front(w->edit->e.p);
+    return;
+  }
+  mem_useUser(indir_alloc,indir_free);
+  ed=mem_alloc(sizeof(glass_editWindow));
+  if (!ed)
+  {
+    mem_useMalloc();
+    werr(FALSE,msgs_lookup("ewNEM"));
+    return;
+  }
+  if (ed->e.d=dbox_create("editWindow"),!ed->e.d)
+  {
+    mem_free(ed);
+    mem_useMalloc();
+    return;
+  }
+  if (ed->e.p=pane_create(dbox_syshandle(ed->e.d)),!ed->e.p)
+  {
+    dbox_delete(ed->e.d);
+    mem_useMalloc();
+    mem_free(ed);
+    return;
+  }
+  ed->w=w;
+  ed->wdef=w->def->desc.w;
+  w->edit=ed;
+  ed->e.panel=0;
+
+  /* --- Set up icon data now --- */
+  editWindow_readData(w);
+  if (ed->wdef.titleflags & wimp_IFONT)
+  {
+    r.r[0]=ed->wdef.titleflags >> 24;
+    r.r[1]=(int)(ed->font);
+    wimpt_noerr(os_swix(XFont_ReadDefn,&r));
+    utils_ctermToNterm(ed->font);
+    ed->fontSize=r.r[2]/16;
+  }
+  else
+  {
+    strcpy(ed->font,"Homerton.Medium");
+    ed->fontSize=12;
+  }
+
+  /* --- Now do handlers, and final setting up --- */
+  dbox_setfield(ed->e.d,glass_EWIDWRITE,"%s",w->id);
+  dbox_setfield(ed->e.d,glass_EWFILEDISP,"%.%s",w->t->filename);
+  dbox_eventHandler(ed->e.d,editWindow__dboxHandler,ed);
+  dbox_rawEventHandler(ed->e.d,editWindow__dboxRaw,ed);
+  dbox_openDisplaced(ed->e.d);
+  editWindow__setPanel(ed,glass_EWCHARS);
+  mem_useMalloc();
+}
diff --git a/StraySrc/Glass/!Glass/c/gPrefs b/StraySrc/Glass/!Glass/c/gPrefs
new file mode 100644 (file)
index 0000000..0fa4874
--- /dev/null
@@ -0,0 +1,1703 @@
+/*
+ * gPrefs.h
+ *
+ * Loading, saving, alteration and setting of preferences
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#include "steel/Steel.h"
+
+#include "steel/prefs.h"
+#include "steel/pane.h"
+#include "steel/blinkC.h"
+#include "steel/buttons.h"
+#include "steel/akbd.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gIcons.h"
+#include "gMenus.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "intMsgs.h"
+#include "colSelect.h"
+#include "window.h"
+
+/*----- Macros ------------------------------------------------------------*/
+
+#define gPrefs__DEFAULTTIME 5
+#define gPrefs__DEFAULTCOUNT 50
+
+/*----- Static global variables -------------------------------------------*/
+
+static gPrefs_prefs gPrefs__current=
+{
+  gPrefs_MINUTES,                      /* Autosave_TimeUnits           */
+  10,                                  /* Autosave_Time                */
+  0,                                   /* Autosave_Alterations         */
+  TRUE,                                        /* Autosave_Prompt              */
+
+  TRUE,                                        /* Interface_DisplayBorders     */
+  TRUE,                                        /* Interface_SlabIcons          */
+  TRUE,                                        /* Interface_DragboxAroundBorder*/
+  FALSE,                               /* Interface_SlabMenu           */
+
+  TRUE,                                        /* WimpExt_DisplayBorders       */
+  TRUE,                                        /* WimpExt_KeyPress             */
+  TRUE,                                        /* WimpExt_DragboxAroundBorder  */
+
+  TRUE,                                        /* Sculptrix_DisplayBorders     */
+  TRUE,                                        /* Sculptrix_SlabIcons          */
+  TRUE,                                        /* Sculptrix_DragboxAroundBorder*/
+  FALSE,                               /* Sculptrix_SlabMenu           */
+
+  TRUE,                                        /* Sprites_LoadSprites          */
+  TRUE,                                        /* Sprites_Load!Sprites         */
+  TRUE,                                        /* Sprites_LoadDefaults         */
+
+  gPrefs_SMALL,                                /* Files_IconSize               */
+  gPrefs_NAME,                         /* Files_SortBy                 */
+
+  FALSE,                               /* Grid_Display                 */
+  FALSE,                               /* Grid_Lock                    */
+  16,                                  /* Grid_Width                   */
+  16,                                  /* Grid_Height                  */
+  FALSE,                               /* Grid_DrawLines               */
+  8,                                   /* Grid_GridColour              */
+  14,                                  /* Grid_GuideColour             */
+  13,                                  /* Grid_SelectedGuideColour     */
+
+  TRUE,                                        /* Select_DrawBorder            */
+  TRUE,                                        /* Select_DottedBorder          */
+  3,                                   /* Select_BorderColour          */
+  TRUE,                                        /* Select_EdgeHandles           */
+  4,                                   /* Select_HandleSize            */
+  7,                                   /* Select_HandleColour          */
+  11,                                  /* Select_SpecialColour         */
+
+  TRUE,                                        /* Confirm_Quit                 */
+  TRUE,                                        /* Confirm_Close                */
+  TRUE,                                        /* Confirm_DelWind              */
+  FALSE,                               /* Confirm_DelIcon              */
+  FALSE,                               /* Confirm_TestCloseEdit        */
+  TRUE,                                        /* Confirm_Overwrite            */
+
+  TRUE,                                        /* Toolbar_Display              */
+  FALSE,                               /* Toolbar_Floating             */
+  {0,0},                               /* Toolbar_Position             */
+  TRUE,                                        /* Toolbar_OnLeft               */
+
+  TRUE,                                        /* Infobar_Display              */
+  FALSE,                               /* Infobar_Floating             */
+  {0,0},                               /* Infobar_Position             */
+  TRUE,                                        /* Infobar_Underneath           */
+
+  FALSE,                               /* Misc_DrawHatch               */
+  TRUE,                                        /* Misc_BlinkCursor             */
+  TRUE,                                        /* Misc_VisibleInWork           */
+  TRUE,                                        /* Misc_CreateOnTop             */
+  TRUE,                                        /* Misc_RenumberOnDelete        */
+  FALSE,                               /* Misc_ControlToEdit           */
+};
+
+static gPrefs_prefs gPrefs__new;
+static dbox gPrefs__dbox;
+static pane gPrefs__pane;
+static dbox gPrefs__panel;
+static dbox_field gPrefs__currentPanel;
+
+/*----- Interpreters for new preferences data types -----------------------*/
+
+static char *gPrefs__readUnit(char *tag,char *args,void *handle);
+static char *gPrefs__writeUnit(char *tag,FILE *fp,void *handle);
+static char *gPrefs__readIconSize(char *tag,char *args,void *handle);
+static char *gPrefs__writeIconSize(char *tag,FILE *fp,void *handle);
+static char *gPrefs__readSort(char *tag,char *args,void *handle);
+static char *gPrefs__writeSort(char *tag,FILE *fp,void *handle);
+static char *gPrefs__readCoords(char *tag,char *args,void *handle);
+static char *gPrefs__writeCoords(char *tag,FILE *fp,void *handle);
+
+/*----- Preferences file description --------------------------------------*/
+
+static prefs_prefstr gPrefs__prefs[]=
+{
+  ";\n"
+  "; Glass preferences\n"
+  ";\n"
+  "\n",
+    0,
+    0,
+    0,
+
+  "Autosave_TimeUnits",
+    gPrefs__readUnit,
+    gPrefs__writeUnit,
+    &gPrefs__current.aUnit,
+  "Autosave_Time",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.aTime,
+  "Autosave_Alterations",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.aAlts,
+  "Autosave_Prompt",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.aPrompt,
+  "\n",
+    0,
+    0,
+    0,
+
+  "Interface_DisplayBorders",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.iDispBorders,
+  "Interface_SlabIcons",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.iSlabIcons,
+  "Interface_DragboxAroundBorder",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.iIncBorder,
+  "Interface_SlabOnMenu",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.iSlabMenu,
+  "\n",
+    0,
+    0,
+    0,
+
+  "WimpExtension_DisplayBorders",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.wDispBorders,
+  "WimpExtension_KeyPress",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.wKeyPress,
+  "WimpExtension_DragboxAroundBorder",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.wIncBorder,
+  "\n",
+    0,
+    0,
+    0,
+
+  "Sculptrix_DisplayBorders",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.sDispBorders,
+  "Sculptrix_SlabIcons",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.sSlabIcons,
+  "Sculptrix_DragboxAroundBorder",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.sIncBorder,
+  "Sculptrix_SlabOnMenu",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.sSlabMenu,
+  "\n",
+    0,
+    0,
+    0,
+
+  "Sprites_LoadSprites",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.sLoadSpr,
+  "Sprites_Load!Sprites",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.sLoadPSpr,
+  "Sprites_LoadDefaults",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.sLoadDef,
+  "\n",
+    0,
+    0,
+    0,
+
+  "Files_IconSize",
+    gPrefs__readIconSize,
+    gPrefs__writeIconSize,
+    &gPrefs__current.fIcons,
+  "Files_SortBy",
+    gPrefs__readSort,
+    gPrefs__writeSort,
+    &gPrefs__current.fSort,
+  "\n",
+    0,
+    0,
+    0,
+
+  "Grid_Display",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.gDisp,
+  "Grid_Lock",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.gLock,
+  "Grid_Width",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.gWidth,
+  "Grid_Height",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.gHeight,
+  "Grid_DrawLines",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.gLines,
+  "Grid_GridColour",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.gGridCol,
+  "Grid_GuideColour",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.gGdeCol,
+  "Grid_SelectedGuideColour",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.gGdeSelCol,
+  "\n",
+    0,
+    0,
+    0,
+
+  "Select_DrawBorder",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.sBorder,
+  "Select_DottedBorder",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.sDotted,
+  "Select_BorderColour",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.sBColour,
+  "Select_EdgeHandles",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.sEdgeHandles,
+  "Select_HandleSize",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.sHandSize,
+  "Select_HandleColour",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.sHColour,
+  "Select_SpecialColour",
+    prefs_readNumeric,
+    prefs_writeNumeric,
+    &gPrefs__current.sSColour,
+  "\n",
+    0,
+    0,
+    0,
+
+  "Confirm_Quit",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.cQuit,
+  "Confirm_Close",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.cClose,
+  "Confirm_DelWind",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.cDelWind,
+  "Confirm_DelIcon",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.cDelIcon,
+  "Confirm_TestCloseEdit",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.cTest,
+  "Confirm_Overwrite",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.cSave,
+  "\n",
+    0,
+    0,
+    0,
+
+  "Toolbar_Display",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.tDisplay,
+  "Toolbar_Floating",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.tFloating,
+  "Toolbar_Position",
+    gPrefs__readCoords,
+    gPrefs__writeCoords,
+    &gPrefs__current.tPosn,
+  "Toolbar_OnLeft",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.tLeft,
+  "\n",
+    0,
+    0,
+    0,
+
+  "Infobar_Display",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.iDisplay,
+  "Infobar_Floating",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.iFloating,
+  "Infobar_Position",
+    gPrefs__readCoords,
+    gPrefs__writeCoords,
+    &gPrefs__current.iPosn,
+  "Infobar_Underneath",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.iUnder,
+  "\n",
+    0,
+    0,
+    0,
+
+  "Misc_DrawHatch",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.mDrawHatch,
+  "Misc_BlinkCursor",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.mBlink,
+  "Misc_VisibleInWork",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.mVisInWork,
+  "Misc_CreateOnTop",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.mCreateTop,
+  "Misc_RenumberOnDelete",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.mDeleteRenum,
+  "Misc_ControlToEdit",
+    prefs_readBoolean,
+    prefs_writeBoolean,
+    &gPrefs__current.mCtrlEdit,
+  0,
+    0,
+    0,
+    0,
+};
+
+/*----- Miscelaneous tables -----------------------------------------------*/
+
+static char *gPrefs__panels[]=
+{
+  "prefSave",
+  "prefIface",
+  "prefSprite",
+  "prefFile",
+  "prefGrid",
+  "prefSel",
+  "prefConf",
+  "prefTool",
+  "prefMisc",
+};
+
+static char *gPrefs__units[]=
+{
+  0,
+  "prHR",
+  "prMI",
+  "prSE",
+};
+
+/*----- Support routines --------------------------------------------------*/
+
+#define max2(a,b) ((a)>(b) ? (a) : (b))
+#define min2(a,b) ((a)<(b) ? (a) : (b))
+
+/*
+ * char *gPrefs__readUnit(char *tag,char *args,void *handle)
+ *
+ * Use
+ *  Interprets a time unit variable in preferences file.
+ *
+ * Parameters
+ *  char *tag == the name of the tag to interpret
+ *  char *args == pointer to args string to interpret
+ *  void *handle == pointer to approriately typed variable
+ *
+ * Returns
+ *  0 for success, or pointer to an error string.
+ */
+
+static char *gPrefs__readUnit(char *tag,char *args,void *handle)
+{
+  unused(tag);
+  if (utils_caselessCmp(args,"hours")==0)
+    *(gPrefs_autoUnits *)handle=gPrefs_HOURS;
+  else if (utils_caselessCmp(args,"minutes")==0)
+    *(gPrefs_autoUnits *)handle=gPrefs_MINUTES;
+  else if (utils_caselessCmp(args,"seconds")==0)
+    *(gPrefs_autoUnits *)handle=gPrefs_SECONDS;
+  else
+  {
+    return (msgs_lookup("prBTU"));
+  }
+  return (0);
+}
+
+/*
+ * char *gPrefs__writeUnit(char *tag,FILE *fp,void *handle)
+ *
+ * Use
+ *  Writes a time unit variable to preferences file.
+ *
+ * Parameters
+ *  char *tag == the name of the tag to interpret
+ *  FILE *fp == the file handle for the file
+ *  void *handle == pointer to approriately typed variable
+ *
+ * Returns
+ *  0 for success, or pointer to an error string.
+ */
+
+static char *gPrefs__writeUnit(char *tag,FILE *fp,void *handle)
+{
+  static char *units[]={0,"hours","minutes","seconds"};
+  fprintf(fp,"%s=%s\n",tag,units[*(gPrefs_autoUnits *)handle]);
+  return (0);
+}
+
+/*
+ * char *gPrefs__readIconSize(char *tag,char *args,void *handle)
+ *
+ * Use
+ *  Interprets an icon size variable in preferences file.
+ *
+ * Parameters
+ *  char *tag == the name of the tag to interpret
+ *  char *args == pointer to args string to interpret
+ *  void *handle == pointer to approriately typed variable
+ *
+ * Returns
+ *  0 for success, or pointer to an error string.
+ */
+
+static char *gPrefs__readIconSize(char *tag,char *args,void *handle)
+{
+  unused(tag);
+  if (utils_caselessCmp(args,"large")==0)
+    *(gPrefs_iconSize *)handle=gPrefs_LARGE;
+  else if (utils_caselessCmp(args,"small")==0)
+    *(gPrefs_iconSize *)handle=gPrefs_SMALL;
+  else
+  {
+    return (msgs_lookup("prBIS"));
+  }
+  return (0);
+}
+
+/*
+ * char *gPrefs__writeIconSize(char *tag,FILE *fp,void *handle)
+ *
+ * Use
+ *  Writes an icon size variable to preferences file.
+ *
+ * Parameters
+ *  char *tag == the name of the tag to interpret
+ *  FILE *fp == the file handle for the file
+ *  void *handle == pointer to approriately typed variable
+ *
+ * Returns
+ *  0 for success, or pointer to an error string.
+ */
+
+static char *gPrefs__writeIconSize(char *tag,FILE *fp,void *handle)
+{
+  static char *units[]={0,"large","small"};
+  fprintf(fp,"%s=%s\n",tag,units[*(gPrefs_iconSize *)handle]);
+  return (0);
+}
+
+/*
+ * char *gPrefs__readSort(char *tag,char *args,void *handle)
+ *
+ * Use
+ *  Interprets a sort type variable in preferences file.
+ *
+ * Parameters
+ *  char *tag == the name of the tag to interpret
+ *  char *args == pointer to args string to interpret
+ *  void *handle == pointer to approriately typed variable
+ *
+ * Returns
+ *  0 for success, or pointer to an error string.
+ */
+
+static char *gPrefs__readSort(char *tag,char *args,void *handle)
+{
+  unused(tag);
+  if (utils_caselessCmp(args,"name")==0)
+    *(gPrefs_sortType *)handle=gPrefs_NAME;
+  else if (utils_caselessCmp(args,"size")==0)
+    *(gPrefs_sortType *)handle=gPrefs_SIZE;
+  else if (utils_caselessCmp(args,"icons")==0)
+    *(gPrefs_sortType *)handle=gPrefs_ICONS;
+  else if (utils_caselessCmp(args,"noSort")==0)
+    *(gPrefs_sortType *)handle=gPrefs_NOSORT;
+  else
+  {
+    return (msgs_lookup("prBST"));
+  }
+  return (0);
+}
+
+/*
+ * char *gPrefs__writeSort(char *tag,FILE *fp,void *handle)
+ *
+ * Use
+ *  Writes a sort type variable to preferences file.
+ *
+ * Parameters
+ *  char *tag == the name of the tag to interpret
+ *  FILE *fp == the file handle for the file
+ *  void *handle == pointer to approriately typed variable
+ *
+ * Returns
+ *  0 for success, or pointer to an error string.
+ */
+
+static char *gPrefs__writeSort(char *tag,FILE *fp,void *handle)
+{
+  static char *units[]={0,"name","size","icons","noSort"};
+  fprintf(fp,"%s %s\n",tag,units[*(gPrefs_sortType *)handle]);
+  return (0);
+}
+
+/*
+ * char *gPrefs__readCoords(char *tag,char *args,void *handle)
+ *
+ * Use
+ *  Interprets a coordinates type variable in preferences file.
+ *
+ * Parameters
+ *  char *tag == the name of the tag to interpret
+ *  char *args == pointer to args string to interpret
+ *  void *handle == pointer to approriately typed variable
+ *
+ * Returns
+ *  0 for success, or pointer to an error string.
+ */
+
+static char *gPrefs__readCoords(char *tag,char *args,void *handle)
+{
+  gPrefs_coords *c=handle;
+  unused(tag);
+  sscanf(args,"%d,%d",&c->x,&c->y);
+  return (0);
+}
+
+/*
+ * char *gPrefs__writeCoords(char *tag,FILE *fp,void *handle)
+ *
+ * Use
+ *  Writes a sort type variable to preferences file.
+ *
+ * Parameters
+ *  char *tag == the name of the tag to interpret
+ *  FILE *fp == the file handle for the file
+ *  void *handle == pointer to approriately typed variable
+ *
+ * Returns
+ *  0 for success, or pointer to an error string.
+ */
+
+static char *gPrefs__writeCoords(char *tag,FILE *fp,void *handle)
+{
+  gPrefs_coords *c=handle;
+  fprintf(fp,"%s=%i,%i\n",tag,c->x,c->y);
+  return (0);
+}
+
+/*
+ * void gPrefs__setupPanel(void)
+ *
+ * Use
+ *  Reads the settings in a panel before it is closed.
+ */
+
+static void gPrefs__setupPanel(void)
+{
+  dbox d=gPrefs__panel;
+  switch (gPrefs__currentPanel)
+  {
+    case glass_PMAUTOSAVE:
+      if (gPrefs__new.aTime)
+      {
+        dbox_selecticon(d,glass_PATIMED,dbox_SETSTATE);
+        dbox_shadeicon(d,glass_PATIMEDOWN,dbox_RESETSTATE);
+        dbox_shadeicon(d,glass_PATIMEWRITE,dbox_RESETSTATE);
+        dbox_shadeicon(d,glass_PATIMEUP,dbox_RESETSTATE);
+        dbox_shadeicon(d,glass_PAUNITSDISP,dbox_RESETSTATE);
+        dbox_shadeicon(d,glass_PAUNITSMENU,dbox_RESETSTATE);
+        dbox_setfield(d,glass_PATIMEWRITE,"%i",gPrefs__new.aTime);
+      }
+      else
+      {
+        dbox_selecticon(d,glass_PATIMED,dbox_RESETSTATE);
+        dbox_shadeicon(d,glass_PATIMEDOWN,dbox_SETSTATE);
+        dbox_shadeicon(d,glass_PATIMEWRITE,dbox_SETSTATE);
+        dbox_shadeicon(d,glass_PATIMEUP,dbox_SETSTATE);
+        dbox_shadeicon(d,glass_PAUNITSDISP,dbox_SETSTATE);
+        dbox_shadeicon(d,glass_PAUNITSMENU,dbox_SETSTATE);
+        dbox_setfield(d,glass_PATIMEWRITE,"%i",gPrefs__DEFAULTTIME);
+      }
+      dbox_setfield(d,glass_PAUNITSDISP,"%s",
+                            msgs_lookup(gPrefs__units[gPrefs__new.aUnit]));
+      if (gPrefs__new.aAlts)
+      {
+        dbox_selecticon(d,glass_PACOUNTED,dbox_SETSTATE);
+        dbox_shadeicon(d,glass_PACOUNTDOWN,dbox_RESETSTATE);
+        dbox_shadeicon(d,glass_PACOUNTWRITE,dbox_RESETSTATE);
+        dbox_shadeicon(d,glass_PACOUNTUP,dbox_RESETSTATE);
+        dbox_setfield(d,glass_PACOUNTWRITE,"%i",gPrefs__new.aAlts);
+      }
+      else
+      {
+        dbox_selecticon(d,glass_PACOUNTED,dbox_RESETSTATE);
+        dbox_shadeicon(d,glass_PACOUNTDOWN,dbox_SETSTATE);
+        dbox_shadeicon(d,glass_PACOUNTWRITE,dbox_SETSTATE);
+        dbox_shadeicon(d,glass_PACOUNTUP,dbox_SETSTATE);
+        dbox_setfield(d,glass_PACOUNTWRITE,"%i",gPrefs__DEFAULTCOUNT);
+      }
+      dbox_selecticon(d,glass_PAPROMPT,gPrefs__new.aPrompt);
+      break;
+    case glass_PMINTERFACE:
+      dbox_selecticon(d,glass_PIDISPBORDER,gPrefs__new.iDispBorders);
+      dbox_selecticon(d,glass_PIMOUSECLICK,gPrefs__new.iSlabIcons);
+      dbox_selecticon(d,glass_PIMENUCLICK,gPrefs__new.iSlabMenu);
+      dbox_shadeicon(d,glass_PIMENUCLICK,!gPrefs__new.iSlabIcons);
+      dbox_selecticon(d,glass_PIINCBORDER,gPrefs__new.iIncBorder);
+
+      dbox_selecticon(d,glass_PWDISPBORDER,gPrefs__new.wDispBorders);
+      dbox_selecticon(d,glass_PWKEYPRESS,gPrefs__new.wKeyPress);
+      dbox_selecticon(d,glass_PWINCBORDER,gPrefs__new.wIncBorder);
+
+      dbox_selecticon(d,glass_PSDISPBORDER,gPrefs__new.sDispBorders);
+      dbox_selecticon(d,glass_PSMOUSECLICK,gPrefs__new.sSlabIcons);
+      dbox_selecticon(d,glass_PSMENUCLICK,gPrefs__new.sSlabMenu);
+      dbox_shadeicon(d,glass_PSMENUCLICK,!gPrefs__new.sSlabIcons);
+      dbox_selecticon(d,glass_PSINCBORDER,gPrefs__new.sIncBorder);
+
+      break;
+    case glass_PMSPRITES:
+      dbox_selecticon(d,glass_PSSPRITES,gPrefs__new.sLoadSpr);
+      dbox_selecticon(d,glass_PSPSPRITES,gPrefs__new.sLoadPSpr);
+      dbox_selecticon(d,glass_PSDEFAULTS,gPrefs__new.sLoadDef);
+      break;
+    case glass_PMFILEDISP:
+      dbox_selecticon(d,glass_PFLARGE,gPrefs__new.fIcons==gPrefs_LARGE);
+      dbox_selecticon(d,glass_PFSMALL,gPrefs__new.fIcons==gPrefs_SMALL);
+      dbox_selecticon(d,glass_PFNAME,gPrefs__new.fSort==gPrefs_NAME);
+      dbox_selecticon(d,glass_PFSIZE,gPrefs__new.fSort==gPrefs_SIZE);
+      dbox_selecticon(d,glass_PFICONS,gPrefs__new.fSort==gPrefs_ICONS);
+     dbox_selecticon(d,glass_PFNOSORT,gPrefs__new.fSort==gPrefs_NOSORT);
+      break;
+    case glass_PMGRID:
+      dbox_selecticon(d,glass_PGDISP,gPrefs__new.gDisp);
+      dbox_selecticon(d,glass_PGLOCK,gPrefs__new.gLock);
+      dbox_setfield(d,glass_PGWWRITE,"%i",gPrefs__new.gWidth);
+      dbox_setfield(d,glass_PGHWRITE,"%i",gPrefs__new.gHeight);
+      dbox_selecticon(d,glass_PGLINES,gPrefs__new.gLines);
+      dbox_selecticon(d,glass_PGPOINTS,!gPrefs__new.gLines);
+      colSelect_setColourButton(d,glass_PGGRIDCOL,gPrefs__new.gGridCol);
+      colSelect_setColourButton(d,glass_PGGUIDECOL,gPrefs__new.gGdeCol);
+      colSelect_setColourButton(d,
+                                glass_PGGDESELCOL,
+                                gPrefs__new.gGdeSelCol);
+      break;
+    case glass_PMSELECTION:
+      dbox_selecticon(d,glass_PSBORDER,gPrefs__new.sBorder);
+      dbox_shadeicon(d,glass_PSDOTTED,!gPrefs__new.sBorder);
+      dbox_shadeicon(d,glass_PSBCOLLABEL,!gPrefs__new.sBorder);
+      dbox_shadeicon(d,glass_PSBCOLOUR,!gPrefs__new.sBorder);
+      dbox_selecticon(d,glass_PSDOTTED,gPrefs__new.sDotted);
+      colSelect_setColourButton(d,glass_PSBCOLOUR,gPrefs__new.sBColour);
+      dbox_selecticon(d,glass_PSCORNEDGE,gPrefs__new.sEdgeHandles);
+      dbox_selecticon(d,glass_PSCORNONLY,!gPrefs__new.sEdgeHandles);
+      dbox_setfield(d,glass_PSSIZEWRITE,"%i",gPrefs__new.sHandSize);
+      colSelect_setColourButton(d,glass_PSHCOLOUR,gPrefs__new.sHColour);
+      colSelect_setColourButton(d,glass_PSSCOLOUR,gPrefs__new.sSColour);
+      break;
+    case glass_PMCONFIRM:
+      dbox_selecticon(d,glass_PCQUIT,gPrefs__new.cQuit);
+      dbox_selecticon(d,glass_PCCLOSE,gPrefs__new.cClose);
+      dbox_selecticon(d,glass_PCDELWIN,gPrefs__new.cDelWind);
+      dbox_selecticon(d,glass_PCDELICON,gPrefs__new.cDelIcon);
+      dbox_selecticon(d,glass_PCTEST,gPrefs__new.cTest);
+      dbox_selecticon(d,glass_PCOVERWRITE,gPrefs__new.cSave);
+      break;
+    case glass_PMTOOLINFO:
+      if (gPrefs__new.tDisplay)
+      {
+        dbox_selecticon(d,glass_PTTOOLDISP,dbox_SETSTATE);
+        dbox_shadeicon(d,glass_PTTOOLFLOAT,dbox_RESETSTATE);
+      }
+      else
+      {
+        dbox_selecticon(d,glass_PTTOOLDISP,dbox_RESETSTATE);
+        dbox_shadeicon(d,glass_PTTOOLFLOAT,dbox_SETSTATE);
+      }
+      dbox_selecticon(d,glass_PTTOOLFLOAT,gPrefs__new.tFloating);
+      if (gPrefs__new.iDisplay)
+      {
+        dbox_selecticon(d,glass_PTINFODISP,dbox_SETSTATE);
+        dbox_shadeicon(d,glass_PTINFOFLOAT,dbox_RESETSTATE);
+      }
+      else
+      {
+        dbox_selecticon(d,glass_PTINFODISP,dbox_RESETSTATE);
+        dbox_shadeicon(d,glass_PTINFOFLOAT,dbox_SETSTATE);
+      }
+      dbox_selecticon(d,glass_PTINFOFLOAT,gPrefs__new.iFloating);
+      break;
+    case glass_PMMISC:
+      dbox_selecticon(d,glass_PMHATCH,gPrefs__new.mDrawHatch);
+      dbox_selecticon(d,glass_PMBLINK,gPrefs__new.mBlink);
+      dbox_selecticon(d,glass_PMVISINWORK,gPrefs__new.mVisInWork);
+      dbox_selecticon(d,glass_PMNEWONTOP,gPrefs__new.mCreateTop);
+      dbox_selecticon(d,glass_PMRENDEL,gPrefs__new.mDeleteRenum);
+      dbox_selecticon(d,glass_PMCTRLEDIT,gPrefs__new.mCtrlEdit);
+      break;
+  }
+}
+
+/*
+ * void gPrefs__closePanel(void)
+ *
+ * Use
+ *  Reads the settings in a panel before it is closed.
+ */
+
+#define Q dbox_READSTATE
+
+static void gPrefs__closePanel(void)
+{
+  dbox d=gPrefs__panel;
+  switch (gPrefs__currentPanel)
+  {
+    case glass_PMAUTOSAVE:
+      if (dbox_selecticon(d,glass_PATIMED,Q))
+      {
+        dbox_scanfield(d,glass_PATIMEWRITE,"%d",&gPrefs__new.aTime);
+        if (!gPrefs__new.aTime)
+        {
+          gPrefs__new.aTime=gPrefs__DEFAULTTIME;
+          dbox_setfield(d,glass_PATIMEWRITE,"%i",gPrefs__new.aTime);
+          note(msgs_lookup("prSILT"),
+               gPrefs__DEFAULTTIME);
+        }
+      }
+      else
+        gPrefs__new.aTime=0;
+      if (dbox_selecticon(d,glass_PACOUNTED,Q))
+      {
+        dbox_scanfield(d,glass_PACOUNTWRITE,"%d",&gPrefs__new.aAlts);
+        if (!gPrefs__new.aAlts)
+        {
+          gPrefs__new.aAlts=gPrefs__DEFAULTCOUNT;
+          dbox_setfield(d,glass_PACOUNTWRITE,"%i",gPrefs__new.aTime);
+          note(msgs_lookup("prSILC"),
+               gPrefs__DEFAULTCOUNT);
+        }
+      }
+      else
+        gPrefs__new.aAlts=0;
+      gPrefs__new.aPrompt=dbox_selecticon(d,glass_PAPROMPT,Q);
+      break;
+    case glass_PMINTERFACE:
+      gPrefs__new.iDispBorders=dbox_selecticon(d,glass_PIDISPBORDER,Q);
+      gPrefs__new.iSlabIcons=dbox_selecticon(d,glass_PIMOUSECLICK,Q);
+      if (gPrefs__new.iSlabIcons)
+        gPrefs__new.iSlabMenu=dbox_selecticon(d,glass_PIMENUCLICK,Q);
+      else
+        gPrefs__new.iSlabMenu=FALSE;
+      gPrefs__new.iIncBorder=dbox_selecticon(d,glass_PIINCBORDER,Q);
+
+      gPrefs__new.wDispBorders=dbox_selecticon(d,glass_PWDISPBORDER,Q);
+      gPrefs__new.wKeyPress=dbox_selecticon(d,glass_PWKEYPRESS,Q);
+      gPrefs__new.wIncBorder=dbox_selecticon(d,glass_PWINCBORDER,Q);
+
+      gPrefs__new.sDispBorders=dbox_selecticon(d,glass_PSDISPBORDER,Q);
+      gPrefs__new.sSlabIcons=dbox_selecticon(d,glass_PSMOUSECLICK,Q);
+      if (gPrefs__new.sSlabIcons)
+        gPrefs__new.sSlabMenu=dbox_selecticon(d,glass_PSMENUCLICK,Q);
+      else
+        gPrefs__new.sSlabMenu=FALSE;
+      gPrefs__new.sIncBorder=dbox_selecticon(d,glass_PSINCBORDER,Q);
+
+      break;
+    case glass_PMSPRITES:
+      gPrefs__new.sLoadSpr=dbox_selecticon(d,glass_PSSPRITES,Q);
+      gPrefs__new.sLoadPSpr=dbox_selecticon(d,glass_PSPSPRITES,Q);
+      gPrefs__new.sLoadDef=dbox_selecticon(d,glass_PSDEFAULTS,Q);
+      break;
+    case glass_PMFILEDISP:
+      if (dbox_selecticon(d,glass_PFLARGE,Q))
+        gPrefs__new.fIcons=gPrefs_LARGE;
+      else
+        gPrefs__new.fIcons=gPrefs_SMALL;
+      if (dbox_selecticon(d,glass_PFNAME,Q))
+        gPrefs__new.fSort=gPrefs_NAME;
+      else if (dbox_selecticon(d,glass_PFSIZE,Q))
+        gPrefs__new.fSort=gPrefs_SIZE;
+      else if (dbox_selecticon(d,glass_PFICONS,Q))
+        gPrefs__new.fSort=gPrefs_ICONS;
+      else
+        gPrefs__new.fSort=gPrefs_NOSORT;
+      break;
+    case glass_PMGRID:
+      gPrefs__new.gDisp=dbox_selecticon(d,glass_PGDISP,Q);
+      gPrefs__new.gLock=dbox_selecticon(d,glass_PGLOCK,Q);
+      dbox_scanfield(d,glass_PGWWRITE,"%d",&gPrefs__new.gWidth);
+      dbox_scanfield(d,glass_PGHWRITE,"%d",&gPrefs__new.gHeight);
+      gPrefs__new.gLines=dbox_selecticon(d,glass_PGLINES,Q);
+      break;
+    case glass_PMSELECTION:
+      gPrefs__new.sBorder=dbox_selecticon(d,glass_PSBORDER,Q);
+      gPrefs__new.sDotted=dbox_selecticon(d,glass_PSDOTTED,Q);
+      gPrefs__new.sEdgeHandles=dbox_selecticon(d,glass_PSCORNEDGE,Q);
+      dbox_scanfield(d,glass_PSSIZEWRITE,"%d",&gPrefs__new.sHandSize);
+      break;
+    case glass_PMCONFIRM:
+      gPrefs__new.cQuit=dbox_selecticon(d,glass_PCQUIT,Q);
+      gPrefs__new.cClose=dbox_selecticon(d,glass_PCCLOSE,Q);
+      gPrefs__new.cDelWind=dbox_selecticon(d,glass_PCDELWIN,Q);
+      gPrefs__new.cDelIcon=dbox_selecticon(d,glass_PCDELICON,Q);
+      gPrefs__new.cTest=dbox_selecticon(d,glass_PCTEST,Q);
+      gPrefs__new.cSave=dbox_selecticon(d,glass_PCOVERWRITE,Q);
+      break;
+    case glass_PMTOOLINFO:
+      gPrefs__new.tDisplay=dbox_selecticon(d,glass_PTTOOLDISP,Q);
+      gPrefs__new.tFloating=dbox_selecticon(d,glass_PTTOOLFLOAT,Q);
+      gPrefs__new.iDisplay=dbox_selecticon(d,glass_PTINFODISP,Q);
+      gPrefs__new.iFloating=dbox_selecticon(d,glass_PTINFOFLOAT,Q);
+      break;
+    case glass_PMMISC:
+      gPrefs__new.mDrawHatch=dbox_selecticon(d,glass_PMHATCH,Q);
+      gPrefs__new.mBlink=dbox_selecticon(d,glass_PMBLINK,Q);
+      gPrefs__new.mVisInWork=dbox_selecticon(d,glass_PMVISINWORK,Q);
+      gPrefs__new.mCreateTop=dbox_selecticon(d,glass_PMNEWONTOP,Q);
+      gPrefs__new.mDeleteRenum=dbox_selecticon(d,glass_PMRENDEL,Q);
+      gPrefs__new.mCtrlEdit=dbox_selecticon(d,glass_PMCTRLEDIT,Q);
+      break;
+  }
+}
+
+#undef Q
+
+/*
+ * void gPrefs__setPanel(dbox_field f)
+ *
+ * Use
+ *  Creates a new panel based on a radio button click or some-such.
+ *
+ * Parameters
+ *  dbox_field f == the radio button associated with the desired panel
+ */
+
+static void gPrefs__panelHandler(dbox d,dbox_field f,void *handle);
+static BOOL gPrefs__panelRaw(dbox d,wimp_eventstr *e,void *handle);
+
+static void gPrefs__setPanel(dbox_field f)
+{
+  dbox d;
+  wimp_wstate s;
+  wimp_icon i;
+  int width,height;
+  int ox,oy;
+  wimp_w behind;
+  wimp_caretstr c;
+  BOOL ownCaret=TRUE;
+  if (f==gPrefs__currentPanel)
+    return;
+  gPrefs__closePanel();
+  wimpt_noerr(wimp_get_wind_state(dbox_syshandle(gPrefs__dbox),&s));
+  wimpt_noerr(wimp_get_icon_info(dbox_syshandle(gPrefs__dbox),
+                                 glass_PMPOSN,&i));
+  ox=s.o.box.x0-s.o.x;
+  oy=s.o.box.y1-s.o.y;
+  if (d=dbox_create(gPrefs__panels[f-glass_PMAUTOSAVE]),!d)
+    return;
+  dbox_eventHandler(d,gPrefs__panelHandler,0);
+  dbox_rawEventHandler(d,gPrefs__panelRaw,0);
+  if (gPrefs__currentPanel)
+  {
+    wimpt_noerr(wimp_get_caret_pos(&c));
+    ownCaret=(c.w==dbox_syshandle(gPrefs__dbox) ||
+              c.w==dbox_syshandle(gPrefs__panel));
+    dbox_selecticon(gPrefs__dbox,gPrefs__currentPanel,dbox_RESETSTATE);
+    wimpt_noerr(wimp_get_wind_state(dbox_syshandle(gPrefs__panel),&s));
+    pane_removePane(gPrefs__pane,dbox_syshandle(gPrefs__panel));
+    dbox_delete(gPrefs__panel);
+  }
+  dbox_selecticon(gPrefs__dbox,f,dbox_SETSTATE);
+  behind=s.o.behind;
+  wimpt_noerr(wimp_get_wind_state(dbox_syshandle(d),&s));
+  width=s.o.box.x1-s.o.box.x0;
+  height=s.o.box.y1-s.o.box.y0;
+  s.o.box.x0=i.box.x0+ox+wimpt_dx();
+  s.o.box.y0=i.box.y0+oy+wimpt_dy();
+  s.o.box.x1=s.o.box.x0+width;
+  s.o.box.y1=s.o.box.y0+height;
+  s.o.y=10000;
+  s.o.behind=behind;
+  gPrefs__panel=d;
+  gPrefs__currentPanel=f;
+  gPrefs__setupPanel();
+  wimpt_noerr(wimp_open_wind(&s.o));
+  if (ownCaret)
+  {
+    c.w=dbox_syshandle(d);
+    c.i=-1;
+    c.x=-500000;
+    c.y=0;
+    c.height=0x02000000;
+    wimpt_noerr(wimp_set_caret_pos(&c));
+  }
+  pane_addPane(gPrefs__pane,dbox_syshandle(d));
+}
+
+/*----- Event handlers ----------------------------------------------------*/
+
+/*
+ * void gPrefs__dboxHandler(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles any and all events directed at the dbox.  Well, almost all...
+ *
+ * Parameters
+ *  dbox d == the dbox handle (gPrefs__dbox)
+ *  dbox_field f == the event that happened
+ *  void *handle == unused data handle
+ */
+
+static void gPrefs__dboxHandler(dbox d,dbox_field f,void *handle)
+{
+  BOOL redraw=FALSE;
+  int oldTime;
+  BOOL toolbar=FALSE;
+  BOOL adjust;
+  unused(handle);
+  switch (f)
+  {
+    case dbox_CLOSE:
+      if (gPrefs__panel)
+        dbox_deleteNoUpdate(gPrefs__panel);
+      pane_delete(gPrefs__pane);
+      dbox_delete(gPrefs__dbox);
+      gPrefs__dbox=0;
+      gPrefs__currentPanel=0;
+      break;
+    case dbox_HELP:
+      help_startHelp();
+      help_addLine(msgs_lookup("prhPREFS"));
+      help_readFromIcon();
+      help_endHelp();
+      break;
+    case glass_PMCANCEL:
+      dbox_clickicon(d,f);
+      if (!dbox_wasAdjustClick())
+        pane_close(gPrefs__pane);
+      else
+      {
+        gPrefs__new=gPrefs__current;
+        gPrefs__setupPanel();
+      }
+      dbox_unclick();
+      if (!dbox_wasAdjustClick())
+      {
+        dbox_deleteNoUpdate(gPrefs__panel);
+        pane_delete(gPrefs__pane);
+        dbox_delete(gPrefs__dbox);
+        gPrefs__dbox=0;
+        gPrefs__currentPanel=0;
+      }
+      break;
+    case glass_PMOK:
+    case glass_PMSAVE:
+      dbox_clickicon(d,f);
+      adjust=dbox_wasAdjustClick();
+      gPrefs__closePanel();
+      oldTime=gPrefs_autoTiming();
+      if
+      (
+        (gPrefs__new.iDispBorders!=gPrefs__current.iDispBorders) ||
+        (gPrefs__new.iIncBorder!=gPrefs__current.iIncBorder) ||
+        (gPrefs__new.wDispBorders!=gPrefs__current.wDispBorders) ||
+        (gPrefs__new.wIncBorder!=gPrefs__current.wIncBorder) ||
+        (gPrefs__new.sDispBorders!=gPrefs__current.sDispBorders) ||
+        (gPrefs__new.sIncBorder!=gPrefs__current.sIncBorder) ||
+        (gPrefs__new.mDrawHatch!=gPrefs__current.mDrawHatch) ||
+        (gPrefs__new.sBorder!=gPrefs__current.sBorder) ||
+        (gPrefs__new.sDotted!=gPrefs__current.sDotted) ||
+        (gPrefs__new.sEdgeHandles!=gPrefs__current.sEdgeHandles) ||
+        (gPrefs__new.sHandSize!=gPrefs__current.sHandSize) ||
+        (gPrefs__new.sBColour!=gPrefs__current.sBColour) ||
+        (gPrefs__new.sHColour!=gPrefs__current.sHColour) ||
+        (gPrefs__new.sSColour!=gPrefs__current.sSColour) ||
+        (gPrefs__new.gLines!=gPrefs__current.gLines) ||
+        (gPrefs__new.gGridCol!=gPrefs__current.gGridCol) ||
+        (gPrefs__new.gGdeCol!=gPrefs__current.gGdeCol) ||
+        (gPrefs__new.gGdeSelCol!=gPrefs__current.gGdeSelCol)
+      )
+        redraw=TRUE;
+      if
+      (
+        (gPrefs__new.tDisplay!=gPrefs__current.tDisplay) ||
+        (gPrefs__new.tFloating!=gPrefs__current.tFloating) ||
+        (gPrefs__new.iDisplay!=gPrefs__current.iDisplay) ||
+        (gPrefs__new.iFloating!=gPrefs__current.iFloating)
+      )
+        toolbar=TRUE;
+      if (gPrefs__new.aAlts!=gPrefs__current.aAlts)
+        oldTime=-1;
+      gPrefs__current=gPrefs__new;
+      if (redraw)
+        intMsgs_send(glass_REDRAW,0);
+      if (gPrefs_autoTiming()!=oldTime)
+        intMsgs_send(glass_AUTOSAVE,gPrefs_autoTiming());
+      if (toolbar)
+        window_updateToolbar();
+      blinkCursor(gPrefs__current.mBlink);
+      if (f==glass_PMSAVE)
+        prefs_write();
+      if (!adjust)
+        pane_close(gPrefs__pane);
+      dbox_unclick();
+      if (!adjust)
+      {
+        dbox_deleteNoUpdate(gPrefs__panel);
+        pane_delete(gPrefs__pane);
+        dbox_delete(gPrefs__dbox);
+        gPrefs__dbox=0;
+        gPrefs__currentPanel=0;
+      }
+      break;
+    case glass_PMAUTOSAVE:
+    case glass_PMINTERFACE:
+    case glass_PMSPRITES:
+    case glass_PMFILEDISP:
+    case glass_PMGRID:
+    case glass_PMSELECTION:
+    case glass_PMCONFIRM:
+    case glass_PMTOOLINFO:
+    case glass_PMMISC:
+      gPrefs__setPanel(f);
+      break;
+  }
+}
+
+/*
+ * BOOL gPrefs__dboxRaw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles open window requests and things for the main Preferences dbox.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  wimp_eventstr *e == the event that happened
+ *  void *handle == a unused pointer
+ *
+ * Returns
+ *  TRUE if the event has been handled;
+ */
+
+static BOOL gPrefs__dboxRaw(dbox d,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  unused(d);
+  unused(handle);
+  switch (e->e)
+  {
+    case wimp_EOPEN:
+      pane_moved(gPrefs__pane);
+      handled=TRUE;
+      break;
+    case wimp_EKEY:
+      switch (e->data.key.chcode)
+      {
+        case akbd_UpK+akbd_Sh:
+          gPrefs__setPanel(max2(gPrefs__currentPanel-1,glass_PMAUTOSAVE));
+          handled=TRUE;
+          break;
+        case akbd_DownK+akbd_Sh:
+          gPrefs__setPanel(min2(gPrefs__currentPanel+1,glass_PMMISC));
+          handled=TRUE;
+          break;
+      }
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void gPrefs__panelHandler(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles normal dbox-type events for the preferences panel.
+ *
+ * Parameters
+ *  dbox d == the dbox handle for the panel
+ *  dbox_field f == the event type
+ *  void *handle == nothing in particular
+ */
+
+static void gPrefs__panelHandler(dbox d,dbox_field f,void *handle)
+{
+  buttons_simpleArrow ast={1,59,FALSE};
+  buttons_simpleArrow asc={1,999,FALSE};
+  buttons_simpleArrow sa={0,999,FALSE};
+  unused(handle);
+
+  switch (f)
+  {
+    case dbox_CLOSE:
+    case dbox_HELP:
+    case glass_PMOK:
+    case glass_PMCANCEL:
+      gPrefs__dboxHandler(gPrefs__dbox,f,0);
+      return;
+  }
+  switch (gPrefs__currentPanel)
+  {
+    case glass_PMAUTOSAVE:
+      switch (f)
+      {
+        case glass_PATIMED:
+          dbox_shadeicon(d,glass_PATIMEDOWN,dbox_TOGGLESTATE);
+          dbox_shadeicon(d,glass_PATIMEUP,dbox_TOGGLESTATE);
+          dbox_shadeicon(d,glass_PATIMEWRITE,dbox_TOGGLESTATE);
+          dbox_shadeicon(d,glass_PAUNITSDISP,dbox_TOGGLESTATE);
+          dbox_shadeicon(d,glass_PAUNITSMENU,dbox_TOGGLESTATE);
+          break;
+        case glass_PACOUNTED:
+          dbox_shadeicon(d,glass_PACOUNTUP,dbox_TOGGLESTATE);
+          dbox_shadeicon(d,glass_PACOUNTDOWN,dbox_TOGGLESTATE);
+          dbox_shadeicon(d,glass_PACOUNTWRITE,dbox_TOGGLESTATE);
+          break;
+        case glass_PATIMEDOWN:
+          buttons_arrow(d,f,d,glass_PATIMEWRITE,0,-1,&ast);
+          break;
+        case glass_PATIMEUP:
+          buttons_arrow(d,f,d,glass_PATIMEWRITE,0,+1,&ast);
+          break;
+        case glass_PACOUNTDOWN:
+          buttons_arrow(d,f,d,glass_PACOUNTWRITE,0,-1,&asc);
+          break;
+        case glass_PACOUNTUP:
+          buttons_arrow(d,f,d,glass_PACOUNTWRITE,0,+1,&asc);
+          break;
+      }
+      break;
+    case glass_PMINTERFACE:
+      switch (f)
+      {
+        case glass_PIMOUSECLICK:
+          dbox_shadeicon(d,glass_PIMENUCLICK,dbox_TOGGLESTATE);
+          break;
+        case glass_PSMOUSECLICK:
+          dbox_shadeicon(d,glass_PSMENUCLICK,dbox_TOGGLESTATE);
+          break;
+      }
+      break;
+    case glass_PMTOOLINFO:
+      switch (f)
+      {
+        case glass_PTTOOLDISP:
+          dbox_shadeicon(d,glass_PTTOOLFLOAT,dbox_TOGGLESTATE);
+          break;
+        case glass_PTINFODISP:
+          dbox_shadeicon(d,glass_PTINFOFLOAT,dbox_TOGGLESTATE);
+          break;
+      }
+      break;
+    case glass_PMGRID:
+      switch (f)
+      {
+        case glass_PGWUP:
+          buttons_arrow(d,f,d,glass_PGWWRITE,0,+1,&sa);
+          break;
+        case glass_PGWDOWN:
+          buttons_arrow(d,f,d,glass_PGWWRITE,0,-1,&sa);
+          break;
+        case glass_PGHUP:
+          buttons_arrow(d,f,d,glass_PGHWRITE,0,+1,&sa);
+          break;
+        case glass_PGHDOWN:
+          buttons_arrow(d,f,d,glass_PGHWRITE,0,-1,&sa);
+          break;
+      }
+      break;
+    case glass_PMSELECTION:
+      switch (f)
+      {
+        case glass_PSSIZEUP:
+          buttons_arrow(d,f,d,glass_PSSIZEWRITE,0,+1,&sa);
+          break;
+        case glass_PSSIZEDOWN:
+          buttons_arrow(d,f,d,glass_PSSIZEWRITE,0,-1,&sa);
+          break;
+        case glass_PSBORDER:
+          dbox_shadeicon(d,glass_PSDOTTED,dbox_TOGGLESTATE);
+          dbox_shadeicon(d,glass_PSBCOLLABEL,dbox_TOGGLESTATE);
+          dbox_shadeicon(d,glass_PSBCOLOUR,dbox_TOGGLESTATE);
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * menu gPrefs__unitsMaker(void *handle)
+ *
+ * Use
+ *  Generates the units menu for the autosave panel and put a tick in the
+ *  right place.
+ *
+ * Parameters
+ *  void *handle == something pointless.
+ *
+ * Returns
+ *  A pointer to the menu.
+ */
+
+static menu gPrefs__unitsMaker(void *handle)
+{
+  static menu m;
+  unused(handle);
+  if (!m)
+    m=menu_new(msgs_lookup("prUNITT"),
+               msgs_lookup("prUNIT"));
+  menu_setflags(m,glass_PUHOURS,FALSE,FALSE);
+  menu_setflags(m,glass_PUMINUTES,FALSE,FALSE);
+  menu_setflags(m,glass_PUSECONDS,FALSE,FALSE);
+  menu_setflags(m,gPrefs__new.aUnit,TRUE,FALSE);
+  return (m);
+}
+
+/*
+ * void gPrefs__unitsHandler(int hit[],void *handle)
+ *
+ * Use
+ *  Responds to menu clicks on the units menu
+ *
+ * Parameters
+ *  int hit[] == the menu hits
+ *  void *handle == an unused data pointer
+ */
+
+static void gPrefs__unitsHandler(int hit[],void *handle)
+{
+  unused(handle);
+  switch (hit[0])
+  {
+    case glass_PUHOURS:
+    case glass_PUMINUTES:
+    case glass_PUSECONDS:
+      gPrefs__new.aUnit=hit[0];
+      if (gPrefs__currentPanel==glass_PMAUTOSAVE)
+        dbox_setfield(gPrefs__panel,
+                      glass_PAUNITSDISP,
+                      "%s",
+                      msgs_lookup(gPrefs__units[hit[0]]));
+      break;
+  }
+}
+
+/*
+ * void gPrefs__unitsHelp(int hit[],void *handle)
+ *
+ * Use
+ *  Responds to help requests for the units menu
+ *
+ * Parameters
+ *  int hit[] == the menu hits
+ *  void *handle == an unused data pointer
+ */
+
+static void gPrefs__unitsHelp(int hit[],void *handle)
+{
+  unused(handle);
+  help_startHelp();
+  help_readFromMenu("prhmUN",hit);
+  help_endHelp();
+}
+
+/*
+ * void gPrefs__colourHandler(dbox d,dbox_field f,int colour,void *handle)
+ *
+ * Use
+ *  Handles the colour buttons in the Preferences dialogue (all of them)
+ *
+ * Parameters
+ *  dbox d == irrelevant dbox handle
+ *  dbox_field f == which colour button has been prodded
+ *  int colour == what it has been prodded to
+ *  void *handle == a pointer (ignored)
+ */
+
+static void gPrefs__colourHandler(dbox d,
+                                  dbox_field f,
+                                  int colour,
+                                  void *handle)
+{
+  unused(d);
+  unused(handle);
+  switch (gPrefs__currentPanel)
+  {
+    case glass_PMGRID:
+      switch (f)
+      {
+        case glass_PGGRIDCOL:
+          gPrefs__new.gGridCol=colour;
+          break;
+        case glass_PGGUIDECOL:
+          gPrefs__new.gGdeCol=colour;
+          break;
+        case glass_PGGDESELCOL:
+          gPrefs__new.gGdeSelCol=colour;
+          break;
+      }
+      break;
+    case glass_PMSELECTION:
+      switch (f)
+      {
+        case glass_PSBCOLOUR:
+          gPrefs__new.sBColour=colour;
+          break;
+        case glass_PSHCOLOUR:
+          gPrefs__new.sHColour=colour;
+          break;
+        case glass_PSSCOLOUR:
+          gPrefs__new.sSColour=colour;
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * BOOL gPrefs__panelRaw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles more unusual events concerned with dialogue boxes.
+ *
+ * Parameters
+ *  dbox d == the panel's handle
+ *  wimp_eventstr *e == the full event
+ *  void *handle == an unused handle
+ *
+ * Returns
+ *  TRUE if the event has been handled
+ */
+
+static BOOL gPrefs__panelRaw(dbox d,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  BOOL cursor=FALSE;
+  unused(handle);
+  if (e->e==wimp_EKEY)
+  {
+    switch (e->data.key.chcode)
+    {
+      case akbd_UpK+akbd_Sh:
+        gPrefs__setPanel(max2(gPrefs__currentPanel-1,glass_PMAUTOSAVE));
+        handled=TRUE;
+        break;
+      case akbd_DownK+akbd_Sh:
+        gPrefs__setPanel(min2(gPrefs__currentPanel+1,glass_PMMISC));
+        handled=TRUE;
+        break;
+    }
+  }
+  if (!handled) switch (gPrefs__currentPanel)
+  {
+    case glass_PMAUTOSAVE:
+      switch (e->e)
+      {
+        case wimp_EBUT:
+          switch (e->data.but.m.i)
+          {
+            case glass_PAUNITSDISP:
+              menu_make(gPrefs__unitsMaker,
+                        gPrefs__unitsHandler,
+                        gPrefs__unitsHelp,0);
+              break;
+            case glass_PAUNITSMENU:
+              dbox_clickicon(d,glass_PAUNITSMENU);
+              menu_make(gPrefs__unitsMaker,
+                        gPrefs__unitsHandler,
+                        gPrefs__unitsHelp,0);
+              dbox_unclick();
+              break;
+          }
+          break;
+        case wimp_EKEY:
+          switch (e->data.key.c.i)
+          {
+            case glass_PATIMEWRITE:
+              switch (e->data.key.chcode)
+              {
+                case akbd_DownK:
+                case akbd_UpK:
+                case akbd_TabK:
+                case akbd_TabK+akbd_Sh:
+                case akbd_UpK+akbd_Ctl:
+                case akbd_DownK+akbd_Ctl:
+                  cursor=TRUE;
+                  break;
+              }
+              handled=buttons_insertChar(d,e->data.key.chcode,'0','9');
+              if (handled || cursor)
+                buttons_arrowClick(d,glass_PATIMEWRITE,1,59,0,FALSE);
+              break;
+            case glass_PACOUNTWRITE:
+              switch (e->data.key.chcode)
+              {
+                case akbd_DownK:
+                case akbd_UpK:
+                case akbd_TabK:
+                case akbd_TabK+akbd_Sh:
+                case akbd_UpK+akbd_Ctl:
+                case akbd_DownK+akbd_Ctl:
+                  cursor=TRUE;
+                  break;
+              }
+              handled=buttons_insertChar(d,e->data.key.chcode,'0','9');
+              if (handled || cursor)
+                buttons_arrowClick(d,glass_PACOUNTWRITE,1,999,0,FALSE);
+              break;
+          }
+          break;
+      }
+      break;
+    case glass_PMGRID:
+      switch (e->e)
+      {
+        case wimp_EBUT:
+          switch (e->data.but.m.i)
+          {
+            case glass_PGGRIDCOL:
+              colSelect(d,
+                        e->data.but.m.i,
+                        e->data.but.m.bbits,
+                        msgs_lookup("prGCOL"),
+                        FALSE,
+                        gPrefs__colourHandler,
+                        0);
+              handled=TRUE;
+              break;
+            case glass_PGGUIDECOL:
+              colSelect(d,
+                        e->data.but.m.i,
+                        e->data.but.m.bbits,
+                        msgs_lookup("prGDCOL"),
+                        FALSE,
+                        gPrefs__colourHandler,
+                        0);
+              handled=TRUE;
+              break;
+            case glass_PGGDESELCOL:
+              colSelect(d,
+                        e->data.but.m.i,
+                        e->data.but.m.bbits,
+                        msgs_lookup("prSGDCOL"),
+                        FALSE,
+                        gPrefs__colourHandler,
+                        0);
+              handled=TRUE;
+              break;
+          }
+          break;
+      }
+      break;
+    case glass_PMSELECTION:
+      switch (e->e)
+      {
+        case wimp_EBUT:
+          switch (e->data.but.m.i)
+          {
+            case glass_PSBCOLOUR:
+              colSelect(d,
+                        e->data.but.m.i,
+                        e->data.but.m.bbits,
+                        msgs_lookup("prSBCOL"),
+                        FALSE,
+                        gPrefs__colourHandler,
+                        0);
+              handled=TRUE;
+              break;
+            case glass_PSHCOLOUR:
+              colSelect(d,
+                        e->data.but.m.i,
+                        e->data.but.m.bbits,
+                        msgs_lookup("prSHCOL"),
+                        FALSE,
+                        gPrefs__colourHandler,
+                        0);
+              handled=TRUE;
+              break;
+            case glass_PSSCOLOUR:
+              colSelect(d,
+                        e->data.but.m.i,
+                        e->data.but.m.bbits,
+                        msgs_lookup("prSSCOL"),
+                        FALSE,
+                        gPrefs__colourHandler,
+                        0);
+              handled=TRUE;
+              break;
+          }
+          break;
+      }
+      break;
+  }
+  return (handled);
+}
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void gPrefs_init(void)
+ *
+ * Use
+ *  Reads preferences file and initialises things accordingly
+ */
+
+void gPrefs_init(void)
+{
+  prefs_preferences(gPrefs__prefs);
+  prefs_read();
+  blink_init();
+  blinkCursor(gPrefs__current.mBlink);
+}
+
+/*
+ * gPrefs_prefs *gPrefs_current(void)
+ *
+ * Use
+ *  Returns the current preferences settings.
+ *
+ * Returns
+ *  A pointer to the structure as defined above.
+ */
+
+gPrefs_prefs *gPrefs_current(void)
+{
+  return (&gPrefs__current);
+}
+
+/*
+ * int gPrefs_autoTiming(void)
+ *
+ * Use
+ *  Returns the current autosave time in centiseconds, or 0 for no timed
+ *  autosave.
+ */
+
+int gPrefs_autoTiming(void)
+{
+  static int mult[]={0,360000,6000,100};
+  return (gPrefs__current.aTime*mult[gPrefs__current.aUnit]);
+}
+
+/*
+ * void gPrefs_edit(void)
+ *
+ * Use
+ *  Opens the preferences dialogue box to allow editing of preferences.
+ */
+
+void gPrefs_edit(void)
+{
+  if (gPrefs__dbox)
+  {
+    dbox_display(gPrefs__dbox,dbox_STATIC_LASTPOS);
+    pane_front(gPrefs__pane);
+  }
+  else
+  {
+    if (gPrefs__dbox=dbox_create("preferences"),!gPrefs__dbox)
+      return;
+    else if (gPrefs__pane=pane_create(dbox_syshandle(gPrefs__dbox)),
+                                       !gPrefs__pane)
+    {
+      dbox_delete(gPrefs__dbox);
+      gPrefs__dbox=0;
+      return;
+    }
+    gPrefs__new=gPrefs__current;
+    dbox_eventHandler(gPrefs__dbox,gPrefs__dboxHandler,0);
+    dbox_rawEventHandler(gPrefs__dbox,gPrefs__dboxRaw,0);
+    dbox_display(gPrefs__dbox,dbox_STATIC_LASTPOS);
+    gPrefs__setPanel(glass_PMAUTOSAVE);
+  }
+}
diff --git a/StraySrc/Glass/!Glass/c/gSprite b/StraySrc/Glass/!Glass/c/gSprite
new file mode 100644 (file)
index 0000000..29c31e5
--- /dev/null
@@ -0,0 +1,1786 @@
+/*
+ * gSprite.c
+ *
+ * Handling of template file sprite windows and areas
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _XFER
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/viewer.h"
+#include "steel/flex.h"
+#include "steel/akbd.h"
+#include "steel/bbc.h"
+#include "steel/choices.h"
+#include "steel/colourtran.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "intMsgs.h"
+#include "gSprite.h"
+#include "gPrefs.h"
+#include "indir.h"
+#include "window.h"
+#include "tfile.h"
+
+/*----- Macros ------------------------------------------------------------*/
+
+#define gSprite__FILEHEIGHT 872 /* Height to open first sprite window     */
+#define gSprite__FILEX 220      /* x position of sprite windows           */
+#define gSprite__FILETOP 920    /* Height after files wrap around         */
+#define gSprite__CHUNK 2048     /* Size in bytes to allocate areas by     */
+#define gSprite__WINDHEIGHT 852 /* Height for individual sprite window    */
+#define gSprite__WINDX 240      /* x position of individual sprite window */
+#define gSprite__WINDTOP 900    /* Height after wrap around               */
+#define gSprite__WINDMINX 340   /* Minimum width of a sprite window       */
+#define gSprite__WINDMINY 150   /* Minimum height of a sprite window      */
+#define gSprite__BOXX 200       /* Size of the box for sprite display (x) */
+#define gSprite__BOXY 148       /* Size of the box for sprite display (y) */
+
+/*----- Type definitions --------------------------------------------------*/
+
+typedef struct
+{
+  glass_tfile *t;                /* Template file owner                    */
+  int serial;                    /* Order the icons were created in        */
+  char name[15];                 /* Name of the sprite                     */
+  viewer_icon i;                 /* My viewer icon                         */
+  wimp_w w;                      /* My window handle                       */
+}
+gSprite__data;
+
+/*----- Static variables --------------------------------------------------*/
+
+static int gSprite__fileHeight=gSprite__FILEHEIGHT;
+                                 /* Height to open next sprite window      */
+static int gSprite__windHeight=gSprite__WINDHEIGHT;
+
+static int gSprite__size;       /* Count up sprite sizes                   */
+static void **gSprite__flex;    /* The flex block for saving selections    */
+static sprite_area *gSprite__default;   /* Default sprite file             */
+static int gSprite__serial;     /* Monotonic time counter                  */
+static glass_tfile *gSprite__selOwner; /* Which window owns selection?     */
+
+/*----- Support routines --------------------------------------------------*/
+
+/*
+ * BOOL gSprite__getMemory(glass_tfile *t,int size)
+ *
+ * Use
+ *  Ensures that the specified quantity of memory is available in the sprite
+ *  area given.  If the memory is not there, it is allocated and the pointer
+ *  is placed in the appropriate place.  Messages are sent round as
+ *  applicable.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file to alllcate memory in
+ *  int size == the quantity of memory required to add to the area
+ *
+ * Returns
+ *  TRUE if the operation succeeded, or FALSE for not enough memory available
+ */
+
+static BOOL gSprite__getMemory(glass_tfile *t,int size)
+{
+  int aligned;
+  sprite_area *s;
+  if (t->s->freeoff+size<t->s->size) /* Check that the memory is there     */
+    return (TRUE);
+  aligned=(t->s->freeoff+size+gSprite__CHUNK-1) & ~(gSprite__CHUNK-1);
+                                 /* Qunatise by the chunk size             */
+  if (s=indir_realloc(t->s,aligned),!s) /* Allocate memory required        */
+    return (FALSE);              /* Say we failed if we did                */
+  s->size=aligned;               /* Insert the new sprite area size        */
+  t->s=s;                        /* And change the pointers to the new one */
+  return (TRUE);
+}
+
+/*
+ * void gSprite__minimise(glass_tfile *t)
+ *
+ * Use
+ *  Attempts to minimise the space taken up by template file t's sprite area
+ *  if wasteful operations took upn too much memory, or sprites have been
+ *  deleted.  Ironically, this requires memory...  However, failure to
+ *  allocate sufficient memory is ignored.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file to minimise
+ */
+
+static void gSprite__minimise(glass_tfile *t)
+{
+  sprite_area *s;
+  int aligned=(t->s->freeoff+gSprite__CHUNK-1) & ~(gSprite__CHUNK-1);
+                                 /* Get the size the area should be        */
+  if (t->s->size==aligned)
+    return;
+  if (s=indir_realloc(t->s,aligned),!s)
+    return;
+  s->size=aligned;
+  t->s=s;
+}
+
+/*
+ * int gSprite__compare(void *a,void *b)
+ *
+ * Use
+ *  Compares creation times of two icons
+ *
+ * Parameters
+ *  both pointers to data attached to icons
+ */
+
+static int gSprite__compare(void *a,void *b)
+{
+  gSprite__data *x=a;
+  gSprite__data *y=b;
+  return (x->serial-y->serial);
+}
+
+/*
+ * void gSprite__gainSelection(glass_tfile *t)
+ *
+ * Use
+ *  Hands the current sprite selection and the input focus to the specified
+ *  template file sprite viewer.
+ *
+ *  Note that the selection model here is more complex than it is in window,
+ *  since the focus tfile may not coincide with the selection owner (since
+ *  menu clicks move the selection owner, but not the focus).
+ *
+ * Parameters
+ *  glass_tfile *t == the sprite viewer to which we give the selection
+ */
+
+static void gSprite__gainSelection(glass_tfile *t)
+{
+  wimp_caretstr c;
+  if (t!=gSprite__selOwner)
+  {
+    if (gSprite__selOwner)
+      viewer_selectAll(gSprite__selOwner->vs,FALSE);
+    gSprite__selOwner=t;
+  }
+  if (t)
+  {
+    c.w=viewer_syshandle(t->vs);
+    c.i=-1;
+    c.x=-250;
+    c.y=0;
+    c.index=-1;
+    c.height=0x02000000;
+    wimpt_noerr(wimp_set_caret_pos(&c));
+  }
+}
+
+/*
+ * void gSprite__closeWindows(void *handle)
+ *
+ * Use
+ *  Destroys any windows open when the template file dies
+ *
+ * Parameters
+ *  void *handle == pointer to window data
+ */
+
+static void gSprite__closeWindows(void *handle)
+{
+  gSprite__data *d=handle;
+  if (d->w)
+  {
+    win_register_event_handler(d->w,0,0);
+    wimpt_noerr(wimp_delete_wind(d->w));
+    win_activedec();
+  }
+  mem_free(d);
+}
+
+/*
+ * void gSprite__sizes(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Adds the size of the given sprite to the total in gSprite__size.
+ *
+ * Parameters
+ *  viewer_icon i == the icon number of the sprite (ignored)
+ *  void *handle == pointer to sprite data
+ */
+
+static void gSprite__sizes(viewer_icon i,void *handle)
+{
+  sprite_id sid;
+  sprite_header *hdr;
+  gSprite__data *d=handle;
+  unused(i);
+  sid.s.name=d->name;
+  sid.tag=0;
+  wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
+  gSprite__size+=hdr->next;
+}
+
+/*
+ * char *gSprite__lower(char *s)
+ *
+ * Use
+ *  Translates the string given to lower case
+ *
+ * Parameters
+ *  char *s == the string to convert
+ *
+ * Returns
+ *  A pointer to the string
+ */
+
+static char *gSprite__lower(char *s)
+{
+  char *p=s;
+  while (*p)
+  {
+    *p=tolower(*p);
+    p++;
+  }
+  return (s);
+}
+
+/*
+ * BOOL gSprite__saveArea(void *handle,char *filename)
+ *
+ * Use
+ *  Saves a sprite area to disk
+ *
+ * Parameters
+ *  char *filename == the filename to save to
+ *  void *handle == pointer to owning template file
+ *
+ * Returns
+ *  TRUE for success
+ */
+
+static BOOL gSprite__saveArea(char *filename,void *handle)
+{
+  glass_tfile *t=handle;
+  if (gPrefs_current()->cSave &&
+      saveas_file_is_safe() &&
+      res_fileExists(filename))
+  {
+    if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename))
+      return (FALSE);
+  }
+  if (utils_complain(sprite_area_save(t->s,filename),msgs_lookup("spESS")))
+    return (FALSE);
+  else
+    return (TRUE);
+}
+
+/*
+ * BOOL gSprite__sendArea(void *handle,int *maxbuf)
+ *
+ * Use
+ *  Sends a sprite area via RAM transfer
+ *
+ * Parameters
+ *  void *handle == pointer to owning template file
+ *  int *maxbuf == pointer to buffer size of other application
+ */
+
+static BOOL gSprite__sendArea(void *handle,int *maxbuf)
+{
+  glass_tfile *t=handle;
+  return (xfersend_sendBlock(&t->s->number,t->s->freeoff-4,maxbuf));
+}
+
+/*
+ * void gSprite__addToSelSave(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Adds the given sprite to the sprite area held in gSprite__flex
+ *
+ * Parameters
+ *  viewer_icon i == the icon number of the sprite to add (ignored)
+ *  void *handle == pointer to sprite data
+ */
+
+static void gSprite__addToSelSave(viewer_icon i,void *handle)
+{
+  gSprite__data *d=handle;
+  sprite_header *hdr;
+  sprite_id sid;
+  void *p=charptr(*gSprite__flex,0)+
+          _ptr(sprite_area,*gSprite__flex,0)->freeoff;
+  unused(i);
+  sid.s.name=d->name;
+  sid.tag=0;
+  wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
+  memcpy(p,hdr,hdr->next);
+  _ptr(sprite_area,*gSprite__flex,0)->freeoff+=hdr->next;
+}
+
+/*
+ * BOOL gSprite__setupSelSave(glass_tfile *t,void **p)
+ *
+ * Use
+ *  Sets up a sprite area to save in a flex block anchored on p.  The flex
+ *  block is allocaed here.  The caller must free the block itself.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file owning the selection
+ *  void **p == pointer to a flex anchor
+ *
+ * Returns
+ *  TRUE if successful
+ */
+
+static BOOL gSprite__setupSelSave(glass_tfile *t,void **p)
+{
+  if (!flex_alloc(p,gSprite__size+16))
+  {
+    werr(FALSE,msgs_lookup("spNEMSLSV"));
+    return (FALSE);
+  }
+  gSprite__flex=p;
+  _ptr(sprite_area,*p,0)->size=gSprite__size+16;
+  _ptr(sprite_area,*p,0)->number=viewer_selected(t->vs);
+  _ptr(sprite_area,*p,0)->freeoff=16;
+  _ptr(sprite_area,*p,0)->sproff=16;
+  viewer_doForIcons(t->vs,TRUE,gSprite__addToSelSave);
+  return (TRUE);
+}
+
+/*
+ * BOOL gSprite__saveSelection(char *filename,void *handle)
+ *
+ * Use
+ *  Saves a selection of sprite to a file
+ *
+ * Parameters
+ *  char *filename == the file to save to
+ *  void *handle == pointer to the owning template file
+ *
+ * Returns
+ *  TRUE for success
+ */
+
+static BOOL gSprite__saveSelection(char *filename,void *handle)
+{
+  glass_tfile *t=handle;
+  void *p;
+  if (gPrefs_current()->cSave &&
+      saveas_file_is_safe() &&
+      res_fileExists(filename))
+  {
+    if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename))
+      return (FALSE);
+  }
+  if (!gSprite__setupSelSave(t,&p))
+    return (FALSE);
+  if (utils_complain(sprite_area_save((sprite_area *)p,filename),
+                     msgs_lookup("spESS")))
+  {
+    flex_free(&p);
+    return (FALSE);
+  }
+  else
+  {
+    flex_free(&p);
+    return (TRUE);
+  }
+}
+
+/*
+ * BOOL gSprite__sendSelection(void *handle,int *maxbuf)
+ *
+ * Use
+ *  Sends a selection of sprite to another application in memory
+ *
+ * Parameters
+ *  void *handle == pointer to the owning template file
+ *  int *maxbuf == the size of the receiving application's buffer
+ *
+ * Returns
+ *  TRUE for success
+ */
+
+static BOOL gSprite__sendSelection(void *handle,int *maxbuf)
+{
+  glass_tfile *t=handle;
+  void *p;
+  if (!gSprite__setupSelSave(t,&p))
+    return (FALSE);
+  if (!xfersend_sendBlock((char *)p+4,gSprite__size+12,maxbuf))
+  {
+    flex_free(&p);
+    return (FALSE);
+  }
+  else
+  {
+    flex_free(&p);
+    return (TRUE);
+  }
+}
+
+/*
+ * BOOL gSprite__saveGrabbed(void *handle,char *filename)
+ *
+ * Use
+ *  Saves a sprite area to disk
+ *
+ * Parameters
+ *  char *filename == the filename to save to
+ *  void *handle == pointer-to-pointer to sprite area
+ *
+ * Returns
+ *  TRUE for success
+ */
+
+static BOOL gSprite__saveGrabbed(char *filename,void *handle)
+{
+  sprite_area **s=handle;
+  if (gPrefs_current()->cSave &&
+      saveas_file_is_safe() &&
+      res_fileExists(filename))
+  {
+    if (!warning(msgs_lookup("spSOFP"),msgs_lookup("spSOF"),filename))
+      return (FALSE);
+  }
+  if (utils_complain(sprite_area_save(*s,filename),msgs_lookup("spESS")))
+    return (FALSE);
+  else
+    return (TRUE);
+}
+
+/*
+ * BOOL gSprite__sendGrabbed(void *handle,int *maxbuf)
+ *
+ * Use
+ *  Sends a sprite area via RAM transfer
+ *
+ * Parameters
+ *  void *handle == pointer-to-pointer to sprite area
+ *  int *maxbuf == pointer to buffer size of other application
+ */
+
+static BOOL gSprite__sendGrabbed(void *handle,int *maxbuf)
+{
+  sprite_area **s=handle;
+  return (xfersend_sendBlock(&(*s)->number,(*s)->freeoff-4,maxbuf));
+}
+
+/*
+ * void gSprite__grab(wimp_mousestr *m,void *handle)
+ *
+ * Use
+ *  Grabs a sprite area from a given window
+ *
+ * Parameters
+ *  wimp_mousestr *m == info about the window/icon the pointer is over
+ *  void *handle ==  a pointer (ignored)
+ */
+
+static void gSprite__grab(wimp_mousestr *m,void *handle)
+{
+  wimp_winfo *w;
+  os_regset r;
+  void *p;
+  void *q;
+  sprite_area s;
+  wimp_msgstr msg;
+  unused(handle);
+  switch (m->w)
+  {
+    case -1:
+    case -2:
+      werr(FALSE,msgs_lookup("spCGS"));
+      return;
+  }
+  if (wimpt_getVersion()>=300)   /* RISC OS 3 allows 'safe' GetWindowInfos */
+    w=mem_alloc(sizeof(wimp_winfo));
+  else
+    w=mem_alloc(sizeof(wimp_winfo)+200*sizeof(wimp_icon));
+  if (!w)
+  {
+    werr(FALSE,msgs_lookup("spNEMGS"));
+    return;
+  }
+  w->w=m->w;
+  r.r[1]=(int)w;
+  if (wimpt_getVersion()>=300)
+    r.r[1]+=1;                   /* RO3 - only window header, not icons    */
+  wimpt_noerr(os_swix(XWimp_GetWindowInfo,&r)); /* Get the information     */
+  q=w->info.spritearea;          /* Get the window's sprite area           */
+  mem_free(w);                   /* No longer needed                       */
+  if ((int)q<0x8000)
+  {
+    note(msgs_lookup("spNAUSA"));
+    return;
+  }
+  else if ((int)q>=0x01800000)
+  {
+    saveas(msgs_lookup("spSVSPR"),
+           msgs_lookup("spGRB"),
+           0xff9,
+           s.freeoff,
+           gSprite__saveGrabbed,
+           gSprite__sendGrabbed,
+           0,
+           &q);
+  }
+  else
+  {
+    msg.hdr.size=20;
+    msg.hdr.your_ref=0;
+    r.r[0]=19;
+    r.r[1]=(int)&msg;
+    r.r[2]=m->w;
+    r.r[3]=m->i;
+    wimpt_noerr(os_swix(XWimp_SendMessage,&r)); /* Find the task's handle  */
+    wimpt_noerr(wimp_transferblock(r.r[2],
+                                   q,
+                                   wimpt_task(),
+                                   (char *)&s,
+                                   sizeof(sprite_area)));
+    if (!flex_alloc(&p,s.freeoff))
+    {
+      werr(FALSE,msgs_lookup("spNEMGS"));
+      return;
+    }
+    wimpt_noerr(wimp_transferblock(r.r[2],q,wimpt_task(),p,s.freeoff));
+    saveas(msgs_lookup("spSVSPR"),
+           msgs_lookup("spGRB"),
+           0xff9,
+           s.freeoff,
+           gSprite__saveGrabbed,
+           gSprite__sendGrabbed,
+           0,
+           &p);
+    flex_free(&p);
+  }
+}
+
+/*
+ * BOOL gSprite__copy(char *buff,void *handle)
+ *
+ * Use
+ *  Copies a sprite, ensuring that the name hasn't been duplicated etc.
+ *
+ * Parameters
+ *  char *buff == pointer to the new name
+ *  void *handle == pointer to data for the sprite
+ *
+ * Returns
+ *  TRUE if everything went OK
+ */
+
+static BOOL gSprite__copy(char *buff,void *handle)
+{
+  gSprite__data *d=handle;
+  gSprite__data *new;
+  sprite_id sid;
+  sprite_header *hdr;
+  viewer_icon i=viewer_findIcon(d->t->vs,buff);
+  sid.s.name=d->name;
+  sid.tag=0;
+  gSprite__lower(buff);
+  if (i==viewer_NOICON || i==d->i)
+  {
+    mem_useUser(indir_alloc,indir_free);
+    if (new=mem_alloc(sizeof(gSprite__data)),!new)
+    {
+      werr(FALSE,msgs_lookup("spNEMCPY"));
+      mem_useMalloc();
+      return (FALSE);
+    }
+    wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
+    if (!gSprite__getMemory(d->t,hdr->next+50))
+    {
+      mem_free(new);
+      mem_useMalloc();
+      werr(FALSE,msgs_lookup("spNEMCPY"));
+      return (FALSE);
+    }
+    wimpt_noerr(sprite_copy(d->t->s,&sid,buff));
+    gSprite__minimise(d->t);
+    strcpy(new->name,buff);
+    new->serial=gSprite__serial++;
+    new->i=viewer_addIcon(d->t->vs,buff,buff,TRUE,new);
+    viewer_setFiletype(new->i,0xff9);
+    mem_useMalloc();
+    new->w=0;
+    new->t=d->t;
+    if (!dbox_wasAdjustClick())
+      viewer_clickSelect(d->t->vs,viewer_NOICON,wimp_BMID);
+    intMsgs_send(glass_SPRITECHANGE,d->t);
+    return (TRUE);
+  }
+  note(msgs_lookup("spNAE"),
+       viewer_textOfIcon(i));
+  return (FALSE);
+
+}
+
+/*
+ * BOOL gSprite__rename(char *buff,void *handle)
+ *
+ * Use
+ *  Renames a sprite, ensuring that the name hasn't been duplicated etc.
+ *
+ * Parameters
+ *  char *buff == pointer to the new name
+ *  void *handle == pointer to data for the sprite
+ *
+ * Returns
+ *  TRUE if everything went OK
+ */
+
+static BOOL gSprite__rename(char *buff,void *handle)
+{
+  gSprite__data *d=handle;
+  sprite_id sid;
+  viewer_icon i=viewer_findIcon(d->t->vs,buff);
+  sid.s.name=d->name;
+  sid.tag=0;
+  gSprite__lower(buff);
+  if (i==viewer_NOICON || i==d->i)
+  {
+    mem_useUser(indir_alloc,indir_free);
+    i=viewer_addIcon(d->t->vs,buff,buff,TRUE,d);
+    mem_useMalloc();
+    if (!i)
+      return (FALSE);
+    viewer_setFiletype(i,0xff9);
+    wimpt_noerr(sprite_rename(d->t->s,&sid,buff));
+    viewer_removeIcon(d->i);
+    d->i=i;
+    strcpy(d->name,buff);
+    intMsgs_send(glass_SPRITECHANGE,d->t);
+    if (!dbox_wasAdjustClick())
+      viewer_clickSelect(d->t->vs,viewer_NOICON,wimp_BMID);
+    event_clear_current_menu();
+    return (TRUE);
+  }
+  note(msgs_lookup("spNAE"),
+       viewer_textOfIcon(i));
+  return (FALSE);
+}
+
+/*
+ * void gSprite__delSprites(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Deletes the given sprite.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle that it is
+ *  void *handle == the sprite data pointer
+ */
+
+static void gSprite__delSprites(viewer_icon i,void *handle)
+{
+  sprite_id sid;
+  gSprite__data *d=handle;
+  unused(i);
+  sid.s.name=d->name;
+  sid.tag=0;
+  wimpt_noerr(sprite_delete(d->t->s,&sid));
+  viewer_removeIcon(d->i);
+  if (d->w)
+  {
+    win_register_event_handler(d->w,0,0);
+    win_activedec();
+    wimpt_noerr(wimp_delete_wind(d->w));
+  }
+  mem_free(d);
+}
+
+/*
+ * void gSprite__createWindow(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Opens a window to display a given sprite.
+ *
+ * Parameters
+ *  viewer_icon i == the icon representing the sprite
+ *  void *handle == the information to add to the window
+ */
+
+static void gSprite__windowHandler(wimp_eventstr *e,void *handle);
+
+static void gSprite__createWindow(viewer_icon i,void *handle)
+{
+  wimp_wstate s;
+  gSprite__data *d=handle;
+  wimp_wind w=
+  {
+    0,0,0,0, 0,0, -1,
+    wimp_WMOVEABLE |
+      wimp_WNEW |
+      wimp_WTITLE |
+      wimp_WTOGGLE |
+      wimp_WVSCR |
+      wimp_WHSCR |
+      wimp_WSIZE |
+      wimp_WBACK |
+      wimp_WQUIT,
+    7,2,7,1,3,1,12,0,
+    0,0,gSprite__WINDMINX,gSprite__WINDMINY,
+    wimp_ITEXT | wimp_IHCENTRE,
+    0,
+    0,
+    0x00010001,
+    "",
+    0,
+  };
+  sprite_id sid;
+  sprite_info info;
+  unused(i);
+  if (!d->w)
+  {
+    strcpy(w.title.text,d->name);
+    sid.s.name=d->name;
+    sid.tag=0;
+    wimpt_noerr(sprite_readsize(d->t->s,&sid,&info));
+    info.width <<= bbc_modevar(info.mode,bbc_XEigFactor);
+    info.height <<= bbc_modevar(info.mode,bbc_YEigFactor);
+    if (info.width>gSprite__WINDMINX)
+      w.ex.x1=info.width;
+    if (info.height>gSprite__WINDMINY)
+      w.ex.y1=info.height;
+    w.box.x0=gSprite__WINDX;
+    w.box.x1=gSprite__WINDX+w.ex.x1;
+    w.box.y1=gSprite__windHeight;
+    w.box.y0=gSprite__windHeight-w.ex.y1;
+    if (w.ex.x1>500)
+      w.box.x1=gSprite__WINDX+500;
+    if (w.ex.y1>500)
+      w.box.y0=gSprite__windHeight-500;
+    if (wimpt_complain(wimp_create_wind(&w,&d->w)))
+      return;
+    win_register_event_handler(d->w,gSprite__windowHandler,d);
+    win_activeinc();
+    gSprite__windHeight-=48;
+    if (gSprite__windHeight<612)
+      gSprite__windHeight=gSprite__WINDTOP;
+  }
+  wimpt_noerr(wimp_get_wind_state(d->w,&s));
+  wimpt_noerr(wimp_open_wind(&s.o));
+}
+
+/*----- Event handlers ----------------------------------------------------*/
+
+/*
+ * BOOL tfile__dragUnknowns(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles unknown events during the period of dragging viewer icons
+ *  around.  It will respond to the following drags:
+ *
+ *  A drag to a blank area of icon bar will open the windows.
+ *
+ *  Otherwise, a selection save will be started, and the windows packaged
+ *  off to another application.
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event to look at
+ *  void *handle == the template file whose sprite area we're dragging from
+ *
+ * Returns
+ *  TRUE if the drag has been processed
+ */
+
+static BOOL gSprite__dragUnknowns(wimp_eventstr *e,void *handle)
+{
+  glass_tfile *t=handle;
+  wimp_mousestr m;
+  BOOL handled=FALSE;
+  switch (e->e)
+  {
+    case wimp_EUSERDRAG:
+      handled=TRUE;
+      win_remove_unknown_event_processor(gSprite__dragUnknowns,t);
+      wimpt_noerr(wimp_get_point_info(&m));
+      if (m.w==viewer_syshandle(t->vs))
+        break;
+      if (m.w==-2 && m.i==-1)
+        viewer_doForIcons(t->vs,TRUE,gSprite__createWindow);
+      else
+      {
+          gSprite__size=0;
+          viewer_doForIcons(t->vs,TRUE,gSprite__sizes);
+          wimpt_fake_event(e);          /* Fool xfersend to send data      */
+          xfersend(0xFF9,
+                   msgs_lookup("spSEL"),
+                   gSprite__size+16,
+                   gSprite__saveSelection,
+                   gSprite__sendSelection,
+                   0,
+                   e,
+                   t);
+      }
+      viewer_selectAll(t->vs,FALSE);
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void gSprite__viewerRedraw(viewer_icon i,
+ *                             wimp_redrawstr *r,
+ *                             wimp_box *box,
+ *                             char *text,
+ *                             char *sprite,
+ *                             BOOL selected,
+ *                             void *handle)
+ *
+ * Use
+ *  Redraws an icon in the sprite viewer.
+ *
+ * Parameters
+ *  viewer_icon i == the icon I'm redrawing
+ *  wimp_redrawstr *r == the redraw structure
+ *  wimp_box *box == the box to fit it in
+ *  char *text == the text to draw
+ *  char *sprite == the sprite to draw (ignored)
+ *  BOOL selected == whether the icon is selected
+ *  void *handle == pointer to the template file
+ */
+
+static void gSprite__viewerRedraw(viewer_icon i,
+                                   wimp_redrawstr *r,
+                                   wimp_box *box,
+                                   char *text,
+                                   char *sprite,
+                                   BOOL selected,
+                                   void *handle)
+{
+  int ox=r->box.x0-r->scx;
+  int oy=r->box.y1-r->scy;
+  sprite_id sid;
+  sprite_header *hdr;
+  sprite_pixtrans colbuff[256];  /* Colour translation table               */
+  sprite_factors zoom;           /* Zoomage table                          */
+  sprite_info info;              /* Info about the sprite                  */
+  glass_tfile *t=handle;
+  int newy;                      /* Bodged height of the sprite            */
+  int xoff,yoff;                 /* x and y offsets to display sprite      */
+  wimp_icon spname;              /* Virtual icon for sprite name           */
+  unused(i);
+  unused(sprite);
+
+  spname.box.x0=box->x0;
+  spname.box.x1=box->x1;
+  spname.box.y0=box->y0;
+  spname.box.y1=box->y0+40;
+  spname.flags=0x1700010b+(selected<<21);
+  spname.data.indirecttext.buffer=text;
+  spname.data.indirecttext.validstring="Sblank";
+  wimpt_noerr(wimp_ploticon(&spname));
+
+  sid.s.name=text;
+  sid.tag=0;
+  wimpt_noerr(sprite_select_rp(t->s,&sid,(sprite_ptr *)&hdr));
+  sid.s.addr=hdr;
+  sid.tag=sprite_id_addr;
+  wimpt_noerr(sprite_readsize(t->s,&sid,&info));
+  if (bbc_modevar(info.mode,bbc_NColour)==63) /* 256 colour mode - handle  */
+    colourtran_select_table(info.mode,0,-1,(wimp_paletteword *)-1,colbuff);
+  else
+    wimpt_noerr(wimp_readpixtrans(t->s,&sid,&zoom,colbuff));
+  zoom.xmag=zoom.ymag=zoom.xdiv=zoom.ydiv=1;
+  info.width <<= bbc_modevar(info.mode,bbc_XEigFactor); /* Now OS units    */
+  info.height <<= bbc_modevar(info.mode,bbc_YEigFactor);
+
+  /* --- Bodge the multipliers to fit the sprite in --- */
+
+  newy=info.height;
+  if (info.width>gSprite__BOXX)
+  {
+    zoom.xmag*=gSprite__BOXX;
+    zoom.ymag*=gSprite__BOXX;
+    zoom.xdiv*=info.width;
+    zoom.ydiv*=info.width;
+    newy=(newy*gSprite__BOXX)/info.width+1;
+  }
+
+  if (newy>gSprite__BOXY)
+  {
+    zoom.xmag*=gSprite__BOXY;
+    zoom.ymag*=gSprite__BOXY;
+    zoom.xdiv*=newy;
+    zoom.ydiv*=newy;
+  }
+
+  info.width=info.width*zoom.xmag/zoom.xdiv;
+  info.height=info.height*zoom.ymag/zoom.ydiv;
+  xoff=(gSprite__BOXX-info.width)/2;
+  yoff=(gSprite__BOXY-info.height)/2+48;
+  zoom.xmag <<= bbc_modevar(info.mode,bbc_XEigFactor);
+  zoom.ymag <<= bbc_modevar(info.mode,bbc_YEigFactor);
+  zoom.xdiv <<= bbc_vduvar(bbc_XEigFactor);
+  zoom.ydiv <<= bbc_vduvar(bbc_YEigFactor);
+
+  wimpt_noerr(sprite_put_scaled(t->s,
+                                &sid,
+                                8,
+                                ox+box->x0+xoff,
+                                oy+box->y0+yoff,
+                                &zoom,
+                                colbuff));
+}
+
+/*
+ * void gSprite__windowHandler(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles events for individual sprite windows
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event to handle
+ *  void *handle == pointer to data structure
+ */
+
+static void gSprite__windowHandler(wimp_eventstr *e,void *handle)
+{
+  gSprite__data *d=handle;
+  wimp_redrawstr r;
+  int ox,oy;
+  BOOL more;
+  sprite_id sid;
+  sprite_factors zoom;
+  sprite_pixtrans colbuff[256];
+  sprite_header *hdr;
+  sprite_info info;
+
+  switch (e->e)
+  {
+    case wimp_EREDRAW:
+      r.w=d->w;
+      wimpt_noerr(wimp_redraw_wind(&r,&more));
+      ox=r.box.x0-r.scx;
+      oy=r.box.y1-r.scy;
+      while (more)
+      {
+        sid.s.name=d->name;
+        sid.tag=0;
+        wimpt_noerr(sprite_select_rp(d->t->s,&sid,(sprite_ptr *)&hdr));
+        sid.s.addr=hdr;
+        sid.tag=sprite_id_addr;
+        wimpt_noerr(sprite_readsize(d->t->s,&sid,&info));
+        if (bbc_modevar(info.mode,bbc_NColour)==63)
+        {
+          colourtran_select_table(info.mode,
+                                  0,
+                                  -1,
+                                  (wimp_paletteword *)-1,
+                                  colbuff);
+        }
+        else
+          wimpt_noerr(wimp_readpixtrans(d->t->s,&sid,&zoom,colbuff));
+        zoom.xmag=zoom.ymag=zoom.xdiv=zoom.ydiv=1;
+        info.width <<= bbc_modevar(info.mode,bbc_XEigFactor);
+        info.height <<= bbc_modevar(info.mode,bbc_YEigFactor);
+
+        info.width=info.width*zoom.xmag/zoom.xdiv;
+        info.height=info.height*zoom.ymag/zoom.ydiv;
+        zoom.xmag <<= bbc_modevar(info.mode,bbc_XEigFactor);
+        zoom.ymag <<= bbc_modevar(info.mode,bbc_YEigFactor);
+        zoom.xdiv <<= bbc_vduvar(bbc_XEigFactor);
+        zoom.ydiv <<= bbc_vduvar(bbc_YEigFactor);
+
+        wimpt_noerr(sprite_put_scaled(d->t->s,&sid,8,ox,oy,&zoom,colbuff));
+
+        wimpt_noerr(wimp_get_rectangle(&r,&more));
+      }
+      break;
+    case wimp_EOPEN:
+      wimpt_noerr(wimp_open_wind(&e->data.o));
+      break;
+    case wimp_ECLOSE:
+      win_register_event_handler(d->w,0,0);
+      win_activedec();
+      wimpt_noerr(wimp_delete_wind(d->w));
+      d->w=0;
+      break;
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MHELPREQUEST:
+          help_startHelp();
+          help_addLine(msgs_lookup("sphSPDW"),d->name);
+          help_endHelp();
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * void gSprite__menuHelp(int hit[],void *handle)
+ *
+ * Use
+ *  Responds to help requests for the sprite viewer menu
+ *
+ * Parameters
+ *  int hit[] == array of menu selections
+ *  void *handle == pointer to owning template file (unused)
+ */
+
+static void gSprite__menuHelp(int hit[],void *handle)
+{
+  unused(handle);
+  help_startHelp();
+  help_readFromMenu("spmhSPM",hit);
+  help_endHelp();
+}
+
+/*
+ * void gSprite__menuHandler(int hit[],void *handle)
+ *
+ * Use
+ *  Responds to menu selections from the sprite viewer menu
+ *
+ * Parameters
+ *  int hit[] == array of menu selections
+ *  void *handle == pointer to owning template file
+ */
+
+static void gSprite__menuHandler(int hit[],void *handle)
+{
+  glass_tfile *t=handle;
+  wimp_mousestr m;
+  char buff[50];
+  dbox d;
+  sprite_id sid;
+  sprite_info info;
+  sprite_header *hdr;
+  switch (hit[0])
+  {
+    case 0:
+      viewer_clickSelect(t->vs,viewer_NOICON,wimp_BMID);
+      break;
+    case glass_SPINFO:
+       if (d=dbox_create("sprFileInfo"),d)
+       {
+         dbox_setfield(d,glass_SAOWNER,"%.%s",t->filename);
+         dbox_setfield(d,
+                       glass_SASIZE,
+                       "%s",
+                       utils_cvtSize(t->s->freeoff-4));
+         dbox_setfield(d,glass_SASPRITES,"%i",t->s->number);
+         mbox(d,"sphSAINF");
+       }
+       break;
+    case glass_SPSEL:
+      switch (hit[1])
+      {
+        case glass_SPSELINFO:
+          if (viewer_selected(t->vs)==1)
+          {
+            if (d=dbox_create("spriteInfo"),d)
+            {
+              sid.s.name=((gSprite__data *)
+                       viewer_iconHandle(viewer_firstSelected(t->vs)))->name;
+              sid.tag=0;
+              wimpt_noerr(sprite_readsize(t->s,&sid,&info));
+              wimpt_noerr(sprite_select_rp(t->s,&sid,(sprite_ptr *)&hdr));
+              dbox_setfield(d,glass_SPNAME,"%s",sid.s.name);
+              dbox_setfield(d,glass_SPMODE,"%i",info.mode);
+              dbox_setfield(d,glass_SPWIDTH,"%i",info.width);
+              dbox_setfield(d,glass_SPHEIGHT,"%i",info.height);
+              dbox_setfield(d,
+                            glass_SPSIZE,
+                            "%s",
+                            utils_cvtSize(hdr->next+16));
+              dbox_setfield(d,
+                            glass_SPMASK,
+                            "%s",
+                            msgs_lookup(info.mask ? "yes" : "no"));
+              dbox_setfield(d,
+                            glass_SPPALETTE,
+                            "%s",
+                            msgs_lookup(hdr->image!=0x2c ? "yes" : "no"));
+              mbox(d,"sphSPINF");
+            }
+          }
+          else
+          {
+            if (d=dbox_create("sprSelInfo"),d)
+            {
+              dbox_setfield(d,glass_SSNUM,"%i",viewer_selected(t->vs));
+              gSprite__size=0;
+              viewer_doForIcons(t->vs,TRUE,gSprite__sizes);
+              dbox_setfield(d,
+                            glass_SPSIZE,
+                            "%s",
+                            utils_cvtSize(gSprite__size+16));
+              mbox(d,"sphSSINF");
+            }
+          }
+          break;
+        case glass_SPSELCOPY:
+          writable
+          (
+            msgs_lookup("spCOPY"),
+            viewer_textOfIcon(viewer_firstSelected(t->vs)),
+            buff,
+            gSprite__copy,
+            viewer_iconHandle(viewer_firstSelected(t->vs))
+          );
+          break;
+        case glass_SPSELRENAME:
+          writable(msgs_lookup("spREN"),
+                   viewer_textOfIcon(viewer_firstSelected(t->vs)),
+                   buff,
+                   gSprite__rename,
+                   viewer_iconHandle(viewer_firstSelected(t->vs)));
+          break;
+        case glass_SPSELSAVE:
+          gSprite__size=0;
+          viewer_doForIcons(t->vs,TRUE,gSprite__sizes);
+          saveas(msgs_lookup("spSVSEL"),
+                 msgs_lookup("spSEL"),
+                 0xff9,
+                 gSprite__size+16,
+                 gSprite__saveSelection,
+                 gSprite__sendSelection,
+                 0,
+                 t);
+          break;
+        case glass_SPSELDELETE:
+          viewer_doForIcons(t->vs,TRUE,gSprite__delSprites);
+          gSprite__minimise(t);
+          intMsgs_send(glass_SPRITECHANGE,t);
+          break;
+      }
+      break;
+    case glass_SPSELALL:
+      viewer_selectAll(t->vs,TRUE);
+      break;
+    case glass_SPCLRSEL:
+      viewer_selectAll(t->vs,FALSE);
+      break;
+    case glass_SPSAVE:
+      saveas(msgs_lookup("spSVSPR"),
+             "Sprites",
+             0xff9,
+             t->s->freeoff-4,
+             gSprite__saveArea,
+             gSprite__sendArea,
+             0,
+             t);
+      break;
+    case glass_SPGRAB:
+      window_grab(gSprite__grab,0);
+      break;
+  }
+  if (wimpt_last_event()->e==wimp_EMENU)
+  {
+    wimpt_noerr(wimp_get_point_info(&m));
+    if (m.bbits!=wimp_BRIGHT)
+      viewer_clickSelect(t->vs,viewer_NOICON,wimp_BMID);
+  }
+}
+
+/*
+ * menu gSprite__menuMaker(void *handle)
+ *
+ * Use
+ *  Creates a menu for the sprite file viewer
+ *
+ * Parameters
+ *  void *handle == pointer to owning template file
+ *
+ * Returns
+ *  Pointer to the menu it has set up
+ */
+
+static menu gSprite__menuMaker(void *handle)
+{
+  static menu m;                 /* The main menu pointer                  */
+  static menu sprsm;             /* Submenu for sprite options             */
+  static char sprName[50];       /* Buffer for sprite name                 */
+  glass_tfile *t=handle;
+  if (!m)                        /* Do we have to create the menu?         */
+  {
+    m=menu_new("Sprites",msgs_lookup("spM"));
+    sprsm=menu_new("_",msgs_lookup("spSS"));
+    menu_submenu(m,glass_SPSEL,sprsm);
+    menu_redirectItem(m,glass_SPSEL,sprName,50,0);
+  }
+  menu_minWidth(m,0);
+  viewer_setupMenu(t->vs,
+                   msgs_lookup("spSPR"),
+                   m,
+                   glass_SPSEL,
+                   sprName);
+  switch (viewer_selected(t->vs))
+  {
+    case 0:
+      menu_setflags(m,glass_SPCLRSEL,FALSE,TRUE);
+      menu_setflags(m,glass_SPSELALL,FALSE,!viewer_icons(t->vs));
+      menu_settitle(sprsm,msgs_lookup("spSPR"));
+      menu_setflags(sprsm,glass_SPSELINFO,FALSE,TRUE);
+      menu_setflags(sprsm,glass_SPSELCOPY,FALSE,TRUE);
+      menu_setflags(sprsm,glass_SPSELRENAME,FALSE,TRUE);
+      menu_setflags(sprsm,glass_SPSELSAVE,FALSE,TRUE);
+      menu_setflags(sprsm,glass_SPSELDELETE,FALSE,TRUE);
+      break;
+    case 1:
+      menu_setflags(m,glass_SPCLRSEL,FALSE,FALSE);
+      menu_setflags(m,glass_SPSELALL,FALSE,FALSE);
+      menu_settitle(sprsm,msgs_lookup("spSPR"));
+      menu_setflags(sprsm,glass_SPSELINFO,FALSE,FALSE);
+      menu_setflags(sprsm,glass_SPSELCOPY,FALSE,FALSE);
+      menu_setflags(sprsm,glass_SPSELRENAME,FALSE,FALSE);
+      menu_setflags(sprsm,glass_SPSELSAVE,FALSE,FALSE);
+      menu_setflags(sprsm,glass_SPSELDELETE,FALSE,FALSE);
+      break;
+    default:
+      menu_setflags(m,glass_SPCLRSEL,FALSE,FALSE);
+      menu_setflags(m,glass_SPSELALL,FALSE,FALSE);
+      menu_settitle(sprsm,msgs_lookup("spSEL"));
+      menu_setflags(sprsm,glass_SPSELINFO,FALSE,FALSE);
+      menu_setflags(sprsm,glass_SPSELCOPY,FALSE,TRUE);
+      menu_setflags(sprsm,glass_SPSELRENAME,FALSE,TRUE);
+      menu_setflags(sprsm,glass_SPSELSAVE,FALSE,FALSE);
+      menu_setflags(sprsm,glass_SPSELDELETE,FALSE,FALSE);
+      break;
+  }
+  menu_setflags(m,glass_SPGRAB,FALSE,window_grabbing());
+  return (m);
+}
+
+/*
+ * void gSprite__simMenu(glass_tfile *t,int hit1,int hit2)
+ *
+ * Use
+ *  Simulates a menu hit on a template file window
+ *
+ * Parameters
+ *  glass_tfile *t == the template file the event is destined for
+ *  int hit1 == the main menu entry number
+ *  int hit2 == the submenu entry number
+ */
+
+static void gSprite__simMenu(glass_tfile *t,int hit1,int hit2)
+{
+  wimp_menustr *m=menu_syshandle(gSprite__menuMaker(t));
+  wimp_menuitem *i=(wimp_menuitem *)(m+1)+(hit1-1);
+  int mnu[3];
+  mnu[0]=hit1;
+  mnu[1]=hit2;
+  mnu[2]=0;
+
+  if ((int)i->submenu==-1 || hit2==0)
+  {
+    if (i->iconflags & wimp_INOSELECT)
+    {
+      bbc_vdu(7);
+      return;
+    }
+    else
+      mnu[1]=0;
+  }
+  else
+  {
+    i=(wimp_menuitem *)(i->submenu+1)+(hit2-1);
+    if (i->iconflags & wimp_INOSELECT)
+    {
+      bbc_vdu(7);
+      return;
+    }
+  }
+  gSprite__menuHandler(mnu,t);
+}
+
+/*
+ * BOOL gSprite__viewerRaw(viewer v,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles raw events destined for the viewer window, and picks out
+ *  interesting ones.
+ *
+ * Parameters
+ *  viewer v == the viewer its going for
+ *  wimp_eventstr *e == what it is
+ *  void *handle == pointer to owning template file
+ *
+ * Returns
+ *  TRUE if the event was worth waiting for
+ */
+
+static BOOL gSprite__viewerRaw(viewer v,wimp_eventstr *e,void *handle)
+{
+  glass_tfile *t=handle;
+  char *filename;
+  int filetype;
+  int estsize;
+  void *p;
+  BOOL handled=FALSE;
+  unused(v);
+  switch (e->e)
+  {
+    case wimp_EKEY:
+      switch (e->data.key.chcode)
+      {
+        case akbd_Fn+1+akbd_Sh: /* sF1 */
+          gSprite__simMenu(t,glass_SPINFO,0);
+          handled=TRUE;
+          break;
+        case 1:                 /* ^A */
+          gSprite__simMenu(t,glass_SPSELALL,0);
+          handled=TRUE;
+          break;
+        case 26:                /* ^Z */
+          gSprite__simMenu(t,glass_SPCLRSEL,0);
+          handled=TRUE;
+          break;
+        case akbd_Fn+3:         /* F3 */
+          gSprite__simMenu(t,glass_SPSAVE,0);
+          handled=TRUE;
+          break;
+        case 7:                 /* ^G */
+          gSprite__simMenu(t,glass_SPGRAB,0);
+          handled=TRUE;
+          break;
+
+        case akbd_Fn+1+akbd_Ctl:/* ^F1 */
+          gSprite__simMenu(t,glass_SPSEL,glass_SPSELINFO);
+          handled=TRUE;
+          break;
+        case 3:                 /* ^C */
+          gSprite__simMenu(t,glass_SPSEL,glass_SPSELCOPY);
+          handled=TRUE;
+          break;
+        case 18:                /* ^R */
+          gSprite__simMenu(t,glass_SPSEL,glass_SPSELRENAME);
+          handled=TRUE;
+          break;
+        case akbd_Fn+3+akbd_Sh: /* sF3 */
+          gSprite__simMenu(t,glass_SPSEL,glass_SPSELSAVE);
+          handled=TRUE;
+          break;
+        case 24:                /* ^X */
+          gSprite__simMenu(t,glass_SPSEL,glass_SPSELDELETE);
+          handled=TRUE;
+          break;
+
+        case akbd_Fn+2+akbd_Ctl:/* ^F2 */
+          viewer_hide(v);
+          handled=TRUE;
+          break;
+      }
+      break;
+
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MDATASAVE:
+          filetype=xferrecv_checkimport(&estsize);
+          switch (filetype)
+          {
+            case 0xff9:
+              if (xferrecv_returnImportedBlock(&p)!=-1)
+              {
+                gSprite_mergeFromMemory(t,&p);
+                flex_free(&p);
+              }
+              break;
+          }
+          handled=TRUE;
+          break;
+        case wimp_MDATALOAD:
+          filetype=xferrecv_checkinsert(&filename);
+          switch (filetype)
+          {
+            case 0xff9:
+              gSprite_mergeFromFile(t,filename);
+              xferrecv_insertfileok();
+              break;
+          }
+          handled=TRUE;
+          break;
+      }
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void gSprite__viewerHandler(viewer v,
+ *                              viewer_icon i,
+ *                              wimp_bbits b,
+ *                              void *vhandle,
+ *                              void *ihandle)
+ *
+ * Use
+ *  Handles events in a sprite viewer
+ *
+ * Parameters
+ *  viewer v == the handle for the viewer that got the event
+ *  viewer_icon i == the icon handle that was 'evented', or an event code
+ *  wimp_bbits b == the mouse button status, if relevant
+ *  void *vhandle == pointer to the owning template file
+ *  void *ihandle == an unused pointer
+ */
+
+static void gSprite__viewerHandler(viewer v,
+                                    viewer_icon i,
+                                    wimp_bbits b,
+                                    void *vhandle,
+                                    void *ihandle)
+{
+  glass_tfile *t=vhandle;
+  unused(ihandle);
+  switch ((int)i)
+  {
+    case (int)viewer_CLOSE:
+      viewer_hide(v);
+      break;
+    case (int)viewer_HELP:
+      help_startHelp();
+      help_addLine(msgs_lookup("sphMVW"));
+      help_endHelp();
+      break;
+    default:
+      if (b!=wimp_BMID)
+      {
+        gSprite__gainSelection(t);
+        viewer_clickSelect(v,i,b);
+      }
+      switch (b)
+      {
+        case wimp_BMID:
+          if (t==gSprite__selOwner ||
+              !gSprite__selOwner ||
+              !viewer_selected(gSprite__selOwner->vs))
+          {
+            gSprite__selOwner=t;
+            viewer_clickSelect(v,i,b);
+          }
+          menu_make(gSprite__menuMaker,
+                    gSprite__menuHandler,
+                    gSprite__menuHelp,
+                    t);
+          break;
+        case wimp_BLEFT:
+        case wimp_BRIGHT:
+          if (i!=viewer_NOICON)
+          {
+            gSprite__createWindow(i,viewer_iconHandle(i));
+            viewer_selectIcon(i,FALSE);
+          }
+          break;
+        case wimp_BDRAGLEFT:
+        case wimp_BDRAGRIGHT:
+          if (i!=viewer_NOICON)
+          {
+            tfile_dragSelected(i,b,"spackage");
+            win_add_unknown_event_processor(gSprite__dragUnknowns,t);
+          }
+          break;
+      }
+      break;
+  }
+}
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void gSprite_kill(glass_tfile *t)
+ *
+ * Use
+ *  Closes the sprite viewer and frees the sprite area
+ *
+ * Parameters
+ *  glass_tfile *t == the template file that's closing
+ */
+
+void gSprite_kill(glass_tfile *t)
+{
+  if (t->vs)
+    viewer_delete(t->vs,gSprite__closeWindows);
+  indir_free(t->s);
+}
+
+/*
+ * void gSprite_display(glass_tfile *t)
+ *
+ * Use
+ *  Displays the sprite viewer for the specified template file.
+ *
+ * glass_tfile *t == the template file whose sprites we want to see
+ */
+
+void gSprite_display(glass_tfile *t)
+{
+  viewer_selectAll(t->vs,FALSE);
+  viewer_display(t->vs);
+}
+
+/*
+ * void gSprite_mergeFromMemory(glass_tfile *t,void **p)
+ *
+ * Use
+ *  Merges a sprite file which is stored in memory.  This is so I can do
+ *  in-memory transfer of sprites.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file owner of the sprite area
+ *  void **p == the flex block stroing the sprite file
+ */
+
+void gSprite_mergeFromMemory(glass_tfile *t,void **p)
+{
+  int sprites=_ptr(sprite_area,*p,-4)->number;
+  int i;
+  int h=_ptr(sprite_area,*p,-4)->sproff-4;
+  int length;
+  sprite_id sid;
+  viewer_icon icn;
+  char buff[15];
+  gSprite__data *d;
+  if (!gSprite__getMemory(t,_ptr(sprite_area,*p,-4)->freeoff))
+  {
+    werr(FALSE,msgs_lookup("spNEMM"));
+    return;
+  }
+  for (i=1;i<=sprites;i++)
+  {
+    length=_ptr(sprite_header,*p,h)->next;
+    buff[12]=0;
+    memcpy(buff,_ptr(sprite_header,*p,h)->name,12);
+    sid.s.name=buff;
+    sid.tag=0;
+
+    /* --- Slight problem --- *
+     *
+     * viewer is deadly cunning, because it uses a nice case-insensitive
+     * string-compare for all this, which handles annoying things like
+     * accents.  Unfortunately, the RISC OS sprite system isn't as cunning,
+     * and so, when viewer says that `Élite' and `élite' are the same,
+     * RISC OS moans that it can't find  the sprite when you delete it.
+     *
+     * Hence we place the sprite deletion in there as a check that it really
+     * does exist in there.  Note that it only deletes the sprite if it
+     * found the icon.
+     */
+
+    if (icn=viewer_findIcon(t->vs,sid.s.name),
+          icn && !sprite_delete(t->s,&sid))
+    {
+      d=viewer_iconHandle(icn);
+      if (d->w)
+      {
+        win_register_event_handler(d->w,0,0);
+        wimpt_noerr(wimp_delete_wind(d->w));
+        d->w=0;
+      }
+      mem_free(d);
+      viewer_removeIcon(icn);
+    }
+    mem_useUser(indir_alloc,indir_free);
+    if (d=mem_alloc(sizeof(gSprite__data)),!d)
+    {
+      mem_useMalloc();
+      werr(FALSE,msgs_lookup("spNEMM"));
+      return;
+    }
+    strcpy(d->name,sid.s.name);
+    d->t=t;
+    d->w=0;
+    d->serial=gSprite__serial++;
+    if (d->i=viewer_addIcon(t->vs,sid.s.name,sid.s.name,TRUE,d),!d->i)
+    {
+      mem_useMalloc();
+      mem_free(d);
+      return;
+    }
+    mem_useMalloc();
+    viewer_setFiletype(d->i,0xff9);
+    memcpy(((char *)t->s)+t->s->freeoff,_ptr(sprite_header,*p,h),length);
+    t->s->freeoff+=length;
+    t->s->number++;
+    h+=length;
+  }
+  gSprite__minimise(t);
+  intMsgs_send(glass_SPRITECHANGE,t);
+}
+
+/*
+ * void gSprite_mergeFromFile(glass_tfile *t,char *name)
+ *
+ * Use
+ *  Merges the given file into the sprite area specified.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file that we're going to load for
+ *  char *name == the name of the file to load
+ */
+
+void gSprite_mergeFromFile(glass_tfile *t,char *name)
+{
+  os_filestr f;                  /* Going to make some OS_File calls       */
+  void *p;                       /* p will point to the file in memory     */
+  f.action=17;                   /* Read catalogue information for file    */
+  f.name=name;                   /* Point to file name to find out about   */
+  if (utils_complain(os_file(&f),msgs_lookup("spEMF")))
+    return;
+  if (!flex_alloc(&p,f.start))
+  {
+    werr(FALSE,msgs_lookup("spNEMM"));
+    return;
+  }
+  f.action=16;                   /* Load the file                          */
+  f.loadaddr=(int)p;             /* Where to load the file                 */
+  f.execaddr=0;                  /* Load it there!!!                       */
+  if (utils_complain(os_file(&f),msgs_lookup("spEMF")))
+  {
+    flex_free(&p);
+    return;
+  }
+  gSprite_mergeFromMemory(t,&p);   /* Now do the merge                    */
+  flex_free(&p);
+}
+
+/*
+ * void gSprite_new(glass_tfile *t)
+ *
+ * Use
+ *  Creates a sprite file for the given template file.  Initially, the file
+ *  is blank.  On failure, an error is generated and sprite area 1 (WIMP
+ *  pool) is used instead.  Note that at present, this section uses indir
+ *  for allocation of sprite areas.
+ *
+ * Parameters
+ *  glass_tfile *t == the file to use
+ */
+
+void gSprite_new(glass_tfile *t)
+{
+  char buff[256];
+  void *def;
+  if (t->s=indir_alloc(gSprite__CHUNK),!t->s)
+  {
+    werr(FALSE,msgs_lookup("spNEMC"));
+    t->s=(sprite_area *)1;       /* Set the WIMP sprite area               */
+    t->vs=0;                     /* Tell the world something's wrong       */
+    return;
+  }
+  sprintf(buff,msgs_lookup("spVT"),t->filename);
+  mem_useUser(indir_alloc,indir_free);
+  t->vs=viewer_create(gSprite__FILEX,
+                      gSprite__fileHeight,
+                      gSprite__BOXX,
+                      gSprite__BOXY+48,
+                      resspr_area(),
+                      buff,
+                      msgs_lookup("spBANR"));
+  mem_useMalloc();
+  if (!t->vs)
+    return;
+  viewer_setCompare(t->vs,gSprite__compare);
+  gSprite__fileHeight-=48;
+  if (gSprite__fileHeight<632)
+    gSprite__fileHeight=gSprite__FILETOP;
+  viewer_eventHandler(t->vs,gSprite__viewerHandler,t);
+  viewer_rawEventHandler(t->vs,gSprite__viewerRaw,t);
+  viewer_redrawHandler(t->vs,gSprite__viewerRedraw,t);
+  t->s->size=gSprite__CHUNK;
+  t->s->number=0;
+  t->s->sproff=16;
+  t->s->freeoff=16;
+  if (gPrefs_current()->sLoadDef && gSprite__default)
+  {
+    def=&gSprite__default->number;
+    gSprite_mergeFromMemory(t,&def);
+  }
+}
+
+/*
+ * sprite_area *gSprite_area(void)
+ *
+ * Use
+ *  Returns the address of the Glass default sprite file, or 1 for the
+ *  WIMP sprite area if no default sprites are loaded
+ */
+
+sprite_area *gSprite_area(void)
+{
+  return (gSprite__default ? gSprite__default : (sprite_area *)1);
+}
+
+/*
+ * void gSprite_init(void)
+ *
+ * Use
+ *  Loads the Glass default sprite area into memory.
+ */
+
+void gSprite_init(void)
+{
+  os_filestr f;                  /* Going to make some OS_File calls       */
+  f.action=17;                   /* Read catalogue information for file    */
+  f.name=choices_name("Defaults.Sprites",FALSE);
+  if (utils_complain(os_file(&f),msgs_lookup("spELD")))
+    return;
+  if (f.action==0)
+    return;
+  if (gSprite__default=mem_alloc(f.start+4),!gSprite__default)
+  {
+    werr(FALSE,msgs_lookup("spNEMLD"));
+    return;
+  }
+  gSprite__default->size=f.start+4;
+  gSprite__default->number=0;
+  gSprite__default->sproff=16;
+  gSprite__default->freeoff=16;
+  if (utils_complain(sprite_area_load(gSprite__default,
+                     choices_name("Defaults.Sprites",FALSE)),
+      msgs_lookup("spELD")))
+    gSprite__default=0;
+}
diff --git a/StraySrc/Glass/!Glass/c/glass b/StraySrc/Glass/!Glass/c/glass
new file mode 100644 (file)
index 0000000..8e46c69
--- /dev/null
@@ -0,0 +1,601 @@
+/*
+ * glass.c
+ *
+ * Main control section and user interface
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <time.h>
+
+#include "dll.h"
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _XFER
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/viewer.h"
+#include "steel/mem.h"
+#include "steel/caretptr.h"
+#include "steel/buttons.h"
+#include "steel/sculptrix.h"
+#include "steel/flex.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gIcons.h"
+#include "gMenus.h"
+
+#include "glass.h"
+#include "toolbox.h"
+#include "tfile.h"
+#include "intMsgs.h"
+#include "gPrefs.h"
+#include "gSprite.h"
+#include "indir.h"
+#include "window.h"
+#include "tearEdit.h"
+
+/*----- External dependencies ---------------------------------------------*/
+
+extern char date[], cright[];
+#define VERSION 100
+
+/*----- Static global variables -------------------------------------------*/
+
+static BOOL glass_genDump;           /* Send timings to dump (stderr)      */
+static BOOL glass_noWindow;          /* Turn off the nice intro window     */
+
+/*----- Icon bar handlers -------------------------------------------------*/
+
+/*
+ * BOOL glass_unknowns(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Vets unknown events.  The important ones at the moment are
+ *  Message_DataOpen and Message_PreQuit.  Glass 1.xx supports the RISC
+ *  OS 3 prequit convention to avoid the old misunderstanding.  This may
+ *  cause problems under RISC OS 2.  If so, they'll just have to upgrade...
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event in question
+ *  void *handle == 0
+ *
+ * Returns
+ *  TRUE if the event has now been processed.
+ */
+
+static BOOL glass_unknowns(wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  int filetype;
+  char *filename;
+  char buff[256];
+  os_regset r;
+  unused(handle);
+  switch (e->e)
+  {
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MDATAOPEN:
+          filetype=xferrecv_checkinsert(&filename);
+          switch (filetype)
+          {
+            case 0xfec:          /* Template file                          */
+              xferrecv_insertfileok();
+              tfile_loadFromFile(filename,xferrecv_nameToImport());
+              handled=TRUE;
+              break;
+          }
+          break;
+        case wimp_MPREQUIT:
+          if (tfile_okToQuit(TRUE))
+            intMsgs_send(glass_KILLFILES);
+          else
+          {
+            e->data.msg.hdr.your_ref=e->data.msg.hdr.my_ref;
+            wimpt_noerr(wimp_sendmessage(wimp_EACK,
+                                         &e->data.msg,
+                                         e->data.msg.hdr.task));
+          }
+          handled=TRUE;
+          break;
+        case wimp_MMODECHANGE:
+          intMsgs_send(glass_MODECHANGE);
+          break;
+        case wimp_SAVEDESK:
+          sprintf(buff,"Run %s\n",getenv("Glass$Dir"));
+          r.r[0]=2;
+          r.r[1]=e->data.msg.data.savedesk.filehandle;
+          r.r[2]=(int)buff;
+          r.r[3]=strlen(buff);
+          wimpt_noerr(os_swix(XOS_GBPB,&r));
+          handled=TRUE;
+          break;
+      }
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void glass_ibarHandler(ibicon i,ibicon_eventType e,void *handle)
+ *
+ * Use
+ *  Handles events for the icon bar icon (such as help requests, load and
+ *  save messages, and of course mouse clicks).
+ *
+ * Parameters
+ *  ibicon i == the handle of the icon
+ *  ibicon_eventType e == what has happened
+ *  void *handle == a dummy handle
+ */
+
+static void glass_ibarHandler(ibicon i,ibicon_eventType e,void *handle)
+{
+  int filetype;                  /* Filetype of a file to import           */
+  char *filename;                /* Filename of a file                     */
+  int estsize;                   /* Estimated size of a file to import     */
+  void *p;                       /* Pointer to loaded file                 */
+  unused(i);                     /* Not actually interested in the icon    */
+  unused(handle);                /* Not at all interested in the handle    */
+  switch (e)                     /* Find out what's going on               */
+  {
+    case ibicon_LEFTCLICK:       /* Clicked with select                    */
+      {
+        glass_tfile *t;
+        if (t=tfile_createTemplateFile(msgs_lookup("tfUNT")),t)
+          viewer_display(t->v);
+      }
+      break;
+    case ibicon_RIGHTCLICK:      /* Clicked with adjust                    */
+      break;                     /* Ignore it and hope it goes away        */
+    case ibicon_LOAD:            /* Load request from Filer                */
+      filetype=xferrecv_checkinsert(&filename); /* Get information         */
+      switch (filetype)
+      {
+        case 0xfec:              /* Template file                          */
+          tfile_loadFromFile(filename,xferrecv_nameToImport());
+          xferrecv_insertfileok();
+          break;
+      }
+      break;
+    case ibicon_SAVE:            /* Save from another application          */
+      filetype=xferrecv_checkimport(&estsize);  /* Get information         */
+      switch (filetype)
+      {
+        case 0xfec:              /* Template file                          */
+          if (xferrecv_returnImportedBlock(&p)!=-1)
+          {
+            tfile_loadFromMemory(&p,xferrecv_nameToImport());
+            flex_free(&p);
+            flex_compact();
+          }
+          break;
+      }
+      break;
+    case ibicon_HELP:            /* Help request                           */
+      help_startHelp();          /* Start a help reply                     */
+      help_addLine(msgs_lookup("wehIB"));
+      help_endHelp();            /* Send the message back                  */
+      break;
+  }
+}
+
+/*
+ * void glass_ibarMenuHandler(int hit[],void *handle)
+ *
+ * Use
+ *  Processes menu clicks for the icon bar menu.
+ *
+ * Parameters
+ *  int hit[] == array of menu hits
+ *  void *handle == 0 (dummy handle)
+ */
+
+static void glass_ibarMenuHandler(int hit[],void *handle)
+{
+  unused(handle);                /* This menu not attached to data struct  */
+  switch (hit[0])                /* Check which item was chosen            */
+  {
+    case glass_IBARINFO:         /* About this program                     */
+      progInfo("Glass",
+               msgs_lookup("wePUR"),
+               cright,
+               VERSION,
+               date);
+      break;
+    case glass_IBARPREFS:        /* Preferences dialogue                   */
+      gPrefs_edit();            /* Edit the preferences...                */
+      break;
+    case glass_IBARTBOX:         /* Toolbox (window manipulation)          */
+      toolbox();                 /* Handles it all...                      */
+      break;
+    case glass_IBARHEAPINFO:     /* Heap info display                      */
+      indir_heapInfo();          /* Display                                */
+      break;
+    case glass_IBARQUIT:         /* Quit program                           */
+      if (tfile_okToQuit(TRUE))  /* Check the user is sure about this      */
+        exit(0);                 /* End Glass and announce success         */
+      break;
+  }
+}
+
+/*
+ * void glass_ibarMenuHelp(int hit[],void *handle)
+ *
+ * Use
+ *  Help processor for icon bar menu.
+ *
+ * Parameters
+ *  int hit[] == the item to give help for
+ *  void *handle == a dummy handle
+ */
+
+static void glass_ibarMenuHelp(int hit[],void *handle)
+{
+  unused(handle);
+  help_startHelp();
+  help_readFromMenu("wemhIB",hit);
+  help_endHelp();
+}
+
+/*----- Initialisation ----------------------------------------------------*/
+
+/*
+ * void glass_exit(void)
+ *
+ * Use
+ *  Exit handler, creates internal broadcast to close down everything.
+ */
+
+static void glass_exit(void)
+{
+  intMsgs_send(glass_CLOSEDOWN);
+}
+
+/*
+ * void glass_iconbar(void)
+ *
+ * Use
+ *  Sets up the icon bar during Glass initialisation.  Essentially, it
+ *  installs an icon bar, attaches a menu to it, and gives it a handler.
+ *  It also establishes a handler for loading and mouse clicks.
+ */
+
+static void glass_iconbar(void)
+{
+  ibicon i;                      /* Handle for the icon we will create     */
+  menu m;                        /* The menu to attach to the icon         */
+  m=menu_new("Glass",msgs_lookup("weIBM"));
+  i=ibicon_create(ibicon_RIGHT,"!glass",ibicon_WIMPAREA,0,0);
+  ibicon_attachMenu(i,m,glass_ibarMenuHandler,glass_ibarMenuHelp,0);
+  ibicon_eventHandler(i,glass_ibarHandler,0);
+}
+
+/*
+ * void glass_scanCLI(int argc,char *argv[],BOOL inited)
+ *
+ * Use
+ *  Scans command line string and loads relevant files
+ *
+ * Parameters
+ *  int argc == the number of words in the string
+ *  char *argv[] == the words, as an array of strings
+ *  BOOL inited == whether we have initialised the WIMP
+ */
+
+static void glass_scanCLI(int argc,char *argv[],BOOL inited)
+{
+  int i;
+  for (i=1;i<argc;i++)
+  {
+    if (utils_caselessCmp(argv[i],"-genDump")==0)
+      glass_genDump=TRUE;
+    else if (utils_caselessCmp(argv[i],"-noWindow")==0)
+      glass_noWindow=TRUE;
+    else if (utils_caselessCmp(argv[i],"-help")==0)
+    {
+      printf
+      (
+        "Glass %i.%02i (%s)\n"
+        "\n"
+        "%s"
+        "\n"
+        "Command line syntax:\n"
+        "  Glass [<option> | <filename>]...\n"
+        "\n"
+        "<filename> == file name to load\n"
+        "<option> is one of:\n"
+        "  -help == display this help\n"
+        "  -genDump == dump timings and other crap to stderr\n"
+        "  -noWindow == don't display startup window\n",
+        VERSION / 100,
+        VERSION % 100,
+        date, cright
+      );
+      exit(0);
+    }
+    else
+    {
+      if (inited)
+        tfile_loadFromFile(argv[i],argv[i]);
+    }
+  }
+}
+
+/*
+ * void glass_wait(int cs)
+ *
+ * Use
+ *  Makes everything stand still for a bit
+ *
+ * Parameters
+ *  in cs == number of centiseconds to wait
+ */
+
+static void glass_wait(int cs)
+{
+  int waiting;
+  os_regset r;
+  wimpt_noerr(os_swix(XOS_ReadMonotonicTime,&r)); /* Now wait for a bit    */
+  waiting=r.r[0];
+  while (r.r[0]-waiting<cs)      /* Half a second should do...             */
+    wimpt_noerr(os_swix(XOS_ReadMonotonicTime,&r)); /* Get the time again  */
+}
+
+/*
+ * void glass_initProgress(dbox d,char *message,int percent)
+ *
+ * Use
+ *  Updates the display on the loading window while we;re initialising
+ *  everything.
+ *
+ * Parameters
+ *  dbox d == the dbox being used
+ *  char *message == the message to display in the little icon.  A null
+ *    pointer indicates that the message is not to change.
+ *  int percent == the percentage complete so far
+ */
+
+static void glass_initProgress(dbox d,char *message,int percent)
+{
+  static dbox dd;
+  if (!dd)
+    dd=d;
+  else if (!d)
+    d=dd;
+  if (d)
+  {
+    buttons_updateSlider(d,glass_CRSLIDER,100,percent,8,FALSE);
+    dbox_setfield(d,glass_CRPERCENT,"%i",percent);
+    if (message)
+      dbox_setfield(d,glass_CRDOING,"%s",message);
+  }
+  else
+    visdelay_percent(percent);
+  if (glass_genDump)
+  {
+    fprintf(stderr,
+            "Glass init timing: %s - %i\n",
+            message ? message : "ditto",
+            clock());
+  }
+}
+
+/*
+ * void glass_initialise(int argc,char *argv[])
+ *
+ * Use
+ *  Does all the tedious initialisation procedure, and the bit with the
+ *  intro window.
+ *
+ * Parameters
+ *  int argc == the number of words in the CLI string
+ *  char *argv[] == the words, as an array of strings
+ */
+
+static void glass_initialise(int argc,char *argv[])
+{
+  sprite_area *a=0;
+  os_regset r;
+  dbox d=0;
+  wimp_redrawstr rdr;
+  BOOL more;
+
+  _dll_setname("Glass");
+
+  glass_scanCLI(argc,argv,FALSE); /* Scan command line arguments           */
+  visdelay_begin();              /* Turn on the hourglass immediately      */
+
+  /* --- Set up STEEL's options --- *
+   *
+   * We need to enable all the external module support, because we need
+   * to handle templates written to use them.  The non-WIMP shading is just
+   * a nice touch.
+   */
+
+#ifdef glass_DEBUGGING
+  #define _options \
+    wimpt_OSCULPTRIX | \
+    wimpt_OINTERFACE | \
+    wimpt_OWIMPEXT | \
+    wimpt_ONOWIMPSHADE | \
+    wimpt_OREMSAVEICON
+#else
+  #define _options \
+    wimpt_OSCULPTRIX | \
+    wimpt_OINTERFACE | \
+    wimpt_OWIMPEXT | \
+    wimpt_ONOWIMPSHADE | \
+    wimpt_OREMSAVEICON | \
+    wimpt_ONOBACKTRACE
+#endif
+
+  wimpt_setOptions(_options,_options);
+
+  wimpt_init("Glass");           /* Crank up the WIMP                      */
+  res_init("Glass");             /* Point to resource files                */
+  mem_flexdInit(0, 0);        /* Initialise flex system                 */
+
+  resspr_init();                 /* Load my copious quantities of sprites  */
+  if (!glass_noWindow)
+  {
+    template_readfile(res_name("LoadTpl"));
+
+    r.r[0]=17;                   /* Need to find the size of banner sprite */
+    r.r[1]=(int)res_name("LoadSpr"); /* Set up name                        */
+    wimpt_noerr(os_swix(XOS_File,&r)); /* Do the call                      */
+    if (!flex_alloc((flex_ptr)&a,r.r[4]+4))  /* Allocate memory for sprites*/
+      a=0;                       /* If failed, don't show sprites          */
+    else
+    {
+      sprite_area_initialise(a,r.r[4]+4); /* Initialise sprite area (!)    */
+      wimpt_noerr(sprite_area_load(a,res_name("LoadSpr")));
+                                 /* Do the load as required                */
+      template_syshandle("loading")->spritearea=a; /* Rig sprite area      */
+    }
+    if (d=dbox_create("loading"),d) /* Create the dialogue box             */
+    {
+      dbox_setfield(d,
+                    glass_CRVERSION,
+                    "%i.%02i (%s)",
+                    VERSION/100,
+                    VERSION%100,
+                    date);
+      dbox_setfield(d, glass_CRGPLNOTE,
+                    "Glass is free software; it may be modified and/or "
+                    "redistributed under the terms of the GNU General "
+                    "Public License.");
+      dbox_setfield(d, glass_CRNOWARRANTY,
+                    "Glass is distributed in the hope that it will be "
+                    "useful, but WITHOUT ANY WARRANTY.");
+      dbox_display(d,dbox_STATIC_CENTRE); /* Display                       */
+      rdr.w=dbox_syshandle(d);     /* Draw the window on the screen NOW    */
+      wimpt_noerr(wimp_redraw_wind(&rdr,&more)); /* Start redraw process   */
+      while (more)                 /* Carry on till it's all done          */
+      {
+        wimpt_noerr(sculptrix_redrawWindow(&rdr)); /* Do the 3D bitties    */
+        buttons_redrawSlider(d,glass_CRSLIDER,100,0,8,FALSE);    /* Slider */
+        wimpt_noerr(wimp_get_rectangle(&rdr,&more)); /* Get the next bit   */
+      }
+    }
+    else
+      visdelay_percent(0);         /* If no box, give percentage, at least */
+
+    if (a)
+    {
+      flex_free((flex_ptr)&a);
+      flex_compact();
+    }
+  }
+  else
+    visdelay_percent(0);           /* If no box, give percentage, at least */
+
+  glass_initProgress(d,msgs_lookup("weILM:Loading messages"),0);
+  msgs_init();                   /* Read messages file (for help messages) */
+
+  glass_initProgress(d,msgs_lookup("weILW"),15);
+  template_init();
+  werr_init();                   /* Load nice error box                    */
+
+  glass_initProgress(d,msgs_lookup("weLDF"),43);
+  gSprite_init();
+  window_init();
+  tearEdit_init();
+
+  glass_iconbar();               /* Set up the icon bar appropriately      */
+
+  glass_initProgress(d,msgs_lookup("weIRP"),53);
+  gPrefs_init();
+
+  caretPtr("ptr_caret",resspr_area(),4,5); /* Enable pointer change        */
+  win_add_unknown_event_processor(glass_unknowns,0);    /* OPEN, PREQUIT   */
+  event_returnMenuHelp(TRUE);
+
+  glass_initProgress(d,msgs_lookup("weILD"),61);
+  indir_init();
+  glass_scanCLI(argc,argv,TRUE);    /* Scan command line arguments again   */
+  if (d)
+    dbox_display(d,dbox_STATIC_LASTPOS);
+  atexit(glass_exit);            /* Exit handler to free up fonts          */
+
+  if (d)
+  {
+    glass_initProgress(d,msgs_lookup("weIFI"),100);
+    glass_wait(50);
+    dbox_delete(d);
+  }
+
+  visdelay_end();                /* Finished initialisation                */
+}
+
+/*
+ * int main(int argc,char *argv[])
+ *
+ * Use
+ *  Control initially passed to this routine.  It essentially sets up all
+ *  initial handlers (the icon bar etc.) and lets the event system handle
+ *  the rest.
+ *
+ * Parameters
+ *  int argc == the number of command line arguments passed
+ *  char *argv == an array of command line arguments
+ *
+ * Returns
+ *  zero == successful completion
+ *  nonzero == abnormal termination
+ *
+ *  Defined return codes are:
+ */
+
+int main(int argc,char *argv[])
+{
+  exception_handler e;           /* Point to return to on an exception     */
+  glass_initialise(argc,argv);   /* Perform necessary initialisation       */
+  visdelay_begin();              /* Display hourglass between polls        */
+  (void)exception_registerHandler(e); /* Return here if anything goes amiss*/
+  mem_useMalloc();               /* Ensure use of standard heap            */
+  for(;;)                        /* And now, just process events until...  */
+    event_process();             /* ...kingdom come.                       */
+  return (0);                    /* Return successfully                    */
+}
diff --git a/StraySrc/Glass/!Glass/c/iconData b/StraySrc/Glass/!Glass/c/iconData
new file mode 100644 (file)
index 0000000..256c08d
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * iconData.c
+ *
+ * Central handling for icon data
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+
+#include "glass.h"
+#include "iconData.h"
+#include "indir.h"
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * BOOL iconData_processIcon
+ * (
+ *   glass_windPointer *w,
+ *   int i;
+ *   iconData_proc proc,
+ *   BOOL updateSize,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Processes one icon in the given window.  This routine will replace all
+ *  the indirection pointers with pointers to blocks from the indirection
+ *  heap.
+ *
+ * Parameters
+ *   glass_windPointer *w == the window data from which the icon is from
+ *   int i == the icon to update (-1 for the title)
+ *   BOOL updateSize == whether to update the window's size variable
+ *   iconData_proc proc == function to return a pointer to an indirected
+ *     string given what's in the data word.  Pass 0 if its actually a
+ *     valid pointer
+ *   void *handle == pointer to pass to 'proc'
+ *
+ * Returns
+ *  FALSE if it ran out of memory, or TRUE for success
+ */
+
+BOOL iconData_processIcon
+(
+  glass_windPointer *w,
+  int i,
+  iconData_proc proc,
+  BOOL updateSize,
+  void *handle
+)
+{
+  char *p;
+  char *q;
+  char *indir;
+  char *valid;
+  int flags;
+  if (i==-1)
+  {
+    flags=w->def->desc.w.titleflags;
+    if (flags & wimp_INDIRECT)
+    {
+      if (proc)
+        indir=proc(w->def->desc.w.title.indirecttext.buffer,handle);
+      else
+        indir=w->def->desc.w.title.indirecttext.buffer;
+      utils_ctermToNterm(indir);
+      if (w->def->desc.w.title.indirecttext.bufflen<strlen(indir)+1)
+        w->def->desc.w.title.indirecttext.bufflen=strlen(indir)+1;
+      p=indir_alloc(w->def->desc.w.title.indirecttext.bufflen);
+      if (!p)
+        return (FALSE);
+
+      /* --- Watch out -- indir might have moved :-( --- */
+
+      if (proc)
+        indir=proc(w->def->desc.w.title.indirecttext.buffer,handle);
+      else
+        indir=w->def->desc.w.title.indirecttext.buffer;
+      utils_ctermToNterm(indir);
+      
+      strcpy(p,indir);
+      if (flags & wimp_ITEXT &&
+                   w->def->desc.w.title.indirecttext.validstring!=(char *)-1)
+      {
+        if (proc)
+          valid=proc(w->def->desc.w.title.indirecttext.validstring,handle);
+        else
+          valid=w->def->desc.w.title.indirecttext.validstring;
+        utils_ctermToNterm(valid);
+        q=indir_alloc(strlen(valid)+1);
+        if (!q)
+        {
+          indir_free(p);
+          return (FALSE);
+        }
+
+        /* --- Aaarrghh -- valid might have moved.  Find it again --- */
+
+        if (proc)
+          valid=proc(w->def->desc.w.title.indirecttext.validstring,handle);
+        else
+          valid=w->def->desc.w.title.indirecttext.validstring;
+        utils_ctermToNterm(valid);
+
+        strcpy(q,valid);
+        w->def->desc.w.title.indirecttext.validstring=q;
+        if (updateSize)
+          w->size+=strlen(valid)+1;
+      }
+      else if ((flags & 3)==2)
+        w->def->desc.w.title.indirectsprite.spritearea=w->t->s;
+      if (updateSize)
+        w->size+=w->def->desc.w.title.indirecttext.bufflen;
+      w->def->desc.w.title.indirecttext.buffer=p;
+    }
+  }
+  else
+  {
+    flags=w->def->i[i].i.flags;
+    if (flags & wimp_INDIRECT)
+    {
+      if (proc)
+        indir=proc(w->def->i[i].i.data.indirecttext.buffer,handle);
+      else
+        indir=w->def->i[i].i.data.indirecttext.buffer;
+      utils_ctermToNterm(indir);
+      if (w->def->i[i].i.data.indirecttext.bufflen<strlen(indir)+1)
+        w->def->i[i].i.data.indirecttext.bufflen=strlen(indir)+1;
+      p=indir_alloc(w->def->i[i].i.data.indirecttext.bufflen);
+      if (!p)
+        return (FALSE);
+
+      /* --- indir may have moved in a nasty way --- */
+
+      if (proc)
+        indir=proc(w->def->i[i].i.data.indirecttext.buffer,handle);
+      else
+        indir=w->def->i[i].i.data.indirecttext.buffer;
+      utils_ctermToNterm(indir);
+
+      strcpy(p,indir);
+      if (flags & wimp_ITEXT && 
+                    w->def->i[i].i.data.indirecttext.validstring!=(char *)-1)
+      {
+        if (proc)
+          valid=proc(w->def->i[i].i.data.indirecttext.validstring,handle);
+        else
+          valid=w->def->i[i].i.data.indirecttext.validstring;
+        utils_ctermToNterm(valid);
+        q=indir_alloc(strlen(valid)+1);
+        if (!q)
+        {
+          indir_free(p);
+          return (FALSE);
+        }
+
+       /* --- There's a saboteur about moving valid around --- */
+
+        if (proc)
+          valid=proc(w->def->i[i].i.data.indirecttext.validstring,handle);
+        else
+          valid=w->def->i[i].i.data.indirecttext.validstring;
+        utils_ctermToNterm(valid);
+
+        strcpy(q,valid);
+        w->def->i[i].i.data.indirecttext.validstring=q;
+        if (updateSize)
+          w->size+=strlen(valid)+1;
+      }
+      else if ((flags & 3)==2)
+        w->def->i[i].i.data.indirectsprite.spritearea=w->t->s;
+      if (updateSize)
+        w->size+=w->def->i[i].i.data.indirecttext.bufflen;
+      w->def->i[i].i.data.indirecttext.buffer=p;
+    }
+  }
+  return (TRUE);
+}
+
+/*
+ * BOOL iconData_handleFont(glass_windPointer *w,wimp_iconflags *f)
+ *
+ * Use
+ *  Processes a font handle, refinding etc. and adding to font reference
+ *  array.  It assumes the icon is from an external source, and doesn't
+ *  attempt to free the font.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon/title to fiddle
+ *  wimp_iconflags *f == icon flags to fiddle with
+ *
+ * Returns
+ *  TRUE if all went well, or FALSE if the icon's font has been lost.  In
+ *  this case the icon has been deantialiased(!) leaving potentially very
+ *  strange colours.
+ */
+
+BOOL iconData_handleFont(glass_windPointer *w,wimp_iconflags *f)
+{
+  os_regset r;
+  int fhandle;
+  char buff[50];
+  if (*f & wimp_IFONT)
+  {
+    fhandle=(*f>>24) & 0xff;
+    r.r[0]=fhandle;
+    r.r[1]=(int)buff;
+    if (os_swix(XFont_ReadDefn,&r))
+    {
+      *f&=~wimp_IFONT;
+      return (FALSE);
+    }
+    r.r[4]=r.r[5]=0;
+    if (os_swix(XFont_FindFont,&r))
+    {
+      *f&=~wimp_IFONT;
+      return (FALSE);
+    }
+    *f=(*f & 0x00ffffff) | (fhandle<<24);
+    w->antiAliased=TRUE;
+    w->fonts[fhandle]++;
+  }
+  return (TRUE);
+}
diff --git a/StraySrc/Glass/!Glass/c/indir b/StraySrc/Glass/!Glass/c/indir
new file mode 100644 (file)
index 0000000..00a9153
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * indir.c
+ *
+ * Control of memory allocation
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdlib.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#include "steel/Steel.h"
+
+#include "steel/buttons.h"
+#include "steel/bbc.h"
+
+
+extern void flex_dump(const char *p);
+
+/*
+ * Glass headers
+ */
+
+#include "gIcons.h"
+
+#include "glass.h"
+#include "heap.h"
+#include "indir.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+static heap_infostr indir__info;
+static BOOL indir__outOfDate;
+static dbox indir__dbox;
+
+/*----- Support routines --------------------------------------------------*/
+
+/*
+ * void indir__update(void *handle)
+ *
+ * Use
+ *  Updates the heap info window if necessary
+ */
+
+static void indir__update(void *handle)
+{
+  unused(handle);
+  if (indir__dbox)
+  {
+    indir__info=heap_info();
+    dbox_setfield(indir__dbox,
+                  glass_HEAPSIZE,
+                  "%s",
+                  utils_cvtSize(indir__info.size));
+    dbox_setfield(indir__dbox,
+                  glass_FREESIZE,
+                  "%s",
+                  utils_cvtSize(indir__info.free));
+    dbox_setfield(indir__dbox,
+                  glass_LARGEST,
+                  "%s",
+                  utils_cvtSize(indir__info.largest));
+    buttons_updateSlider(indir__dbox,
+                         glass_HEAPSLIDE,
+                         indir__info.size,
+                         indir__info.size-indir__info.free,
+                         11,
+                         FALSE);
+  }
+  if (indir__outOfDate)
+  {
+    win_removeIdleClaimer(indir__update,0);
+    indir__outOfDate=FALSE;
+  }
+}
+
+/*----- Event handlers ----------------------------------------------------*/
+
+/*
+ * void indir__dboxRedraw(wimp_redrawstr *r,void *handle)
+ *
+ * Use
+ *  Redraws the dbox used to show heap information
+ *
+ * Parameters
+ *  wimp_redrawstr *r == information about the redraw
+ *  void *handle == a pointer (ignored)
+ */
+
+static void indir__dboxRedraw(wimp_redrawstr *r,void *handle)
+{
+  unused(r);
+  unused(handle);
+  buttons_redrawSlider(indir__dbox,glass_HEAPSLIDE,indir__info.size,
+                                 indir__info.size-indir__info.free,11,FALSE);
+}
+
+/*
+ * BOOL indir__dboxRaw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles raw events (just redraw requests for the moment) for the heap
+ *  info dialogue.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  wimp_eventstr *e == the event that occurred
+ *  void *handle == a pointer (ignored)
+ *
+ * Returns
+ *  TRUE if the event has been dealt with
+ */
+
+static BOOL indir__dboxRaw(dbox d,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  unused(d);
+  unused(handle);
+  switch (e->e)
+  {
+    case wimp_EREDRAW:
+      wimpt_redraw(indir__dboxRedraw,0);
+      handled=TRUE;
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void indir__dboxHandler(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles events for the heap info dialogue box.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the event that occurred
+ *  void *handle == a pointer (ignored)
+ */
+
+static void indir__dboxHandler(dbox d,dbox_field f,void *handle)
+{
+  unused(handle);
+  switch (f)
+  {
+    case dbox_CLOSE:
+      dbox_delete(d);
+      win_remove_idle_claimer(indir__update,0);
+      indir__dbox=0;
+      break;
+  #ifdef _dll_NODLL
+    case 9:
+      dbox_clickicon(d,f);
+      dbox_unclick();
+      bbc_vdu(26);
+      bbc_vdu(4);
+      bbc_vdu(12);
+      bbc_vdu(14);
+      flex_dump("Glass flex dump");
+      bbc_get();
+      bbc_vdu(15);
+      bbc_vdu(5);
+      wimpt_forceredraw();
+      break;
+  #endif
+    case dbox_HELP:
+      help_startHelp();
+      help_addLine(msgs_lookup("idhHPINF"));
+      help_endHelp();
+      break;
+  }
+}
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void indir_init(void)
+ *
+ * Use
+ *  Jumps in to ensure that indir gets the first flex block, so it doesn't
+ *  move.
+ */
+
+void indir_init(void)
+{
+  heap_init();
+}
+
+/*
+ * void *indir_alloc(int size)
+ *
+ * Use
+ *  Allocate memory from heap.
+ *
+ * Parameters
+ *  int size == the number of bytes the caller wants
+ */
+
+void *indir_alloc(size_t size)
+{
+  if (!indir__outOfDate)
+  {
+    indir__outOfDate=TRUE;
+    win_addIdleClaimer(indir__update,win_DONTCARE,0);
+  }
+  return (heap_alloc(size));
+}
+
+/*
+ * void indir_free(void *p)
+ *
+ * Use
+ *  Reclaims the memory from the block pointed to by p.  Some simple checks
+ *  are used to ensure that p is valid.
+ *
+ * Parameters
+ *  void *p == pointer to a block to free.
+ */
+
+void indir_free(void *p)
+{
+  if (!indir__outOfDate)
+  {
+    indir__outOfDate=TRUE;
+    win_addIdleClaimer(indir__update,win_DONTCARE,0);
+  }
+  heap_free(p);
+}
+
+/*
+ * void *indir_realloc(void *p,int newsize)
+ *
+ * Use
+ *  Resizes a heap block.
+ *
+ * Parameters
+ *  void *p == pointer to block to resize
+ *  int newsize == the new size to make it
+ *
+ * Returns
+ *  Pointer to the block (may have moved) or 0 (failure, block didn't move)
+ */
+
+void *indir_realloc(void *p,int newsize)
+{
+  if (!indir__outOfDate)
+  {
+    indir__outOfDate=TRUE;
+    win_addIdleClaimer(indir__update,win_DONTCARE,0);
+  }
+  return (heap_realloc(p,newsize));
+}
+
+/*
+ * void indir_heapInfo(void)
+ *
+ * Use
+ *  Displays a dialogue box showing current heap stats
+ */
+
+void indir_heapInfo(void)
+{
+  if (!indir__dbox)
+  {
+    indir__dbox=dbox_create("heapInfo");
+    indir__outOfDate=FALSE;
+    indir__update(0);
+  #ifndef _dll_NODLL
+    dbox_shadeicon(indir__dbox,9,TRUE);
+  #endif
+    dbox_eventHandler(indir__dbox,indir__dboxHandler,0);
+    dbox_rawEventHandler(indir__dbox,indir__dboxRaw,0);
+  }
+  dbox_display(indir__dbox,dbox_STATIC_LASTPOS);
+}
diff --git a/StraySrc/Glass/!Glass/c/intMsgs b/StraySrc/Glass/!Glass/c/intMsgs
new file mode 100644 (file)
index 0000000..f53d5c7
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * intMsgs.h
+ *
+ * Definitions of Glass internal broadcasts
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdarg.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#include "steel/Steel.h"
+
+/*
+ * Glass headers
+ */
+
+#include "glass.h"
+#include "intMsgs.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+/*
+ * This array is to explain to intMsgs_send how many parameters there are
+ * for each message.  -1 as an entry indicates special processing (i.e. the
+ * entries are not all 1 word in length.
+ */
+
+static int intMsgs__parameters[]=
+{
+  1,                             /* glass_DELETEWINDOW                  */
+  1,                             /* glass_DELETEFILE                    */
+  0,                             /* glass_KILLFILES                     */
+  0,                             /* glass_CLOSEDOWN                     */
+  1,                             /* glass_RENAME                        */
+  1,                             /* glass_SAVEFILE                      */
+  1,                             /* glass_REDRAW                        */
+  1,                             /* glass_AUTOSAVE                      */
+  1,                             /* glass_SPRITECHANGE                  */
+  0,                             /* glass_MODECHANGE                    */
+};
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void intMsgs_send(glass_intMessage type,...)
+ *
+ * Use
+ *  Sends out an internal broadcast message.  The routine constructs a
+ *  Message_StraylightInternal block and sends it out via win_broadcast.
+ *  The parameters should be as for the entries in the appropriate
+ *  structure, in order (i.e one for glass_DELETEWINDOW, two for
+ *  glass_DELETEICON).
+ *
+ * Parameters
+ *  glass_intMessage type == the message type.  This is used to decide
+ *    how many and what type of parameters to accept.
+ */
+
+void intMsgs_send(glass_intMessage type,...)
+{
+  va_list ap;
+  int i;
+  wimp_eventstr e;
+  va_start(ap,type);
+  e.data.msg.hdr.action=wimp_MINTERNAL;
+  e.data.msg.data.words[0]=type;
+  if (intMsgs__parameters[type]==-1)
+  {
+     switch (type)
+     {
+       default:
+         werr(TRUE,msgs_lookup("imSMT"));
+         break;
+     }
+  }
+  else for (i=1;i<=intMsgs__parameters[type];i++)
+    e.data.msg.data.words[i]=va_arg(ap,int);
+  e.e=wimp_ESEND;
+  win_broadcast(&e);
+  va_end(ap);
+}
diff --git a/StraySrc/Glass/!Glass/c/tearEdit b/StraySrc/Glass/!Glass/c/tearEdit
new file mode 100644 (file)
index 0000000..2850488
--- /dev/null
@@ -0,0 +1,1387 @@
+/*
+ * tearEdit.c
+ *
+ * Editing icons in tearoff menus
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel and RISC_OSLib headers
+ */
+
+#define _STDAPP
+#include "steel/Steel.h"
+
+#include "steel/buttons.h"
+#include "steel/akbd.h"
+#include "steel/buffer.h"
+#include "steel/colourtran.h"
+#include "steel/tearoff.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+
+#include "glass.h"
+#include "window.h"
+#include "tfile.h"
+#include "indir.h"
+#include "tearEdit.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+static glass_windPointer *tearEdit__window;   /* The window with the icon  */
+static int tearEdit__icon=-1;           /* The icon we're editing          */
+
+static tearoff tearEdit__main;         /* The main tearoff edit menu      */
+static tearoff tearEdit__data;
+static tearoff tearEdit__appear;
+static tearoff tearEdit__actions;
+static tearoff tearEdit__btype;
+static tearoff tearEdit__colours;
+
+/*----- Menu structure ----------------------------------------------------*
+ *
+ * Icon data => Data => [dbox]
+ *              Indirected => [dbox]
+ *              Text
+ *              Sprite
+ * Appearance => Anti-aliased => Font => [font menu]
+ *                               Size => [dbox]
+ *               Horizontally centred
+ *               Vertically centred
+ *               Right aligned
+ *               Border
+ *               Filled background
+ *               Half-size sprite
+ *               Needs help
+ * Actions => Button type => [type menu]
+ *            ESG => [dbox]
+ *            Adjust toggles
+ *            Selected
+ *            Shaded
+ * Colours => Foreground => [dbox]
+ *            Background => [dbox]
+ * Position => [dbox]
+ * Size => [dbox]
+ */
+
+/*----- Icon numbers for dialogues ----------------------------------------*/
+
+#define tearEdit__DATAOK 0
+#define tearEdit__DATAWRITE 1
+
+#define tearEdit__ESGOK 0
+#define tearEdit__ESGUP 1
+#define tearEdit__ESGDOWN 2
+#define tearEdit__ESGWRITE 3
+
+#define tearEdit__INDOK 0
+#define tearEdit__INDINDIR 2
+#define tearEdit__INDSWRITE 4
+#define tearEdit__INDSUP 5
+#define tearEdit__INDSDOWN 6
+#define tearEdit__INDMINIMISE 7
+#define tearEdit__INDPART 8
+#define tearEdit__INDVALID 9
+#define tearEdit__INDVALSTRING 10
+
+#define tearEdit__COLOUROK 0
+#define tearEdit__COLOURCOLS 2
+
+#define tearEdit__POSOK 0
+#define tearEdit__POSUP 2
+#define tearEdit__POSDOWN 3
+#define tearEdit__POSLEFT 4
+#define tearEdit__POSRIGHT 5
+#define tearEdit__POSWRITE 6
+
+/*----- Item numbers for menus --------------------------------------------*/
+
+enum
+{
+  tearEdit__MAINDATA=1,
+  tearEdit__MAINAPPEAR,
+  tearEdit__MAINACTIONS,
+  tearEdit__MAINCOLOURS,
+  tearEdit__MAINPOS,
+  tearEdit__MAINSIZE
+};
+
+enum
+{
+  tearEdit__DATADATA=1,
+  tearEdit__DATAINDIR,
+  tearEdit__DATATEXT,
+  tearEdit__DATASPRITE
+};
+
+enum
+{
+  tearEdit__APPEARHCENTRE=1,
+  tearEdit__APPEARVCENTRE,
+  tearEdit__APPEARRALIGN,
+  tearEdit__APPEARBORDER,
+  tearEdit__APPEARFILLED,
+  tearEdit__APPEARHALF,
+  tearEdit__APPEARHELP
+};
+
+enum
+{
+  tearEdit__ACTIONSBTYPE=1,
+  tearEdit__ACTIONSESG,
+  tearEdit__ACTIONSADJUST,
+  tearEdit__ACTIONSSELECT,
+  tearEdit__ACTIONSSHADE
+};
+
+enum
+{
+  tearEdit__COLOURSFORE=1,
+  tearEdit__COLOURSBACK
+};
+
+/*----- Messing about with indirected data --------------------------------*/
+
+/*
+ * void tearEdit__setData(wimp_icon *icn,
+ *                        char *data,
+ *                        char *valid,
+ *                        int newsize)
+ *
+ * Use
+ *  Sets an icon's data as required, possibly extending the data buffer and
+ *  indirecting if required.  Old buffers are freed and new ones allocated
+ *  etc.
+ *
+ * Parameters
+ *  wimp_icon *icn == the icon to edit in this way
+ *  char *data == pointer to the new data string, or 0 to leave it alone
+ *  char *valid == pointer to the new validation string, or 0 to leave it
+ *    alone, or tearEdit__NOVALID to delete it
+ *  int newsize == the size of the new indirection buffer, or
+ *    tearEdit__NOINDIR to not indirect the string
+ */
+
+#define tearEdit__NOVALID ((char *)(-1))
+#define tearEdit__NOINDIR (-1)
+#define tearEdit__NOCHANGE (-2)
+
+static void tearEdit__setData(wimp_icon *icn,
+                              char *data,
+                              char *valid,
+                              int newsize)
+{
+  char nonind[13];
+  int maxlen=newsize;
+  wimp_iconflags nf=icn->flags;
+  char *p=0,*q;
+
+  /* --- Fill in default arguments --- */
+
+  if (!data)
+  {
+    if (tst(icn->flags,8))
+    {
+      data=icn->data.indirecttext.buffer;
+      utils_ctermToNterm(data);
+    }
+    else
+    {
+      memcpy(nonind,icn->data.text,12);
+      nonind[12]=0;
+      utils_ctermToNterm(nonind);
+      data=nonind;
+    }
+  }
+
+  if (!valid)
+  {
+    if (tst(icn->flags,0) && tst(icn->flags,8))
+    {
+      valid=icn->data.indirecttext.validstring;
+      if (valid!=tearEdit__NOVALID)
+        utils_ctermToNterm(valid);
+    }
+    else
+      valid=tearEdit__NOVALID;
+  }
+
+  if (maxlen==tearEdit__NOCHANGE)
+  {
+    if (tst(icn->flags,8))
+      maxlen=icn->data.indirecttext.bufflen;
+    else
+      maxlen=tearEdit__NOINDIR;
+  }
+
+  /* --- Set up new icon flags --- */
+
+  if (maxlen==tearEdit__NOINDIR)
+  {
+    maxlen=12;
+    reset(nf,8);
+  }
+  else
+    set(nf,8);
+
+  if (strlen(data)>=maxlen)
+  {
+    set(nf,8);
+    maxlen=strlen(data)+1;
+  }
+
+  /* --- Set up new buffers for data --- */
+
+  if (tst(nf,8))
+  {
+    if (p=indir_alloc(maxlen),!p)
+    {
+      werr(FALSE,msgs_lookup("teNEMUI"));
+      return;
+    }
+    if (tst(nf,0) && valid!=tearEdit__NOVALID)
+    {
+      if (q=indir_alloc(strlen(valid)+1),!q)
+      {
+        indir_free(p);
+        werr(FALSE,msgs_lookup("teNEMUI"));
+        return;
+      }
+      window_redrawIcon(tearEdit__window,tearEdit__icon);
+      strcpy(q,valid);
+      valid=q;
+      tearEdit__window->size+=strlen(valid)+1;
+    }
+    strcpy(p,data);
+    tearEdit__window->size+=maxlen;
+  }
+
+  /* --- Clear out the old buffers now --- */
+
+  if (tst(icn->flags,8))
+  {
+    tearEdit__window->size-=icn->data.indirecttext.bufflen;
+    if (tst(icn->flags,0) &&
+        icn->data.indirecttext.validstring!=tearEdit__NOVALID)
+    {
+      utils_ctermToNterm(icn->data.indirecttext.validstring);
+      tearEdit__window->size-=strlen(icn->data.indirecttext.validstring)+1;
+    }
+  }
+
+  /* --- Now copy the new data across --- */
+
+  if (tst(nf,8))
+  {
+    icn->data.indirecttext.bufflen=maxlen;
+    icn->data.indirecttext.buffer=p;
+    if ((nf & 3)==2)
+      icn->data.indirectsprite.spritearea=tearEdit__window->t->s;
+    else
+      icn->data.indirecttext.validstring=valid;
+  }
+  else
+    memcpy(icn->data.text,data,12);
+
+  icn->flags=nf;
+
+  /* --- That's it (phew!) --- */
+
+  window_redrawIcon(tearEdit__window,tearEdit__icon);
+  tfile_markAsAltered(tearEdit__window->t);
+}
+
+/*----- Icon data dialogue boxes ------------------------------------------*/
+
+/* --- Alter data --- */
+
+/*
+ * void tearEdit__dataBox(void)
+ *
+ * Use
+ *  Displays a dialogue box allowing the user to change an icon's data.
+ */
+
+static void tearEdit__dataBox(void)
+{
+  dbox d;
+  wimp_icon *icn;
+  char nonind[256];
+  char *data;
+  BOOL done=FALSE;
+
+  if (!tearEdit__window || tearEdit__icon==-1)
+    return;
+  icn=&tearEdit__window->def->i[tearEdit__icon].i;
+  if (!(icn->flags & 3))
+    return;
+
+  if (tst(icn->flags,8))
+    data=icn->data.indirecttext.buffer;
+  else
+  {
+    memcpy(nonind,icn->data.text,12);
+    nonind[13]=0;
+    data=nonind;
+  }
+  utils_ctermToNterm(data);
+
+  d=dbox_create("teditData");
+  if (!d)
+    return;
+
+  dbox_setfield(d,tearEdit__DATAWRITE,"%s",data);
+  dbox_display(d,dbox_MENU_OVERPTR);
+
+  while (!done)
+  {
+    switch (dbox_fillin(d))
+    {
+      case dbox_CLOSE:
+        done=TRUE;
+        break;
+      case tearEdit__DATAOK:
+        dbox_clickicon(d,tearEdit__DATAOK);
+        dbox_getfield(d,tearEdit__DATAWRITE,nonind,256);
+        tearEdit__setData(icn,nonind,0,tearEdit__NOCHANGE);
+        if (dbox_wasAdjustClick())
+          dbox_unclick();
+        else
+        {
+          dbox_hide(d);
+          dbox_unclick();
+          done=TRUE;
+        }
+        break;
+    }
+  }
+
+  dbox_delete(d);
+}
+
+/* --- Alter indirection --- */
+
+/*
+ * void tearEdit__setupIndBox(dbox d,wimp_icon *icn,BOOL *ind,BOOL *val)
+ *
+ * Use
+ *  Sets up the icons in an indirection dialogue box.
+ *
+ * Parameters
+ *  dbox d == the dialogue box's handle
+ *  wimp_icon *icn == the icon to read the definition from
+ *  BOOL *ind == (output) whether the icon is indirected
+ *  BOOL *val == (output) whether the icon has a validation string
+ */
+
+static void tearEdit__setupIndBox(dbox d,wimp_icon *icn,BOOL *ind,BOOL *val)
+{
+  if (tst(icn->flags,8))
+  {
+    *ind=TRUE;
+    dbox_selecticon(d,tearEdit__INDINDIR,TRUE);
+    dbox_shadeicon(d,tearEdit__INDSUP,FALSE);
+    dbox_shadeicon(d,tearEdit__INDSDOWN,FALSE);
+    dbox_shadeicon(d,tearEdit__INDSWRITE,FALSE);
+    dbox_shadeicon(d,tearEdit__INDMINIMISE,FALSE);
+    dbox_shadeicon(d,tearEdit__INDPART,FALSE);
+    dbox_setfield(d,tearEdit__INDSWRITE,"%i",icn->data.indirecttext.bufflen);
+    if (tst(icn->flags,0))
+    {
+      if (icn->data.indirecttext.validstring!=tearEdit__NOVALID)
+      {
+        *val=TRUE;
+        dbox_selecticon(d,tearEdit__INDVALID,TRUE);
+        dbox_shadeicon(d,tearEdit__INDVALSTRING,FALSE);
+        utils_ctermToNterm(icn->data.indirecttext.validstring);
+        dbox_setfield(d,
+                      tearEdit__INDVALSTRING,
+                      "%s",
+                      icn->data.indirecttext.validstring);
+      }
+      else
+      {
+        *val=FALSE;
+        dbox_selecticon(d,tearEdit__INDVALID,FALSE);
+        dbox_shadeicon(d,tearEdit__INDVALID,FALSE);
+        dbox_shadeicon(d,tearEdit__INDVALSTRING,TRUE);
+        dbox_setfield(d,tearEdit__INDVALSTRING,"");
+      }
+    }
+    else
+    {
+      *val=FALSE;
+      dbox_selecticon(d,tearEdit__INDVALID,FALSE);
+      dbox_shadeicon(d,tearEdit__INDVALID,TRUE);
+      dbox_shadeicon(d,tearEdit__INDVALSTRING,TRUE);
+      dbox_setfield(d,tearEdit__INDVALSTRING,"");
+    }
+  }
+  else
+  {
+    *ind=FALSE;
+    dbox_selecticon(d,tearEdit__INDINDIR,FALSE);
+    dbox_shadeicon(d,tearEdit__INDSUP,TRUE);
+    dbox_shadeicon(d,tearEdit__INDSDOWN,TRUE);
+    dbox_shadeicon(d,tearEdit__INDSWRITE,TRUE);
+    dbox_shadeicon(d,tearEdit__INDMINIMISE,TRUE);
+    dbox_shadeicon(d,tearEdit__INDPART,TRUE);
+    dbox_setfield(d,tearEdit__INDSWRITE,"12");
+    *val=FALSE;
+    dbox_selecticon(d,tearEdit__INDVALID,FALSE);
+    dbox_shadeicon(d,tearEdit__INDVALID,TRUE);
+    dbox_shadeicon(d,tearEdit__INDVALSTRING,TRUE);
+    dbox_setfield(d,tearEdit__INDVALSTRING,"");
+  }
+}
+
+/*
+ * void tearEdit__indirBox(void)
+ *
+ * Use
+ *  Displays and handles an indirection dialogue box.
+ */
+
+static void tearEdit__indirBox(void)
+{
+  dbox d;
+  char buff[256];
+  wimp_icon *icn;
+  int size;
+  BOOL done=FALSE;
+  BOOL ind;
+  BOOL val;
+  buttons_simpleArrow sa={0,9999,FALSE};
+  dbox_field f;
+
+  if (!tearEdit__window || tearEdit__icon==-1)
+    return;
+
+  icn=&tearEdit__window->def->i[tearEdit__icon].i;
+  if (!(icn->flags & 3))
+    return;
+
+  d=dbox_create("teditIndir");
+  if (!d)
+    return;
+
+  tearEdit__setupIndBox(d,icn,&ind,&val);
+
+  dbox_display(d,dbox_MENU_OVERPTR);
+  while (!done)
+  {
+    switch (f=dbox_fillin(d),f)
+    {
+      case dbox_CLOSE:
+        done=TRUE;
+        break;
+      case tearEdit__INDINDIR:
+        ind=!ind;
+        dbox_shadeicon(d,tearEdit__INDSUP,!ind);
+        dbox_shadeicon(d,tearEdit__INDSDOWN,!ind);
+        dbox_shadeicon(d,tearEdit__INDSWRITE,!ind);
+        dbox_shadeicon(d,tearEdit__INDMINIMISE,!ind);
+        dbox_shadeicon(d,tearEdit__INDPART,!ind);
+        if (tst(icn->flags,0))
+        {
+          dbox_shadeicon(d,tearEdit__INDVALID,!ind);
+          dbox_shadeicon(d,tearEdit__INDVALSTRING,!(ind && val));
+        }
+        break;
+      case tearEdit__INDSUP:
+        buttons_arrow(d,f,d,tearEdit__INDSWRITE,0,+1,&sa);
+        break;
+      case tearEdit__INDSDOWN:
+        buttons_arrow(d,f,d,tearEdit__INDSWRITE,0,-1,&sa);
+        break;
+      case tearEdit__INDMINIMISE:
+        dbox_clickicon(d,f);
+        if (icn->flags & wimp_INDIRECT)
+        {
+          dbox_setfield(d,tearEdit__INDSWRITE,"%i",
+                        strlen(icn->data.indirecttext.buffer)+1);
+        }
+        else
+        {
+          char buff[15];
+          memcpy(buff,icn->data.text,12);
+          buff[12]=0;
+          utils_ctermToNterm(buff);
+          dbox_setfield(d,tearEdit__INDSWRITE,"%i",strlen(buff)+1);
+        }
+        dbox_unclick();
+        break;
+      case tearEdit__INDVALID:
+        val=!val;
+        dbox_shadeicon(d,tearEdit__INDVALSTRING,!val);
+        break;
+      case tearEdit__INDOK:
+        dbox_clickicon(d,tearEdit__INDOK);
+        if (ind)
+        {
+          dbox_scanfield(d,tearEdit__INDSWRITE,"%d",&size);
+          if (val)
+          {
+            dbox_getfield(d,tearEdit__INDVALSTRING,buff,256);
+            tearEdit__setData(icn,0,buff,size);
+          }
+          else
+            tearEdit__setData(icn,0,tearEdit__NOVALID,size);
+        }
+        else
+          tearEdit__setData(icn,0,tearEdit__NOVALID,tearEdit__NOINDIR);
+        if (dbox_wasAdjustClick())
+        {
+          tearEdit__setupIndBox(d,icn,&ind,&val);
+          dbox_unclick();
+        }
+        else
+        {
+          dbox_hide(d);
+          dbox_unclick();
+          done=TRUE;
+        }
+        break;
+    }
+  }
+
+  dbox_delete(d);
+}
+
+/*----- ESG dialogue box --------------------------------------------------*/
+
+/*
+ * BOOL tearEdit__esgRaw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles raw events for the ESG dialogue box (basically, it forces the
+ *  ESG number to be in the correct range when you type it in.
+ *
+ * Parameters
+ *  dbox d == the dialogue box handle for the ESG dbox
+ *  wimp_eventstr *e == the event wot happened
+ *  void *handle == a handle wot we ignore
+ */
+
+static BOOL tearEdit__esgRaw(dbox d,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  BOOL cursor=FALSE;
+  unused(handle);
+
+  switch (e->e)
+  {
+    case wimp_EKEY:
+      switch (e->data.key.c.i)
+      {
+        case tearEdit__ESGWRITE:
+          switch (e->data.key.chcode)
+          {
+            case akbd_DownK:
+            case akbd_UpK:
+            case akbd_TabK:
+            case akbd_TabK+akbd_Sh:
+            case akbd_UpK+akbd_Ctl:
+            case akbd_DownK+akbd_Ctl:
+              cursor=TRUE;
+              break;
+          }
+          handled=buttons_insertChar(d,e->data.key.chcode,'0','9');
+          if (handled || cursor)
+            buttons_arrowClick(d,tearEdit__ESGWRITE,0,31,0,FALSE);
+          break;
+      }
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void tearEdit__esgBox(void)
+ *
+ * Use
+ *  Allows the user to choose an exclusive selection group for an icon.
+ */
+
+static void tearEdit__esgBox(void)
+{
+  dbox d;
+  BOOL done=FALSE;
+  wimp_icon *icn;
+  int esg;
+  buttons_simpleArrow sa={0,31,FALSE};
+  dbox_field f;
+
+  if (!tearEdit__window || tearEdit__icon==-1)
+    return;
+
+  d=dbox_create("teditESG");
+  if (!d)
+    return;
+
+  icn=&tearEdit__window->def->i[tearEdit__icon].i;
+
+  dbox_setfield(d,tearEdit__ESGWRITE,"%i",(icn->flags & 0x001F0000)>>16);
+  dbox_rawEventHandler(d,tearEdit__esgRaw,0);
+
+  dbox_display(d,dbox_MENU_OVERPTR);
+  while (!done)
+  {
+    switch (f=dbox_fillin(d),f)
+    {
+      case dbox_CLOSE:
+        done=TRUE;
+        break;
+      case tearEdit__ESGUP:
+        buttons_arrow(d,f,d,tearEdit__ESGWRITE,0,+1,&sa);
+        break;
+      case tearEdit__ESGDOWN:
+        buttons_arrow(d,f,d,tearEdit__ESGWRITE,0,-1,&sa);
+        break;
+      case tearEdit__ESGOK:
+        dbox_clickicon(d,tearEdit__ESGOK);
+        dbox_scanfield(d,tearEdit__ESGWRITE,"%d",&esg);
+        icn->flags &= ~0x001F0000;
+        icn->flags |= esg<<16;
+        window_redrawIcon(tearEdit__window,tearEdit__icon);
+        tfile_markAsAltered(tearEdit__window->t);
+        if (dbox_wasAdjustClick())
+          dbox_unclick();
+        else
+        {
+          dbox_hide(d);
+          dbox_unclick();
+          done=TRUE;
+        }
+        break;
+    }
+  }
+
+  dbox_delete(d);
+}
+
+/*----- Colour dialogue boxes ---------------------------------------------*/
+
+/*
+ * void tearEdit__addBorder(dbox d,int colour)
+ *
+ * Use
+ *  Adds a border around the specified colour.
+ *
+ * Parameters
+ *  dbox d == the colour dialogue box's handle
+ *  int colour == the number of the colour to select
+ */
+
+static void tearEdit__addBorder(dbox d,int colour)
+{
+  static wimp_paletteword blacknwhite[]={0,0,0,0, 0,255,255,255,};
+  static wimp_palettestr wimppal;
+  int col;
+
+  wimpt_noerr(wimp_readpalette(&wimppal));
+  wimpt_noerr(colourtran_return_Oppcolourformode(wimppal.c[colour],
+                                                 0,
+                                                 blacknwhite,
+                                                 &col));
+  wimpt_noerr(colourtran_return_colourformode(blacknwhite[col],
+                                              12,
+                                              wimppal.c,
+                                              &col));
+
+  /* --- We now have the correctly contrasting colour in col --- */
+
+  wimpt_noerr(wimp_set_icon_state(dbox_syshandle(d),
+                                  colour+tearEdit__COLOURCOLS,
+                                  5 | (col<<24),
+                                  0x0F000005));
+}
+
+#define tearEdit__removeBorder(d,colour) \
+  wimpt_noerr(wimp_set_icon_state(dbox_syshandle(d), \
+                                  colour+tearEdit__COLOURCOLS, \
+                                  0x00000000, \
+                                  0x0F000005)); \
+
+/*
+ * void tearEdit__colourBox(BOOL fore)
+ *
+ * Use
+ *  Displays a dialogue box from which the user may choose an icon colour.
+ *
+ * Parameters
+ *  BOOL fore == whether this is the foreground or background we're editing
+ */
+
+static void tearEdit__colourBox(BOOL fore)
+{
+  dbox d;
+  wimp_icon *icn;
+  BOOL done=FALSE;
+  int colour;
+  dbox_field f;
+
+  if (!tearEdit__window || tearEdit__icon==-1)
+    return;
+
+  icn=&tearEdit__window->def->i[tearEdit__icon].i;
+
+  if (tst(icn->flags,6))
+    return;
+
+  d=dbox_create("teditColour");
+  if (!d)
+    return;
+
+  if (fore)
+    colour=(icn->flags & 0x0F000000)>>24;
+  else
+    colour=(icn->flags & 0xF0000000)>>28;
+
+  win_settitle(dbox_syshandle(d),msgs_lookup(fore ? "teFG" : "teBG"));
+
+  tearEdit__addBorder(d,colour);
+
+  dbox_display(d,dbox_MENU_OVERPTR);
+  while (!done)
+  {
+    switch (f=dbox_fillin(d),f)
+    {
+      case dbox_CLOSE:
+        done=TRUE;
+        break;
+      case tearEdit__COLOUROK:
+        dbox_clickicon(d,tearEdit__COLOUROK);
+        if (fore)
+        {
+          icn->flags &= ~0x0F000000;
+          icn->flags |= colour<<24;
+        }
+        else
+        {
+          icn->flags &= ~0xF0000000;
+          icn->flags |= colour<<28;
+        }
+        window_redrawIcon(tearEdit__window,tearEdit__icon);
+        tfile_markAsAltered(tearEdit__window->t);
+        if (dbox_wasAdjustClick())
+          dbox_unclick();
+        else
+        {
+          dbox_hide(d);
+          dbox_unclick();
+          done=TRUE;
+        }
+        break;
+      default:
+        if (f>=tearEdit__COLOURCOLS &&
+            f<tearEdit__COLOURCOLS+16 &&
+            f!=colour+tearEdit__COLOURCOLS)
+        {
+          tearEdit__removeBorder(d,colour);
+          colour=f-tearEdit__COLOURCOLS;
+          tearEdit__addBorder(d,colour);
+        }
+        break;
+    }
+  }
+
+  dbox_delete(d);
+}
+
+/*----- Size and position dialogue boxes ----------------------------------*/
+
+/*
+ * void tearEdit__coordsArrows(dbox d,dbox_field f,int diff,void *handle)
+ *
+ * Use
+ *  Handles a click event on one of the position or size arrow buttons in
+ *  the dialogue box.  See the structure definition below for a description
+ *  of the data structure required.
+ */
+
+typedef struct
+{
+  BOOL xOrY;
+  BOOL sizing;
+}
+tearEdit__coordsArrowstr;
+
+static void tearEdit__coordsArrows(dbox d,
+                                   dbox_field f,
+                                   int diff,
+                                   void *handle)
+{
+  tearEdit__coordsArrowstr *s=handle;
+  int x,y;
+  int *v;
+
+  dbox_scanfield(d,f,"%d,%d",&x,&y);
+  v=s->xOrY ? &x : &y;
+  *v+=diff;
+  if (s->sizing && *v<0)
+    *v=0;
+  dbox_setfield(d,f,"%i,%i",x,y);
+}
+
+/*
+ * void tearEdit__coordsBox(BOOL size)
+ *
+ * Use
+ *  Displays a dialogue box and allows the user to alter either the size or
+ *  position of an icon.
+ *
+ * Parameters
+ *  BOOL size == whether to alter the size or position
+ */
+
+static void tearEdit__coordsBox(BOOL size)
+{
+  dbox d;
+  BOOL done=FALSE;
+  dbox_field f;
+  wimp_icon *icn;
+  int x,y;
+  tearEdit__coordsArrowstr ca;
+
+  if (!tearEdit__window || tearEdit__icon==-1)
+    return;
+
+  d=dbox_create(size ? "teditSize" : "teditPos");
+  if (!d)
+    return;
+
+  icn=&tearEdit__window->def->i[tearEdit__icon].i;
+  if (size)
+  {
+    x=icn->box.x1-icn->box.x0;
+    y=icn->box.y1-icn->box.y0;
+  }
+  else
+  {
+    x=icn->box.x0;
+    y=icn->box.y0;
+  }
+  ca.sizing=size;
+
+  dbox_setfield(d,tearEdit__POSWRITE,"%i,%i",x,y);
+  dbox_display(d,dbox_MENU_OVERPTR);
+
+  while (!done)
+  {
+    f=dbox_fillin(d);
+    switch (f)
+    {
+      case dbox_CLOSE:
+        done=TRUE;
+        break;
+      case tearEdit__POSUP:
+        ca.xOrY=FALSE;
+        buttons_arrow(d,f,d,tearEdit__POSWRITE,
+                      tearEdit__coordsArrows,+wimpt_dy(),&ca);
+        break;
+      case tearEdit__POSDOWN:
+        ca.xOrY=FALSE;
+        buttons_arrow(d,f,d,tearEdit__POSWRITE,
+                      tearEdit__coordsArrows,-wimpt_dy(),&ca);
+        break;
+      case tearEdit__POSLEFT:
+        ca.xOrY=TRUE;
+        buttons_arrow(d,f,d,tearEdit__POSWRITE,
+                      tearEdit__coordsArrows,-wimpt_dx(),&ca);
+        break;
+      case tearEdit__POSRIGHT:
+        ca.xOrY=TRUE;
+        buttons_arrow(d,f,d,tearEdit__POSWRITE,
+                      tearEdit__coordsArrows,+wimpt_dx(),&ca);
+        break;
+      case tearEdit__POSOK:
+        dbox_clickicon(d,f);
+        dbox_scanfield(d,tearEdit__POSWRITE,"%d,%d",&x,&y);
+        window_redrawIcon(tearEdit__window,tearEdit__icon);
+        if (size)
+        {
+          icn->box.x1=icn->box.x0+x;
+          icn->box.y1=icn->box.y0+y;
+        }
+        else
+        {
+          icn->box.x1+=x-icn->box.x0;
+          icn->box.y1+=y-icn->box.y0;
+          icn->box.x0=x;
+          icn->box.y0=y;
+        }
+        window_redrawIcon(tearEdit__window,tearEdit__icon);
+        tfile_markAsAltered(tearEdit__window->t);
+        if (dbox_wasAdjustClick())
+          dbox_unclick();
+        else
+        {
+          dbox_hide(d);
+          dbox_unclick();
+          done=TRUE;
+        }
+        break;
+    }
+  }
+  dbox_delete(d);
+}
+
+/*----- Menu handling -----------------------------------------------------*/
+
+/*
+ * void tearEdit__mainHits(tearoff_message m,int hit,void *handle)
+ * etc.
+ *
+ * Use
+ *  Handles menu events for the main edit icon menu level
+ *
+ * Parameters
+ *  tearoff_message m == the type of event that happened
+ *  int hit == the item it happened to
+ *  void *handle == a waste of a good argument register
+ */
+
+static void tearEdit__mainHits(tearoff_message m,int hit,void *handle)
+{
+  unused(handle);
+  switch (m)
+  {
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      switch (hit)
+      {
+        case tearEdit__MAINPOS:
+          tearEdit__coordsBox(FALSE);
+          break;
+        case tearEdit__MAINSIZE:
+          tearEdit__coordsBox(TRUE);
+          break;
+      }
+      break;
+  }
+}
+
+static void tearEdit__dataHits(tearoff_message m,int hit,void *handle)
+{
+  unused(handle);
+  switch (m)
+  {
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      switch (hit)
+      {
+        case tearEdit__DATADATA:
+          tearEdit__dataBox();
+          break;
+        case tearEdit__DATAINDIR:
+          tearEdit__indirBox();
+          break;
+        case tearEdit__DATATEXT:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_ITEXT;
+          tearEdit__setData(&tearEdit__window->def->i[tearEdit__icon].i,
+                            0,
+                            tearEdit__NOVALID,
+                            tearEdit__NOCHANGE);
+          break;
+        case tearEdit__DATASPRITE:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_ISPRITE;
+          tearEdit__setData(&tearEdit__window->def->i[tearEdit__icon].i,
+                            0,
+                            0,
+                            tearEdit__NOCHANGE);
+          break;
+      }
+      break;
+  }
+}
+
+static void tearEdit__appearHits(tearoff_message m,int hit,void *handle)
+{
+  unused(handle);
+  switch (m)
+  {
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      switch (hit)
+      {
+        case tearEdit__APPEARHCENTRE:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IHCENTRE;
+          window_redrawIcon(tearEdit__window,tearEdit__icon);
+          tfile_markAsAltered(tearEdit__window->t);
+          break;
+        case tearEdit__APPEARVCENTRE:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IVCENTRE;
+          window_redrawIcon(tearEdit__window,tearEdit__icon);
+          tfile_markAsAltered(tearEdit__window->t);
+          break;
+        case tearEdit__APPEARRALIGN:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IRJUST;
+          window_redrawIcon(tearEdit__window,tearEdit__icon);
+          tfile_markAsAltered(tearEdit__window->t);
+          break;
+        case tearEdit__APPEARBORDER:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IBORDER;
+          window_redrawIcon(tearEdit__window,tearEdit__icon);
+          tfile_markAsAltered(tearEdit__window->t);
+          break;
+        case tearEdit__APPEARFILLED:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IFILLED;
+          window_redrawIcon(tearEdit__window,tearEdit__icon);
+          tfile_markAsAltered(tearEdit__window->t);
+          break;
+        case tearEdit__APPEARHALF:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^=
+                                                  wimp_IHALVESPRITE;
+          window_redrawIcon(tearEdit__window,tearEdit__icon);
+          tfile_markAsAltered(tearEdit__window->t);
+          break;
+        case tearEdit__APPEARHELP:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IREDRAW;
+          window_redrawIcon(tearEdit__window,tearEdit__icon);
+          tfile_markAsAltered(tearEdit__window->t);
+          break;
+      }
+      break;
+  }
+}
+
+static void tearEdit__actionsHits(tearoff_message m,int hit,void *handle)
+{
+  unused(handle);
+  switch (m)
+  {
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      switch (hit)
+      {
+        case tearEdit__ACTIONSESG:
+          tearEdit__esgBox();
+          break;
+        case tearEdit__ACTIONSADJUST:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_IESG_NOC;
+          window_redrawIcon(tearEdit__window,tearEdit__icon);
+          tfile_markAsAltered(tearEdit__window->t);
+          break;
+        case tearEdit__ACTIONSSELECT:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_ISELECTED;
+          window_redrawIcon(tearEdit__window,tearEdit__icon);
+          tfile_markAsAltered(tearEdit__window->t);
+          break;
+        case tearEdit__ACTIONSSHADE:
+          tearEdit__window->def->i[tearEdit__icon].i.flags ^= wimp_INOSELECT;
+          window_redrawIcon(tearEdit__window,tearEdit__icon);
+          tfile_markAsAltered(tearEdit__window->t);
+          break;
+      }
+      break;
+  }
+}
+
+static void tearEdit__btypeHits(tearoff_message m,int hit,void *handle)
+{
+  unused(handle);
+  if (m==tearoff_SELECTION && hit>=1 && hit<=16)
+  {
+    tearEdit__window->def->i[tearEdit__icon].i.flags &= ~0x0000F000;
+    tearEdit__window->def->i[tearEdit__icon].i.flags |= (hit-1)<<12;
+    window_redrawIcon(tearEdit__window,tearEdit__icon);
+    tfile_markAsAltered(tearEdit__window->t);
+  }
+}
+
+static void tearEdit__coloursHits(tearoff_message m,int hit,void *handle)
+{
+  unused(handle);
+  switch (m)
+  {
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      switch (hit)
+      {
+        case tearEdit__COLOURSFORE:
+          tearEdit__colourBox(TRUE);
+          break;
+        case tearEdit__COLOURSBACK:
+          tearEdit__colourBox(FALSE);
+          break;
+      }
+      break;
+  }
+}
+
+/*----- External functions ------------------------------------------------*/
+
+/*
+ * void tearEdit_open(void)
+ *
+ * Use
+ *  Opens the edit icon menu, as a submenu if appropriate, otherwise as a
+ *  full menu.
+ */
+
+void tearEdit_open(void)
+{
+  tearoff_displayMenu(tearEdit__main,0);
+}
+
+/*
+ * void tearEdit_update(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Updates the edit icon menu from the specified window and icon.  If the
+ *  window handle is 0, or the icon is -1 then the menu is made unavailable
+ *  (i.e. its items are shaded).  Otherwise, the menu is updated to reflect
+ *  the state of the icon.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon to edit
+ *  int icon == the icon to be editing in the menu
+ */
+
+void tearEdit_update(glass_windPointer *w,int icon)
+{
+  int i;
+  wimp_iconflags f;
+  int b;
+
+  /* --- Remember the new magic icon --- */
+
+  tearEdit__window=w;
+  tearEdit__icon=icon;
+
+  /* --- If there isn't an icon any more, shade the menu --- */
+
+  if (!w || icon==-1)
+  {
+    for (i=tearEdit__MAINDATA;i<=tearEdit__MAINSIZE;i++)
+    {
+      tearoff_shadeItem(tearEdit__main,i,TRUE);
+      tearoff_selectItem(tearEdit__main,i,FALSE);
+    }
+    for (i=tearEdit__DATADATA;i<=tearEdit__DATASPRITE;i++)
+    {
+      tearoff_shadeItem(tearEdit__data,i,TRUE);
+      tearoff_selectItem(tearEdit__data,i,FALSE);
+    }
+    for (i=tearEdit__APPEARHCENTRE;i<=tearEdit__APPEARHELP;i++)
+    {
+      tearoff_shadeItem(tearEdit__appear,i,TRUE);
+      tearoff_selectItem(tearEdit__appear,i,FALSE);
+    }
+    for (i=tearEdit__ACTIONSBTYPE;i<=tearEdit__ACTIONSSHADE;i++)
+    {
+      tearoff_shadeItem(tearEdit__actions,i,TRUE);
+      tearoff_selectItem(tearEdit__actions,i,FALSE);
+    }
+    for (i=1;i<=16;i++)
+    {
+      tearoff_shadeItem(tearEdit__btype,i,TRUE);
+      tearoff_selectItem(tearEdit__btype,i,FALSE);
+    }
+    for (i=tearEdit__COLOURSFORE;i<=tearEdit__COLOURSBACK;i++)
+      tearoff_shadeItem(tearEdit__colours,i,TRUE);
+  }
+  else
+  {
+    /* --- Read information about the icon --- */
+
+    f=w->def->i[icon].i.flags;
+
+    /* --- Unshade the main menu --- */
+
+    tearoff_shadeItem(tearEdit__main,tearEdit__MAINDATA,FALSE);
+    tearoff_shadeItem(tearEdit__main,tearEdit__MAINAPPEAR,FALSE);
+    tearoff_shadeItem(tearEdit__main,tearEdit__MAINACTIONS,FALSE);
+    tearoff_shadeItem(tearEdit__main,tearEdit__MAINCOLOURS,tst(f,6));
+    tearoff_shadeItem(tearEdit__main,tearEdit__MAINPOS,FALSE);
+    tearoff_shadeItem(tearEdit__main,tearEdit__MAINSIZE,FALSE);
+
+    /* --- Handle data things --- */
+
+    tearoff_shadeItem(tearEdit__data,tearEdit__DATADATA,!(f & 3));
+    tearoff_shadeItem(tearEdit__data,tearEdit__DATAINDIR,!(f & 3));
+    tearoff_selectItem(tearEdit__data,tearEdit__DATAINDIR,tst(f,8));
+    tearoff_shadeItem(tearEdit__data,tearEdit__DATATEXT,FALSE);
+    tearoff_selectItem(tearEdit__data,tearEdit__DATATEXT,tst(f,0));
+    tearoff_shadeItem(tearEdit__data,tearEdit__DATASPRITE,FALSE);
+    tearoff_selectItem(tearEdit__data,tearEdit__DATASPRITE,tst(f,1));
+
+    /* --- Handle appearance things --- */
+
+    tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARHCENTRE,FALSE);
+    tearoff_selectItem(tearEdit__appear,tearEdit__APPEARHCENTRE,tst(f,3));
+    tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARVCENTRE,FALSE);
+    tearoff_selectItem(tearEdit__appear,tearEdit__APPEARVCENTRE,tst(f,4));
+    tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARRALIGN,FALSE);
+    tearoff_selectItem(tearEdit__appear,tearEdit__APPEARRALIGN,tst(f,9));
+
+    tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARBORDER,FALSE);
+    tearoff_selectItem(tearEdit__appear,tearEdit__APPEARBORDER,tst(f,2));
+    tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARFILLED,FALSE);
+    tearoff_selectItem(tearEdit__appear,tearEdit__APPEARFILLED,tst(f,5));
+    tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARHALF,!tst(f,1));
+    tearoff_selectItem(tearEdit__appear,tearEdit__APPEARHALF,tst(f,11));
+    tearoff_shadeItem(tearEdit__appear,tearEdit__APPEARHELP,FALSE);
+    tearoff_selectItem(tearEdit__appear,tearEdit__APPEARHELP,tst(f,7));
+
+    /* --- Handle actions things --- */
+
+    tearoff_shadeItem(tearEdit__actions,tearEdit__ACTIONSBTYPE,FALSE);
+    tearoff_shadeItem(tearEdit__actions,tearEdit__ACTIONSESG,FALSE);
+    tearoff_shadeItem(tearEdit__actions,tearEdit__ACTIONSADJUST,FALSE);
+    tearoff_selectItem(tearEdit__actions,tearEdit__ACTIONSADJUST,tst(f,10));
+    tearoff_shadeItem(tearEdit__actions,tearEdit__ACTIONSSELECT,FALSE);
+    tearoff_selectItem(tearEdit__actions,tearEdit__ACTIONSSELECT,tst(f,21));
+    tearoff_shadeItem(tearEdit__actions,tearEdit__ACTIONSSHADE,FALSE);
+    tearoff_selectItem(tearEdit__actions,tearEdit__ACTIONSSHADE,tst(f,22));
+
+    /* --- Handle button type --- */
+
+    b=(f & 0x0000F000)>>12;
+    for (i=1;i<=16;i++)
+    {
+      tearoff_shadeItem(tearEdit__btype,i,FALSE);
+      tearoff_selectItem(tearEdit__btype,i,(i-1==b) ?
+                                             tearoff_RADIOED :
+                                             FALSE);
+    }
+
+    /* --- Handle colours --- */
+
+    tearoff_shadeItem(tearEdit__colours,tearEdit__COLOURSFORE,tst(f,6));
+    tearoff_shadeItem(tearEdit__colours,tearEdit__COLOURSBACK,tst(f,6));
+  }
+}
+
+/*
+ * void tearEdit_init(void)
+ *
+ * Use
+ *  Initialises the tearoff menus for editing icons and starts up the tearoff
+ *  menu manager.
+ */
+
+void tearEdit_init(void)
+{
+  char *buf=buffer_find();
+  int i;
+
+  /* --- If we're already up and running, then someone's stupid --- */
+
+  if (tearEdit__main)
+    return;
+
+  tearoff_init();
+
+  tearEdit__main=tearoff_create(msgs_lookup("teEIMT"),
+                                msgs_lookup("teEIM"),
+                                TRUE,
+                                tearEdit__mainHits,
+                                0,
+                                0);
+
+  tearEdit__data=tearoff_create(msgs_lookup("teEIDT"),
+                                msgs_lookup("teEID"),
+                                TRUE,
+                                tearEdit__dataHits,
+                                0,
+                                0);
+
+  tearEdit__appear=tearoff_create(msgs_lookup("teAPMT"),
+                                  msgs_lookup("teAPM"),
+                                  TRUE,
+                                  tearEdit__appearHits,
+                                  0,
+                                  0);
+
+  tearEdit__actions=tearoff_create(msgs_lookup("teACMT"),
+                                   msgs_lookup("teACM"),
+                                   TRUE,
+                                   tearEdit__actionsHits,
+                                   0,
+                                   0);
+
+  tearEdit__colours=tearoff_create(msgs_lookup("teCMT"),
+                                   msgs_lookup("teCM"),
+                                   TRUE,
+                                   tearEdit__coloursHits,
+                                   0,
+                                   0);
+
+  /* --- Change this code to use Edit Icon messages --- */
+
+  tearEdit__btype=tearoff_create(msgs_lookup("eiBTMT"),
+                                 msgs_lookup("eiBTYPE0"),
+                                 TRUE,
+                                 tearEdit__btypeHits,
+                                 0,
+                                 0);
+  for (i=1;i<=15;i++)
+  {
+    sprintf(buf,"eiBTYPE%i",i);
+    tearEdit__btype=tearoff_extendMenu(tearEdit__btype,msgs_lookup(buf));
+  }
+  tearoff_shadeItem(tearEdit__btype,13,TRUE);
+  tearoff_shadeItem(tearEdit__btype,14,TRUE);
+
+  if (!tearEdit__main ||
+      !tearEdit__data ||
+      !tearEdit__appear ||
+      !tearEdit__actions ||
+      !tearEdit__colours ||
+      !tearEdit__btype)
+    exit(1);
+
+  tearoff_attachSubMenu(tearEdit__main,
+                        tearEdit__MAINDATA,
+                        tearEdit__data);
+  tearoff_attachSubMenu(tearEdit__main,
+                        tearEdit__MAINAPPEAR,
+                        tearEdit__appear);
+  tearoff_attachSubMenu(tearEdit__main,
+                        tearEdit__MAINACTIONS,
+                        tearEdit__actions);
+  tearoff_attachSubMenu(tearEdit__main,
+                        tearEdit__MAINCOLOURS,
+                        tearEdit__colours);
+  tearoff_attachSubMenu(tearEdit__actions,
+                        tearEdit__ACTIONSBTYPE,
+                        tearEdit__btype);
+
+  tearEdit_update(0,-1);
+}
diff --git a/StraySrc/Glass/!Glass/c/tfile b/StraySrc/Glass/!Glass/c/tfile
new file mode 100644 (file)
index 0000000..5c6e846
--- /dev/null
@@ -0,0 +1,3006 @@
+/*
+ * tfile.c
+ *
+ * Control of template files
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _XFER
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/viewer.h"
+#include "steel/mem.h"
+#include "steel/nopoll.h"
+#include "steel/flex.h"
+#include "steel/akbd.h"
+#include "steel/alarm.h"
+#include "steel/bbc.h"
+#include "steel/buffer.h"
+#include "steel/font.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gIcons.h"
+#include "gMenus.h"
+
+#include "glass.h"
+#include "toolbox.h"
+#include "intMsgs.h"
+#include "tfile.h"
+#include "gPrefs.h"
+#include "gSprite.h"
+#include "indir.h"
+#include "window.h"
+#include "editWin.h"
+#include "iconData.h"
+
+/*----- Constants ---------------------------------------------------------*/
+
+#define tfile__FILEHEIGHT 892    /* Height to open first template window   */
+#define tfile__FILEX 200         /* x position of template file windows    */
+#define tfile__FILETOP 940       /* Height after files wrap around         */
+
+#define tfile__WINDHEIGHT 872    /* Height to create first window          */
+#define tfile__WINDX 450         /* x position of template windows         */
+#define tfile__WINDTOP 920       /* Height after windows wrap around       */
+
+/*----- Static global variables -------------------------------------------*/
+
+static int tfile__unsavedFiles;   /* Number of files not saved             */
+static int tfile__fileHeight=tfile__FILEHEIGHT;
+                                 /* Height to open next template window    */
+static int tfile__windHeight=tfile__WINDHEIGHT;
+static int tfile__selectSize;    /* Size in bytes of current selection     */
+static int tfile__selectIcons;   /* Number of icons in current selection   */
+static int tfile__selectIndSz;   /* Indirected data size for selection     */
+static char tfile__grabName[15]; /* Name for the grabbed window            */static glass_tfile *tfile__selOwner;   /* Owner of the current selection   */
+
+/*----- Support routines --------------------------------------------------*/
+
+/*
+ * void tfile__tidyFonts(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Closes down the fonts on a particular template file.
+ *
+ * Parameters
+ *  viewer_icon i == the icon (ignored)
+ *  void *handle == the file to close
+ */
+
+static void tfile__tidyFonts(viewer_icon ic,void *handle)
+{
+  int i,j;
+  glass_windPointer *w=handle;
+  unused(ic);
+  if (w->antiAliased)
+  {
+    for (i=0;i<256;i++)
+    {
+      for (j=0;j<w->fonts[i];j++)
+        wimpt_noerr(font_lose(i));
+    }
+  }
+  w->antiAliased=FALSE;
+}
+
+/*
+ * void tfile__reFindFonts(viewer_icon ic,void *handle)
+ *
+ * Use
+ *  Scans the given window, refinding all the fonts it used.  This is
+ *  because (at present) on a mode change, the aspect ratio can become
+ *  utterly trashed.  I can't afford to wait until the Font Manager gets
+ *  rewritten to work properly, so I have to do it myself...
+ *
+ *  After this call, the window needs recreating if it's being displayed.
+ *  It will pick up the Open_Window_Request, and recreate on that if it
+ *  finds it has some fonts in it.
+ *
+ *  This call also resets the antiAliased flag if it finds no fonts in a
+ *  window.
+ *
+ * Parameters
+ *  viewer_icon ic == the viewer icon of the window to rescan (ignored)
+ *  void *handle == an undercover glass_windPointer * to the window
+ */
+
+static void tfile__reFindFonts(viewer_icon ic,void *handle)
+{
+  glass_windPointer *w=handle;
+  int i;
+  int icf;
+  os_regset r;
+  int fhand;
+  int newhand;
+  BOOL usedAFont=FALSE;
+  char buff[50];
+  unused(ic);
+
+  if (!w->antiAliased)
+    return;
+  icf=w->def->desc.w.titleflags;
+  if (icf & wimp_IFONT)
+  {
+    usedAFont=TRUE;
+    fhand=(icf>>24) & 0xff;
+    r.r[0]=fhand;
+    r.r[1]=(int)buff;
+    wimpt_noerr(os_swix(XFont_ReadDefn,&r));
+    r.r[4]=r.r[5]=0;
+    if (!wimpt_complain(os_swix(XFont_FindFont,&r)))
+    {
+      newhand=r.r[0];
+      r.r[0]=fhand;
+      wimpt_noerr(os_swix(XFont_LoseFont,&r));
+      w->fonts[fhand]--;
+      w->fonts[newhand]++;
+      w->def->desc.w.titleflags=(icf & 0x00ffffff) | (newhand<<24);
+    }
+  }
+  for (i=0;i<w->def->desc.w.nicons;i++)
+  {
+    icf=w->def->i[i].i.flags;
+    if (icf & wimp_IFONT)
+    {
+      usedAFont=TRUE;
+      fhand=(icf>>24) & 0xff;
+      r.r[0]=fhand;
+      r.r[1]=(int)buff;
+      wimpt_noerr(os_swix(XFont_ReadDefn,&r));
+      r.r[4]=r.r[5]=0;
+      if (!wimpt_complain(os_swix(XFont_FindFont,&r)))
+      {
+        newhand=r.r[0];
+        r.r[0]=fhand;
+        wimpt_noerr(os_swix(XFont_LoseFont,&r));
+        w->fonts[fhand]--;
+        w->fonts[newhand]++;
+        w->def->i[i].i.flags=(icf & 0x00ffffff) | (newhand<<24);
+      }
+    }
+  }
+  w->antiAliased=usedAFont;
+}
+
+/*
+ * void tfile__gainSelection(glass_tfile *t)
+ *
+ * Use
+ *  Hands the current tfile selection and the input focus to the specified
+ *  template file.
+ *
+ *  Note that the selection model here is more complex than it is in window,
+ *  since the focus tfile may not coincide with the selection owner (since
+ *  menu clicks move the selection owner, but not the focus).
+ *
+ * Parameters
+ *  glass_tfile *t == the template to which we give the focus
+ */
+
+static void tfile__gainSelection(glass_tfile *t)
+{
+  wimp_caretstr c;
+  if (t!=tfile__selOwner)
+  {
+    if (tfile__selOwner)
+      viewer_selectAll(tfile__selOwner->v,FALSE);
+    tfile__selOwner=t;
+  }
+  if (t)
+  {
+    c.w=viewer_syshandle(t->v);
+    c.i=-1;
+    c.x=-250;
+    c.y=0;
+    c.index=-1;
+    c.height=0x02000000;
+    wimpt_noerr(wimp_set_caret_pos(&c));
+  }
+}
+
+/*
+ * void tfile__doDeleteWindow(void *handle)
+ *
+ * Use
+ *  Deletes, trashes and exterminates a window.
+ *
+ * Parameters
+ *  void *handle ==  the window to eliminate
+ */
+
+static void tfile__doDeleteWindow(void *handle)
+{
+  int i;
+  glass_windPointer *w=handle;
+  window_hasBeenDeleted(w);
+  if (w->def->desc.w.titleflags & wimp_INDIRECT)
+  {
+    indir_free(w->def->desc.w.title.indirecttext.buffer);
+    if ((w->def->desc.w.titleflags & wimp_ITEXT) &&
+        (w->def->desc.w.title.indirecttext.validstring!=(char *)-1))
+      indir_free(w->def->desc.w.title.indirecttext.validstring);
+  }
+  for (i=0;i<w->def->desc.w.nicons;i++)
+  {
+    if (w->def->i[i].i.flags & wimp_INDIRECT)
+    {
+      indir_free(w->def->i[i].i.data.indirecttext.buffer);
+      if ((w->def->i[i].i.flags & wimp_ITEXT) &&
+          (w->def->i[i].i.data.indirecttext.validstring!=(char *)-1))
+        indir_free(w->def->i[i].i.data.indirecttext.validstring);
+    }
+  }
+  if (w->def)
+    flex_free((flex_ptr)&w->def);
+  if (w->h)
+  {
+    win_register_event_handler(w->h,0,0);
+    win_activedec();
+    wimpt_noerr(wimp_delete_wind(w->h));
+  }
+  tfile__tidyFonts(0,w);
+  mem_free(w);
+}
+
+/*
+ * void tfile__deleteTemplateFile(void *handle)
+ *
+ * Use
+ *  Trashes the named template file.
+ *
+ * Parameters
+ *  void *handle == the template file to murder
+ */
+
+static void tfile__deleteTemplateFile(void *handle)
+{
+  glass_tfile *t=handle;
+  intMsgs_send(glass_DELETEFILE,t);
+  if (t==tfile__selOwner)
+    tfile__selOwner=0;
+  gSprite_kill(t);
+  if (t->alts)
+    tfile__unsavedFiles--;
+  viewer_delete(t->v,tfile__doDeleteWindow);
+  if (t->autod)
+    dbox_delete(t->autod);
+  if (t->autoAlarm)
+    alarm_remove(t->autoAlarm,t);
+  mem_free(t);
+  flex_compact();
+}
+
+/*
+ * glass_windPointer *tfile__newWindow(glass_tfile *t,char *name)
+ *
+ * Use
+ *  Creates a new window entry in the template file specified.  It is up to
+ *  the caller to write the window definition.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file to add the window to
+ *  char *name == the name of the window
+ *
+ * Returns
+ *  A pointer to the window structure
+ */
+
+static glass_windPointer *tfile__newWindow(glass_tfile *t,char *name)
+{
+  glass_windPointer *w;
+  int i;
+  static int serial;             /* Serial number - monotonic increasing   */
+  mem_useUser(indir_alloc,indir_free);
+  w=mem_alloc(sizeof(glass_windPointer));
+  if (!w)
+  {
+    werr(FALSE,msgs_lookup("tfNEMCRT"));
+    mem_useMalloc();
+    return (0);
+  }
+  strcpy(w->id,name);
+  w->def=0;
+  w->t=t;
+  w->h=0;
+  w->edit=0;
+  w->size=0;
+  w->gridx=gPrefs_current()->gWidth;
+  w->gridy=gPrefs_current()->gHeight;
+  w->gridShow=gPrefs_current()->gDisp;
+  w->gridLock=gPrefs_current()->gLock;
+  w->serial=serial++;                  /* Increment serial number count    */
+  for (i=0;i<glass_GUIDELIMIT;i++)
+    w->guide[i].active=FALSE;
+  w->antiAliased=FALSE;
+  for (i=0;i<256;i++)
+    w->fonts[i]=0;
+  if (w->i=viewer_addIcon(t->v,name,"tmpltvicon",TRUE,w),!w->i)
+  {
+    mem_free(w);
+    mem_useMalloc();
+    return (0);
+  }
+  viewer_setFiletype(w->i,0xfec);
+  mem_useMalloc();
+  return (w);
+}
+
+/*
+ * void tfile__size(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Adds the size of the window given by handle to the global variables
+ *  tfile__selectSize and tfile__selectIndSz.
+ *
+ * Parameters
+ *  viewer_icon i == the viewer icon handle (ignored)
+ *  void *handle == the window to count
+ */
+
+static void tfile__size(viewer_icon i,void *handle)
+{
+  glass_windPointer *w=handle;
+  unused(i);
+  tfile__selectSize+=w->size;
+  tfile__selectIndSz+=w->size-
+                      sizeof(glass_window)-
+                      (w->def->desc.w.nicons-1)*
+                         sizeof(glass_iconDescription);
+}
+
+/*
+ * void tfile__icons(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Adds the number of icons in  the window given by handle to the global
+ *  variable tfile__selectIcons.
+ *
+ * Parameters
+ *  viewer_icon i == the viewer icon handle (ignored)
+ *  void *handle == the window to count
+ */
+
+static void tfile__icons(viewer_icon i,void *handle)
+{
+  glass_windPointer *w=handle;
+  unused(i);
+  tfile__selectIcons+=w->def->desc.w.nicons;
+}
+
+/*
+ * BOOL tfile__create(char *new,void *handle)
+ *
+ * Use
+ *  Creates a new window.
+ *
+ * Parameters
+ *  char *new == the name for the new window
+ *  void *handle == pointer to the tfile
+ */
+
+static BOOL tfile__create(char *new,void *handle)
+{
+  glass_tfile *t=handle;
+  viewer_icon icn;
+  glass_windPointer *wnew;
+  wimp_wind *w=&template_find("default")->window;
+
+  icn=viewer_findIcon(t->v,new);
+  if (icn==viewer_NOICON)
+  {
+    wnew=tfile__newWindow(t,new);
+    if (!wnew)
+      return (FALSE);
+    tfile_markAsAltered(t);
+    wnew->size=sizeof(glass_window)-sizeof(glass_iconDescription);
+    if (!flex_alloc((flex_ptr)&wnew->def,wnew->size))
+    {
+      viewer_removeIcon(wnew->i);
+      mem_free(wnew);
+      werr(FALSE,msgs_lookup("tfNEMCRT"));
+      return (FALSE);
+    }
+    wnew->def->desc.w=*w;
+    wnew->def->desc.w.nicons=0;
+    if (!iconData_handleFont(wnew,&wnew->def->desc.w.titleflags))
+      werr(FALSE,msgs_lookup("tfFERC"));
+    if (wnew->def->desc.w.titleflags & wimp_IFONT)
+    {
+      wnew->antiAliased=TRUE;
+      wnew->fonts[(wnew->def->desc.w.titleflags>>24) & 0xff]++;
+    }
+    if (!iconData_processIcon(wnew,-1,0,TRUE,0))
+    {
+      werr(FALSE,msgs_lookup("tfNEMCRT"));
+      tfile_deleteWindow(0,wnew);
+      return (FALSE);
+    }
+    wnew->def->desc.w.box.y1=tfile__windHeight;
+    wnew->def->desc.w.box.y0=tfile__windHeight +
+                             wnew->def->desc.w.ex.y0 -
+                             wnew->def->desc.w.ex.y1;
+    wnew->def->desc.w.box.x0=tfile__WINDX;
+    wnew->def->desc.w.box.x1=tfile__WINDX -
+                             wnew->def->desc.w.ex.x0 +
+                             wnew->def->desc.w.ex.x1;
+    if (wnew->def->desc.w.box.y0<tfile__windHeight-500)
+      wnew->def->desc.w.box.y0=tfile__windHeight-500;
+    if (wnew->def->desc.w.box.x1>tfile__WINDX+700)
+      wnew->def->desc.w.box.x1=tfile__WINDX+700;
+    wnew->def->desc.w.scx=wnew->def->desc.w.ex.x0;
+    wnew->def->desc.w.scy=wnew->def->desc.w.ex.y1;
+    tfile__windHeight-=48;
+    if (tfile__windHeight<632)
+      tfile__windHeight=tfile__WINDTOP;
+
+    return (TRUE);
+  }
+  note(msgs_lookup("tfNAE"),viewer_textOfIcon(icn));
+  return (FALSE);
+}
+
+/*
+ * char *tfile__grabData(char *ptr,void *handle)
+ *
+ * Use
+ *  Grabs data from the destination task, as required when setting up a
+ *  grabbed window.
+ *
+ * Parameters
+ *  char *ptr == pointer to data string (in other task's workspace)
+ *  void *handle == not a pointer at all, actually the source task's handle
+ *
+ * Returns
+ *  A pointer to a string in my own workspace (static char array)
+ */
+
+static char *tfile__grabData(char *ptr,void *handle)
+{
+  char *buff=buffer_find();
+  wimp_t t=(int)handle;
+  if (t)
+  {
+    if (wimp_transferblock(t,ptr,wimpt_task(),buff,256))
+      return ("<error>");
+  }
+  else
+    return ("<indirected>");
+  return (buff);
+}
+
+/*
+ * void tfile__grab(wimp_mousestr *m,void *handle)
+ *
+ * Use
+ *  Grabs a window definition, inserting it neatly into the template file.
+ *
+ * Parameters
+ *  wimp_mousestr *m == info about the window
+ *  void *handle == pointer to destination template file
+ */
+
+static void tfile__grab(wimp_mousestr *m,void *handle)
+{
+  glass_tfile *t=handle;
+  glass_windPointer *wnew;
+  wimp_winfo *w;
+  os_regset r;
+  int numicons;
+  wimp_t task;
+  wimp_msgstr msg;
+  int i;
+  int ioff;
+  BOOL fonterr=FALSE;
+
+  wnew=tfile__newWindow(t,tfile__grabName);
+  if (!wnew)
+    return;
+  tfile_markAsAltered(t);
+  if (wimpt_getVersion()>=300)   /* RISC OS 3 allows 'safe' GetWindowInfos */
+    w=mem_alloc(sizeof(wimp_winfo));
+  else
+    w=mem_alloc(sizeof(wimp_winfo)+200*sizeof(wimp_icon));
+  if (!w)
+  {
+    werr(FALSE,msgs_lookup("tfNEMGW"));
+    viewer_removeIcon(wnew->i);
+    mem_free(wnew);
+    return;
+  }
+  w->w=m->w;
+  r.r[1]=(int)w;
+  if (wimpt_getVersion()>=300)
+    r.r[1]++;                    /* RO3 - only window header, not icons    */
+  wimpt_noerr(os_swix(XWimp_GetWindowInfo,&r)); /* Get the information     */
+  numicons=w->info.nicons;
+  mem_free(w);
+  wnew->size=sizeof(glass_window)+
+             (numicons-1)*sizeof(glass_iconDescription);
+  if (!flex_alloc((flex_ptr)&w,
+                  sizeof(wimp_winfo)+numicons*sizeof(wimp_icon)))
+  {
+    viewer_removeIcon(wnew->i);
+    mem_free(wnew);
+    werr(FALSE,msgs_lookup("tfNEMGW"));
+    return;
+  }
+  if (!flex_alloc((flex_ptr)&wnew->def,wnew->size))
+  {
+    flex_free((flex_ptr)&w);
+    viewer_removeIcon(wnew->i);
+    mem_free(wnew);
+    werr(FALSE,msgs_lookup("tfNEMGW"));
+    return;
+  }
+  w->w=m->w;
+  r.r[1]=(int)w;
+  wimpt_noerr(os_swix(XWimp_GetWindowInfo,&r)); /* Read the window properly*/
+
+  msg.hdr.size=20;
+  msg.hdr.your_ref=0;
+  msg.hdr.action=0;
+  r.r[0]=19;
+  r.r[1]=(int)&msg;
+  r.r[2]=m->w;
+  r.r[3]=m->i;
+  if (os_swix(XWimp_SendMessage,&r))
+    task=0;
+  else
+    task=r.r[2];
+
+  wnew->def->desc.w=w->info;
+  wnew->def->desc.w.nicons=0;
+  if (!iconData_handleFont(wnew,&wnew->def->desc.w.titleflags) && !fonterr)
+  {
+    werr(FALSE,msgs_lookup("tfFERG"));
+    fonterr=TRUE;
+  }
+  if (!iconData_processIcon(wnew,-1,tfile__grabData,TRUE,(void *)task))
+  {
+    flex_free((flex_ptr)&w);
+    tfile_deleteWindow(0,wnew);
+    werr(FALSE,msgs_lookup("tfNEMGW"));
+    return;
+  }
+
+  ioff=sizeof(wimp_winfo);
+  for (i=0;i<numicons;i++)
+  {
+    wnew->def->i[i].i=*_ptr(wimp_icon,w,ioff);
+    wnew->def->i[i].edit=0;
+    if (!iconData_handleFont(wnew,&wnew->def->i[i].i.flags) && !fonterr)
+    {
+      werr(FALSE,msgs_lookup("tfFERG"));
+      fonterr=TRUE;
+    }
+    if (!iconData_processIcon(wnew,i,tfile__grabData,TRUE,(void *)task))
+    {
+      flex_free((flex_ptr)&w);
+      tfile_deleteWindow(0,wnew);
+      werr(FALSE,msgs_lookup("tfNEMGW"));
+      return;
+    }
+    wnew->def->desc.w.nicons++;
+    ioff+=sizeof(wimp_icon);
+  }
+  flex_free((flex_ptr)&w);
+}
+
+/*
+ * BOOL tfile__grabGetName(char *name,void *handle)
+ *
+ * Use
+ *  Handles the writable box for a grab window job and starts the grab op
+ *
+ * Parameters
+ *  char *name == the user's name for the window
+ *  void *handle == the template file to grab to
+ *
+ * Returns
+ *  TRUE if the name was valid and the grab has been set up
+ */
+
+static BOOL tfile__grabGetName(char *name,void *handle)
+{
+  glass_tfile *t=handle;
+  viewer_icon icn;
+
+  icn=viewer_findIcon(t->v,name);
+  if (icn==viewer_NOICON)
+  {
+    strcpy(tfile__grabName,name);
+    event_clear_current_menu();
+    window_grab(tfile__grab,t);
+    return (TRUE);
+  }
+  note(msgs_lookup("tfNAE"),
+       viewer_textOfIcon(icn));
+  return (FALSE);
+}
+
+/*
+ * BOOL tfile__copy(char *new,void *handle)
+ *
+ * Use
+ *  Copies the specified window
+ *
+ * Parameters
+ *  char *new == the name for the new window
+ *  void *handle == pointer to the window structure
+ */
+
+static BOOL tfile__copy(char *new,void *handle)
+{
+  glass_windPointer *w=handle;
+  viewer_icon icn;
+  glass_windPointer *wnew;
+  int i;
+  int numicons;
+  BOOL fonterr=FALSE;
+
+  icn=viewer_findIcon(w->t->v,new);
+  if (icn==viewer_NOICON)
+  {
+    wnew=tfile__newWindow(w->t,new);
+    if (!wnew)
+      return (FALSE);
+    tfile_markAsAltered(w->t);
+    wnew->size=w->size;
+    numicons=w->def->desc.w.nicons;
+    if (!flex_alloc((flex_ptr)&wnew->def,
+                    sizeof(glass_window)
+                      +(numicons-1)*sizeof(glass_iconDescription)))
+    {
+      viewer_removeIcon(wnew->i);
+      mem_free(wnew);
+      werr(FALSE,msgs_lookup("tfNEMCW"));
+      return (FALSE);
+    }
+    memcpy
+    (
+      wnew->def,
+      w->def,
+      sizeof(glass_window)+(numicons-1)*sizeof(glass_iconDescription)
+    );
+    wnew->def->desc.w.nicons=0;
+    if (!iconData_handleFont(wnew,&wnew->def->desc.w.titleflags) && !fonterr)
+    {
+      werr(FALSE,msgs_lookup("tfFERCP"));
+      fonterr=TRUE;
+    }
+    if (!iconData_processIcon(wnew,-1,0,FALSE,0))
+    {
+      werr(FALSE,msgs_lookup("tfNEMCW"));
+      tfile_deleteWindow(0,wnew);
+      return (FALSE);
+    }
+    for (i=0;i<numicons;i++)
+    {
+      if (!iconData_handleFont(wnew,&wnew->def->i[i].i.flags) && !fonterr)
+      {
+        werr(FALSE,msgs_lookup("tfFERCP"));
+        fonterr=TRUE;
+      }
+      if (!iconData_processIcon(wnew,i,0,FALSE,0))
+      {
+        werr(FALSE,msgs_lookup("tfNEMCW"));
+        tfile_deleteWindow(0,wnew);
+        return (FALSE);
+      }
+      wnew->def->desc.w.nicons++;
+    }
+    return (TRUE);
+  }
+  note(msgs_lookup("tfNAE"),
+       viewer_textOfIcon(icn));
+  return (FALSE);
+}
+
+/*
+ * void tfile__openWindows(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Opens a window.  This is called when the user drags icons to the icon
+ *  bar and expects them to be displayed.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle of the icon representing the window
+ *   (ignored)
+ *  void *handle == pointer to the window's static information
+ */
+
+static void tfile__openWindows(viewer_icon i,void *handle)
+{
+  glass_windPointer *w=handle;
+  unused(i);
+  window_open(w,FALSE);
+}
+
+/*----- Variables used during the save process ----------------------------*/
+
+#ifndef glass_DEMO
+
+static void **tfile__flex;       /* A flex block for saving data           */
+static int tfile__flexSize;      /* Size of the flex block                 */
+static int tfile__flexUsed;      /* How much of the block has been used    */
+static BOOL tfile__abortSave;    /* If TRUE, abort the save process        */
+static int tfile__nextIndex;     /* Offset to next free index entry        */
+static char tfile__fontbinding[256]; /* Conversion realh -> internh        */
+static char tfile__backbinding[256]; /* Reverse font binding               */
+static char tfile__nextFont;     /* The next free internal font handle     */
+
+/*----- Save templates support routines -----------------------------------*/
+
+/*
+ * This section contains the actual code to save a template file or
+ * selection.
+ */
+
+/*
+ * BOOL tfile__saveAlloc(int size)
+ *
+ * Use
+ *  Ensures that a certain quantity of space is present in the save flex
+ *  block.
+ *
+ * Parameters
+ *  int size == the size required in bytes
+ *
+ * Returns
+ *  TRUE if successful, or FALSE if allocation failed.  An error is also
+ *  reported.
+ */
+
+static BOOL tfile__saveAlloc(int size)
+{
+  int szreqd;
+  if (tfile__flexSize-tfile__flexUsed>size)
+    return (TRUE);
+  szreqd=(tfile__flexUsed+size+8191) & ~8191;
+  if (!flex_extend(tfile__flex,szreqd))
+  {
+    werr(FALSE,msgs_lookup("tfNEMST"));
+    return (FALSE);
+  }
+  tfile__flexSize=szreqd;
+  return (TRUE);
+}
+
+/*
+ * BOOL tfile__addBlock(void *p,size_t sz)
+ *
+ * Use
+ *  Adds a block of data to the end of the save block.
+ *
+ * Parameters
+ *  void *p == pointer to the block
+ *  size_t sz == the size of the block
+ *
+ * Returns
+ *  TRUE if successful
+ */
+
+static BOOL tfile__addBlock(void *p,size_t sz)
+{
+  if (!tfile__saveAlloc(sz))
+    return (FALSE);
+  memcpy(_ptr(void,*tfile__flex,tfile__flexUsed),p,sz);
+  tfile__flexUsed+=sz;
+  return (TRUE);
+}
+
+#define tfile__writeString(s,off) \
+  { \
+    strcpy(charptr(*tfile__flex,off),s); \
+    charptr(*tfile__flex,off)[strlen(s)]=13; \
+  }
+
+/*
+ * BOOL tfile__addString(char *s)
+ *
+ * Use
+ *  Adds a ctrl-terminated string to the end of the save block.
+ *
+ * Parameters
+ *  char *s == pointer to the string to store
+ *
+ * Returns
+ *  TRUE if successful
+ */
+
+static BOOL tfile__addString(char *s)
+{
+  int len;
+  utils_ctermToNterm(s);
+  len=strlen(s);
+  if (!tfile__saveAlloc(len+1))
+    return (FALSE);
+  tfile__writeString(s,tfile__flexUsed);
+  tfile__flexUsed+=len+1;
+  return (TRUE);
+}
+
+/*
+ * void tfile__processWindow(viewer_icon icn,void *handle)
+ *
+ * Use
+ *  Saves the window given onto the end of the flex block being used for
+ *  such a purpose.  A save may be aborted by setting the variable
+ *  tfile__abortSave.
+ *
+ * Parameters
+ *  viewer_icon icn == the icon representing the window to be saved (ignored)
+ *  void *handle == pointer to the window structure in memory
+ */
+
+static void tfile__processWindow(viewer_icon icn,void *handle)
+{
+  int start;
+  int i;
+  int idef;
+  int ifont,rfont;
+  glass_windPointer *w=handle;
+  unused(icn);
+  if (tfile__abortSave)
+    return;
+  while (tfile__flexUsed & 3)
+    *charptr(*tfile__flex,tfile__flexUsed++)=0;
+
+  /* --- Start on the index --- */
+  intptr(*tfile__flex,tfile__nextIndex)[0]=start=tfile__flexUsed;
+  intptr(*tfile__flex,tfile__nextIndex)[2]=1;
+  tfile__writeString(w->id,tfile__nextIndex+12);
+
+  /* --- Now copy the window and icons --- */
+  if (!tfile__addBlock(&w->def->desc.w,sizeof(wimp_wind)))
+  {
+    tfile__abortSave=TRUE;
+    return;
+  }
+  for (i=0;i<w->def->desc.w.nicons;i++)
+  {
+    if (!tfile__addBlock(&w->def->i[i].i,sizeof(wimp_icon)))
+    {
+      tfile__abortSave=TRUE;
+      return;
+    }
+  }
+
+  /* --- Process window def for indirection and fonts --- */
+  _ptr(wimp_wind,*tfile__flex,start)->spritearea=(void *)1;
+  if (w->def->desc.w.titleflags & wimp_IFONT)
+  {
+    rfont=w->def->desc.w.titleflags >> 24;
+    if (tfile__fontbinding[rfont])
+      ifont=tfile__fontbinding[rfont];
+    else
+    {
+      ifont=tfile__fontbinding[rfont]=tfile__nextFont++;
+      tfile__backbinding[ifont]=rfont;
+    }
+    _ptr(wimp_wind,*tfile__flex,start) -> titleflags=
+              (w->def->desc.w.titleflags & 0x00ffffff) | (ifont << 24);
+  }
+  if (w->def->desc.w.titleflags & wimp_INDIRECT)
+  {
+    _ptr(wimp_wind,*tfile__flex,start) -> title.indirecttext.buffer=
+                                            (char *)(tfile__flexUsed-start);
+    if (!tfile__addString(w->def->desc.w.title.indirecttext.buffer))
+    {
+      tfile__abortSave=TRUE;
+      return;
+    }
+    if (w->def->desc.w.titleflags & wimp_ITEXT)
+    {
+      if (w->def->desc.w.title.indirecttext.validstring!=(char *)-1)
+      {
+        _ptr(wimp_wind,*tfile__flex,start)->title.indirecttext.validstring=
+                                             (char *)(tfile__flexUsed-start);
+        if (!tfile__addString(w->def->desc.w.title.indirecttext.validstring))
+        {
+          tfile__abortSave=TRUE;
+          return;
+        }
+      }
+    }
+    else if (w->def->desc.w.titleflags & wimp_ISPRITE)
+    {
+      _ptr(wimp_wind,*tfile__flex,start)->title.indirectsprite.spritearea=
+                                                                   (void *)1;
+    }
+  }
+
+  /* --- Now the same for the icons --- */
+  idef=start+sizeof(wimp_wind);
+  for (i=0;i<w->def->desc.w.nicons;i++)
+  {
+    if (w->def->i[i].i.flags & wimp_IFONT)
+    {
+      rfont=w->def->i[i].i.flags >> 24;
+      if (tfile__fontbinding[rfont])
+        ifont=tfile__fontbinding[rfont];
+      else
+      {
+        ifont=tfile__fontbinding[rfont]=tfile__nextFont++;
+        tfile__backbinding[ifont]=rfont;
+      }
+      _ptr(wimp_icon,*tfile__flex,idef)->flags=
+               (w->def->i[i].i.flags & 0x00ffffff) | (ifont << 24);
+    }
+    if (w->def->i[i].i.flags & wimp_INDIRECT)
+    {
+      _ptr(wimp_icon,*tfile__flex,idef)->data.indirecttext.buffer=
+                                             (char *)(tfile__flexUsed-start);
+      if (!tfile__addString(w->def->i[i].i.data.indirecttext.buffer))
+      {
+        tfile__abortSave=TRUE;
+        return;
+      }
+      if (w->def->i[i].i.flags & wimp_ITEXT)
+      {
+        if (w->def->i[i].i.data.indirecttext.validstring!=(char *)-1)
+        {
+          _ptr(wimp_icon,*tfile__flex,idef)->data.indirecttext.validstring=
+                                             (char *)(tfile__flexUsed-start);
+          if (!tfile__addString(w->def->i[i].i.data.
+                                indirecttext.validstring))
+          {
+            tfile__abortSave=TRUE;
+            return;
+          }
+        }
+      }
+      else if (w->def->i[i].i.flags & wimp_ISPRITE)
+      {
+        _ptr(wimp_icon,*tfile__flex,idef)->data.indirectsprite.spritearea=
+                                                                   (void *)1;
+      }
+    }
+    idef+=sizeof(wimp_icon);
+  }
+  intptr(*tfile__flex,tfile__nextIndex)[1]=tfile__flexUsed-start;
+  tfile__nextIndex+=24;
+}
+
+/*
+ * BOOL tfile__setupSave(glass_tfile *t,
+ *                       glass_windPointer *w,
+ *                       void **p,
+ *                       BOOL onlySelected)
+ *
+ * Use
+ *  Sets up a flex block for saving a template file, selection or single
+ *  window.  To save a template file or selection, set t==tfile, w==0.  To
+ *  save a window, set t==0, w==window.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file that we're saving
+ *  glass_windPointer *w == the window we're saving
+ *  void **p == pointer used as flex anchor (free after use yourself)
+ *  BOOL onlySelected == do we only save the selected templates?
+ *
+ * Returns
+ *  TRUE if operation completed successfully
+ */
+
+static BOOL tfile__setupSave(glass_tfile *t,
+                             glass_windPointer *w,
+                             void **p,
+                             BOOL onlySelected)
+{
+  int i;
+  int numwin;
+  os_regset r;
+  char buff[40];
+  if (!flex_alloc(p,tfile__selectSize))
+  {
+    werr(FALSE,msgs_lookup("tfNEMST"));
+    return (FALSE);
+  }
+  tfile__flex=p;
+  tfile__flexSize=tfile__selectSize;
+  tfile__flexUsed=0;
+  tfile__abortSave=FALSE;
+  for (i=0;i<256;i++)
+  {
+    tfile__fontbinding[i]=0;
+    tfile__backbinding[i]=0;
+  }
+  tfile__nextFont=1;
+
+  /* --- Header --- */
+  if (!tfile__saveAlloc(16))
+  {
+    flex_free(p);
+    return (FALSE);
+  }
+  intptr(*tfile__flex,0)[0]=-1;
+  intptr(*tfile__flex,0)[1]=0;
+  intptr(*tfile__flex,0)[2]=0;
+  intptr(*tfile__flex,0)[3]=0;
+  tfile__flexUsed+=16;
+
+  /* --- Set up index entries --- */
+  if (t)
+  {
+    if (onlySelected)
+      numwin=viewer_selected(t->v);
+    else
+      numwin=viewer_icons(t->v);
+  }
+  else
+    numwin=1;
+  if (!tfile__saveAlloc(24*numwin+4))
+  {
+    flex_free(p);
+    return (FALSE);
+  }
+
+  /* --- Now insert window and icon definitions --- */
+  tfile__nextIndex=16;
+  tfile__flexUsed+=24*numwin+4;
+  if (t)
+    viewer_doForIcons(t->v,onlySelected,tfile__processWindow);
+  else
+    tfile__processWindow(0,w);
+  if (tfile__abortSave)
+  {
+    flex_free(p);
+    return (FALSE);
+  }
+
+  /* --- Terminate the index and fill in the fonts --- */
+  intptr(*tfile__flex,tfile__nextIndex)[0]=0;
+  if (tfile__nextFont!=1)
+  {
+    tfile__flexUsed=(tfile__flexUsed+3) & (~3);
+    if (!tfile__saveAlloc(48*(tfile__nextFont-1)))
+    {
+      flex_free(p);
+      return (FALSE);
+    }
+    intptr(*tfile__flex,0)[0]=tfile__flexUsed;
+    for (i=1;i<tfile__nextFont;i++)
+    {
+      r.r[0]=tfile__backbinding[i];
+      r.r[1]=(int)buff;
+      wimpt_noerr(os_swix(XFont_ReadDefn,&r));
+      intptr(*tfile__flex,tfile__flexUsed)[0]=r.r[2];
+      intptr(*tfile__flex,tfile__flexUsed)[1]=r.r[3];
+      tfile__writeString(buff,tfile__flexUsed+8);
+      tfile__flexUsed+=48;
+    }
+  }
+  return (TRUE);
+}
+
+/*
+ * BOOL tfile__saveTemplates(char *filename,void *handle)
+ *
+ * Use
+ *  Saves a template file to disk
+ *
+ * Parameters
+ *  char *filename == the file to save to
+ *  void *handle == pointer to the template file
+ *
+ * Returns
+ *  TRUE if successful
+ */
+
+static BOOL tfile__saveTemplates(char *filename,void *handle)
+{
+  void *p;
+  os_filestr f;
+  glass_tfile *t=handle;
+  if
+  (
+    gPrefs_current()->cSave &&
+    saveas_file_is_safe() &&
+    utils_caselessCmp(filename,t->filename)!=0 &&
+    res_fileExists(filename)
+  )
+  {
+    if (!warning(msgs_lookup("tfSOFP"),msgs_lookup("tfSOF"),filename))
+      return (FALSE);
+  }
+  if (!tfile__setupSave(t,0,&p,FALSE))
+    return (FALSE);
+  f.action=10;
+  f.name=filename;
+  f.loadaddr=0xfec;
+  f.start=(int)p;
+  f.end=f.start+tfile__flexUsed;
+  if (utils_complain(os_file(&f),msgs_lookup("tfERT")))
+  {
+    flex_free(&p);
+    return (FALSE);
+  }
+  else
+  {
+    flex_free(&p);
+    if (saveas_file_is_safe())
+      tfile_markAsSaved(t,filename);
+    return (TRUE);
+  }
+}
+
+/*
+ * BOOL tfile__sendTemplates(void *handle,int *maxbuf)
+ *
+ * Use
+ *  Saves a template file to another application via RAM transfer
+ *
+ * Parameters
+ *  void *handle == pointer to the template file
+ *  int *maxbuf == pointer to receiving app's buffer size
+ *
+ * Returns
+ *  TRUE if successful
+ */
+
+static BOOL tfile__sendTemplates(void *handle,int *maxbuf)
+{
+  void *p;
+  glass_tfile *t=handle;
+  if (!tfile__setupSave(t,0,&p,FALSE))
+    return (FALSE);
+  if (xfersend_sendBlock(p,tfile__flexUsed,maxbuf))
+  {
+    flex_free(&p);
+    return (TRUE);
+  }
+  else
+  {
+    flex_free(&p);
+    return (FALSE);
+  }
+}
+
+/*
+ * BOOL tfile__saveSelection(char *filename,void *handle)
+ *
+ * Use
+ *  Saves a template selection to disk
+ *
+ * Parameters
+ *  char *filename == the file to save to
+ *  void *handle == pointer to the template file
+ *
+ * Returns
+ *  TRUE if successful
+ */
+
+static BOOL tfile__saveSelection(char *filename,void *handle)
+{
+  void *p;
+  os_filestr f;
+  glass_tfile *t=handle;
+  if
+  (
+    gPrefs_current()->cSave &&
+    saveas_file_is_safe() &&
+    res_fileExists(filename)
+  )
+  {
+    if (!warning(msgs_lookup("tfSOFP"),msgs_lookup("tfSOF"),filename))
+      return (FALSE);
+  }
+  if (!tfile__setupSave(t,0,&p,TRUE))
+    return (FALSE);
+  f.action=10;
+  f.name=filename;
+  f.loadaddr=0xfec;
+  f.start=(int)p;
+  f.end=f.start+tfile__flexUsed;
+  if (utils_complain(os_file(&f),msgs_lookup("tfERT")))
+  {
+    flex_free(&p);
+    return (FALSE);
+  }
+  else
+  {
+    flex_free(&p);
+    return (TRUE);
+  }
+}
+
+/*
+ * BOOL tfile__sendSelection(void *handle,int *maxbuf)
+ *
+ * Use
+ *  Saves a template selection to another application via RAM transfer
+ *
+ * Parameters
+ *  void *handle == pointer to the template file
+ *  int *maxbuf == pointer to receiving app's buffer size
+ *
+ * Returns
+ *  TRUE if successful
+ */
+
+static BOOL tfile__sendSelection(void *handle,int *maxbuf)
+{
+  void *p;
+  glass_tfile *t=handle;
+  if (!tfile__setupSave(t,0,&p,TRUE))
+    return (FALSE);
+  if (xfersend_sendBlock(p,tfile__flexUsed,maxbuf))
+  {
+    flex_free(&p);
+    return (TRUE);
+  }
+  else
+  {
+    flex_free(&p);
+    return (FALSE);
+  }
+}
+
+/*
+ * BOOL tfile__saveWindow(char *filename,void *handle)
+ *
+ * Use
+ *  Saves a template selection to disk
+ *
+ * Parameters
+ *  char *filename == the file to save to
+ *  void *handle == pointer to the window
+ *
+ * Returns
+ *  TRUE if successful
+ */
+
+static BOOL tfile__saveWindow(char *filename,void *handle)
+{
+  void *p;
+  os_filestr f;
+  glass_windPointer *w=handle;
+  if
+  (
+    gPrefs_current()->cSave &&
+    saveas_file_is_safe() &&
+    res_fileExists(filename)
+  )
+  {
+    if (!warning(msgs_lookup("tfSOFP"),msgs_lookup("tfSOF"),filename))
+      return (FALSE);
+  }
+  if (!tfile__setupSave(0,w,&p,TRUE))
+    return (FALSE);
+  f.action=10;
+  f.name=filename;
+  f.loadaddr=0xfec;
+  f.start=(int)p;
+  f.end=f.start+tfile__flexUsed;
+  if (utils_complain(os_file(&f),msgs_lookup("tfERT")))
+  {
+    flex_free(&p);
+    return (FALSE);
+  }
+  else
+  {
+    flex_free(&p);
+    return (TRUE);
+  }
+}
+
+/*
+ * BOOL tfile__sendWindow(void *handle,int *maxbuf)
+ *
+ * Use
+ *  Saves a template selection to another application via RAM transfer
+ *
+ * Parameters
+ *  void *handle == pointer to the window
+ *  int *maxbuf == pointer to receiving app's buffer size
+ *
+ * Returns
+ *  TRUE if successful
+ */
+
+static BOOL tfile__sendWindow(void *handle,int *maxbuf)
+{
+  void *p;
+  glass_windPointer *w=handle;
+  if (!tfile__setupSave(0,w,&p,TRUE))
+    return (FALSE);
+  if (xfersend_sendBlock(p,tfile__flexUsed,maxbuf))
+  {
+    flex_free(&p);
+    return (TRUE);
+  }
+  else
+  {
+    flex_free(&p);
+    return (FALSE);
+  }
+}
+
+#else
+
+static BOOL tfile__demoSave(void)
+{
+  note(msgs_lookup("tfCSID"));
+}
+
+static BOOL tfile__saveTemplates(char *filename,void *handle)
+{
+  unused(filename);
+  unused(handle);
+  return (tfile__demoSave());
+}
+
+static BOOL tfile__sendTemplates(void *handle,int *maxbuf)
+{
+  unused(handle);
+  unused(maxbuf);
+  return (tfile__demoSave());
+}
+
+static BOOL tfile__saveSelection(char *filename,void *handle)
+{
+  unused(filename);
+  unused(handle);
+  return (tfile__demoSave());
+}
+
+static BOOL tfile__sendSelection(void *handle,int *maxbuf)
+{
+  unused(handle);
+  unused(maxbuf);
+  return (tfile__demoSave());
+}
+
+static BOOL tfile__saveWindow(char *filename,void *handle)
+{
+  unused(filename);
+  unused(handle);
+  return (tfile__demoSave());
+}
+
+static BOOL tfile__sendWindow(void *handle,int *maxbuf)
+{
+  unused(handle);
+  unused(maxbuf);
+  return (tfile__demoSave());
+}
+
+#endif
+
+/*----- Autosave handling -------------------------------------------------*
+ *
+ * This is here to avoid having to prototype the save code
+ */
+
+/*
+ * void tfile__closeQbox(int now,void *handle)
+ *
+ * Use
+ *  Closes the autosave message dialogue box.
+ *
+ * Parameters
+ *  int now == the time now (ignored)
+ *  void *handle == dialogue box handle
+ */
+
+static void tfile__closeQbox(int now,void *handle)
+{
+  unused(now);
+  dbox_delete((dbox)handle);
+}
+
+/*
+ * void tfile__autoHandler(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles events for the autosave prompt box
+ *
+ * Parameters
+ *  dbox d == the dbox's handle
+ *  dbox_field f == what happened
+ *  void *handle == pointer to the template file
+ */
+
+static void tfile__autoHandler(dbox d,dbox_field f,void *handle)
+{
+  glass_tfile *t=handle;
+  wimp_wstate s;
+  switch (f)
+  {
+    case glass_APSAVE:
+      if (strchr(t->filename,'.'))
+      {
+        dbox_clickicon(d,f);
+        wimpt_noerr(wimp_get_wind_state(dbox_syshandle(d),&s));
+        dbox_hide(d);
+        if (!tfile__saveTemplates(t->filename,t))
+          wimpt_noerr(wimp_open_wind(&s.o));
+        dbox_unclick();
+        break;
+      }
+      /* If no path, drop through to saveas... */
+    case glass_APSAVEAS:
+      dbox_clickicon(d,glass_APSAVEAS);
+      dbox_unclick();
+      tfile_saveTemplates(t);
+      break;
+    case glass_APCANCEL:
+      dbox_clickicon(d,f);
+      dbox_hide(d);
+      dbox_unclick();
+      /* Intentional drop through */
+    case dbox_CLOSE:
+      dbox_delete(d);
+      t->autod=0;
+      break;
+  }
+}
+
+/*
+ * void tfile__doAutosave(glass_tfile *t)
+ *
+ * Use
+ *  Starts an autosave for the given template file.  Multiple autosaves
+ *  are permitted simultaneously.  Stick that in Impression's pipeline and
+ *  process it...
+ *
+ * Parameters
+ *  glass_tfile *t == the template file to autosave
+ */
+
+static void tfile__doAutosave(int now,void *handle)
+{
+  BOOL useDbox;
+  dbox qwin;
+  int at;
+  glass_tfile *t=handle;
+  unused(now);
+  useDbox=gPrefs_current()->aPrompt;
+  if (t->loaded==FALSE || t->autoSaved==FALSE)
+    useDbox=TRUE;
+  if (t->autoAlarm)
+    alarm_remove(t->autoAlarm,t);
+  t->autoAlarm=0;
+  t->autoTime=0;
+  t->alts=-1;
+  if (useDbox)
+  {
+    if (t->autod)
+      return;
+    t->autod=dbox_create("autoPrompt");
+    if (!t->autod)
+    {
+      if (at=gPrefs_autoTiming(),at)
+      {
+        t->autoTime=alarm_timenow();
+        t->autoAlarm=t->autoTime+at;
+        alarm_set(t->autoAlarm,tfile__doAutosave,t);
+      }
+      return;
+    }
+    dbox_setfield(t->autod,glass_APNAME,"%.%s",t->filename);
+    dbox_shadeicon(t->autod,glass_APSAVE,!strchr(t->filename,'.'));
+    dbox_eventHandler(t->autod,tfile__autoHandler,t);
+    dbox_openDisplaced(t->autod);
+  }
+  else
+  {
+    qwin=dbox_create("autoMessage");
+    if (qwin)
+    {
+      dbox_setfield(qwin,glass_AMNAME,"%.%s",t->filename);
+      dbox_display(qwin,dbox_MENU_CENTRE);
+      nopoll_showDbox(qwin,nopoll_CENTRE);
+      alarm_set(alarm_timenow()+100,tfile__closeQbox,qwin);
+    }
+    tfile__saveTemplates(t->filename,t);
+  }
+}
+
+/*----- Event handlers ----------------------------------------------------*/
+
+/*
+ * void tfile__close(glass_tfile *t,BOOL checkMouse)
+ *
+ * Use
+ *  Closes a template file, asking user for confirmation etc.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file to kill
+ *  BOOL checkMouse == whether to check the mouse buttons to open the parent
+ */
+
+static void tfile__close(glass_tfile *t,BOOL checkMouse)
+{
+  wimp_mousestr m;
+  char buff[256];
+  char *name;
+  event_clear_current_menu(); /* The menu will be closed - it will try */
+                             /* to deselect an non-existant item...    */
+  if (checkMouse)
+  {
+    wimpt_noerr(wimp_get_point_info(&m));
+    if (m.bbits==wimp_BRIGHT && t->loaded)
+    {
+      sprintf(buff,"Filer_OpenDir %s",t->filename);
+      utils_leafname(buff)[-1]=0;
+      os_cli(buff);
+    }
+    if (m.bbits==wimp_BRIGHT && akbd_pollsh())
+      return;
+  }
+  if (t->alts && gPrefs_current()->cClose)
+  {
+    if (t->loaded)
+      name=t->filename;
+    else
+      name=msgs_lookup("tfTMP");
+    tfile__selectSize=0;
+    viewer_doForIcons(t->v,FALSE,tfile__size);
+    viewer_clickSelect(t->v,viewer_NOICON,wimp_BMID);
+    saveWarn(t->loaded,
+             tfile__deleteTemplateFile,
+             msgs_lookup("tfSVTIT"),
+             name,0xfec,
+             tfile__selectSize,
+             tfile__saveTemplates,
+             tfile__sendTemplates,
+             0,
+             t);
+  }
+  else
+    tfile__deleteTemplateFile(t); /* Destroy the underlying data       */
+}
+
+/*
+ * void tfile__redrawViewer(viewer_icon i,wimp_redrawstr *r,
+ *          wimp_box *box,char *text,char *sprite,BOOL selected,void *handle)
+ *
+ * Use
+ *  Redraws a small icon in the viewer window.
+ *
+ * Parameters
+ *  viewer_icon i == the icon I'm redrawing
+ *  wimp_redrawstr *r == the redraw structure
+ *  wimp_box *box == the box to fit it in
+ *  char *text == the text to draw
+ *  char *sprite == the sprite to draw (ignored)
+ *  BOOL selected == whether the icon is selected
+ *  void *handle == pointer to the template file
+ */
+
+static void tfile__redrawViewer(viewer_icon i,
+                                wimp_redrawstr *r,
+                                wimp_box *box,
+                                char *text,
+                                char *sprite,
+                                BOOL selected,
+                                void *handle)
+{
+  wimp_icon icn={0,0,0,0,0x17000113,""};
+  unused(i);
+  unused(r);
+  unused(sprite);
+  unused(handle);
+  icn.box=*box;
+  icn.flags|=(selected<<21);
+  icn.data.indirecttext.buffer=text;
+  icn.data.indirecttext.validstring="Ssmtmpltvicon";
+  icn.data.indirecttext.bufflen=13;
+  wimpt_noerr(wimp_ploticon(&icn));
+}
+
+/*
+ * int tfile__sort(void *a,void *b)
+ *
+ * Use
+ *  Compares two windows in the current sorting method.
+ *
+ * Parameters
+ *  void *a == pointer to the first window
+ *  void *b == pointer to the second window
+ *
+ * Returns
+ *  Somehow 'a-b'.
+ */
+
+static int tfile__sort(void *a,void *b)
+{
+  glass_windPointer *x=a;
+  glass_windPointer *y=b;
+  int result=0;
+  switch (x->t->sort)
+  {
+    case gPrefs_NAME:
+      result=utils_caselessCmp(x->id,y->id);
+      break;
+    case gPrefs_SIZE:
+      result=y->size-x->size;
+      break;
+    case gPrefs_ICONS:
+      result=y->def->desc.w.nicons-x->def->desc.w.nicons;
+      break;
+    case gPrefs_NOSORT:
+      result=x->serial-y->serial;
+      break;
+  }
+  if (!result)
+    result=utils_caselessCmp(x->id,y->id);
+  return (result);
+}
+
+/*
+ * void tfile__tfileMenuHelp(int hit[],void *handle)
+ *
+ * Use
+ *  Responds to help requests for template file menu.
+ *
+ * Parameters
+ *  int hit[] == array of menu selections
+ *  void *handle == pointer to template file control block
+ */
+
+static void tfile__tfileMenuHelp(int hit[],void *handle)
+{
+  unused(handle);
+  help_startHelp();
+  help_readFromMenu("tfmhTF",hit);
+  help_endHelp();
+}
+
+/*
+ * void tfile__tfileMenuHandler(int hit[],void *handle)
+ *
+ * Use
+ *  Responds to menu events for template file menu.
+ *
+ * Parameters
+ *  int hit[] == array of menu selections
+ *  void *handle == pointer to template file control block
+ */
+
+static void tfile__tfileMenuHandler(int hit[],void *handle)
+{
+  glass_tfile *t=handle;
+  char buff[15];
+  dbox d;
+  unused(t);
+  switch (hit[0])
+  {
+    case 0:
+      viewer_clickSelect(t->v,viewer_NOICON,wimp_BMID);
+      break;
+    case glass_TFINFO:
+      if (d=dbox_create("fileInfo"),d)
+      {
+        dbox_setfield(d,glass_FINAME,"%.%s",t->filename);
+        tfile__selectSize=0;
+        tfile__selectIndSz=0;
+        viewer_doForIcons(t->v,FALSE,tfile__size);
+        dbox_setfield(d,
+                      glass_FISIZE,
+                      "%s",
+                      utils_cvtSize(tfile__selectSize));
+        dbox_setfield(d,
+                      glass_FIINDSZ,
+                      "%s",
+                      utils_cvtSize(tfile__selectIndSz));
+        dbox_setfield(d,glass_FIWINDOWS,"%i",viewer_icons(t->v));
+        dbox_setfield(d,
+                      glass_FIMODIFIED,
+                      "%s",
+                      msgs_lookup(t->alts ? "yes" : "no"));
+        mbox(d,"tfhFI");
+      }
+      break;
+    case glass_TFDISP:
+      switch (hit[1])
+      {
+        case glass_TFDLARGE:
+          if (t->isz!=gPrefs_LARGE)
+          {
+            t->isz=gPrefs_LARGE;
+            viewer_setIconSize(t->v,200,112);
+            viewer_redrawHandler(t->v,0,t);
+          }
+          break;
+        case glass_TFDSMALL:
+          if (t->isz!=gPrefs_SMALL)
+          {
+            t->isz=gPrefs_SMALL;
+            viewer_setIconSize(t->v,248,36);
+            viewer_redrawHandler(t->v,tfile__redrawViewer,t);
+          }
+          break;
+        case glass_TFDSORTNAME:
+          if (t->sort!=gPrefs_NAME)
+          {
+            t->sort=gPrefs_NAME;
+            viewer_setCompare(t->v,tfile__sort);
+          }
+          break;
+        case glass_TFDSORTSIZE:
+          if (t->sort!=gPrefs_SIZE)
+          {
+            t->sort=gPrefs_SIZE;
+            viewer_setCompare(t->v,tfile__sort);
+          }
+          break;
+        case glass_TFDSORTICONS:
+          if (t->sort!=gPrefs_ICONS)
+          {
+            t->sort=gPrefs_ICONS;
+            viewer_setCompare(t->v,tfile__sort);
+          }
+          break;
+        case glass_TFDNOSORT:
+          if (t->sort!=gPrefs_NOSORT)
+          {
+            t->sort=gPrefs_NOSORT;
+            viewer_setCompare(t->v,tfile__sort);
+          }
+          break;
+      }
+      break;
+    case glass_TFSEL:
+      switch (hit[1])
+      {
+        case glass_TFSELINFO:
+          if (viewer_selected(t->v)==1)
+            tfile_windowInfo((glass_windPointer *)
+                              viewer_iconHandle(viewer_firstSelected(t->v)));
+          else
+          {
+            if (d=dbox_create("selInfo"),d)
+            {
+              tfile__selectSize=0;
+              tfile__selectIndSz=0;
+              viewer_doForIcons(t->v,TRUE,tfile__size);
+              dbox_setfield(d,
+                            glass_SISIZE,
+                            "%s",
+                            utils_cvtSize(tfile__selectSize));
+              dbox_setfield(d,
+                            glass_SIINDSZ,
+                            "%s",
+                            utils_cvtSize(tfile__selectIndSz));
+              tfile__selectIcons=0;
+              viewer_doForIcons(t->v,TRUE,tfile__icons);
+              dbox_setfield(d,glass_SIICONS,"%i",tfile__selectIcons);
+              dbox_setfield(d,glass_SINUM,"%i",viewer_selected(t->v));
+              mbox(d,"tfhSI");
+            }
+          }
+          break;
+        case glass_TFSELEDIT:
+          editWindow(viewer_iconHandle(viewer_firstSelected(t->v)));
+          break;
+        case glass_TFSELCOPY:
+          writable
+          (
+            msgs_lookup("tfCOPY"),
+            viewer_textOfIcon(viewer_firstSelected(t->v)),
+            buff,
+            tfile__copy,
+            viewer_iconHandle(viewer_firstSelected(t->v))
+          );
+          break;
+        case glass_TFSELRENAME:
+          writable
+          (
+            msgs_lookup("tfREN"),
+            viewer_textOfIcon(viewer_firstSelected(t->v)),
+            buff,
+            tfile_rename,
+            viewer_iconHandle(viewer_firstSelected(t->v))
+          );
+          break;
+        case glass_TFSELSAVE:
+          tfile__selectSize=0;
+          viewer_doForIcons(t->v,TRUE,tfile__size);
+          saveas(msgs_lookup("tfSVSEL"),
+                 msgs_lookup("tfSEL"),
+                 0xfec,
+                 tfile__selectSize,
+                 tfile__saveSelection,
+                 tfile__sendSelection,
+                 0,
+                 t);
+          break;
+        case glass_TFSELDELETE:
+          if (gPrefs_current()->cDelWind)
+          {
+            if (!warning(msgs_lookup("tfDELWP"),msgs_lookup("tfDELW")))
+              break;
+          }
+          viewer_doForIcons(t->v,TRUE,tfile_deleteWindow);
+          tfile_markAsAltered(t);
+          break;
+      }
+      break;
+    case glass_TFSELALL:
+      tfile__gainSelection(t);
+      viewer_selectAll(t->v,TRUE);
+      break;
+    case glass_TFCLRSEL:
+      viewer_selectAll(t->v,FALSE);
+      break;
+    case glass_TFSAVE:
+      tfile_saveTemplates(t);
+      break;
+    case glass_TFCREATE:
+      writable(msgs_lookup("tfCRT"),"",buff,tfile__create,t);
+      break;
+    case glass_TFGRAB:
+      writable(msgs_lookup("tfGRAB"),"",buff,tfile__grabGetName,t);
+      break;
+    case glass_TFSHWSPR:
+      gSprite_display(t);
+      break;
+    default:
+      break;
+  }
+}
+
+/*
+ * menu tfile__tfileMenuMaker(void *handle)
+ *
+ * Use
+ *  Generates the menu for a template file window.
+ *
+ * Parameters
+ *  void *handle == the template file window to deal with
+ *
+ * Returns
+ *  A pointer to the menu structure to display.
+ */
+
+static menu tfile__tfileMenuMaker(void *handle)
+{
+  static menu m;                 /* The main menu pointer                  */
+  static menu disp;              /* Submenu for display options            */
+  static menu windsm;            /* Submenu for window options             */
+#ifdef glass_NOTLAZY
+  static menu stylesm;           /* Submenu for styles options             */
+#endif
+  static char windName[50];      /* Buffer for window name                 */
+  glass_tfile *t=handle;
+  glass_windPointer *w;
+
+  if (!m)                        /* Do we have to create the menu?         */
+  {
+    m=menu_new("Glass",msgs_lookup("tfM"));
+    disp=menu_new(msgs_lookup("tfDSPT"),
+                  msgs_lookup("tfDSPM"));
+    windsm=menu_new("_",msgs_lookup("tfWS"));
+#ifdef glass_NOTLAZY
+    stylesm=menu_new(msgs_lookup("tfISST:Icon styles"),
+                     msgs_lookup("tfISS:"
+                                 "Edit style...,"
+                                 "New style...,"
+                                ">Save..."));
+#endif
+    menu_submenu(m,glass_TFSEL,windsm);
+#ifdef glass_NOTLAZY
+    menu_submenu(m,glass_TFSTYLES,stylesm);
+#endif
+    menu_submenu(m,glass_TFDISP,disp);
+    menu_redirectItem(m,glass_TFSEL,windName,50,0);
+  }
+  menu_minWidth(m,0);
+  viewer_setupMenu(t->v,
+                   msgs_lookup("tfWIN"),
+                   m,
+                   glass_TFSEL,
+                   windName);
+  switch (viewer_selected(t->v))
+  {
+    case 0:
+      menu_setflags(m,glass_TFCLRSEL,FALSE,TRUE);
+      menu_setflags(m,glass_TFSELALL,FALSE,!viewer_icons(t->v));
+      menu_settitle(windsm,msgs_lookup("tfWIN"));
+      menu_setflags(windsm,glass_TFSELINFO,FALSE,TRUE);
+      menu_setflags(windsm,glass_TFSELEDIT,FALSE,TRUE);
+      menu_setflags(windsm,glass_TFSELCOPY,FALSE,TRUE);
+      menu_setflags(windsm,glass_TFSELRENAME,FALSE,TRUE);
+      menu_setflags(windsm,glass_TFSELSAVE,FALSE,TRUE);
+      menu_setflags(windsm,glass_TFSELDELETE,FALSE,TRUE);
+      break;
+    case 1:
+      w=viewer_iconHandle(viewer_firstSelected(t->v));
+      menu_setflags(m,glass_TFCLRSEL,FALSE,FALSE);
+      menu_setflags(m,glass_TFSELALL,FALSE,FALSE);
+      menu_settitle(windsm,msgs_lookup("tfWIN"));
+      menu_setflags(windsm,glass_TFSELINFO,FALSE,FALSE);
+#ifndef glass_DEMO
+      menu_setflags(windsm,glass_TFSELEDIT,FALSE,w->testMode);
+#else
+      menu_setflags(windsm,glass_TFSELEDIT,FALSE,FALSE);
+#endif
+      menu_setflags(windsm,glass_TFSELCOPY,FALSE,FALSE);
+      menu_setflags(windsm,glass_TFSELRENAME,FALSE,FALSE);
+      menu_setflags(windsm,glass_TFSELSAVE,FALSE,FALSE);
+      menu_setflags(windsm,glass_TFSELDELETE,FALSE,FALSE);
+      break;
+    default:
+      menu_setflags(m,glass_TFCLRSEL,FALSE,FALSE);
+      menu_setflags(m,glass_TFSELALL,FALSE,FALSE);
+      menu_settitle(windsm,msgs_lookup("tfSEL"));
+      menu_setflags(windsm,glass_TFSELINFO,FALSE,FALSE);
+      menu_setflags(windsm,glass_TFSELEDIT,FALSE,TRUE);
+      menu_setflags(windsm,glass_TFSELCOPY,FALSE,TRUE);
+      menu_setflags(windsm,glass_TFSELRENAME,FALSE,TRUE);
+      menu_setflags(windsm,glass_TFSELSAVE,FALSE,FALSE);
+      menu_setflags(windsm,glass_TFSELDELETE,FALSE,FALSE);
+      break;
+  }
+  menu_setflags(m,glass_TFSHWSPR,FALSE,!t->vs);
+  menu_setflags(m,glass_TFGRAB,FALSE,window_grabbing());
+  menu_setflags(disp,glass_TFDLARGE,t->isz==gPrefs_LARGE,FALSE);
+  menu_setflags(disp,glass_TFDSMALL,t->isz==gPrefs_SMALL,FALSE);
+  menu_setflags(disp,glass_TFDSORTNAME,t->sort==gPrefs_NAME,FALSE);
+  menu_setflags(disp,glass_TFDSORTSIZE,t->sort==gPrefs_SIZE,FALSE);
+  menu_setflags(disp,glass_TFDSORTICONS,t->sort==gPrefs_ICONS,FALSE);
+  menu_setflags(disp,glass_TFDNOSORT,t->sort==gPrefs_NOSORT,FALSE);
+  return (m);
+}
+
+/*
+ * void tfile__simMenu(glass_tfile *t,int hit1,int hit2)
+ *
+ * Use
+ *  Simulates a menu hit on a template file window
+ *
+ * Parameters
+ *  glass_tfile *t == the template file the event is destined for
+ *  int hit1 == the main menu entry number
+ *  int hit2 == the submenu entry number
+ */
+
+static void tfile__simMenu(glass_tfile *t,int hit1,int hit2)
+{
+  wimp_menustr *m=menu_syshandle(tfile__tfileMenuMaker(t));
+  wimp_menuitem *i=(wimp_menuitem *)(m+1)+(hit1-1);
+  int mnu[3];
+  mnu[0]=hit1;
+  mnu[1]=hit2;
+  mnu[2]=0;
+
+  if ((int)i->submenu==-1 || hit2==0)
+  {
+    if (i->iconflags & wimp_INOSELECT)
+    {
+      bbc_vdu(7);
+      return;
+    }
+    else
+      mnu[1]=0;
+  }
+  else
+  {
+    i=(wimp_menuitem *)(i->submenu+1)+(hit2-1);
+    if (i->iconflags & wimp_INOSELECT)
+    {
+      bbc_vdu(7);
+      return;
+    }
+  }
+  tfile__tfileMenuHandler(mnu,t);
+}
+
+/*
+ * BOOL tfile__dragUnknowns(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles unknown events during the period of dragging viewer icons
+ *  around.  It will respond to the following drags:
+ *
+ *  A drag to a blank area of icon bar will open the windows.
+ *
+ *  Otherwise, a selection save will be started, and the windows packaged
+ *  off to another application.
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event to look at
+ *  void *handle == the template file we're dragging from
+ *
+ * Returns
+ *  TRUE if the drag has been processed
+ */
+
+static BOOL tfile__dragUnknowns(wimp_eventstr *e,void *handle)
+{
+  glass_tfile *t=handle;
+  wimp_mousestr m;
+  BOOL handled=FALSE;
+  switch (e->e)
+  {
+    case wimp_EUSERDRAG:
+      handled=TRUE;
+      win_remove_unknown_event_processor(tfile__dragUnknowns,t);
+      wimpt_noerr(wimp_get_point_info(&m));
+      if (m.w==viewer_syshandle(t->v))
+        break;
+      if (m.w==-2 && m.i==-1)
+        viewer_doForIcons(t->v,TRUE,tfile__openWindows);
+      else
+      {
+          tfile__selectSize=0;
+          viewer_doForIcons(t->v,TRUE,tfile__size);
+          wimpt_fake_event(e);          /* Fool xfersend to send data      */
+          xfersend(0xFEC,
+                   msgs_lookup("tfSEL"),
+                   tfile__selectSize,
+                   tfile__saveSelection,
+                   tfile__sendSelection,
+                   0,
+                   e,
+                   t);
+      }
+      viewer_selectAll(t->v,FALSE);
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * BOOL tfile__raw(viewer v,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles intMsgs from other parts of the system
+ *
+ * Parameters
+ *  viewer v == the handle for the viewer window
+ *  wimp_eventstr *e == the event to process
+ *  void *handle == the template file
+ *
+ * Returns
+ *  TRUE if event was processed
+ */
+
+static BOOL tfile__raw(viewer v,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  char *filename;
+  int estsize;
+  int filetype;
+  void *p;
+  glass_tfile *t=handle;
+  int at;
+  switch (e->e)
+  {
+    case wimp_EKEY:
+      switch (e->data.key.chcode)
+      {
+        case akbd_Fn+1+akbd_Sh: /* sF1 */
+          tfile__simMenu(t,glass_TFINFO,0);
+          handled=TRUE;
+          break;
+        case 1:                 /* ^A */
+          tfile__simMenu(t,glass_TFSELALL,0);
+          handled=TRUE;
+          break;
+        case 26:                /* ^Z */
+          tfile__simMenu(t,glass_TFCLRSEL,0);
+          handled=TRUE;
+          break;
+        case akbd_Fn+3:         /* F3 */
+          tfile__simMenu(t,glass_TFSAVE,0);
+          handled=TRUE;
+          break;
+        case 14:                /* ^N */
+          tfile__simMenu(t,glass_TFCREATE,0);
+          handled=TRUE;
+          break;
+        case 7:                 /* ^G */
+          tfile__simMenu(t,glass_TFGRAB,0);
+          handled=TRUE;
+          break;
+        case 19:                /* ^S */
+          tfile__simMenu(t,glass_TFSHWSPR,0);
+          handled=TRUE;
+          break;
+
+        case akbd_Fn+5:         /* F5 */
+          tfile__simMenu(t,glass_TFDISP,glass_TFDLARGE);
+          handled=TRUE;
+          break;
+        case akbd_Fn+5+akbd_Sh: /* sF5 */
+          tfile__simMenu(t,glass_TFDISP,glass_TFDSMALL);
+          handled=TRUE;
+          break;
+        case akbd_Fn+6:         /* F6 */
+          tfile__simMenu(t,glass_TFDISP,glass_TFDSORTNAME);
+          handled=TRUE;
+          break;
+        case akbd_Fn+6+akbd_Sh: /* sF6 */
+          tfile__simMenu(t,glass_TFDISP,glass_TFDSORTSIZE);
+          handled=TRUE;
+          break;
+        case akbd_Fn+6+akbd_Ctl:/* ^F6 */
+          tfile__simMenu(t,glass_TFDISP,glass_TFDSORTICONS);
+          handled=TRUE;
+          break;
+        case akbd_Fn+6+akbd_Ctl+akbd_Sh:/* s^F6 */
+          tfile__simMenu(t,glass_TFDISP,glass_TFDNOSORT);
+          handled=TRUE;
+          break;
+
+        case akbd_Fn+1+akbd_Ctl:/* ^F1 */
+          tfile__simMenu(t,glass_TFSEL,glass_TFSELINFO);
+          handled=TRUE;
+          break;
+        case 5:                 /* ^E */
+          tfile__simMenu(t,glass_TFSEL,glass_TFSELEDIT);
+          handled=TRUE;
+          break;
+        case 3:                 /* ^C */
+          tfile__simMenu(t,glass_TFSEL,glass_TFSELCOPY);
+          handled=TRUE;
+          break;
+        case 18:                /* ^R */
+          tfile__simMenu(t,glass_TFSEL,glass_TFSELRENAME);
+          handled=TRUE;
+          break;
+        case akbd_Fn+3+akbd_Sh: /* sF3 */
+          tfile__simMenu(t,glass_TFSEL,glass_TFSELSAVE);
+          handled=TRUE;
+          break;
+        case 24:                /* ^X */
+          tfile__simMenu(t,glass_TFSEL,glass_TFSELDELETE);
+          handled=TRUE;
+          break;
+
+        case akbd_Fn+2+akbd_Ctl:/* ^F2 */
+          tfile__close(t,FALSE);
+          handled=TRUE;
+          break;
+      }
+      break;
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MDATASAVE:
+          filetype=xferrecv_checkimport(&estsize);
+          switch (filetype)
+          {
+            case 0xfec:          /* Template files                         */
+              if (xferrecv_returnImportedBlock(&p)!=-1)
+              {
+                tfile_markAsAltered(t);
+                tfile_mergeFromMemory(&p,t);
+                flex_free(&p);
+              }
+              break;
+            case 0xff9:          /* Sprite files (I think)                 */
+              if (t->vs)
+              {
+                if (xferrecv_returnImportedBlock(&p)!=-1)
+                {
+                  gSprite_mergeFromMemory(t,&p);
+                  flex_free(&p);
+                }
+              }
+              break;
+          }
+          break;
+        case wimp_MDATALOAD:
+          filetype=xferrecv_checkinsert(&filename);
+          switch (filetype)
+          {
+            case 0xfec:          /* Template files                         */
+              tfile_mergeFromFile(filename,t);
+              tfile_markAsAltered(t);
+              xferrecv_insertfileok();
+              break;
+            case 0xff9:          /* Sprite files (I think)                 */
+              if (t->vs)
+              {
+                gSprite_mergeFromFile(t,filename);
+                xferrecv_insertfileok();
+              }
+              break;
+          }
+          break;
+        case wimp_MINTERNAL:
+          switch (e->data.msg.data.words[0])
+          {
+            case glass_KILLFILES:
+              tfile__deleteTemplateFile(t);
+              break;
+            case glass_CLOSEDOWN:
+              viewer_doForIcons(v,FALSE,tfile__tidyFonts);
+              handled=TRUE;
+              break;
+            case glass_MODECHANGE:
+              viewer_doForIcons(v,FALSE,tfile__reFindFonts);
+              handled=TRUE;
+              break;
+            case glass_AUTOSAVE:
+              if (t->autoAlarm)
+                alarm_remove(t->autoAlarm,t);
+              t->autoAlarm=0;
+              if (t->autoTime)
+              {
+                if (at=gPrefs_autoTiming(),at)
+                {
+                  t->autoAlarm=t->autoTime+at;
+                  alarm_set(t->autoAlarm,tfile__doAutosave,t);
+                }
+              }
+              if (gPrefs_current()->aAlts!=0 &&
+                  t->alts>=gPrefs_current()->aAlts)
+                tfile__doAutosave(0,t);
+              break;
+          }
+          break;
+      }
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void tfile__tfileHandler(viewer v,
+ *                          viewer_icon i,
+ *                          wimp_bbits b,
+ *                          void *vhandle,
+ *                          void *ihandle)
+ *
+ * Use
+ *  Handles events for a template file window (including things like menu
+ *  clicks).
+ *
+ * Parameters
+ *  viewer v == the viewer that the event happened to
+ *  viewer_icon i == the icon it happened to
+ *  wimp_bbits b == the mouse button status
+ *  void *vhandle == pointer to the template file structure
+ *  void *ihandle == pointer to the window pointer structure
+ */
+
+static void tfile__tfileHandler(viewer v,
+                                viewer_icon i,
+                                wimp_bbits b,
+                                void *vhandle,
+                                void *ihandle)
+{
+  glass_tfile *t=vhandle;
+  glass_windPointer *wp=ihandle;
+  switch ((int)i)
+  {
+    case (int)viewer_CLOSE:      /* If the user closes the window          */
+      tfile__close(t,TRUE);      /*  Try to close it :-)                   */
+      break;
+    case (int)viewer_HELP:       /* Help request for the window            */
+      help_startHelp();          /* Prepare a reply                        */
+      help_addLine(msgs_lookup("tfhTF"));
+      help_endHelp();            /* Send the message to Help application   */
+      break;
+    default:
+      if (b!=wimp_BMID)
+      {
+        tfile__gainSelection(t);
+        viewer_clickSelect(v,i,b);
+      }
+      switch (b)
+      {
+        case wimp_BMID:
+          if (t==tfile__selOwner ||
+              !tfile__selOwner ||
+              !viewer_selected(tfile__selOwner->v) )
+          {
+            tfile__selOwner=t;
+            viewer_clickSelect(v,i,b);
+          }
+          menu_make(tfile__tfileMenuMaker,
+                    tfile__tfileMenuHandler,
+                    tfile__tfileMenuHelp,
+                    t);
+          break;
+        case wimp_BLEFT:
+          if (i!=viewer_NOICON)
+          {
+            if (akbd_pollsh() && wp->h)
+              window_close(wp);
+            else
+              window_open(wp,FALSE); /* Open the window on-screen          */
+            viewer_selectIcon(i,FALSE); /* And deslect the icon            */
+          }
+          break;
+        case wimp_BRIGHT:
+          if (i!=viewer_NOICON)
+          {
+            if (akbd_pollsh() && wp->h)
+              window_close(wp);
+            else
+              window_open(wp,TRUE); /* Open the window on-screen           */
+            viewer_selectIcon(i,FALSE); /* And deslect the icon            */
+          }
+          break;
+        case wimp_BDRAGLEFT:
+        case wimp_BDRAGRIGHT:
+          if (i!=viewer_NOICON)
+          {
+            tfile_dragSelected(i,b,"tpackage");
+            win_add_unknown_event_processor(tfile__dragUnknowns,t);
+          }
+          break;
+      }
+      break;
+  }
+}
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * BOOL tfile_okToQuit(BOOL ask)
+ *
+ * Use
+ *  Ensures that it is 'safe' for Glass to quit.
+ *
+ * Parameters
+ *  BOOL ask == should I open a dialogue to ask the user?
+ *
+ * Returns
+ *  TRUE if it is safe to quit, or FALSE if not.
+ */
+
+BOOL tfile_okToQuit(BOOL ask)
+{
+  char *q;
+  if (tfile__unsavedFiles==0 || !gPrefs_current()->cQuit)
+    return (TRUE);
+  else if (ask==FALSE)
+    return (FALSE);
+  else if (tfile__unsavedFiles==1)
+    q=msgs_lookup("tfOTQ1");
+  else
+    q=msgs_lookup("tfOTQM");
+  return (warning(msgs_lookup("tfOTQP"),q,tfile__unsavedFiles));
+}
+
+/*
+ * void tfile_markAsAltered(glass_tfile *t)
+ *
+ * Use
+ *  Marks down another alteration for the template file, changing the window
+ *  title if required etc.  Also handles stuff for autosave etc.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file to alter
+ */
+
+void tfile_markAsAltered(glass_tfile *t)
+{
+  char buff[256];
+  int at;
+  t->alts++;
+  if (t->alts==1 || t->alts==0)
+  {
+    sprintf(buff,"%s *",t->filename);
+    viewer_settitle(t->v,buff);
+    if (t->alts==1)
+      tfile__unsavedFiles++;
+    t->alts=1;
+  }
+  if (t->sort==gPrefs_SIZE || t->sort==gPrefs_ICONS)
+    viewer_setCompare(t->v,tfile__sort);
+  if (!t->autoTime)
+  {
+    t->autoTime=alarm_timenow();
+    if (at=gPrefs_autoTiming(),at)
+    {
+      t->autoAlarm=t->autoTime+at;
+      alarm_set(t->autoAlarm,tfile__doAutosave,t);
+    }
+    else
+      t->autoAlarm=0;
+  }
+  if (gPrefs_current()->aAlts!=0 && t->alts>=gPrefs_current()->aAlts)
+    tfile__doAutosave(0,t);
+}
+
+/*
+ * void tfile_markAsSaved(glass_tfile *t,char *newTitle)
+ *
+ * Use
+ *  Marks a template file as having been saved.  Turns off autosave and
+ *  things.
+ *
+ * Parameters
+ *  glass_tfile *t == the file to mark
+ *  char *newtitle == the new title to give to the window
+ */
+
+void tfile_markAsSaved(glass_tfile *t,char *newTitle)
+{
+  char buff[256];
+  if (t->alts)
+  {
+    t->alts=0;
+    tfile__unsavedFiles--;
+  }
+  t->loaded=TRUE;
+  strcpy(t->filename,newTitle);
+  viewer_settitle(t->v,newTitle);
+  intMsgs_send(glass_SAVEFILE,t);
+  if (t->vs)
+  {
+    sprintf(buff,msgs_lookup("spVT"),newTitle);
+    viewer_settitle(t->vs,buff);
+  }
+  if (t->autoAlarm)
+    alarm_remove(t->autoAlarm,t);
+  t->autoAlarm=0;
+  t->autoTime=0;
+  if (t->autod)
+  {
+    dbox_deleteNoUpdate(t->autod);
+    t->autoSaved=TRUE;
+    t->autod=0;
+  }
+}
+
+/*
+ * void tfile_windowInfo(glass_windPointer *w)
+ *
+ * Use
+ *  Displays an info box for a single window
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to display info on
+ */
+
+void tfile_windowInfo(glass_windPointer *w)
+{
+  dbox d=dbox_create("windInfo");
+  if (!d)
+    return;
+  dbox_setfield(d,glass_WINAME,"%s",w->id);
+  dbox_setfield(d,glass_WISIZE,"%s",utils_cvtSize(w->size));
+  dbox_setfield(d,
+                glass_WIINDSZ,
+                "%s",
+                utils_cvtSize(w->size-
+                              sizeof(glass_window)-
+                              (w->def->desc.w.nicons-1)*
+                                   sizeof(glass_iconDescription)));
+  dbox_setfield(d,glass_WIICONS,"%i",w->def->desc.w.nicons);
+  mbox(d,"tfhWI");
+}
+
+/*
+ * void tfile_deleteWindow(glass_windPointer *w)
+ *
+ * Use
+ *  Deletes a single window.
+ *
+ * Parameters
+ *  viewer_icon i == the icon to get
+ *  void *handle ==  the window to eliminate (as a glass_windPointer *)
+ */
+
+void tfile_deleteWindow(viewer_icon i,void *handle)
+{
+  glass_windPointer *w=handle;
+  unused(i);
+  intMsgs_send(glass_DELETEWINDOW,w);
+  viewer_removeIcon(w->i);
+  tfile__doDeleteWindow(w);
+}
+
+/*
+ * BOOL tfile_rename(char *newName,void *handle)
+ *
+ * Use
+ *  Renames the specified window
+ *
+ * Parameters
+ *  char *newName == the new name of the window
+ *  void *handle == pointer to the window structure
+ */
+
+BOOL tfile_rename(char *newName,void *handle)
+{
+  glass_windPointer *w=handle;
+  viewer_icon i;
+  if (strcmp(newName,w->id)==0)
+    return (TRUE);
+  i=viewer_findIcon(w->t->v,newName);
+  if (i==viewer_NOICON || i==w->i)
+  {
+    viewer_removeIcon(w->i);
+    mem_useUser(indir_alloc,indir_free);
+    strcpy(w->id,newName);
+    i=viewer_addIcon(w->t->v,newName,"tmpltvicon",TRUE,w);
+    viewer_setFiletype(i,0xfec);
+    mem_useMalloc();
+    w->i=i;
+    intMsgs_send(glass_RENAME,w);
+    tfile_markAsAltered(w->t);
+    event_clear_current_menu();
+    return (TRUE);
+  }
+  note(msgs_lookup("tfNAE"),
+       viewer_textOfIcon(i));
+  return (FALSE);
+}
+
+/*
+ * void tfile_saveTemplates(glass_tfile *t)
+ *
+ * Use
+ *  Saves a template file using a standard dialogue box
+ *
+ * Parameters
+ *  glass_tfile *t == the template file to save
+ */
+
+void tfile_saveTemplates(glass_tfile *t)
+{
+  char *name;
+  if (t->loaded)
+    name=t->filename;
+  else
+    name=msgs_lookup("tfTMP");
+  tfile__selectSize=0;
+  viewer_doForIcons(t->v,FALSE,tfile__size);
+  saveas(msgs_lookup("tfSVTIT"),
+         name,
+         0xfec,
+         tfile__selectSize,
+         tfile__saveTemplates,
+         tfile__sendTemplates,
+         0,
+         t);
+}
+
+/*
+ * void tfile_saveWindow(glass_windPointer *w)
+ *
+ * Use
+ *  Saves a single window using a standard dialogue box
+ *
+ * Parameters
+ *  glass_windPointer *w == pointer to the window to save
+ */
+
+void tfile_saveWindow(glass_windPointer *w)
+{
+  tfile__selectSize=w->size;
+  saveas(msgs_lookup("tfSVWTIT"),
+         msgs_lookup("tfWIN"),
+         0xfec,
+         w->size,
+         tfile__saveWindow,
+         tfile__sendWindow,
+         0,
+         w);
+}
+
+/*
+ * BOOL tfile_mergeFromMemory(void **p,glass_tfile *t)
+ *
+ * Use
+ *  Actually does a merge operation.  The target file is a glass_tfile in
+ *  memory (internal format) and the source file is a memory image of a
+ *  normal template file.
+ *
+ * Parameters
+ *  void **p == a flex anchor pointer to the source file
+ *  glass_tfile *t == a pointer to the destination file
+ *
+ * Returns
+ *  TRUE for success
+ */
+
+typedef struct { char **p; int offset; } tfile__datPackage;
+
+static char *tfile__dataProc(char *data,void *handle)
+{
+  tfile__datPackage *p=handle;
+  return (((int)data)+*(p->p)+p->offset);
+}
+
+BOOL tfile_mergeFromMemory(void **p,glass_tfile *t)
+{
+  int fontData;                  /* Offset of font ata from start of file  */
+  glass_windPointer *w;          /* For each window we come across         */
+  int index;                     /* Current index entry we're looking at   */
+  int objoff;                    /* Offset of window we're looking at      */
+  int iconoff;                   /* Offset of icon we're looking at        */
+  wimp_iconflags icf;            /* Icon flags for something or other      */
+  int fheight;                   /* Height of a font required              */
+  int fwidth;                    /* Width of a font required               */
+  int fhandle;                   /* Font handle                            */
+  int fptr;                      /* Offset of font name                    */
+  char name[13];                 /* For the name of the template           */
+
+  int objtype;                   /* Type of current template entry         */
+  BOOL foundOdd=FALSE;           /* Found an odd type of data yet?         */
+  int numicons;                  /* Number of icons in a window            */
+  int i;                         /* A loop counter                         */
+  viewer_icon icn;               /* Icon for checking for duplicates       */
+  BOOL fquiet=FALSE;             /* Shut up about font failures.           */
+  tfile__datPackage pk;
+
+  fontData=*intptr(*p,0);        /* Offset of font data from *p            */
+  for (index=16;*intptr(*p,index);index+=24) /* Go through index entries   */
+  {
+    objoff=*intptr(*p,index);    /* Offset of this entry                   */
+    objtype=*intptr(*p,index+8); /* Type of this entry                     */
+    switch (objtype)             /* Which type is it?                      */
+    {
+      case 1:                    /* Window                                 */
+        pk.p=(char **)p;
+        pk.offset=objoff;
+
+        memcpy(name,charptr(*p,index+12),12);
+        name[12]=0;
+        utils_ctermToNterm(name);
+        if (icn=viewer_findIcon(t->v,name),icn)
+          tfile_deleteWindow(icn,viewer_iconHandle(icn));
+        if (w=tfile__newWindow(t,name),!w)
+          return (FALSE);        /* Failed to create the window            */
+        memcpy(&numicons,intptr(*p,objoff+84),sizeof(int));
+        w->size=sizeof(glass_window)+
+                (numicons-1)*sizeof(glass_iconDescription);
+        if (!flex_alloc((flex_ptr)&w->def,w->size))
+        {
+          viewer_removeIcon(w->i);
+          mem_free(w);
+          werr(FALSE,msgs_lookup("tfNEMTL"));
+          return (FALSE);
+        }
+        memcpy(&w->def->desc.w,_ptr(void,*p,objoff),sizeof(wimp_wind));
+        icf=w->def->desc.w.titleflags; /* Get title icon flags             */
+        if (icf & wimp_IFONT)    /* Handle anti-aliased fonts              */
+        {
+          fhandle=(icf & 0xff000000) >> 24; /* Get internal font handle    */
+          fptr=fontData+(fhandle-1)*48; /* Get pointer                     */
+          /* Bug fix - not word aligned!! */
+          memcpy(&fwidth,intptr(*p,fptr)+0,sizeof(int));
+          memcpy(&fheight,intptr(*p,fptr)+1,sizeof(int));
+          utils_ctermToNterm(charptr(*p,fptr+8)); /* Font name             */
+          if (font_find(charptr(*p,fptr+8),fwidth,fheight,0,0,&fhandle))
+          {
+            if (!fquiet)
+            {
+              werr(FALSE,msgs_lookup("tfCFF"));
+              fquiet=TRUE;
+            }
+            icf&=~wimp_IFONT;    /* Stop anti-aliasing (gives odd colours) */
+          }
+          else
+          {
+            icf=(icf & 0x00ffffff) | (fhandle << 24);
+            w->antiAliased=TRUE;
+            w->fonts[fhandle]++;
+          }
+          w->def->desc.w.titleflags=icf;
+        }
+        w->def->desc.w.nicons=0; /* Don't want deletion routine dying      */
+        if (!iconData_processIcon(w,-1,tfile__dataProc,TRUE,&pk))
+        {
+          werr(FALSE,msgs_lookup("tfNEMTL"));
+          tfile_deleteWindow(0,w);
+          return (FALSE);
+        }
+        iconoff=objoff+88;       /* Point to first icon definition         */
+        for (i=0;i<numicons;i++)
+        {
+          memcpy(&w->def->i[i].i,charptr(*p,iconoff),sizeof(wimp_icon));
+          w->def->i[i].selected=FALSE;
+          w->def->i[i].edit=0;
+          icf=w->def->i[i].i.flags; /* Get title icon flags                */
+          if (icf & wimp_IFONT)  /* Handle anti-aliased fonts              */
+          {
+            fhandle=(icf & 0xff000000) >> 24; /* Get internal font handle  */
+            fptr=fontData+(fhandle-1)*48; /* Get pointer                   */
+            /* Bug fix - not word aligned!! */
+            memcpy(&fwidth,intptr(*p,fptr)+0,sizeof(int));
+            memcpy(&fheight,intptr(*p,fptr)+1,sizeof(int));
+            utils_ctermToNterm(charptr(*p,fptr+8)); /* Font name           */
+            if (font_find(charptr(*p,fptr+8),fwidth,fheight,0,0,&fhandle))
+            {
+              if (!fquiet)
+              {
+                werr(FALSE,msgs_lookup("tfCFF"));
+                fquiet=TRUE;
+              }
+              icf&=~wimp_IFONT;    /* Stop anti-aliasing                   */
+            }
+            else
+            {
+              icf=(icf & 0x00ffffff) | (fhandle << 24);
+              w->antiAliased=TRUE;
+              w->fonts[fhandle]++;
+            }
+            w->def->i[i].i.flags=icf;
+          }
+          if (!iconData_processIcon(w,i,tfile__dataProc,TRUE,&pk))
+          {
+            werr(FALSE,msgs_lookup("tfNEMTL"));
+            tfile_deleteWindow(0,w);
+            return (FALSE);
+          }
+          w->def->desc.w.nicons++; /* Tidy up next icon along              */
+          iconoff+=sizeof(wimp_icon); /* Move pointer along                */
+        }
+        break;
+      default:                   /* Anything we don't know - tell the user */
+        if (!foundOdd)           /* Don't generate the message again       */
+        {
+          werr(FALSE,msgs_lookup("tfUTEC"));
+          foundOdd=TRUE;         /* Stop message repeating                 */
+        }
+        break;
+    }
+  }
+  return (TRUE);
+}
+
+/*
+ * BOOL tfile_mergeFromFile(char *file,glass_tfile *t)
+ *
+ * Use
+ *  Merges the template file given into the given template file structure.
+ *
+ * Parameters
+ *  char *file == the file to load
+ *  glass_tfile *t == the template file structure to merge with
+ */
+
+BOOL tfile_mergeFromFile(char *file,glass_tfile *t)
+{
+  os_filestr f;                  /* Going to make some OS_File calls       */
+  void *p;                       /* p will point to the file in memory     */
+  f.action=17;                   /* Read catalogue information for file    */
+  f.name=file;                   /* Point to file name to find out about   */
+  if (utils_complain(os_file(&f),
+      msgs_lookup("tfELF")))
+  {
+    return (FALSE);
+  }
+  if (!flex_alloc(&p,f.start))
+  {
+    werr(FALSE,msgs_lookup("tfNEMTL"));
+    return (FALSE);
+  }
+  f.action=16;                   /* Load the file                          */
+  f.loadaddr=(int)p;             /* Where to load the file                 */
+  f.execaddr=0;                  /* Load it there!!!                       */
+  if (utils_complain(os_file(&f),
+      msgs_lookup("tfELF")))
+  {
+    flex_free(&p);
+    flex_compact();
+    return (FALSE);
+  }
+  tfile_mergeFromMemory(&p,t);   /* Now do the merge                       */
+  flex_free(&p);
+  flex_compact();
+  return (TRUE);
+}
+
+/*
+ * glass_tfile *tfile_createTemplateFile(char *name)
+ *
+ * Use
+ *  Creates a template file with the given name, but doesn't open its viewer.
+ *
+ * Returns
+ *  A pointer to the file structure, or zero as failure.
+ */
+
+glass_tfile *tfile_createTemplateFile(char *name)
+{
+  glass_tfile *t;
+  int ix,iy;
+  mem_useUser(indir_alloc,indir_free);
+  t=mem_alloc(sizeof(glass_tfile));
+  if (!t)                        /* Allocates memory for file structure    */
+  {
+    werr(FALSE,msgs_lookup("tfNEMTF"));
+    mem_useMalloc();
+    return (0);
+  }
+  ix=(gPrefs_current()->fIcons==gPrefs_LARGE) ? 200 : 248;
+  iy=(gPrefs_current()->fIcons==gPrefs_LARGE) ? 112 : 36;
+  if
+  (
+    t->v=viewer_create           /* Now create the viewer window           */
+    (
+      tfile__FILEX,              /* Coords to open window                  */
+      tfile__fileHeight,
+      ix,                        /* Width of 'icons'                       */
+      iy,                        /* Height of 'icons'                      */
+      resspr_area(),             /* Sprite area for 'icons'                */
+      name,                      /* What to display in the title bar       */
+      msgs_lookup("tfBANR") /* Viewer banner line     */
+    ),
+    !t->v                        /* TRUE if creation failed                */
+  )
+  {
+    mem_free(t);                 /* Dispose of unwanted file structure     */
+    mem_useMalloc();
+    return (0);                  /* Inform caller we buggered it up        */
+  }
+  mem_useMalloc();
+  strcpy(t->filename,name);      /* Remember the name                      */
+  t->alts=0;                     /* No alterations yet                     */
+  t->loaded=FALSE;               /* They can change this if they need to   */
+  t->autoSaved=FALSE;            /* Not been autosaved yet                 */
+  t->autod=0;                    /* No autosave dialogue box               */
+  t->autoTime=0;                 /* No autosave time                       */
+  t->autoAlarm=0;                /* No autosave alarm                      */
+  t->isz=gPrefs_current()->fIcons;
+  t->sort=gPrefs_current()->fSort;
+  viewer_eventHandler(t->v,tfile__tfileHandler,t); /* Add event handler    */
+  viewer_rawEventHandler(t->v,tfile__raw,t); /* Raw, for broadcasts        */
+  viewer_redrawHandler(t->v,
+                       t->isz==gPrefs_LARGE ? 0 : tfile__redrawViewer,
+                       t);
+  viewer_setCompare(t->v,tfile__sort);
+  tfile__fileHeight-=48;         /* Displace the next file window          */
+  if (tfile__fileHeight<652)     /* Start at the top again if too low      */
+    tfile__fileHeight=tfile__FILETOP;
+  gSprite_new(t);
+  return (t);
+}
+
+/*
+ * glass_tfile *tfile_loadFromMemory(void **p,char *name)
+ *
+ * Use
+ *  Loads a file from memory, i.e. from another application via RAM
+ *  transfer.
+ *
+ * Parameters
+ *  void **p == the memory block that contains the file to load.
+ *  char *name == the name to give to the file.
+ *
+ * Returns
+ *  A pointer to the template file, or 0
+ */
+
+glass_tfile *tfile_loadFromMemory(void **p,char *name)
+{
+  glass_tfile *t=tfile_createTemplateFile(name);
+  if (!t)
+    return (0);
+  t->loaded=TRUE;
+  if (!tfile_mergeFromMemory(p,t))
+  {
+    tfile__deleteTemplateFile(t);
+    return (0);
+  }
+  if (t->sort==gPrefs_SIZE || t->sort==gPrefs_ICONS)
+    viewer_setCompare(t->v,tfile__sort);
+  viewer_display(t->v);          /* Show the viewer window in its glory    */
+  return (t);
+}
+
+/*
+ * glass_tfile *tfile_loadFromFile(char *file,char *name)
+ *
+ * Use
+ *  Loads a template file into memory, translating the file into Glass's
+ *  internal format.  It does not create any windows, although it does
+ *  allocate font handles.
+ *
+ * Parameters
+ *  char *file == the name of the file to load
+ *  char *name == the name to insert in the title bar
+ *
+ * Returns
+ *  A pointer to the structure definition, or 0 for failure.  Note that this
+ *  will only occur if no windows could be loaded.
+ */
+
+glass_tfile *tfile_loadFromFile(char *file,char *name)
+{
+  glass_tfile *t=tfile_createTemplateFile(name);
+  char buff[256];
+  char fbuff[256];
+  char *parent;
+  if (!t)
+    return (0);
+  t->loaded=TRUE;
+  if (!tfile_mergeFromFile(file,t))
+  {
+    tfile__deleteTemplateFile(t);
+    return (0);
+  }
+  strcpy(fbuff,name);
+  utils_leafname(fbuff)[-1]=0;
+  parent=utils_leafname(fbuff);
+  parent[-1]=0;
+  if (gPrefs_current()->sLoadPSpr)
+  {
+    sprintf(buff,"%s.%s.!Sprites",fbuff,parent);
+    if (res_fileExists(buff))
+      gSprite_mergeFromFile(t,buff);
+    else
+    {
+      sprintf(buff,"%s.!Sprites",fbuff);
+      if (res_fileExists(buff))
+        gSprite_mergeFromFile(t,buff);
+    }
+  }
+  if (gPrefs_current()->sLoadSpr)
+  {
+    sprintf(buff,"%s.%s.Sprites",fbuff,parent);
+    if (res_fileExists(buff))
+      gSprite_mergeFromFile(t,buff);
+  }
+  viewer_display(t->v);          /* Show the viewer window in its glory    */
+  return (t);
+}
+
+/*
+ * void tfile_dragSelected(viewer_icon i,wimp_bbits b,char *package)
+ *
+ * Use
+ *  As for viewer_dragSelected, but uses the specified sprite as the
+ *  'package' sprite is solid sprite drags are enabled.
+ *
+ * Parameters
+ *  viewer_icon i == the icon to drag
+ *  wimp_bbits b == the button status that started it off
+ *  char *package == the sprite to use for a package drag
+ */
+
+void tfile_dragSelected(viewer_icon i,wimp_bbits b,char *package)
+{
+  sprite_id sid;
+  sid.s.name=package;
+  sid.tag=0;
+  sprite_rename(resspr_area(),&sid,"package");
+  viewer_dragSelected(i,b);
+  sid.s.name="package";
+  sprite_rename(resspr_area(),&sid,package);
+}
diff --git a/StraySrc/Glass/!Glass/c/toolbox b/StraySrc/Glass/!Glass/c/toolbox
new file mode 100644 (file)
index 0000000..ee21703
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ * toolbox.c
+ *
+ * Toolbox handling
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#include "steel/Steel.h"
+
+#include "steel/sculptrix.h"
+#include "steel/pointer.h"
+#include "steel/bbc.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gIcons.h"
+
+#include "glass.h"
+#include "toolbox.h"
+
+/*----- Constants ---------------------------------------------------------*/
+
+/*----- Static global variables -------------------------------------------*/
+
+static BOOL toolbox__opened;
+static dbox toolbox__dbox;
+static dbox_field toolbox__selected=-1;
+static BOOL toolbox__released;
+static int toolbox__oldCol;
+
+/*----- Function prototypes -----------------------------------------------*/
+
+static void toolbox__idles(void *handle);
+void toolSupprt_doDrag(wimp_dragstr *d);
+
+/*----- Low-level routines ------------------------------------------------*/
+
+/*
+ * void toolbox__deselect(void)
+ *
+ * Use
+ *  Deselects the current tool (if any)
+ */
+
+static void toolbox__deselect(void)
+{
+  wimpt_noerr(sculptrix_doSlab(dbox_syshandle(toolbox__dbox),
+                               toolbox__selected,
+                               toolbox__oldCol,
+                               0));
+  win_removeIdleClaimer(toolbox__idles,0);
+  pointer_reset_shape();
+  toolbox__selected=-1;
+}
+
+/*
+ * void toolbox__selectTool(dbox_field f)
+ *
+ * Use
+ *  Selects the given tool, and sets up event handlers and things as
+ *  necessary.
+ *
+ * Parameters
+ *  dbox_field f == the field to select
+ */
+
+static void toolbox__selectTool(dbox_field f)
+{
+  if (toolbox__selected!=-1)
+  {
+    if (toolbox__selected==f)
+    {
+      toolbox__deselect();
+      return;
+    }
+    else
+    {
+      wimpt_noerr(sculptrix_doSlab(dbox_syshandle(toolbox__dbox),
+                                   toolbox__selected,
+                                   toolbox__oldCol,
+                                   0));
+      win_removeIdleClaimer(toolbox__idles,0);
+    }
+  }
+  wimpt_noerr(sculptrix_doSlab(dbox_syshandle(toolbox__dbox),
+                               f,
+                               sculptrix_slabColour(),
+                               &toolbox__oldCol));
+  win_addIdleClaimer(toolbox__idles,2,0);
+  toolbox__selected=f;
+  toolbox__released=FALSE;
+}
+
+/*----- Event handlers ----------------------------------------------------*/
+
+/*
+ * void toolbox__idles(void *handle)
+ *
+ * Use
+ *  Handles polling while the toolbox is active.
+ *
+ * Parameters
+ *  void *handle == 0
+ */
+
+static void toolbox__idles(void *handle)
+{
+  wimp_mousestr m;
+  wimp_wstate s;
+  wimp_dragstr d;
+  int sel;
+  static sprite_id id={"ptr_tbx",0};
+  static int trans[6]={0,0,2,3,4,1};
+  wimp_eventstr e;
+  unused(handle);
+  wimpt_noerr(pointer_set_shape(resspr_area(),&id,0,0));
+  wimpt_noerr(wimp_get_point_info(&m));
+  if (!m.bbits)
+    toolbox__released=TRUE;
+  if ((m.bbits==4 || m.bbits==1) && m.w!=dbox_syshandle(toolbox__dbox)
+                                                        && toolbox__released)
+  {
+    sel=toolbox__selected;
+    toolbox__released=FALSE;
+    if (m.bbits==4)
+      toolbox__deselect();
+    e.e=wimp_EUSERDRAG;
+    wimpt_fake_event(&e);
+    event_process();             /* Stop any drags in rest of program      */
+    switch (sel)
+    {
+      case glass_TBCLOSE:
+        s.o.w=m.w;
+        wimp_sendwmessage(wimp_ECLOSE,(wimp_msgstr *)&s.o,m.w,m.i);
+        break;
+      case glass_TBBACK:
+        wimp_get_wind_state(m.w,&s);
+        s.o.behind=-2;
+        wimp_sendwmessage(wimp_EOPEN,(wimp_msgstr *)&s.o,m.w,m.i);
+        break;
+      default:
+        d.window=m.w;
+        d.type=trans[sel];
+        d.box.x0=d.box.x1=m.x;
+        d.box.y0=d.box.y1=m.y;
+        toolSupprt_doDrag(&d);
+        break;
+    }
+    toolbox__released=FALSE;
+    if (m.bbits==4)
+      toolbox__deselect();
+  }
+  else if (bbc_inkey(-113))
+    toolbox__deselect();
+}
+
+/*
+ * void toolbox__events(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles events for the toolbox window.
+ *
+ * Parameters
+ *  dbox d == toolbox__dbox
+ *  dbox_field f == the event to handle (icon handle or special code)
+ *  void *handle == 0
+ */
+
+static void toolbox__events(dbox d,dbox_field f,void *handle)
+{
+  unused(d);
+  unused(handle);
+  switch (f)
+  {
+    case dbox_CLOSE:
+      dbox_hide(toolbox__dbox);
+      if (toolbox__selected!=-1)
+        toolbox__deselect();
+      dbox_delete(toolbox__dbox);
+      toolbox__dbox=0;
+      break;
+    case dbox_HELP:
+      help_startHelp();
+      help_addLine(msgs_lookup("tbhTB"));
+      help_readFromIcon();
+      help_endHelp();
+      break;
+    case glass_TBCLOSE:
+    case glass_TBBACK:
+    case glass_TBSIZE:
+    case glass_TBHSCR:
+    case glass_TBVSCR:
+    case glass_TBMOVE:
+      toolbox__selectTool(f);
+      break;
+  }
+}
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * BOOL toolbox_toolSelected(void)
+ *
+ * Returns
+ *  TRUE if there is a tool selected.  This is useful for handlers thinking
+ *  of starting drag events.
+ */
+
+BOOL toolbox_toolSelected(void)
+{
+  return (toolbox__selected!=-1);
+}
+
+/*
+ * void toolbox(void)
+ *
+ * Use
+ *  Opens the toolbox window.
+ */
+
+void toolbox(void)
+{
+  wimp_wstate s;
+  int xoff,yoff;
+  if (!toolbox__dbox)            /* Is it open yet?                        */
+  {
+    if (toolbox__dbox=dbox_create("toolbox"),!toolbox__dbox)
+      return;
+    if (!toolbox__opened)        /* Move to top-right corner to start off  */
+    {
+      wimpt_noerr(wimp_get_wind_state(dbox_syshandle(toolbox__dbox),&s));
+      xoff=wimpt_scwidth()-s.o.box.x1;
+      yoff=wimpt_scheight()-s.o.box.y1;
+      s.o.box.x0+=xoff;
+      s.o.box.x1+=xoff;
+      s.o.box.y0+=yoff;
+      s.o.box.y1+=yoff;
+      wimpt_noerr(wimp_open_wind(&s.o));
+      toolbox__opened=TRUE;
+    }
+    dbox_eventHandler(toolbox__dbox,toolbox__events,0);
+  }
+  dbox_display(toolbox__dbox,TRUE);
+}
diff --git a/StraySrc/Glass/!Glass/c/wDragging b/StraySrc/Glass/!Glass/c/wDragging
new file mode 100644 (file)
index 0000000..73d1548
--- /dev/null
@@ -0,0 +1,742 @@
+/*
+ * wDragging.c
+ *
+ * Handling of drag operations in windows
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/akbd.h"
+#include "steel/coords.h"
+#include "steel/bbc.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "tfile.h"
+#include "window.h"
+#include "_window.h"
+#include "editIcon.h"
+#include "editWin.h"
+
+/*----- Private variables -------------------------------------------------*/
+
+static int window__dragType=-1;  /* The drag type (one of the macros above */
+static int window__dragX;        /* Last x position in drag                */
+static int window__dragY;        /* Last y position in drag                */
+static int window__startX;       /* Drag start position                    */
+static int window__startY;       /* Drag start position                    */
+static BOOL window__dragDraw;    /* Do we update the drag drawing?         */
+static wimp_box window__dragBox; /* Bounding box for the icon drag         */
+static glass_windPointer *window__dragWindow; /* Window containing drag op */
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * void window__align(glass_windPointer *w,int *x,int *y)
+ *
+ * Use
+ *  Aligns the given point to the *nearest* grid point.  The point is
+ *  fiddled in-situ.  It does the Right Thing with negative points.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window we're using
+ *  int *x == pass-by-reference x coord of point
+ *  int *y == pass-by-reference y coord of point
+ */
+
+void window__align(glass_windPointer *w,int *x,int *y)
+{
+  if (*x<0)
+    *x-=w->gridx/2;
+  else
+    *x+=w->gridx/2;
+  if (*y<0)
+    *y-=w->gridy/2;
+  else
+    *y+=w->gridy/2;
+  *x-=*x % w->gridx;
+  *y-=*y % w->gridy;
+}
+
+/*
+ * void window__getDragCoords(glass_windPointer *w,int *x,int *y)
+ *
+ * Use
+ *  Gets the (window) coordinates for the drag op, taking everything into
+ *  account, and scrolling the window if necessary.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window owning the drag
+ *  int *x == where to put x coord
+ *  int *y == where to put y coord
+ */
+
+static void window__getDragCoords(glass_windPointer *w, int *x, int *y)
+{
+  /* --- Re-engineered by [mdw] 3 February 1998 --- *
+   *
+   * This function is a mess.  So's the rest of the program, but this is
+   * the function I particularly wanted to change today.
+   */
+
+  wimp_mousestr m;
+  wimp_box box;
+  int type = window__dragType;
+  int mx, my;
+  int xbudge = 0, ybudge = 0;
+  unsigned xbudged = ~0, ybudged = ~0;
+  unsigned snaps;
+
+  /* --- Snap type flags --- */
+
+  enum {
+    SNAP_CONSTRAIN = 1,
+    SNAP_GUIDES = 2,
+    SNAP_GRID = 4,
+    SNAP_PIXEL = 8,
+    SNAP_NONE = 0,
+    SNAP_ALL = 0x0F
+  };
+
+  /* --- A little fiddling with the window --- */
+
+  {
+    wimp_wstate s;
+    int ox, oy;
+    int d;
+
+    /* --- Find out where the mouse is at the moment --- */
+
+    wimpt_noerr(wimp_get_point_info(&m));
+    wimpt_noerr(wimp_get_wind_state(w->h, &s));
+    ox = s.o.box.x0 - s.o.x;
+    oy = s.o.box.y1 - s.o.y;
+
+    /* --- If it's outside the window, then scroll it so it isn't --- */
+
+    if ((d = m.x - s.o.box.x0) < 0)
+      s.o.x += d;
+    else if ((d = m.x - s.o.box.x1) > 0)
+      s.o.x += d;
+    if ((d = m.y - s.o.box.y0) < 0)
+      s.o.y += d;
+    else if ((d = m.y - s.o.box.y1) > 0)
+      s.o.y += d;
+
+    wimpt_noerr(wimp_open_wind(&s.o));
+    wimpt_noerr(wimp_get_wind_state(w->h, &s));
+
+    /* --- Convert the mouse coordinates to window-relative ones --- */
+
+    m.x -= ox;
+    m.y -= oy;
+
+    /* --- If the scroll position has changed, update window block --- */
+
+    if (s.o.x != w->def->desc.w.scx || s.o.y != w->def->desc.w.scy) {
+      w->def->desc.w.scx = s.o.x;
+      w->def->desc.w.scy = s.o.y;
+      if (!w->t->alts)             /* Moving window alters template */
+        tfile_markAsAltered(w->t); /* But only if not already altered */
+      editWindow_windowMoved(w);
+    }
+  }
+
+  /* --- Some words on the snapping procedure --- *
+   *
+   * There are several stages of snapping, with different priorities.
+   * The top priority is the pixel grid; nothing can interfere with that.
+   * Next comes the `constrain' key: if Control is pressed, the dragged
+   * object will only move either horizontally or vertically but not both.
+   * After this comes snapping to guides: an object near a guideline will
+   * snap so that either an edge or centreline is over the guide.  Last,
+   * but not least, comes the good old-fashioned gridsnap.
+   */
+
+  /* --- Sort out funny drag types --- */
+
+  switch (type) {
+    case window__GRABICON:
+      type = window__MAIN;
+    case window__MAIN:
+      snaps = SNAP_ALL;
+      break;
+    case window__TOPLEFT:
+    case window__TOPRIGHT:
+    case window__BOTTOMLEFT:
+    case window__BOTTOMRIGHT:
+      snaps = SNAP_ALL;
+      if (gPrefs_current()->sEdgeHandles)
+        snaps &= ~SNAP_CONSTRAIN;
+      break;
+    case window__TOP:
+    case window__BOTTOM:
+    case window__LEFT:
+    case window__RIGHT:
+      snaps = SNAP_ALL & ~SNAP_CONSTRAIN;
+      break;
+    default:
+      snaps = SNAP_NONE;
+      break;
+  }
+
+  /* --- Some simplification --- */
+
+  mx = m.x - window__startX;
+  my = m.y - window__startY;
+
+  /* --- Stage one: constrain --- *
+   *
+   * If the constrain key is set then I look to see whether the mouse
+   * has moved more horizontally or vertically since the drag commenced,
+   * and constrain the drag in the appropriate direction.
+   */
+
+  if ((snaps & SNAP_CONSTRAIN) && akbd_pollctl()) {
+    if (abs(mx) > abs(my)) {
+      ybudge = -my;
+      ybudged = SNAP_CONSTRAIN;
+    } else {
+      xbudge = -mx;
+      xbudged = SNAP_CONSTRAIN;
+    }
+  }
+
+  /* --- Stage two: guidelines --- *
+   *
+   * Work out the bounding box of the dragged object.  If a moving edge is
+   * near a guide, or the whole object is moving and the centre is near a
+   * guide, then snap the object against the guide.  Which guide is chosen
+   * and which edge gets snapped is determined by proximity, and is decided
+   * independently in the x and y directions.  (In olden times, there were
+   * priorities for various edges and lower-numbered guides `won'.  This is
+   * bad.)
+   */
+
+  if (snaps & SNAP_GUIDES) {
+    int gxdist = window__SNAPDIST;
+    int gydist = window__SNAPDIST;
+    int i;
+    int d, dabs;
+
+    /* --- Transform the bounding box according to drag type --- */
+
+    box = window__dragBox;
+    if (type & window__TOP)
+      box.y1 += my;
+    if (type & window__BOTTOM)
+      box.y0 += my;
+    if (type & window__LEFT)
+      box.x0 += mx;
+    if (type & window__RIGHT)
+      box.x1 += mx;
+
+    /* --- Unknown bit of bodging removed temporarily --- *
+     *
+     * This bodge should have been done in the grab-icon code.
+     */
+
+#ifdef notdef
+    if (window__dragType == window__GRABICON) {
+      box.x1 -= wimpt_dx();
+      box.y1 -= wimpt_dy();
+    }
+#endif
+
+    /* --- Now nip off through the guides array --- */
+
+    for (i = 0; i < glass_GUIDELIMIT; i++) {
+
+      /* --- Make sure this guide is sensible --- */
+
+      if (!w->guide[i].active)
+        continue;
+
+      /* --- Handle horizontal guides --- */
+
+      if ((type & (window__TOP | window__BOTTOM)) &&
+          ybudged >= SNAP_GUIDES &&
+          w->guide[i].horiz) {
+
+        /* --- Catch the top edge --- */
+
+        if (type & window__TOP) {
+          d = w->guide[i].coord - box.y1; dabs = abs(d);
+          if (dabs <= gydist) {
+            gydist = dabs;
+            ybudge = d;
+            ybudged = SNAP_CONSTRAIN;
+          }
+        }
+
+        /* --- Catch the bottom edge --- */
+
+        if (type & window__BOTTOM) {
+          d = w->guide[i].coord - box.y0; dabs = abs(d);
+          if (dabs <= gydist) {
+            gydist = dabs;
+            ybudge = d;
+            ybudged = SNAP_CONSTRAIN;
+          }
+        }
+
+        /* --- Catch the centre --- */
+
+        if (type == window__MAIN) {
+          d = w->guide[i].coord - (box.y1 + box.y0) / 2; dabs = abs(d);
+          if (dabs <= gydist) {
+            gydist = dabs;
+            ybudge = d;
+            ybudged = SNAP_CONSTRAIN;
+          }
+        }
+      }
+
+      /* --- Handle vertical guides --- */
+
+      if ((type & (window__LEFT | window__RIGHT)) &&
+          xbudged >= SNAP_GUIDES &&
+          !w->guide[i].horiz) {
+
+        /* --- Catch the left edge --- */
+
+        if (type & window__LEFT) {
+          d = w->guide[i].coord - box.x0; dabs = abs(d);
+          if (dabs <= gxdist) {
+            gxdist = dabs;
+            xbudge = d;
+            xbudged = SNAP_CONSTRAIN;
+          }
+        }
+
+        /* --- Catch the right edge --- */
+
+        if (type & window__RIGHT) {
+          d = w->guide[i].coord - box.x1; dabs = abs(d);
+          if (dabs <= gxdist) {
+            gxdist = dabs;
+            xbudge = d;
+            xbudged = SNAP_CONSTRAIN;
+          }
+        }
+
+        /* --- Catch the top edge --- */
+
+        if (type == window__MAIN) {
+          d = w->guide[i].coord - (box.x1 + box.x0) / 2; dabs = abs(d);
+          if (dabs <= gxdist) {
+            gxdist = dabs;
+            xbudge = d;
+            xbudged = SNAP_CONSTRAIN;
+          }
+        }
+      }
+    }
+  }
+
+  /* --- Stage three: snap to the grid --- */
+
+  if ((snaps & SNAP_GRID) && w->gridLock) {
+    int tx = mx + xbudge, ty = my + ybudge;
+    window__align(w, &tx, &ty);
+    if (xbudged >= SNAP_GRID) {
+      xbudge = tx - mx;
+      xbudged = SNAP_GRID;
+    }
+    if (ybudged >= SNAP_GRID) {
+      ybudge = ty - my;
+      ybudged = SNAP_GRID;
+    }
+  }
+
+  /* --- Stage four: snap to the pixels --- */
+
+  if (snaps & SNAP_PIXEL) {
+    xbudge &= ~(wimpt_dx() - 1);
+    ybudge &= ~(wimpt_dy() - 1);
+  }
+
+  /* --- Return the totally mangled coordinates --- */
+
+  *x = m.x + xbudge;
+  *y = m.y + ybudge;
+}
+
+/*
+ * void window__finishDrag(void)
+ *
+ * Use
+ *  Terminates the drag operation apropriately, releasing handlers, memory
+ *  etc.
+ */
+
+static void window__dragIdles(void *handle);
+
+static void window__finishDrag(void)
+{
+  glass_windPointer *w=window__dragWindow;
+  wimp_redrawstr r;
+  BOOL more;
+  int x,y;
+  int i;
+  wimp_wstate s;
+  wimp_box box;
+  wimp_box ibx;
+
+  /* --- We've stopped dragging -- release the idle events --- */
+
+  win_removeIdleClaimer(window__dragIdles,0);
+
+  /* --- If there's no destination window, give up now --- */
+
+  if (!window__dragWindow)
+  {
+    bbc_vdu(7);
+    window__dragType=-1;
+    window__setPtrShape(-2);
+    return;
+  }
+
+  /* --- Find out where the drag ended --- */
+
+  window__getDragCoords(w,&x,&y);
+
+  /* --- Undraw the drag rectangle(s) --- */
+
+  if (!window__dragDraw)   /* Don't try and remove if not yet plotted! */
+  {
+    wimpt_noerr(wimp_get_wind_state(w->h,&s));
+    r.w=w->h;
+    r.box.x0=s.o.x;
+    r.box.x1=r.box.x0+s.o.box.x1-s.o.box.x0;
+    r.box.y1=s.o.y;
+    r.box.y0=r.box.y1+s.o.box.y0-s.o.box.y1;
+    wimpt_noerr(wimp_update_wind(&r,&more));
+    while (more)
+    {
+      window__rotate(0);
+      window__redrawDragBox(w,&r,window__dragX,window__dragY);
+      wimpt_noerr(wimp_get_rectangle(&r,&more));
+    }
+  }
+
+  /* --- Now work out what we actually have to do --- */
+
+  switch (window__dragType)
+  {
+    case window__SELECT:
+      box.x0=(window__startX < x) ? window__startX : x;
+      box.x1=(window__startX > x) ? window__startX : x;
+      box.y0=(window__startY < y) ? window__startY : y;
+      box.y1=(window__startY > y) ? window__startY : y;
+      for (i=0;i<w->def->desc.w.nicons;i++)
+      {
+        window_boundingBox(w,i,&ibx);
+        if (coords_boxesoverlap(&box,&ibx))
+          window__select(w,i,TRUE);
+      }
+      window__updateMenu(w);
+      break;
+    case window__HORGUIDE:
+      for (i=0;i<glass_GUIDELIMIT;i++)
+      {
+        if (w->guide[i].active &&
+            w->guide[i].selected &&
+            w->guide[i].horiz)
+        {
+          window__redrawGuide(w,i);
+          w->guide[i].coord+=y-window__startY;
+          window__redrawGuide(w,i);
+        }
+      }
+      break;
+    case window__VERGUIDE:
+      for (i=0;i<glass_GUIDELIMIT;i++)
+      {
+        if (w->guide[i].active &&
+            w->guide[i].selected &&
+            !w->guide[i].horiz)
+        {
+          window__redrawGuide(w,i);
+          w->guide[i].coord+=x-window__startX;
+          window__redrawGuide(w,i);
+        }
+      }
+      break;
+    case window__GRABICON:
+      box=window__qGrabbedIcon()->box;
+      box.y1+=y-window__startY;
+      box.y0+=y-window__startY;
+      box.x0+=x-window__startX;
+      box.x1+=x-window__startX;
+      window__doGrabIcon(&box,window__dragWindow);
+      break;
+    default:
+      for (i=0;i<w->def->desc.w.nicons;i++)
+      {
+        if (w->def->i[i].selected)
+        {
+          window_redrawIcon(w,i);
+          if (window__dragType & window__TOP)
+            w->def->i[i].i.box.y1+=y-window__startY;
+          if (window__dragType & window__BOTTOM)
+            w->def->i[i].i.box.y0+=y-window__startY;
+          if (window__dragType & window__LEFT)
+            w->def->i[i].i.box.x0+=x-window__startX;
+          if (window__dragType & window__RIGHT)
+            w->def->i[i].i.box.x1+=x-window__startX;
+          if (window__dragType & window__TOP)
+          {
+            if (w->def->i[i].i.box.y1<w->def->i[i].i.box.y0)
+              w->def->i[i].i.box.y1=w->def->i[i].i.box.y0;
+          }
+          if (window__dragType & window__BOTTOM)
+          {
+            if (w->def->i[i].i.box.y0>w->def->i[i].i.box.y1)
+              w->def->i[i].i.box.y0=w->def->i[i].i.box.y1;
+          }
+          if (window__dragType & window__LEFT)
+          {
+            if (w->def->i[i].i.box.x0>w->def->i[i].i.box.x1)
+              w->def->i[i].i.box.x0=w->def->i[i].i.box.x1;
+          }
+          if (window__dragType & window__RIGHT)
+          {
+            if (w->def->i[i].i.box.x1<w->def->i[i].i.box.x0)
+              w->def->i[i].i.box.x1=w->def->i[i].i.box.x0;
+          }
+          window_redrawIcon(w,i);
+          tfile_markAsAltered(w->t);
+          editIcon_iconMoved(w,i);
+        }
+      }
+      break;
+  }
+  window__dragType=-1;
+  window__setPtrShape(-2);
+}
+
+/*
+ * void window__dragIdles(void *handle)
+ *
+ * Use
+ *  Redraws the window during a drag operation
+ *
+ * Parameters
+ *  void *handle == pointer to the window owning the drag
+ */
+
+static void window__dragIdles(void *handle)
+{
+  glass_windPointer *w=window__dragWindow;
+  int x,y;
+  wimp_redrawstr r;
+  BOOL more;
+  wimp_wstate s;
+  BOOL moved;
+  wimp_mousestr m;
+  unused(handle);
+  wimpt_noerr(wimp_get_point_info(&m));
+  if (!m.bbits)
+  {
+    window__finishDrag();
+    return;
+  }
+  if (!w)
+    return;
+  wimpt_noerr(wimp_get_wind_state(w->h,&s));
+  r.w=w->h;
+  r.box.x0=s.o.x;
+  r.box.x1=r.box.x0+s.o.box.x1-s.o.box.x0;
+  r.box.y1=s.o.y;
+  r.box.y0=r.box.y1+s.o.box.y0-s.o.box.y1;
+  if (bbc_inkey(-113))
+  {
+    if (!window__dragDraw)
+    {
+      wimpt_noerr(wimp_update_wind(&r,&more));
+      while (more)
+      {
+        window__rotate(0);
+        window__redrawDragBox(w,&r,window__dragX,window__dragY);
+        wimpt_noerr(wimp_get_rectangle(&r,&more));
+      }
+    }
+    win_removeIdleClaimer(window__dragIdles,0);
+    window__dragType=-1;
+    return;
+  }
+  window__getDragCoords(w,&x,&y);
+  moved=(x!=window__dragX || y!=window__dragY);
+  wimpt_noerr(wimp_update_wind(&r,&more));
+  if (!moved && !window__dragDraw)
+    window__setDash();
+  else
+    window__rotate(+2);
+  while (more)
+  {
+    window__setXORColour(w,window__DRAGCOL);
+    if (!window__dragDraw && moved)
+    {
+      window__rotate(-2);
+      window__redrawDragBox(w,&r,window__dragX,window__dragY);
+      window__rotate(+2);
+      window__redrawDragBox(w,&r,x,y);
+    }
+    else
+      window__redrawDragBox(w,&r,x,y);
+    wimpt_noerr(wimp_get_rectangle(&r,&more));
+  }
+  window__dragDraw=FALSE;
+  window__dragX=x;
+  window__dragY=y;
+}
+
+/*
+ * void window__startDrag(int type,
+ *                        wimp_box *box,
+ *                        glass_windPointer *w,
+ *                        int x,int y)
+ *
+ * Use
+ *  Starts a drag operation in the specified window
+ *
+ * Parameters
+ *  int type == what sort of drag this is
+ *  wimp_box *box == the bounding box of the object we're dragging
+ *  glass_windPointer *w == the window in which the drag is taking place
+ *  int x,int y == the mouse position the drag will start from
+ */
+
+void window__startDrag(int type,
+                       wimp_box *box,
+                       glass_windPointer *w,
+                       int x,int y)
+{
+  window__dragType=type;
+  window__dragBox=*box;
+  window__dragWindow=w;
+  window__dragX=window__startX=x;
+  window__dragY=window__startY=y;
+  window__dragDraw=TRUE;
+  win_addIdleClaimer(window__dragIdles,window__DRAGTIME,0);
+}
+
+/*
+ * glass_windPointer *window__dragWind(void)
+ *
+ * Use
+ *  Returns the current dragging window
+ */
+
+glass_windPointer *window__dragWind(void)
+{
+  return (window__dragWindow);
+}
+
+/*
+ * void window__setDragWind(glass_windPointer *w)
+ *
+ * Use
+ *  Claims the current drag operation for the given window
+ */
+
+void window__setDragWind(glass_windPointer *w)
+{
+  window__dragWindow=w;
+}
+
+/*
+ * int window__qDragType(void)
+ *
+ * Use
+ *  Returns the current drag type
+ */
+
+int window__qDragType(void)
+{
+  return (window__dragType);
+}
+
+/*
+ * wimp_box window__qDragBox(void)
+ *
+ * Use
+ *  Returns the bounding box of the things being dragged
+ */
+
+wimp_box window__qDragBox(void)
+{
+  return (window__dragBox);
+}
+
+/*
+ * void window__dragCoords(int *x,int *y)
+ *
+ * Use
+ *  Returns the current drag position
+ */
+
+void window__dragCoords(int *x,int *y)
+{
+  *x=window__dragX;
+  *y=window__dragY;
+}
+
+/*
+ * void window__dragStart(int *x,int *y)
+ *
+ * Use
+ *  Returns the initial drag position
+ */
+
+void window__dragStart(int *x,int *y)
+{
+  *x=window__startX;
+  *y=window__startY;
+}
diff --git a/StraySrc/Glass/!Glass/c/wGrab b/StraySrc/Glass/!Glass/c/wGrab
new file mode 100644 (file)
index 0000000..22b19be
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * wGrab.c
+ *
+ * Handling of grab operations (generally, and grab icons)
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/pointer.h"
+#include "steel/bbc.h"
+#include "steel/buffer.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "tfile.h"
+#include "window.h"
+#include "_window.h"
+#include "iconData.h"
+
+/*----- Private variables -------------------------------------------------*/
+
+static BOOL window__grabbing;
+static void (*window__grabproc)(wimp_mousestr *m,void *handle);
+static wimp_mousestr *window__grabhandle;
+static wimp_icon window__grabbedIcon; /* The icon definition we're grabbing*/
+static wimp_t window__grabTask;  /* Source task for grab operation         */
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * void window__grabIdles(void *handle)
+ *
+ * Use
+ *  Handles the waiting bit in grab mode
+ *
+ * Parameters
+ *  void *handle == an unused pointer
+ */
+
+static void window__grabIdles(void *handle)
+{
+  wimp_mousestr m;
+  static sprite_id id={"ptr_grab",0};
+  static BOOL released;
+  unused(handle);
+
+  wimpt_noerr(pointer_set_shape(resspr_area(),&id,0,0));
+  wimpt_noerr(wimp_get_point_info(&m));
+  if (!m.bbits)
+    released=TRUE;
+  if ((m.bbits==4 || m.bbits==1) && released)
+  {
+    released=FALSE;
+    win_removeIdleClaimer(window__grabIdles,0);
+    pointer_reset_shape();
+    window__grabbing=FALSE;
+    window__grabproc(&m,window__grabhandle);
+  }
+  else if (bbc_inkey(-113))
+  {
+    win_removeIdleClaimer(window__grabIdles,0);
+    window__grabbing=FALSE;
+    pointer_reset_shape();
+    released=FALSE;
+  }
+}
+
+/*
+ * char *window__grabData(char *ptr,void *handle)
+ *
+ * Use
+ *  Grabs data from the destination task, as required when setting up a
+ *  grabbed icon.
+ *
+ * Parameters
+ *  char *ptr == pointer to data string (in other task's workspace)
+ *  void *handle == a pointer (ignored)
+ *
+ * Returns
+ *  A pointer to a string in my own workspace (static char array)
+ */
+
+static char *window__grabData(char *ptr,void *handle)
+{
+  char *buff=buffer_find();
+  os_error *e;
+  unused(handle);
+  if (window__grabTask)
+  {
+    if (e=wimp_transferblock(window__grabTask,ptr,wimpt_task(),buff,256),e)
+      return (e->errmess);
+  }
+  else
+    return ("<indirected>");
+  return (buff);
+}
+
+/*
+ * void window__doGrabIcon(wimp_box *b,glass_windPointer *w)
+ *
+ * Use
+ *  Actually does a window grab job after all the pallaver.
+ *
+ * Parameters
+ *  wimp_box *b == the box in which the icon is contained
+ *  glass_windPointer *w == the window into which the icon is to be created
+ *
+ * Returns
+ *  TRUE if the evtn has been successfully handled.
+ */
+
+void window__doGrabIcon(wimp_box *b,glass_windPointer *w)
+{
+  wimp_wstate s;
+  int i;
+  i=window__createIcon(w);
+  if (i==-1)
+    return;
+  w->def->i[i].i=window__grabbedIcon;
+  if (!iconData_handleFont(w,&w->def->i[i].i.flags))
+    werr(FALSE,msgs_lookup("wdFERGI"));
+  iconData_processIcon(w,i,window__grabData,TRUE,0);
+  wimpt_noerr(wimp_get_wind_state(w->h,&s));
+  w->def->i[i].i.box=*b;
+  window_redrawIcon(w,i);
+  tfile_markAsAltered(w->t);
+  window__updateMenu(w);
+}
+
+/*
+ * void window__grabIcon(wimp_mousestr *m,void *handle)
+ *
+ * Use
+ *  Grabs an icon from another application.
+ *
+ * Parameters
+ *  wimp_mousestr *m == pointer to info about which icon to get
+ *  void *handle == pointer to destination window
+ */
+
+void window__grabIcon(wimp_mousestr *m,void *handle)
+{
+  wimp_wstate s;
+  wimp_icon i;
+  int ox;
+  int oy;
+  os_regset r;
+  wimp_msgstr msg;
+  wimp_box bound;
+  unused(handle);
+
+  if (m->i<0)
+  {
+    note(msgs_lookup("wdNITG"));
+    return;
+  }
+  if (wimp_get_wind_state(m->w,&s))
+  {
+    note(msgs_lookup("wdCGI"));
+    return;
+  }
+  wimpt_noerr(wimp_get_icon_info(m->w,m->i,&i));
+  msg.hdr.size=20;
+  msg.hdr.your_ref=0;
+  msg.hdr.action=0;
+  r.r[0]=19;
+  r.r[1]=(int)&msg;
+  r.r[2]=m->w;
+  r.r[3]=m->i;
+  if (os_swix(XWimp_SendMessage,&r))
+    window__grabTask=0;
+  else
+    window__grabTask=r.r[2];
+  ox=s.o.box.x0-s.o.x;
+  oy=s.o.box.y1-s.o.y;
+  window__grabbedIcon=i;
+  if (i.flags & wimp_ITEXT &&
+      i.flags & wimp_INDIRECT &&
+      i.data.indirecttext.validstring!=(char *)-1)
+  {
+    i.data.indirecttext.validstring=
+             window__grabData(i.data.indirecttext.validstring,0);
+    window__bound(&i,&bound,FALSE);
+  }
+  else
+    bound=i.box;
+  window__startDrag(window__GRABICON,&bound,0,m->x-ox,m->y-oy);
+  window__setPtrShape(-2);
+}
+
+/*
+ * void window_grab(void (*proc)(wimp_mousestr *m,void *handle),void *handle)
+ *
+ * Use
+ *  Turns on 'grab mode' and calls the specified routine when a mouse button
+ *  is clicked.
+ *
+ * Parameters
+ *  void (*proc)(wimp_mousestr *m,void *handle) == the routine to call
+ *  void *handle == the handle to call the routine with
+ */
+
+void window_grab(void (*proc)(wimp_mousestr *m,void *handle),void *handle)
+{
+  if (window__grabbing)
+  {
+    note(msgs_lookup("wdAGRB"));
+    return;
+  }
+  window__grabproc=proc;
+  window__grabhandle=handle;
+  win_addIdleClaimer(window__grabIdles,2,0);
+  window__grabbing=TRUE;
+}
+
+/*
+ * wimp_icon *window__qGrabbedIcon(void)
+ *
+ * Use
+ *  Returns a pointer to the icon being grabbed
+ */
+
+wimp_icon *window__qGrabbedIcon(void)
+{
+  return (&window__grabbedIcon);
+}
+
+/*
+ * BOOL window_grabbing(void)
+ *
+ * Use
+ *  Returns whether grab mode is set or not
+ *
+ * Returns
+ *  TRUE if grab mode set
+ */
+
+BOOL window_grabbing(void)
+{
+  return (window__grabbing);
+}
diff --git a/StraySrc/Glass/!Glass/c/wGraph b/StraySrc/Glass/!Glass/c/wGraph
new file mode 100644 (file)
index 0000000..e95d9e5
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * wGraph.c
+ *
+ * Low-level graphics handling
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/bbc.h"
+#include "steel/colourtran.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "window.h"
+#include "_window.h"
+
+/*----- Private variables -------------------------------------------------*/
+
+static int window__dashPos;      /* Current rotating dash position         */
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * void window__colourChange(int col1,int col2)
+ *
+ * Use
+ *  Sets up the current foreground colour so that when plotted over colour
+ *  col1 it looks like col2 and vice-versa.  The effects of plotting over
+ *  other colours is defined to be psychedelically interesting, but not
+ *  pretty.
+ *
+ *  Basically, all it does is suss out what the colours really mean and XOR
+ *  them together.
+ *
+ * Parameters
+ *  int col1,int col2 == the Wimp colour numbers to swap between
+ */
+
+void window__colourChange(int col1,int col2)
+{
+  wimp_palettestr pal;
+  int x,y;
+  wimpt_noerr(wimp_readpalette(&pal));
+  wimpt_noerr(colourtran_return_colournumber(pal.c[col1],&x));
+  wimpt_noerr(colourtran_return_colournumber(pal.c[col2],&y));
+  if (os_swiv(XOS_SetColour,3,x^y))
+  {
+    if (wimpt_bpp()==8)
+    {
+      wimpt_noerr(colourtran_colournumbertoGCOL(x^y,&x));
+      bbc_vduq(18,3,x>>2);
+      bbc_vduq(23,17,2,(x & 3)<<6,0,0,0,0,0,0);
+    }
+    else
+      bbc_vduq(18,3,x^y);
+  }
+}
+
+/*
+ * void window__setXORColour(glass_windPointer *w,int col)
+ *
+ * Use
+ *  Sets up the current foreground colour so that it appears to be WIMP
+ *  colour col on the specified window background.  Lots of tedious
+ *  ColourTransing to do on this, with no real reward, but at least it will
+ *  look vaguely right in 256 colour modes.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window in which to set the colour
+ *  int col == the colour to set
+ */
+
+void window__setXORColour(glass_windPointer *w,int col)
+{
+  int old=w->def->desc.w.colours[3];
+
+  /* --- Make sure the background isn't transparent --- */
+
+  if (old==255)
+    old=1;
+
+  window__colourChange(old,col);
+}
+
+/*
+ * void window__makeDashPattern(int ptn)
+ *
+ * Use
+ *  Sets the OS dash pattern to the given pattern (only the lowest byte
+ *  is considered).
+ *
+ * Parameters
+ *  int ptn == the LSB of this word contains the dash pattern as a bit
+ *   pattern
+ */
+
+void window__makeDashPattern(int ptn)
+{
+  int byte1,byte2;
+  byte1=242;
+  byte2=8;
+  wimpt_noerr(os_byte(163,&byte1,&byte2)); /* Dot-dash length              */
+  bbc_vduq(23,6,ptn,ptn,ptn,ptn,ptn,ptn,ptn,ptn);
+}
+
+/*
+ * void window__setDash(void)
+ *
+ * Use
+ *  Sets the dashed pattern so that it looks as if a 'rotating' box is being
+ *  dragged, like the WIMP's, only better...  The box is set up so that a
+ *  SINGLE exclusive-or plot will move the dash round.
+ */
+
+#define SECTION(x,i) ((((x)<<(i)) & 0xff00) >> 8)
+
+void window__setDash(void)
+{
+  int dash=SECTION(0xFCFCFC,window__dashPos);
+  int newDash;
+  window__dashPos+=2;
+  if (window__dashPos>7)
+    window__dashPos=0;
+  newDash=SECTION(0xFCFCFC,window__dashPos);
+  dash^=newDash;
+  window__makeDashPattern(dash);
+  window__setXORColour(window__dragWind(),window__DRAGCOL);
+}
+
+/*
+ * void window__rotate(int by)
+ *
+ * Use
+ *  Rotates the current rotating-dash pattern by a given amount.  This is
+ *  used to rotate the dash box while the box is moving.
+ *
+ * Parameters
+ *  int by == the number of steps to rotate the dash pattern.
+ */
+
+void window__rotate(int by)
+{
+  window__dashPos+=by;
+  if (window__dashPos<0)
+    window__dashPos=6;
+  else if (window__dashPos>7)
+    window__dashPos=0;
+  window__makeDashPattern(SECTION(0xFCFCFC,window__dashPos));
+  window__setXORColour(window__dragWind(),window__DRAGCOL);
+}
+
+/*
+ * void window__rectangle(int x,int y,int w,int h)
+ *
+ * Use
+ *  Draws a rectangle, using the current dotted line pattern
+ *
+ * Parameters
+ *  int x == the left side of the rectangle
+ *  int y == the right side of the rectangle
+ *  int w == the width of the rectangle (may be <0)
+ *  int h == the height of the rectangle (may be <0)
+ */
+
+void window__rectangle(int x,int y,int w,int h)
+{
+  bbc_plot(bbc_DottedBoth+bbc_MoveCursorAbs,x,y);
+  bbc_plot(bbc_DottedBoth+bbc_DrawRelFore,0,h);
+  bbc_plot(bbc_DottedExInit+bbc_DrawRelFore,w,0);
+  bbc_plot(bbc_DottedExInit+bbc_DrawRelFore,0,-h);
+  bbc_plot(bbc_DottedExBoth+bbc_DrawRelFore,-w,0);
+}
diff --git a/StraySrc/Glass/!Glass/c/wIcons b/StraySrc/Glass/!Glass/c/wIcons
new file mode 100644 (file)
index 0000000..97a0f76
--- /dev/null
@@ -0,0 +1,672 @@
+/*
+ * wIcons.c
+ *
+ * Manipulation of icons within template windows
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/interface.h"
+#include "steel/sculptrix.h"
+#include "steel/flex.h"
+#include "steel/bbc.h"
+#include "steel/font.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "tfile.h"
+#include "window.h"
+#include "_window.h"
+#include "editIcon.h"
+#include "indir.h"
+#include "iconData.h"
+#include "tearEdit.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * void window__bound(wimp_icon *i,wimp_box *box,BOOL force)
+ *
+ * Use
+ *  Works out the bounding box (including 3D border) of the given pseudoicon.
+ *
+ * Parameters
+ *  wimp_icon *i == pointer to an icon definition
+ *  wimp_box *box == where to put the result
+ *  BOOL force == force reading of the border, even if disabled in prefs
+ */
+
+void window__bound(wimp_icon *i,wimp_box *box,BOOL force)
+{
+  os_regset r;
+  wimp_icon j;
+
+  /* --- Get the answer from Sculptrix --- */
+
+  j=*i;
+  if (gPrefs_current()->sDispBorders &&
+      (force || gPrefs_current()->sIncBorder) &&
+      sculptrix_boundingBox(&j))
+  {
+    *box=j.box;
+    return;
+  }
+
+  /* --- Ask Interface if there's a bounding box at all --- */
+
+  if (gPrefs_current()->iDispBorders &&
+      (force || gPrefs_current()->iIncBorder))
+  {
+    r.r[1]=(int)&j;
+    wimpt_noerr(os_swix(XInterface_BoundingBox,&r));
+    *box=j.box;
+  }
+  else
+    *box=i->box;
+
+  /* --- Now ask WimpExtension --- */
+
+  if (gPrefs_current()->wDispBorders &&
+      (force || gPrefs_current()->wIncBorder))
+  {
+    r.r[0]=2;
+    r.r[1]=(int)i;
+    wimpt_noerr(os_swix(XWimpExt_BorderOp,&r));
+    box->x0=min2(box->x0,r.r[2]);
+    box->y0=min2(box->y0,r.r[3]);
+    box->x1=max2(box->x1,r.r[4]);
+    box->y1=max2(box->y1,r.r[5]);
+  }
+}
+
+/*
+ * void window__removeTrailingDeleted(glass_windPointer *w)
+ *
+ * Use
+ *  Removes trailing deleted icons from a window (i.e. ones that can be
+ *  safely deleted properly without messing up icon numbers).
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to blitz
+ */
+
+void window__removeTrailingDeleted(glass_windPointer *w)
+{
+  int i=w->def->desc.w.nicons-1;
+  int dead=0;
+  while (w->def->i[i].i.flags & wimp_IDELETED)
+  {
+    i--;                         /* Now points to top undeleted icon       */
+    dead++;
+  }
+  flex_extend((flex_ptr)&w->def,
+              sizeof(glass_window)+
+              i*sizeof(glass_iconDescription));
+  w->size-=dead*sizeof(glass_iconDescription);
+  w->def->desc.w.nicons-=dead;
+}
+
+/*
+ * int window__createIcon(glass_windPointer *w)
+ *
+ * Use
+ *  Creates a slot for an icon in the window specified, according to current
+ *  preferences.  The contents of the icon array are unspecified (and
+ *  probably not too useful).
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to create the icon in
+ *
+ * Returns
+ *  Icon number that can be used, or -1 if the operation failed.
+ */
+
+int window__createIcon(glass_windPointer *w)
+{
+  int i;
+
+  /* --- Find a space to create the icon --- *
+   *
+   * If we're using up deleted spaces, then loop through to find the lowest
+   * free one.
+   */
+
+  if (!gPrefs_current()->mCreateTop)
+  {
+    for (i=0;i<w->def->desc.w.nicons;i++)
+    {
+      if (w->def->i[i].i.flags & wimp_IDELETED)
+      {
+        w->def->i[i].selected=FALSE;
+        w->def->i[i].edit=0;
+        return (i);
+      }
+    }
+  }
+  else
+    i=w->def->desc.w.nicons;
+
+  /* --- We need to add a new icon on the end --- */
+
+  if (!flex_extend((flex_ptr)&w->def,
+                   sizeof(glass_window)+
+                   i*sizeof(glass_iconDescription)))
+  {
+    werr(FALSE,msgs_lookup("wdNEMCI"));
+    return (-1);
+  }
+  w->def->desc.w.nicons++;
+  w->size+=sizeof(glass_iconDescription);
+  w->def->i[i].selected=FALSE;
+  w->def->i[i].copied=FALSE;
+  w->def->i[i].edit=0;
+  return (i);
+}
+
+/*
+ * void window__renumber(glass_windPointer *w,BOOL renum)
+ *
+ * Use
+ *  Sets the renumber flag of the given window to the given state.
+ *  Everything is set up properly according to the new state.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to renumber
+ *  BOOL renum == the new state of the flag
+ */
+
+void window__renumber(glass_windPointer *w,BOOL renum)
+{
+  int i;
+
+  /* --- Make sure we've got something to do --- */
+
+  if (renum==w->renumber)
+    return;
+
+  /* --- Unselect all the guidelines --- */
+
+  for (i=0;i<glass_GUIDELIMIT;i++)
+  {
+    if (w->guide[i].selected)
+    {
+      w->guide[i].selected=FALSE;
+      window__redrawGuide(w,i);
+    }
+  }
+
+  /* --- Now change the selection boxes for all the icons --- *
+   *
+   * For each one, we undraw the old box, change the renumber state, and
+   * draw the new one.  Klugey, but it works.
+   */
+
+  for (i=0;i<w->def->desc.w.nicons;i++)
+  {
+    if (w->def->i[i].selected)
+    {
+      window__select(w,i,FALSE);
+      w->renumber=!w->renumber;
+      window__select(w,i,TRUE);
+      w->renumber=!w->renumber;
+    }
+  }
+
+  /* --- Update the window state information, and the info bar --- */
+
+  w->renumber=!w->renumber;
+  window__toggleRenumber(w);
+}
+
+/*
+ * void window__copyIcons(glass_windPointer *w)
+ *
+ * Use
+ *  Copies the selected icons into the given window.  If the icons are
+ *  already in the given window, they are duplicated and offset by a small
+ *  quantity.  If the icons are in a different window, then they are
+ *  centred over the current visible area.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to put the icons
+ */
+
+void window__copyIcons(glass_windPointer *w)
+{
+  int xoff;
+  int yoff;
+  wimp_box bound;
+  BOOL started;
+  int i;
+  wimp_wstate s;
+  int ni;
+  BOOL fonterr=FALSE;
+  glass_windPointer *wso=window_selectionOwner();
+
+  /* --- Work out where to put the selected icons --- *
+   *
+   * If we're copying to the same window, we just displace them a bit.  If
+   * we're copying between windows, we need to centre them in the new
+   * window.
+   */
+
+  if (w==wso)
+  {
+    xoff=w->gridx;
+    yoff=-w->gridy;
+  }
+  else
+  {
+    started=FALSE;
+
+    /* --- Calculate the bounding box of the selection --- */
+
+    for (i=0;i<wso->def->desc.w.nicons;i++)
+    {
+      if (wso->def->i[i].selected)
+      {
+        if (started)
+        {
+          if (wso->def->i[i].i.box.x0<bound.x0)
+            bound.x0=wso->def->i[i].i.box.x0;
+          if (wso->def->i[i].i.box.x1>bound.x1)
+            bound.x1=wso->def->i[i].i.box.x1;
+          if (wso->def->i[i].i.box.y0<bound.y0)
+            bound.y0=wso->def->i[i].i.box.y0;
+          if (wso->def->i[i].i.box.y1>bound.y1)
+            bound.y1=wso->def->i[i].i.box.y1;
+        }
+        else
+        {
+          bound=wso->def->i[i].i.box;
+          started=TRUE;
+        }
+      }
+    }
+
+    /* --- Work out how to centre the icons --- */
+
+    wimpt_noerr(wimp_get_wind_state(w->h,&s));
+    xoff=(s.o.x+(s.o.box.x1-s.o.box.x0)/2-(bound.x1-bound.x0)/2);
+    yoff=(s.o.y-(s.o.box.y1-s.o.box.y0)/2-(bound.y1-bound.y0)/2);
+    xoff-=bound.x0;
+    yoff-=bound.y0;
+
+    /* --- If there's a grid lock, keep the same grid alignment --- */
+
+    if (w->gridLock)
+      window__align(w,&xoff,&yoff);
+
+    /* --- Also retain the pixel alignment --- */
+
+    xoff&=~(wimpt_dx()-1);
+    yoff&=~(wimpt_dy()-1);
+  }
+
+  /* --- We've altered the template file --- */
+
+  tfile_markAsAltered(w->t);
+
+  /* --- Now actually do the copy --- */
+
+  for (i=0;i<wso->def->desc.w.nicons;i++)
+  {
+    if (wso->def->i[i].selected)
+    {
+
+      /* --- Find out there to put the copy --- */
+
+      ni=window__createIcon(w);
+      if (ni==-1)
+        return;
+
+      /* --- Reposition the copied icon nicely --- */
+
+      w->def->i[ni].i=wso->def->i[i].i;
+      w->def->i[ni].i.box.x0+=xoff;
+      w->def->i[ni].i.box.x1+=xoff;
+      w->def->i[ni].i.box.y0+=yoff;
+      w->def->i[ni].i.box.y1+=yoff;
+
+      /* --- Set up the copied icon's font information --- */
+
+      if (!iconData_handleFont(w,&w->def->i[ni].i.flags) && !fonterr)
+      {
+        werr(FALSE,msgs_lookup("wdFERCPY"));
+        fonterr=TRUE;
+      }
+
+      /* --- Set up the copied icon's indirected data nicely --- */
+
+      if (!iconData_processIcon(w,ni,0,TRUE,0))
+      {
+        werr(FALSE,msgs_lookup("wdNEMCP"));
+        w->def->i[ni].i.flags&=~wimp_INDIRECT;
+        window_deleteIcon(w,ni);
+        return;
+      }
+      window_redrawIcon(w,ni);
+      w->def->i[ni].copied=TRUE;
+    }
+  }
+
+  /* --- Now move the selection across, and select the copies --- */
+
+  for (i=0;i<wso->def->desc.w.nicons;i++)
+    window__select(wso,i,FALSE);
+  for (i=0;i<w->def->desc.w.nicons;i++)
+  {
+    if (w->def->i[i].copied)
+      window__select(w,i,TRUE);
+    w->def->i[i].copied=FALSE;
+  }
+  window__gainSelection(w);
+}
+
+/*
+ * void window__nudgeIcons(glass_windPointer *w,wimp_box *nudge)
+ *
+ * Use
+ *  Nudges the selected icons in the specified window, by adding the box
+ *  given to each icon's bounding box.  The nudge box is multiplied either by
+ *  the current grid size (if grid lock is enabled) or by the pixel size (if
+ *  it isn't) before addition.  A nudge is considered to be a single
+ *  alteration for the purposes of autosave-counting.  If no icons are moved
+ *  then the selected guidelines are moved instead.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icons to nudge
+ *  wimp_box *nudge == the box to add to the coordinates of the icons
+ */
+
+void window__nudgeIcons(glass_windPointer *w,wimp_box *nudge)
+{
+  int i;
+  wimp_box b;
+  wimp_box *bp;
+  BOOL doneOne=FALSE;
+
+  /* --- Make sure we're not dragging something --- */
+
+  if (window__qDragType()!=-1)
+    return;
+
+  /* --- Multiply up the nudge rectangle --- */
+
+  if (w->gridLock)
+  {
+    nudge->x0*=w->gridx;
+    nudge->y0*=w->gridy;
+    nudge->x1*=w->gridx;
+    nudge->y1*=w->gridy;
+  }
+  else
+  {
+    nudge->x0*=wimpt_dx();
+    nudge->y0*=wimpt_dy();
+    nudge->x1*=wimpt_dx();
+    nudge->y1*=wimpt_dy();
+  }
+
+  /* --- Nudge the selected icons --- *
+   *
+   * Remember to make sure that we don't turn the icon inside-out.
+   */
+
+  for (i=0;i<w->def->desc.w.nicons;i++)
+  {
+    if (w->def->i[i].selected)
+    {
+      doneOne=TRUE;
+      window_boundingBox(w,i,&b);
+      bp=&w->def->i[i].i.box;
+      if (bp->x0+nudge->x0<=bp->x1+nudge->x1)
+        b.x0+=nudge->x0;
+      if (bp->x1+nudge->x1>=bp->x0+nudge->x0)
+        b.x1+=nudge->x1;
+      if (bp->y0+nudge->y0<=bp->y1+nudge->y1)
+        b.y0+=nudge->y0;
+      if (bp->y1+nudge->y1>=bp->y0+nudge->y0)
+        b.y1+=nudge->y1;
+      window_setBox(w,i,&b);
+    }
+  }
+
+  /* --- If no icons moved, nudge the guidelines --- *
+   *
+   * Only move guidelines if the box is sensible -- i.e. we're not just
+   * moving an edge, we're moving the whole box either horizontally or
+   * vertically
+   */
+
+  if (!doneOne && nudge->x0==nudge->x1 && nudge->y0==nudge->y1)
+  {
+    for (i=0;i<glass_GUIDELIMIT;i++)
+    {
+      if (w->guide[i].selected)
+      {
+        doneOne=TRUE;
+        window__redrawGuide(w,i);
+        if (w->guide[i].horiz)
+          w->guide[i].coord+=nudge->y0;
+        else
+          w->guide[i].coord+=nudge->x0;
+        window__redrawGuide(w,i);
+      }
+    }
+  }
+
+  /* --- If we did something, bump the alteration count --- */
+
+  if (!doneOne)
+    bbc_vdu(7);
+  else
+    tfile_markAsAltered(w->t);
+}
+
+/*
+ * void window_boundingBox(glass_windPointer *w,int icon,wimp_box *box)
+ *
+ * Use
+ *  Gets the bounding box of the icon given and returns it in the block
+ *  pointed to by box
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon to 'boxise'
+ *  wimp_box *box == where to put the result
+ */
+
+void window_boundingBox(glass_windPointer *w,int icon,wimp_box *box)
+{
+  window__bound(&w->def->i[icon].i,box,FALSE);
+}
+
+/*
+ * void window_setBox(glass_windPointer *w,int icon,wimp_box *box)
+ *
+ * Use
+ *  Sets the icon bounding box to the box given, taking into account
+ *  Interface borders and so on.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number
+ *  wimp_box *box == the new box for the icon
+ */
+
+void window_setBox(glass_windPointer *w,int icon,wimp_box *box)
+{
+  wimp_box bound;
+  window_boundingBox(w,icon,&bound);
+  window_redrawIcon(w,icon);
+  w->def->i[icon].i.box.x0+=box->x0-bound.x0;
+  w->def->i[icon].i.box.x1+=box->x1-bound.x1;
+  w->def->i[icon].i.box.y0+=box->y0-bound.y0;
+  w->def->i[icon].i.box.y1+=box->y1-bound.y1;
+  window_redrawIcon(w,icon);
+  editIcon_iconMoved(w,icon);
+}
+
+/*
+ * void window_deleteIcon(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Deletes the icon specified, good an' proper.
+ *
+ * Parameters
+ *  glass_windPointer *w == the scene of the crime
+ *  int icon == the victim...
+ */
+
+void window_deleteIcon(glass_windPointer *w,int icon)
+{
+  int fhand;
+  editIcon_close(w,icon);
+
+  if (w->def->i[icon].selected)
+    w->selno--;
+  if (w==window_selectionOwner() && icon==window__selectedIcon())
+    window__setSelectedIcon(-1);
+
+  window_redrawIcon(w,icon);
+  if (w->def->i[icon].i.flags & wimp_IFONT)
+  {
+    fhand=(w->def->i[icon].i.flags>>24) & 0xff;
+    wimpt_noerr(font_lose(fhand));
+    w->fonts[fhand]--;
+  }
+  if (w->def->i[icon].i.flags & wimp_INDIRECT)
+  {
+    w->size-=w->def->i[icon].i.data.indirecttext.bufflen;
+    indir_free(w->def->i[icon].i.data.indirecttext.buffer);
+    if (w->def->i[icon].i.flags & wimp_ITEXT &&
+        w->def->i[icon].i.data.indirecttext.validstring!=(char *)-1)
+    {
+      utils_ctermToNterm(w->def->i[icon].i.data.indirecttext.validstring);
+      w->size-=strlen(w->def->i[icon].i.data.indirecttext.validstring)+1;
+      indir_free(w->def->i[icon].i.data.indirecttext.validstring);
+    }
+  }
+
+  w->def->i[icon].i.flags=wimp_IDELETED; /* This is a late icon            */
+  w->def->i[icon].selected=FALSE;
+
+  if (gPrefs_current()->mDeleteRenum)
+    window_renumber(w,icon,w->def->desc.w.nicons-1);
+  tfile_markAsAltered(w->t);
+  window__removeTrailingDeleted(w);
+}
+
+/*
+ * void window_renumber(glass_windPointer *w,int icon,int new)
+ *
+ * Use
+ *  Renumbers an icon, by removing it from the array, shuffling others out
+ *  the way, and the putting it in its new position (i.e. it's an insert
+ *  renumber, not a swap renumber like the old version - which wasn't
+ *  terribly useful...)
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon to renumber
+ *  int new == the new number to give it
+ *
+ * Returns
+ *  TRUE if successful
+ */
+
+BOOL window_renumber(glass_windPointer *w,int icon,int new)
+{
+  glass_iconDescription idef=w->def->i[icon];
+  int i;
+  int si=window__selectedIcon();
+
+  if (new<0 || new>=w->def->desc.w.nicons)
+  {
+    note(msgs_lookup("wdIIRN"));
+    return (FALSE);
+  }
+  if (new==icon)
+    return (TRUE);
+  editIcon_renumber(w,icon,new);
+
+  if (new<icon)
+  {
+    if (w==window_selectionOwner() && si!=-1)
+    {
+      if (si==icon)
+        window__renumberSelectedIcon(new);
+      else if (si>=new && si<icon)
+        window__renumberSelectedIcon(si+1);
+    }
+    for (i=icon;i>new;i--)
+    {
+      editIcon_renumber(w,i-1,i);
+      w->def->i[i]=w->def->i[i-1];
+    }
+  }
+  else
+  {
+    if (w==window_selectionOwner() && si!=-1)
+    {
+      if (si==icon)
+        window__renumberSelectedIcon(new);
+      else if (si<=new && si>icon)
+        window__renumberSelectedIcon(si-1);
+    }
+    for (i=icon;i<new;i++)
+    {
+      editIcon_renumber(w,i+1,i);
+      w->def->i[i]=w->def->i[i+1];
+    }
+  }
+  w->def->i[new]=idef;
+  window_redrawIcon(w,new);
+  return (TRUE);
+}
diff --git a/StraySrc/Glass/!Glass/c/wMenus b/StraySrc/Glass/!Glass/c/wMenus
new file mode 100644 (file)
index 0000000..1b8ce2c
--- /dev/null
@@ -0,0 +1,1250 @@
+/*
+ * wMenus.c
+ *
+ * Handling the Template Window Menu
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/buttons.h"
+#include "steel/choices.h"
+#include "steel/bbc.h"
+#include "steel/buffer.h"
+#include "steel/tearoff.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "tfile.h"
+#include "window.h"
+#include "_window.h"
+#include "editIcon.h"
+#include "editWin.h"
+#include "align.h"
+#include "iconData.h"
+#include "tearEdit.h"
+
+/*----- Private data ------------------------------------------------------*/
+
+static int window__menuX;        /* x-position of pointer on menu click    */
+static int window__menuY;        /* y-position of pointer on menu click    */
+static int window__newIcons;     /* Number of new icon types defined       */
+
+static glass_windPointer* window__menuWin; /* Which window owns the menu   */
+
+static tearoff window__mRoot;    /* Root of menu structure                 */
+static tearoff window__mMisc;    /* Misc submenu                           */
+static tearoff window__mSelect;  /* Select submenu                         */
+static tearoff window__mButton;  /* Button type submenu                    */
+static tearoff window__mIcon;    /* Icon submenu                           */
+static tearoff window__mCreate;  /* Icon types submenu                     */
+static tearoff window__mGuide;   /* Guides submenu                         */
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * glass_windPointer *window__menuOwner(void)
+ *
+ * Use
+ *  Returns which window currently owns the menu.
+ *
+ * Returns
+ *  A pointer to the window's anchor block.
+ */
+
+glass_windPointer *window__menuOwner(void)
+{
+  return (window__menuWin);
+}
+
+/*
+ * void window__doTable(unsigned short *p,int s,unsigned int f,tearoff t)
+ *
+ * Use
+ *  Updates a tearoff menu using the given table.
+ *
+ * Parameters
+ *  unsigned short *p == pointer to shade flags table
+ *  int s == number of items in table
+ *  unsigned int f == which flags to use to mask with
+ *  tearoff t == which tearoff menu to play with
+ */
+
+static void window__doTable(const unsigned short *p,
+                            int s,unsigned int f,tearoff t)
+{
+  unsigned int *tbl=(unsigned int *)p;
+  int i;
+  unsigned int w;
+  for (i=0;i<s;i++)
+  {
+    w = (i&1 ? w>>16 : *tbl++);
+    tearoff_shadeItem(t,i+1,(w & f)!=0);
+  }
+}
+
+/*
+ * void window__updateMenu(glass_windPointer *w)
+ *
+ * Use
+ *  Updates the menu attached to the main window.
+ *
+ * Parameters
+ *  glass_windPointer *w == pointer to owning menu
+ */
+
+void window__updateMenu(glass_windPointer *w)
+{
+  int i;
+  unsigned int sflags;
+  int gflags;
+  glass_windPointer *wso=window_selectionOwner();
+
+  /* --- Redesign --- *
+   *
+   * Based on the Sapphire idea, we define a number of shade flags,
+   * and a big table which says which items need to be shaded when.
+   *
+   * The table is carefully organised so as not to give clues about how
+   * to implement test mode.  This isn't important.
+   */
+
+  #define s_all (1<<15)
+
+  #define s_guide (1<<0 | s_all)
+  #define s_gsel (1<<1 | s_all)
+  #define s_sel (1<<2 | s_all)
+  #define s_icon (1<<3 | s_all)
+  #define s_ren (1<<4 | s_all)
+  #define s_copy (1<<5 | s_all)
+  #define s_grid (1<<6 | s_all)
+
+#ifndef glass_DEMO
+  #define s_test (1<<7 | s_all)
+#else
+  #define s_test (s_all)
+#endif
+
+  #define s_qs (s_test | s_ren)
+  #define s_s (s_sel | s_qs)
+
+  /* --- Shading table --- *
+   *
+   * Each entry packed into a single byte.  This is quite good, for C ;-)
+   */
+
+  const static unsigned short root[]=
+                  { s_all, s_all, s_test, s_qs, s_qs, s_qs, s_qs };
+
+  const static unsigned short misc[]=
+                  { s_all, s_qs, s_ren, s_qs, s_qs, s_all };
+
+  const static unsigned short select[]=
+                  { s_icon|s_qs,  s_s, s_qs|s_copy, s_s,
+                    s_sel|s_test, s_s, s_s, s_s, s_s,
+                    s_s|s_grid,   s_s,
+                    s_s,          s_s};
+
+  const static unsigned short icon[]=
+                  { s_qs, s_qs, s_qs };
+
+  const static unsigned short guide[]=
+                  { s_qs|s_guide, s_qs|s_gsel, s_qs|s_gsel, s_qs, s_qs };
+
+  /* --- Build the mask word --- */
+
+  if (!w)
+    sflags=s_all;
+  else
+  {
+    sflags=0;
+
+    /* --- Work out guide status --- */
+
+    gflags=0;
+    for (i=0;i<glass_GUIDELIMIT;i++)
+    {
+      if (w->guide[i].active)
+        gflags|=1;
+      if (w->guide[i].selected)
+        gflags|=2;
+    }
+
+    /* --- Now set flags appropriately --- */
+
+    if (!(gflags & 1))           sflags|=s_guide & ~s_all;
+    if (!(gflags & 2))           sflags|=s_gsel  & ~s_all;
+    if (!w->selno)               sflags|=s_sel   & ~s_all;
+    if (!w->def->desc.w.nicons)  sflags|=s_icon  & ~s_all;
+    if (w->renumber)             sflags|=s_ren   & ~s_all;
+    if (!wso || !wso->selno)     sflags|=s_copy  & ~s_all;
+    if (!w->gridLock)            sflags|=s_grid  & ~s_all;
+
+  #ifndef glass_DEMO
+    if (w->testMode)             sflags|=s_test  & ~s_all;
+  #endif
+  }
+
+  /* --- Now shade all the items --- */
+
+  window__doTable(root,sizeof(root)/2,sflags,window__mRoot);
+  window__doTable(misc,sizeof(misc)/2,sflags,window__mMisc);
+  window__doTable(select,sizeof(select)/2,sflags,window__mSelect);
+  window__doTable(icon,sizeof(icon)/2,sflags,window__mIcon);
+  window__doTable(guide,sizeof(guide)/2,sflags,window__mGuide);
+
+  for (i=0;i<16;i++)
+    tearoff_shadeItem(window__mButton,i+1,(s_s & sflags)!=0);
+
+  for (i=0;i<window__newIcons;i++)
+    tearoff_shadeItem(window__mCreate,i+1,(s_qs & sflags)!=0);
+
+  /* --- Tick the items that need it --- */
+
+#ifndef glass_DEMO
+  tearoff_selectItem(window__mMisc,glass_TWMTEST,w && w->testMode);
+#endif
+  tearoff_selectItem(window__mSelect,glass_TWSORDER,w && w->renumber);
+
+  /* --- That's it, then --- *
+   *
+   * We need to remember which window all of this applies to so that the
+   * user doesn't get all confused.
+   */
+
+  window__menuWin=w;
+}
+
+/*
+ * void window__gridBox(glass_windPointer *w)
+ *
+ * Use
+ *  Displays and processes a grid dialogue box
+ */
+
+static void window__gridBox(glass_windPointer *w)
+{
+  dbox d;
+  dbox_field f;
+  buttons_simpleArrow sa={0,999,FALSE};
+  wimp_redrawstr r;
+  BOOL shade;
+  BOOL done=FALSE;
+  wimp_wstate s;
+
+  if (d=dbox_create("grid"),!d)
+    return;
+  dbox_selecticon(d,glass_GDISP,w->gridShow);
+  dbox_selecticon(d,glass_GLOCK,w->gridLock);
+  dbox_setfield(d,glass_GWWRITE,"%i",w->gridx);
+  dbox_setfield(d,glass_GHWRITE,"%i",w->gridy);
+  shade=!(w->gridShow || w->gridLock);
+  dbox_shadeicon(d,glass_GWUP,shade);
+  dbox_shadeicon(d,glass_GWDOWN,shade);
+  dbox_shadeicon(d,glass_GWWRITE,shade);
+  dbox_shadeicon(d,glass_GHUP,shade);
+  dbox_shadeicon(d,glass_GHDOWN,shade);
+  dbox_shadeicon(d,glass_GHWRITE,shade);
+  dbox_display(d,dbox_MENU_OVERPTR);
+  done=FALSE;
+  while (!done)
+  {
+    switch (f=dbox_fillin(d),f)
+    {
+      case dbox_CLOSE:
+        done=TRUE;
+        break;
+      case glass_GOK:
+        dbox_clickicon(d,glass_GOK);
+        w->gridShow=dbox_selecticon(d,glass_GDISP,dbox_READSTATE);
+        w->gridLock=dbox_selecticon(d,glass_GLOCK,dbox_READSTATE);
+        dbox_scanfield(d,glass_GWWRITE,"%d",&w->gridx);
+        dbox_scanfield(d,glass_GHWRITE,"%d",&w->gridy);
+        wimpt_noerr(wimp_get_wind_state(w->h,&s));
+        r.w=w->h;
+        r.box.x0=s.o.x;
+        r.box.x1=r.box.x0+s.o.box.x1-s.o.box.x0;
+        r.box.y1=s.o.y;
+        r.box.y0=r.box.y1+s.o.box.y0-s.o.box.y1;
+        wimpt_noerr(wimp_force_redraw(&r));
+        window__updateMenu(w);
+        if (!dbox_wasAdjustClick())
+          dbox_hide(d);
+        dbox_unclick();
+        if (!dbox_wasAdjustClick())
+          done=TRUE;
+        break;
+      case glass_GDISP:
+      case glass_GLOCK:
+        shade=!(dbox_selecticon(d,glass_GDISP,dbox_READSTATE) ||
+                dbox_selecticon(d,glass_GLOCK,dbox_READSTATE));
+        dbox_shadeicon(d,glass_GWUP,shade);
+        dbox_shadeicon(d,glass_GWDOWN,shade);
+        dbox_shadeicon(d,glass_GWWRITE,shade);
+        dbox_shadeicon(d,glass_GHUP,shade);
+        dbox_shadeicon(d,glass_GHDOWN,shade);
+        dbox_shadeicon(d,glass_GHWRITE,shade);
+        break;
+      case glass_GWUP:
+        buttons_arrow(d,f,d,glass_GWWRITE,0,+1,&sa);
+        break;
+      case glass_GWDOWN:
+        buttons_arrow(d,f,d,glass_GWWRITE,0,-1,&sa);
+        break;
+      case glass_GHUP:
+        buttons_arrow(d,f,d,glass_GHWRITE,0,+1,&sa);
+        break;
+      case glass_GHDOWN:
+        buttons_arrow(d,f,d,glass_GHWRITE,0,-1,&sa);
+        break;
+    }
+  }
+  dbox_delete(d);
+}
+
+/*
+ * void window__thHelp(char *prefix,int hit)
+ *
+ * Use
+ *  Does help for a tearoff menu.
+ *
+ * Parameters
+ *  char *prefix == pointer to prefix string
+ *  int hit == which item
+ */
+
+static void window__thHelp(char *prefix,int hit)
+{
+  char *p=buffer_find();
+  sprintf(p,"%s%i",prefix,hit);
+  help_startHelp();
+  help_addLine(msgs_lookup(p));
+  help_endHelp();
+}
+
+/*
+ * void window__mhRoot(tearoff_message m,int hit,void *handle)
+ *
+ * Use
+ *  Handles events on the root menu
+ *
+ * Parameters
+ *  tearoff_message m == what happened
+ *  int hit == what item it happened to
+ *  void *handle == nothing interesting
+ */
+
+static void window__mhRoot(tearoff_message m,int hit,void *handle)
+{
+  glass_windPointer *w=handle ? handle : window__menuWin;
+  unused(handle);
+
+  switch (m)
+  {
+    case tearoff_HELP:
+      window__thHelp("wmhRT",hit);
+      break;
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      switch (hit)
+      {
+        case glass_TWSAVE:
+          if (w)
+            tfile_saveWindow(w);
+          break;
+        case glass_TWEDIT:
+          tearEdit_open();
+          break;
+        case glass_TWGRID:
+          #ifndef glass_DEMO
+            if (w && !w->renumber && !w->testMode)
+              window__gridBox(w);
+          #else
+            if (w && !w->renumber)
+              window__gridBox(w);
+          #endif
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * void window__mhMisc(tearoff_message m,int hit,void *handle)
+ *
+ * Use
+ *  Handles events on the misc submenu
+ *
+ * Parameters
+ *  tearoff_message m == what happened
+ *  int hit == what item it happened to
+ *  void *handle == nothing interesting
+ */
+
+static void window__mhMisc(tearoff_message m,int hit,void *handle)
+{
+  glass_windPointer *w=handle ? handle : window__menuWin;
+  int i;
+  int stop;
+  BOOL checked;
+  BOOL done;
+  int xoff,yoff;
+  wimp_box b;
+
+#ifndef glass_DEMO
+  wimp_wstate s;
+  wimp_caretstr c;
+  wimp_icon icn;
+  wimp_w whand;
+  glass_windPointer *wso=window_selectionOwner();
+#endif
+
+  unused(handle);
+
+  switch (m)
+  {
+    case tearoff_HELP:
+      window__thHelp("wmhMSC",hit);
+      break;
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      switch (hit)
+      {
+        case glass_TWMINFO:
+          if (w)
+            tfile_windowInfo(w);
+          break;
+        case glass_TWMEDITWIN:
+          editWindow(w);
+          break;
+      #ifndef glass_DEMO
+        case glass_TWMTEST:
+          checked=!gPrefs_current()->cTest;
+          if (w->edit)
+          {
+            if (!checked)
+            {
+              if (!warning(msgs_lookup("wdTCEP"),msgs_lookup("wdTCE")))
+                return;
+              checked=TRUE;
+            }
+            editWindow_close(w);
+          }
+          for (i=0;i<w->def->desc.w.nicons;i++)
+          {
+            if (w->def->i[i].edit)
+            {
+              if (!checked)
+              {
+                if (!warning(msgs_lookup("wdTCEP"),msgs_lookup("wdTCE")))
+                  return;
+                checked=TRUE;
+              }
+              editIcon_close(w,i);
+            }
+          }
+          if (w->testMode)         /* Are we coming out of test mode?      */
+          {
+            for (i=0;i<w->def->desc.w.nicons;i++)
+            {
+              wimpt_noerr(wimp_get_icon_info(w->h,i,&icn));
+              if (memcmp(&icn,&w->def->i[i].i,sizeof(wimp_icon)))
+              {
+                tfile_markAsAltered(w->t);
+                w->def->i[i].i=icn;
+              }
+            }
+          }
+          w->testMode=!w->testMode;
+          if (whand=window__recreate(w),!whand)
+          {
+            w->testMode=!w->testMode;
+            return;
+          }
+          wimpt_noerr(wimp_get_wind_state(w->h,&s));
+          if (w->ownPointer)
+          {
+            win_removeIdleClaimer(window__winIdles,w);
+            window__setPtrShape(window__SELECT);
+          }
+          wimpt_noerr(wimp_close_wind(w->h)); /* Closed, guv'nor           */
+          win_register_event_handler(w->h,0,0); /* Won't need this now     */
+          wimpt_noerr(wimp_delete_wind(w->h)); /* Delete the window        */
+          w->h=whand;
+          win_register_event_handler(w->h,
+                   w->testMode ? window__testEvents : window__events,w);
+          s.o.w=w->h;
+          if (w==wso)
+            window__toggleTest(w);
+          wimpt_noerr(wimp_open_wind(&s.o));
+          if (w==wso)
+          {
+            window__setToolBarPositions(0);
+            if (w->testMode)
+            {
+              if (window__selectedIcon()!=-1)
+                tearEdit_update(0,-1);
+            }
+            else
+            {
+              c.w=w->h;
+              c.i=-1;
+              c.x=w->def->desc.w.ex.x0-50;
+              c.y=0;
+              c.height=0x02000000;
+              c.index=-1;
+              wimpt_noerr(wimp_set_caret_pos(&c));
+              tearEdit_update(w,window__selectedIcon());
+            }
+          }
+          window__updateMenu(w);
+
+          /* --- Our good mate the Window Manager --- *
+           *
+           * Because the RISC OS 3 Window Manager is about as braindead as
+           * it's possible to get without being written by Microsoft, it
+           * decides that it would be a simply super idea to move our window
+           * back on the screen at this point, screwing up the cached window
+           * position.
+           */
+
+          wimpt_noerr(wimp_get_wind_state(w->h,&s));
+          if (memcmp(&s.o.box,&w->def->desc.w,24))
+          {
+            w->def->desc.w.box=s.o.box;
+            w->def->desc.w.scx=s.o.x;
+            w->def->desc.w.scy=s.o.y;
+            if (!w->t->alts)
+              tfile_markAsAltered(w->t);
+          }
+
+          break;
+      #endif
+        case glass_TWMREMDEL:
+          stop=w->def->desc.w.nicons-1;
+          done=FALSE;
+          for (i=0;i<=stop;i++)
+          {
+            if (w->def->i[i].i.flags & wimp_IDELETED)
+            {
+              window_renumber(w,i--,stop--);
+              done=TRUE;
+            }
+          }
+          if (done)
+          {
+            window__removeTrailingDeleted(w);
+            tfile_markAsAltered(w->t);
+          }
+          break;
+        case glass_TWMBRINGBK:
+          for (i=0;i<w->def->desc.w.nicons;i++)
+          {
+            window_boundingBox(w,i,&b);
+            xoff=yoff=0;
+            if (b.x0<w->def->desc.w.ex.x0)
+              xoff=w->def->desc.w.ex.x0-b.x0;
+            if (b.x1>w->def->desc.w.ex.x1)
+              xoff=w->def->desc.w.ex.x1-b.x1;
+            if (b.y0<w->def->desc.w.ex.y0)
+              yoff=w->def->desc.w.ex.y0-b.y0;
+            if (b.y1>w->def->desc.w.ex.y1)
+              yoff=w->def->desc.w.ex.y1-b.y1;
+            if (xoff || yoff)
+            {
+              b.x0+=xoff;
+              b.x1+=xoff;
+              b.y0+=yoff;
+              b.y1+=yoff;
+              window_setBox(w,i,&b);
+              tfile_markAsAltered(w->t);
+            }
+          }
+          break;
+        case glass_TWMCLOSE:
+          event_clear_current_menu();
+          window_close(w);
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * void window__mhSelect(tearoff_message m,int hit,void *handle)
+ *
+ * Use
+ *  Handles events on the select submenu
+ *
+ * Parameters
+ *  tearoff_message m == what happened
+ *  int hit == what item it happened to
+ *  void *handle == nothing interesting
+ */
+
+static void window__mhSelect(tearoff_message m,int hit,void *handle)
+{
+  glass_windPointer *w=handle ? handle : window__menuWin;
+  int i;
+  BOOL stop;
+  BOOL checked;
+  wimp_box b;
+  int xoff,yoff;
+
+  unused(handle);
+
+  switch (m)
+  {
+    case tearoff_HELP:
+      window__thHelp("wmhSEL",hit);
+      break;
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      switch (hit)
+      {
+        case glass_TWSALL:
+          window__gainSelection(w);
+          for (i=0;i<w->def->desc.w.nicons;i++)
+            window__select(w,i,TRUE);
+          window__updateMenu(w);
+          break;
+        case glass_TWSCLR:
+          window__gainSelection(w);
+          for (i=0;i<w->def->desc.w.nicons;i++)
+            window__select(w,i,FALSE);
+          window__updateMenu(w);
+          break;
+        case glass_TWSCOPY:
+          window__copyIcons(w);
+          window__updateMenu(w);
+          break;
+        case glass_TWSDEL:
+          if (gPrefs_current()->cDelIcon)
+          {
+            if (!warning(msgs_lookup("wdCDIP"),msgs_lookup("wdCDI")))
+              return;
+          }
+          i=0;
+          while (i<w->def->desc.w.nicons)
+          {
+            if (w->def->i[i].selected)
+              window_deleteIcon(w,i);
+            else
+              i++;
+          }
+          window__updateMenu(w);
+          break;
+        case glass_TWSFRONT:
+          stop=w->def->desc.w.nicons-1;
+          for (i=0;i<=stop;i++)
+          {
+            if (w->def->i[i].selected)
+            {
+              window_renumber(w,i,w->def->desc.w.nicons-1);
+              i--;
+              stop--;
+            }
+          }
+          tfile_markAsAltered(w->t);
+          break;
+        case glass_TWSRAISE:
+          if (w->def->i[w->def->desc.w.nicons - 1].selected) {
+            bbc_vdu(7);
+            break;
+          }
+          for (i=w->def->desc.w.nicons - 1; i >= 0; i--) {
+            if (w->def->i[i].selected)
+              window_renumber(w, i, i + 1);
+          }
+          tfile_markAsAltered(w->t);
+          break;
+        case glass_TWSLOWER:
+          if (w->def->i[0].selected) {
+            bbc_vdu(7);
+            break;
+          }
+          for (i = 0; i < w->def->desc.w.nicons ;i++) {
+            if (w->def->i[i].selected)
+              window_renumber(w, i, i - 1);
+          }
+          tfile_markAsAltered(w->t);
+          break;
+        case glass_TWSBACK:
+          stop=0;
+          for (i=w->def->desc.w.nicons-1;i>=stop;i--)
+          {
+            if (w->def->i[i].selected)
+            {
+              window_renumber(w,i,0);
+              i++;
+              stop++;
+            }
+          }
+          tfile_markAsAltered(w->t);
+          break;
+        case glass_TWSORDER:
+          checked=!gPrefs_current()->cTest;
+          if (w->edit)
+          {
+            if (!checked)
+            {
+              if (!warning(msgs_lookup("wdTCRP"),msgs_lookup("wdTCR")))
+                return;
+              checked=TRUE;
+            }
+            editWindow_close(w);
+          }
+          for (i=0;i<w->def->desc.w.nicons;i++)
+          {
+            if (w->def->i[i].edit)
+            {
+              if (!checked)
+              {
+                if (!warning(msgs_lookup("wdTCRP"),msgs_lookup("wdTCR")))
+                  return;
+                checked=TRUE;
+              }
+              editIcon_close(w,i);
+            }
+          }
+          window__renumber(w,!w->renumber);
+          window__updateMenu(w);
+          break;
+        case glass_TWSPULL:
+          for (i=0;i<w->def->desc.w.nicons;i++)
+          {
+            if (w->def->i[i].selected)
+            {
+              window_boundingBox(w,i,&b);
+              xoff=b.x1-b.x0;
+              yoff=b.y1-b.y0;
+              window__align(w,&b.x0,&b.y1);
+              b.x1=b.x0+xoff;
+              b.y0=b.y1-yoff;
+              window_setBox(w,i,&b);
+              tfile_markAsAltered(w->t);
+            }
+          }
+          break;
+        case glass_TWSALIGN:
+          align();
+          break;
+        case glass_TWSEDIT:
+          for (i=0;i<w->def->desc.w.nicons;i++)
+          {
+            if (w->def->i[i].selected)
+              editIcon(w,i);
+          }
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * void window__mhButton(tearoff_message m,int hit,void *handle)
+ *
+ * Use
+ *  Handles events on the foo submenu
+ *
+ * Parameters
+ *  tearoff_message m == what happened
+ *  int hit == what item it happened to
+ *  void *handle == nothing interesting
+ */
+
+static void window__mhButton(tearoff_message m,int hit,void *handle)
+{
+  glass_windPointer *w=handle ? handle : window__menuWin;
+  int i;
+
+  unused(handle);
+
+  switch (m)
+  {
+    case tearoff_HELP:
+      window__thHelp("wmhBUT",hit);
+      break;
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      if (hit)
+      {
+        for (i=0;i<w->def->desc.w.nicons;i++)
+        {
+          if (w->def->i[i].selected)
+          {
+            w->def->i[i].i.flags&=~0x0000f000;
+            w->def->i[i].i.flags|=(hit-1)<<12;
+            tfile_markAsAltered(w->t);
+          }
+        }
+      }
+      break;
+  }
+}
+
+/*
+ * void window__newIcon(int which,glass_windPointer *w)
+ *
+ * Use
+ *  Creates a new icon in the window.
+ *
+ * Parameters
+ *  int which == which icon type to use
+ *  glass_windPointer *w == the window to build it in
+ */
+
+static void window__newIcon(int which,glass_windPointer *w)
+{
+  int i;
+  wimp_wind *wdef;
+  wimp_icon *idef;
+  wimp_box b;
+  int xoff,yoff;
+  const static wimp_icon defidef={0,0,200,48,0x0f00603f,"<Untitled>"};
+
+  if (i=window__createIcon(w),i==-1)
+    return;
+  wdef=&template_find("default")->window;
+  idef=(wimp_icon *)(wdef+1);
+  switch (wdef->nicons)
+  {
+    case 0:
+      w->def->i[i].i=defidef;
+      break;
+    default:
+      w->def->i[i].i=idef[which];
+      break;
+  }
+  if (!iconData_handleFont(w,&w->def->i[i].i.flags))
+    werr(FALSE,msgs_lookup("wdFERCI"));
+  if (!iconData_processIcon(w,i,0,TRUE,0))
+  {
+    werr(FALSE,msgs_lookup("wdNEMCI"));
+    w->def->i[i].i.flags&=~wimp_INDIRECT;
+    window_deleteIcon(w,i);
+    return;
+  }
+  window_boundingBox(w,i,&b);
+  xoff=window__menuX-b.x0;
+  yoff=window__menuY-b.y1;
+  if (w->gridLock)
+    window__align(w,&xoff,&yoff);
+  w->def->i[i].i.box.x0+=xoff;
+  w->def->i[i].i.box.x1+=xoff;
+  w->def->i[i].i.box.y0+=yoff;
+  w->def->i[i].i.box.y1+=yoff;
+  window_redrawIcon(w,i);
+  tfile_markAsAltered(w->t);
+  window__menuX+=w->gridx;
+  window__menuY-=w->gridy;
+}
+
+/*
+ * void window__mhIcon(tearoff_message m,int hit,void *handle)
+ *
+ * Use
+ *  Handles events on the icon submenu
+ *
+ * Parameters
+ *  tearoff_message m == what happened
+ *  int hit == what item it happened to
+ *  void *handle == nothing interesting
+ */
+
+static void window__mhIcon(tearoff_message m,int hit,void *handle)
+{
+  glass_windPointer *w=handle ? handle : window__menuWin;
+  unused(handle);
+
+  switch (m)
+  {
+    case tearoff_HELP:
+      window__thHelp("wmhICN",hit);
+      break;
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      switch (hit)
+      {
+        case glass_TWINEW:
+          window__newIcon(0,w);
+          window__updateMenu(w);
+          break;
+        case glass_TWIPAL:
+          window__showPalette();
+          break;
+        case glass_TWIGRAB:
+          window_grab(window__grabIcon,w);
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * void window__mhCreate(tearoff_message m,int hit,void *handle)
+ *
+ * Use
+ *  Handles events on the new icon submenu
+ *
+ * Parameters
+ *  tearoff_message m == what happened
+ *  int hit == what item it happened to
+ *  void *handle == nothing interesting
+ */
+
+static void window__mhCreate(tearoff_message m,int hit,void *handle)
+{
+  glass_windPointer *w=handle ? handle : window__menuWin;
+  unused(handle);
+
+  if (!w)
+  {
+    bbc_vdu(7);
+    return;
+  }
+
+  switch (m)
+  {
+    case tearoff_HELP:
+      help_startHelp();
+      help_addLine(msgs_lookup("wmhNI"));
+      help_endHelp();
+      break;
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      if (hit)
+      {
+        window__newIcon(hit-1,w);
+        window__updateMenu(w);
+      }
+      break;
+  }
+}
+
+/*
+ * void window__mhGuide(tearoff_message m,int hit,void *handle)
+ *
+ * Use
+ *  Handles events on the guide submenu
+ *
+ * Parameters
+ *  tearoff_message m == what happened
+ *  int hit == what item it happened to
+ *  void *handle == nothing interesting
+ */
+
+static void window__mhGuide(tearoff_message m,int hit,void *handle)
+{
+  glass_windPointer *w=handle ? handle : window__menuWin;
+  int i;
+
+  unused(handle);
+
+  switch (m)
+  {
+    case tearoff_HELP:
+      window__thHelp("wmhGD",hit);
+      break;
+    case tearoff_SELECTION:
+    case tearoff_SUBMENU:
+      switch (hit)
+      {
+        case glass_TWGSELALL:
+          window__gainSelection(w);
+          for (i=0;i<glass_GUIDELIMIT;i++)
+          {
+            if (w->guide[i].active && !w->guide[i].selected)
+            {
+              w->guide[i].selected=TRUE;
+              window__redrawGuide(w,i);
+            }
+          }
+          window__updateMenu(w);
+          break;
+        case glass_TWGCLRSEL:
+          for (i=0;i<glass_GUIDELIMIT;i++)
+          {
+            if (w->guide[i].active && w->guide[i].selected)
+            {
+              w->guide[i].selected=FALSE;
+              window__redrawGuide(w,i);
+            }
+          }
+          window__updateMenu(w);
+          break;
+        case glass_TWGHORIZ:
+          for (i=0;i<glass_GUIDELIMIT;i++)
+          {
+            if (!w->guide[i].active)
+            {
+              w->guide[i].active=TRUE;
+              w->guide[i].horiz=TRUE;
+              w->guide[i].coord=window__menuY;
+              w->guide[i].selected=FALSE;
+              window__redrawGuide(w,i);
+              window__menuY-=w->gridy;
+              break;
+            }
+          }
+          if (i==glass_GUIDELIMIT)
+            note(msgs_lookup("wdTMG"),glass_GUIDELIMIT);
+          window__updateMenu(w);
+          break;
+        case glass_TWGVERT:
+          for (i=0;i<glass_GUIDELIMIT;i++)
+          {
+            if (!w->guide[i].active)
+            {
+              w->guide[i].active=TRUE;
+              w->guide[i].horiz=FALSE;
+              w->guide[i].coord=window__menuX;
+              w->guide[i].selected=FALSE;
+              window__redrawGuide(w,i);
+              window__menuX+=w->gridx;
+              break;
+            }
+          }
+          if (i==glass_GUIDELIMIT)
+            note(msgs_lookup("wdTMG"),glass_GUIDELIMIT);
+          window__updateMenu(w);
+          break;
+        case glass_TWGDEL:
+          for (i=0;i<glass_GUIDELIMIT;i++)
+          {
+            if (w->guide[i].active && w->guide[i].selected)
+            {
+              w->guide[i].active=w->guide[i].selected=FALSE;
+              window__redrawGuide(w,i);
+            }
+          }
+          window__updateMenu(w);
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * void window__simMenu(glass_windPointer *w,int hit1,int hit2)
+ *
+ * Use
+ *  Simulates a menu hit on the specified item.  Gives a beep if the item
+ *  is unavailable.  Otherwise, the hit is sent to the current selection
+ *  owner.  [fixed to allow which window is used rather than only the
+ *  selection owner, 1 November 1993]
+ *
+ * Use
+ *  glass_windPointer *w == the window in which to simulate the event
+ *  int hit1 == first hit in the sequence
+ *  int hit2 == second hit in the sequence
+ */
+
+void window__simMenu(glass_windPointer *w,int hit1,int hit2)
+{
+  /* --- A bit of a hack(tm) --- *
+   *
+   * The old Wimp-menu based code used to simulate menu events to try to
+   * do key shortcuts and the button bar.  We try to emulate the old
+   * behaviour, although the implementation is a /little/ different.  The
+   * old code used to peek about in the menu blocks to find submenus.
+   * We can't do this any more, because the tearoff structure is hidden,
+   * so we keep a big table of our own to help us find our way around.
+   * Actually, this makes the code /much/ smaller.
+   */
+
+  const static struct
+  {
+    tearoff_selectProc p;
+    tearoff *t;
+  }
+  table[]={ window__mhRoot,   &window__mRoot, /* Funny entry for root menu */
+            window__mhMisc,   &window__mMisc,
+            0,                0,
+            window__mhSelect, &window__mSelect,
+            window__mhIcon,   &window__mIcon,
+            0,                0,
+            window__mhButton, &window__mButton };
+
+
+  if (!hit2)
+    hit2=hit1;
+
+  if (table[hit1].t && !tearoff_isShaded(*table[hit1].t,hit2))
+    table[hit1].p(tearoff_SELECTION,hit2,w);
+  else
+    bbc_vdu(7);
+}
+
+/*
+ * void window__showMenu(int x,int y,glass_windPointer *w)
+ *
+ * Use
+ *  Displays the Template Window Menu
+ *
+ * Parameters
+ *  int x,int y == the (window) position to display the menu
+ *  glass_windPointer *w == the window to display the menu for
+ */
+
+void window__showMenu(int x,int y,glass_windPointer *w)
+{
+  window__menuX=x;
+  window__menuY=y;
+  window__updateMenu(w);
+  tearoff_displayMenu(window__mRoot,w);
+}
+
+/*
+ * void window__menuInit(void)
+ *
+ * Use
+ *  Initialises the create icon menu
+ */
+
+void window__menuInit(void)
+{
+  wimp_wind *wdef;
+  wimp_icon *idef;
+  int i;
+  char *p;
+  char buff[15];
+
+  /* --- First set up the create menu --- */
+
+  template_readfile(choices_name("Defaults.Templates",FALSE));
+  wdef=&template_find("default")->window;
+  idef=(wimp_icon *)(wdef+1);
+  window__newIcons=wdef->nicons;
+  switch (wdef->nicons)
+  {
+    case 0:
+    case 1:
+      break;
+    default:
+      for (i=0;i<wdef->nicons;i++)
+      {
+        if (idef[i].flags & wimp_INDIRECT)
+        {
+          p=idef[i].data.indirecttext.buffer;
+          utils_ctermToNterm(p);
+          if (*p=='`')
+            p++;
+          if (window__mCreate)
+            window__mCreate=tearoff_extendMenu(window__mCreate,p);
+          else
+            window__mCreate=tearoff_create(msgs_lookup("wdCRTMT"),
+                                           p,TRUE,window__mhCreate,800,0);
+          if (p[-1]=='`')
+          {
+            p[-1]=0;
+            idef[i].data.indirecttext.bufflen=1;
+          }
+        }
+        else
+        {
+          memcpy(buff,idef[i].data.text,12);
+          utils_ctermToNterm(buff);
+          buff[12]=0;
+          p=buff;
+          if (*p=='`')
+            p++;
+          if (window__mCreate)
+            window__mCreate=tearoff_extendMenu(window__mCreate,p);
+          else
+            window__mCreate=tearoff_create(msgs_lookup("wdCRTMT"),
+                                           p,TRUE,window__mhCreate,800,0);
+          if (p[-1]=='`')
+            p[-1]=0;
+        }
+      }
+      break;
+  }
+
+  /* --- Create the main menu tree --- */
+
+  window__mRoot=tearoff_create(msgs_lookup("wdWMT"),
+    msgs_lookup("wdWM"),
+    TRUE,window__mhRoot,0,0);
+
+  window__mMisc=tearoff_create(msgs_lookup("wdMISCMT"),
+    msgs_lookup("wdMISCM"),
+    FALSE,window__mhMisc,0,0);
+
+  window__mSelect=tearoff_create(msgs_lookup("wdSELMT"),
+    msgs_lookup("wdSELM"),
+    TRUE,window__mhSelect,0,0);
+
+  window__mIcon=tearoff_create(msgs_lookup("wdICNMT"),
+    msgs_lookup("wdICNM"),
+    FALSE,window__mhIcon,0,0);
+
+  window__mGuide=tearoff_create(msgs_lookup("wdGDEMT"),
+    msgs_lookup("wdGDEM"),
+    TRUE,window__mhGuide,0,0);
+
+ window__mButton=tearoff_create(msgs_lookup("eiBTMT"),
+                                 msgs_lookup("eiBTYPE0"),
+                                 FALSE,
+                                 window__mhButton,
+                                 0,
+                                 0);
+  p=buffer_find();
+  for (i=1;i<=15;i++)
+  {
+    sprintf(p,"eiBTYPE%i",i);
+    window__mButton=tearoff_extendMenu(window__mButton,msgs_lookup(p));
+  }
+
+  tearoff_attachSubMenu(window__mRoot,glass_TWMISC,window__mMisc);
+  tearoff_attachSubMenu(window__mRoot,glass_TWSELECT,window__mSelect);
+  tearoff_attachSubMenu(window__mRoot,glass_TWICON,window__mIcon);
+  tearoff_attachSubMenu(window__mRoot,glass_TWGDE,window__mGuide);
+  tearoff_attachSubMenu(window__mSelect,glass_TWSBTYPE,window__mButton);
+  if (window__mCreate)
+    tearoff_attachSubMenu(window__mIcon,glass_TWINEW,window__mCreate);
+}
diff --git a/StraySrc/Glass/!Glass/c/wMousePtr b/StraySrc/Glass/!Glass/c/wMousePtr
new file mode 100644 (file)
index 0000000..d1c15d0
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * wMousePtr.c
+ *
+ * Finding the posisiton and changing the shape of the mouse pointer
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/pointer.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "window.h"
+#include "_window.h"
+
+/*----- Tables ------------------------------------------------------------*/
+
+/*
+ * This table defines the mapping from drag zones to pointer shapes, to
+ * indicate to the user what operations are possible.  There is some
+ * redundancy since there are some 'reserved' zone numbers, and they go up
+ * to &F.  Each entry takes up 20 bytes, though, so things aren't exactly
+ * critical as a result of this.
+ */
+
+static struct
+{
+  char name[12];
+  int x;
+  int y;
+}
+window__ptr[]=
+{
+  "",0,0,              /* 0 */
+  "ptr_tb",7,5,        /* 1 */
+  "ptr_tb",7,5,        /* 2 */
+  "",0,0,              /* 3 */
+  "ptr_lr",11,4,       /* 4 */
+  "ptr_tlbr",9,5,      /* 5 */
+  "ptr_trbl",9,5,      /* 6 */
+  "ptr_hand",10,9,     /* 7 */
+  "ptr_lr",11,4,       /* 8 */
+  "ptr_trbl",9,5,      /* 9 */
+  "ptr_tlbr",9,5,      /* a */
+  "",0,0,              /* b */
+  "",0,0,              /* c */
+  "ptr_tb",7,5,        /* d */
+  "ptr_lr",11,4,       /* e */
+  "",0,0,              /* f */
+};
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * BOOL window__inSizedBox(int px,int py,int x,int y,int d)
+ *
+ * Use
+ *  Returns whether the point passed as (px,py) is contained within the
+ *  square box with bottom-left corner (x,y) and side length d.
+ *
+ * Parameters
+ *  As described above
+ *
+ * Returns
+ *  TRUE if the point lies within the box, or FALSE if not
+ */
+
+static BOOL window__inSizedBox(int px,int py,int x,int y,int d)
+{
+  x&=~(wimpt_dx()-1);
+  y&=~(wimpt_dy()-1);
+  d=(d+wimpt_dy()-1) &~ (wimpt_dy()-1);
+  if (px>=x && py>=y && px<=x+d && py<=y+d)
+    return (TRUE);
+  else
+    return (FALSE);
+}
+
+/*
+ * int window__pointerInfo(glass_windPointer *w,int from,BOOL zones)
+ *
+ * Use
+ *  Returns the icon number of the icon which the pointer is over.  Guides
+ *  are also checked for.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to use info from
+ *  int from == number to search down from (or -1 for the top).  This is
+ *   useful for selection, multiple clicks moving down overlapping icons.
+ *  BOOL zones == search for drag zones.  If this is set, the routine
+ *   searches for selected icons only.  If it is clear, zones are not
+ *   checked.
+ *
+ * Returns
+ *  An icon number, or -1 for the background.
+ */
+
+#define HW window__HANDLEWIDTH
+
+int window__pointerInfo(glass_windPointer *w,int from,BOOL zones)
+{
+  int i;
+  wimp_mousestr m;
+  int ox;
+  int oy;
+  int tries;
+  wimp_box box;
+  BOOL found=FALSE;
+
+  /* --- Find out where the pointer is in the window --- */
+
+  wimpt_noerr(wimp_get_point_info(&m));
+  if (m.w!=w->h)
+    return (-1);
+  zones=zones&&!w->renumber;
+  ox=w->def->desc.w.box.x0-w->def->desc.w.scx;
+  oy=w->def->desc.w.box.y1-w->def->desc.w.scy;
+  m.x-=ox;
+  m.y-=oy;
+
+  /* --- Start the search from the right place --- *
+   *
+   * The search can be relative to an icon, for the depth-selection system
+   * to work.  If this is the case, we do two passes through the icon array
+   * and start off half-way through.  If we're just searching from the top
+   * then we just do one pass.
+   */
+
+  if (from==-1)
+  {
+    i=w->def->desc.w.nicons-1;
+    tries=1;
+  }
+  else
+  {
+    i=from-1;
+    tries=2;
+  }
+
+  /* --- The main search loop --- *
+   *
+   * There's nothing really exciting about this.  It's just a brute-force
+   * rectangle comparison.  If it finds something, then it returns
+   * immediately.
+   *
+   * We try to be a little cleverer -- we check if the pointer is anywhere
+   * near the icon rectangle and only read the actual bounding area if it
+   * is really worthwhile.
+   */
+
+  for (;tries;tries--)
+  {
+    while (i>=0)                 /* Find higher icons first...             */
+    {
+      if (w->def->i[i].i.flags & wimp_IDELETED)
+      {
+        i--;
+        continue;                /* Don't find deleted icons...            */
+      }
+      if (m.x>=w->def->i[i].i.box.x0-20-HW &&
+          m.x<=w->def->i[i].i.box.x1+20+HW &&
+          m.y>=w->def->i[i].i.box.y0-20-HW &&
+          m.y<=w->def->i[i].i.box.y1+32+HW)
+      {                          /* Roughly in the right place             */
+
+        /* --- Find the actual bounding box of the icon --- */
+
+        window_boundingBox(w,i,&box);
+
+        /* --- If we're searching for drag zones, do that --- */
+
+        if (w->def->i[i].selected && zones)
+        {
+         if (window__inSizedBox(m.x,
+                                m.y,
+                                box.x1-HW,
+                                box.y0-wimpt_dy()-HW,
+                                HW*2))
+            return (i | window__BOTTOMRIGHT);
+          if (window__inSizedBox(m.x,
+                                 m.y,
+                                 box.x0-wimpt_dx()-HW,
+                                 box.y0-wimpt_dy()-HW,
+                                 HW*2))
+            return (i | window__BOTTOMLEFT);
+         if (window__inSizedBox(m.x,
+                                m.y,
+                                box.x0-wimpt_dx()-HW,
+                                box.y1-HW,
+                                HW*2))
+            return (i | window__TOPLEFT);
+          if (window__inSizedBox(m.x,
+                                 m.y,
+                                 box.x1-HW,
+                                 box.y1-HW,
+                                 HW*2))
+            return (i | window__TOPRIGHT);
+          if (gPrefs_current()->sEdgeHandles)
+          {
+            if (window__inSizedBox(m.x,
+                                   m.y,
+                                   box.x0+(box.x1-box.x0-HW*2)/2,
+                                   box.y0-wimpt_dy()-HW,
+                                   HW*2))
+              return (i | window__BOTTOM);
+            if (window__inSizedBox(m.x,
+                                   m.y,
+                                   box.x1-HW,
+                                   box.y0+(box.y1-box.y0-HW*2)/2,
+                                   HW*2))
+              return (i | window__RIGHT);
+            if (window__inSizedBox(m.x,
+                                   m.y,
+                                   box.x0-wimpt_dx()-HW,
+                                   box.y0+(box.y1-box.y0-HW*2)/2,
+                                   HW*2))
+              return (i | window__LEFT);
+            if (window__inSizedBox(m.x,
+                                   m.y,
+                                   box.x0+(box.x1-box.x0-HW*2)/2,
+                                   box.y1-HW,
+                                   HW*2))
+              return (i | window__TOP);
+          }
+        }
+
+        /* --- If no match in the zones, check the actual icon --- *
+         *
+         * If it's in the icon, then we've found a match.  If we're searching
+         * for drag zones, and it's not selected, then just remember we've
+         * found an icon, so don't try to match guidelines.  Otherwise, we
+         * just return the match.
+         */
+
+        if (m.x>=box.x0 && m.x<box.x1 && m.y>=box.y0 && m.y<box.y1)
+        {
+          if (zones) {
+            if (w->def->i[i].selected)
+              return (i | window__MAIN);
+            else
+              found=TRUE;
+          } else
+            return (i);
+        }
+      }
+      i--;
+    }
+    i=w->def->desc.w.nicons-1;
+  }
+
+  /* --- We couldn't find anything in the icons, so try guidelines --- */
+
+  if (!found)
+  {
+    for (i=0;i<glass_GUIDELIMIT;i++)
+    {
+      if (w->guide[i].active)
+      {
+        if (w->guide[i].horiz && abs(m.y-w->guide[i].coord)<8)
+          return (i | window__HORGUIDE);
+        else if (abs(m.x-w->guide[i].coord)<8)
+          return (i | window__VERGUIDE);
+      }
+    }
+  }
+
+  /* --- Not a sausage, so we failed --- */
+
+  return (-1);
+}
+
+#undef HW
+
+/*
+ * BOOL window__pointerOverIcon(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Informs the caller if the pointer is over the bounding box of the icon
+ *  specified.
+ *
+ * Parameters
+ *  glass_windPointer *w == window containing icon
+ *  int icon == icon to check for
+ */
+
+BOOL window__pointerOverIcon(glass_windPointer *w,int icon)
+{
+  wimp_box box;
+  wimp_wstate s;
+  wimp_mousestr m;
+  wimpt_noerr(wimp_get_wind_state(w->h,&s));
+  wimpt_noerr(wimp_get_point_info(&m));
+  window_boundingBox(w,icon,&box);
+  m.x-=s.o.box.x0-s.o.x;
+  m.y-=s.o.box.y1-s.o.y;
+  return (m.x>=box.x0 && m.x<=box.x1 && m.y>=box.y0 && m.y<=box.y1);
+}
+
+/*
+ * void window__setPtrShape(int icon)
+ *
+ * Use
+ *  Sets the pointer shape accoding to the 'drag zone' part of the given
+ *  icon number.
+ *
+ * Parameters
+ *  int icon == the icon number
+ */
+
+void window__setPtrShape(int icon)
+{
+  static int last;
+  static int wouldbe;
+  sprite_id sid;
+  if (icon==-2)
+    icon=wouldbe;
+  wouldbe=icon;
+  if (window__qDragType()!=-1)
+    icon=window__qDragType();
+  icon=(icon&window__ZONEMASK)>>24;
+  if (icon==last)
+    return;
+  if (window__ptr[icon].name[0])
+  {
+    sid.s.name=window__ptr[icon].name;
+    sid.tag=0;
+    pointer_set_shape(resspr_area(),
+                      &sid,
+                      window__ptr[icon].x,
+                      window__ptr[icon].y);
+  }
+  else
+    pointer_reset_shape();
+  last=icon;
+}
diff --git a/StraySrc/Glass/!Glass/c/wPalette b/StraySrc/Glass/!Glass/c/wPalette
new file mode 100644 (file)
index 0000000..f154237
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * wPalette.c
+ *
+ * Handling of the Icon Palette
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/interface.h"
+#include "steel/sculptrix.h"
+#include "steel/caretPtr.h"
+#include "steel/flex.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "gSprite.h"
+#include "window.h"
+#include "_window.h"
+
+/*----- Private data ------------------------------------------------------*/
+
+static wimp_w window__palette;   /* Window handle of floating icon palette */
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * void window__paletteHandler(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles events for the icon palette window.
+ *
+ * Parameters
+ *  wimp_eventstr *e == pointer to the current event
+ *  void *handle == an unimportant pointer
+ */
+
+static void window__paletteHandler(wimp_eventstr *e,void *handle)
+{
+  BOOL more=TRUE;
+  wimp_redrawstr r;
+  wimp_wstate s;
+  wimp_wind *t;
+  os_regset reg;
+  wimp_icon *ic;
+  unused(handle);
+  switch (e->e)
+  {
+    case wimp_EREDRAW:
+      r.w=e->data.o.w;
+      wimpt_noerr(wimp_redraw_wind(&r,&more));
+      while (more)
+      {
+        if (gPrefs_current()->sDispBorders)
+        {
+          sculptrix_setSpriteArea(gSprite_area());
+          sculptrix_redrawWindow(&r);
+        }
+        if (gPrefs_current()->iDispBorders)
+          interface_render3dWindow(&r);
+        if (gPrefs_current()->wDispBorders)
+        {
+          reg.r[1]=(int)&r;
+          os_swix(XWimpExt_Redraw,&reg);
+        }
+        wimpt_noerr(wimp_get_rectangle(&r,&more));
+      }
+      break;
+    case wimp_EOPEN:
+      wimpt_noerr(wimp_open_wind(&e->data.o));
+      break;
+    case wimp_ECLOSE:
+      wimpt_noerr(wimp_get_wind_state(window__palette,&s));
+      t=&template_find("default")->window;
+      t->box=s.o.box;
+      t->scx=s.o.x;
+      t->scy=s.o.y;
+      win_register_event_handler(window__palette,0,0);
+      wimpt_noerr(wimp_delete_wind(window__palette));
+      win_activedec();
+      window__palette=0;
+      break;
+    case wimp_EPTRENTER:
+      caretPtr__pointer(FALSE); /* Don't change pointer in this window */
+      break;
+    case wimp_EBUT:
+      if ((e->data.but.m.bbits==0x40 || e->data.but.m.bbits==0x10) &&
+          e->data.but.m.i!=-1 &&
+          !window_grabbing())
+      {
+        t=&template_find("default")->window;
+        ic=(wimp_icon *)(t+1);
+        window__grabIcon(&e->data.but.m,0);
+        window__qGrabbedIcon()->flags=ic[e->data.but.m.i].flags;
+      }
+      break;
+  }
+}
+
+/*
+ * void window__showPalette(void)
+ *
+ * Use
+ *  Displays the palette window, as set up in the Defaults template file.
+ */
+
+void window__showPalette(void)
+{
+  wimp_wind *w;
+  wimp_wind *t;
+  wimp_icon *ic;
+  wimp_wstate s;
+  int i;
+  int size;
+  static char title[25];
+  if (!window__palette)
+  {
+    t=&template_find("default")->window;
+    size=sizeof(wimp_wind)+t->nicons*sizeof(wimp_icon);
+    if (!flex_alloc((flex_ptr)&w,size))
+    {
+      werr(FALSE,
+           msgs_lookup("wdNEMIP"));
+      return;
+    }
+    memcpy(w,t,size);
+    ic=(wimp_icon *)(w+1);
+    for (i=0;i<w->nicons;i++)
+      ic[i].flags=(ic[i].flags&~0x0000f000)|0x00006000;
+    strcpy(title,msgs_lookup("wdIPT"));
+    w->spritearea=gSprite_area();
+    w->titleflags=wimp_INDIRECT | wimp_IHCENTRE | wimp_ITEXT;
+    w->title.indirecttext.buffer=title;
+    w->title.indirecttext.validstring=(char *)-1;
+    w->flags=wimp_WQUIT |
+             wimp_WBACK |
+             wimp_WTITLE |
+             wimp_WNEW |
+             wimp_WMOVEABLE;
+    if (utils_complain(wimp_create_wind(w,&window__palette),
+                  msgs_lookup("wdERIP")))
+    {
+      flex_free((flex_ptr)&w);
+      window__palette=0;
+      return;
+    }
+    flex_free((flex_ptr)&w);
+    win_activeinc();
+    win_register_event_handler(window__palette,window__paletteHandler,0);
+  }
+  wimpt_noerr(wimp_get_wind_state(window__palette,&s));
+  s.o.behind=-1;
+  wimpt_noerr(wimp_open_wind(&s.o));
+}
diff --git a/StraySrc/Glass/!Glass/c/wRedraw b/StraySrc/Glass/!Glass/c/wRedraw
new file mode 100644 (file)
index 0000000..3082c20
--- /dev/null
@@ -0,0 +1,678 @@
+/*
+ * wRedraw.c
+ *
+ * Redrawing template windows
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/interface.h"
+#include "steel/sculptrix.h"
+#include "steel/bbc.h"
+#include "steel/coords.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "window.h"
+#include "_window.h"
+#include "tearEdit.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * void window__drawSelectBox(glass_windPointer *w,
+ *                            int icon,
+ *                           BOOL makesi,
+ *                            wimp_redrawstr *r)
+ *
+ * Use
+ *  Draws the selection box around an icon
+ *
+ * Parameters
+ *  glass_windPointer *w == the window
+ *  int icon == the icon
+ *  BOOL makesi == whether we're going between a selected and main selected
+ *    icon.
+ *  wimp_redrawstr *r == the redraw structure
+ */
+
+#define HW window__HANDLEWIDTH
+
+void window__drawSelectBox(glass_windPointer *w,
+                           int icon,
+                           BOOL makesi,
+                           wimp_redrawstr *r)
+{
+  wimp_box box;
+  int ox=r->box.x0-r->scx;
+  int oy=r->box.y1-r->scy;
+
+  window_boundingBox(w,icon,&box);
+
+  /* --- If we're in test mode, do nothing --- */
+
+#ifndef glass_DEMO
+  if (w->testMode)
+    /* Blank */;
+  else
+#endif
+
+  /* --- If we're not renumbering, draw in all the fancy bits --- */
+
+  if (!w->renumber)
+  {
+
+    /* --- Make sure the user wants a border, and draw the right one --- */
+
+    if (gPrefs_current()->sBorder && !makesi)
+    {
+      window__setXORColour(w,window__SELBOXCOL);
+      if (gPrefs_current()->sDotted)
+      {
+        window__makeDashPattern(0xf0);
+        window__rectangle(ox+box.x0-wimpt_dx(),
+                          oy+box.y0-wimpt_dy(),
+                          box.x1-box.x0+wimpt_dx(),
+                          box.y1-box.y0+wimpt_dy());
+      }
+      else
+      {
+        bbc_rectangle(ox+box.x0-wimpt_dx(),
+                      oy+box.y0-wimpt_dy(),
+                      box.x1-box.x0+wimpt_dx(),
+                      box.y1-box.y0+wimpt_dy());
+      }
+    }
+
+    /* --- Draw in all the drag handles --- */
+
+    if (makesi)
+      window__colourChange(window__MSELBOXCOL,window__HANDCOL);
+    else if (icon==window__selectedIcon())
+      window__setXORColour(w,window__MSELBOXCOL);
+    else
+      window__setXORColour(w,window__HANDCOL);
+
+    /* If edges are wanted, fill them in */
+
+    if (gPrefs_current()->sEdgeHandles)
+    {
+      bbc_rectanglefill(ox+box.x0-wimpt_dx()-HW,
+                        oy+box.y0+(box.y1-box.y0-HW*2)/2,
+                        HW*2,
+                        HW*2);
+      bbc_rectanglefill(ox+box.x1-HW,
+                        oy+box.y0+(box.y1-box.y0-HW*2)/2,
+                        HW*2,
+                        HW*2);
+      bbc_rectanglefill(ox+box.x0+(box.x1-box.x0-HW*2)/2,
+                        oy+box.y0-wimpt_dy()-HW,
+                        HW*2,
+                        HW*2);
+      bbc_rectanglefill(ox+box.x0+(box.x1-box.x0-HW*2)/2,
+                        oy+box.y1-HW,
+                        HW*2,
+                        HW*2);
+    }
+
+    /* Corners are always drawn */
+
+    bbc_rectanglefill(ox+box.x0-wimpt_dx()-HW,
+                      oy+box.y0-wimpt_dy()-HW,
+                      HW*2,
+                      HW*2);
+    bbc_rectanglefill(ox+box.x1-HW,
+                      oy+box.y0-wimpt_dy()-HW,
+                      HW*2,
+                      HW*2);
+    bbc_rectanglefill(ox+box.x0-wimpt_dx()-HW,
+                      oy+box.y1-HW,
+                      HW*2,
+                      HW*2);
+    bbc_rectanglefill(ox+box.x1-HW,
+                      oy+box.y1-HW,
+                      HW*2,
+                      HW*2);
+  }
+  else
+
+  /* --- Otherwise, we do the funny renumbering corner bits --- */
+
+  {
+    window__setXORColour(w,window__HANDCOL);
+    bbc_move(ox+box.x0-8,oy+box.y1-wimpt_dy()-12);
+    bbc_drawby(0,20);
+    bbc_drawby(20,0);
+    bbc_move(ox+box.x1-wimpt_dx()+8,oy+box.y1-wimpt_dy()-12);
+    bbc_drawby(0,20);
+    bbc_drawby(-20,0);
+    bbc_move(ox+box.x0-8,oy+box.y0+12);
+    bbc_drawby(0,-20);
+    bbc_drawby(20,0);
+    bbc_move(ox+box.x1-wimpt_dx()+8,oy+box.y0+12);
+    bbc_drawby(0,-20);
+    bbc_drawby(-20,0);
+  }
+}
+
+#undef HW
+
+/*
+ * void window__redrawDragBox(glass_windPointer *w,
+ *                            wimp_redrawstr *r,
+ *                            int x,
+ *                            int y)
+ *
+ * Use
+ *  Redraws the screen during a drag operation, either to update the window
+ *  during the drag, or to redraw the window should something silly happen
+ *  to it.
+ *
+ * Parameters
+ *  glass_windPointer *w == pointer to the window owning drag
+ *  wimp_redrawstr *r == pointer to current redraw
+ *  int x,int y == coordinates to draw drag relative to...
+ */
+
+void window__redrawDragBox(glass_windPointer *w,wimp_redrawstr *r,
+                           int x,int y)
+{
+  int ox=r->box.x0-r->scx;
+  int oy=r->box.y1-r->scy;
+  int i;
+  wimp_box box;
+  int bw;
+  int bh;
+  int type=window__qDragType();
+  int sx,sy;
+
+  /* --- If we don't know which window to draw in, don't --- */
+
+  if (!window__dragWind())
+    return;
+
+  /* --- Work out what we have to draw --- */
+
+  window__dragStart(&sx,&sy);
+  switch (type)
+  {
+
+    /* --- A selection box -- draw a rubber rectangle --- */
+
+    case window__SELECT:         /* Drag out a box to select icons         */
+      window__rectangle(sx+ox,sy+oy,x-sx,y-sy);
+      break;
+
+    /* --- We're grabbing an icon, so this is like a move --- *
+     *
+     * We can't actually use the main move code, because it works on all
+     * selected icons, and the one we're drawing doesn't actually exist as
+     * such.
+     */
+
+    case window__GRABICON:
+      box=window__qDragBox();
+      box.y1+=y-sy;
+      box.y0+=y-sy;
+      box.x0+=x-sx;
+      box.x1+=x-sx;
+      window__rectangle(ox+box.x0,
+                        oy+box.y0,
+                        box.x1-box.x0-wimpt_dx(),
+                        box.y1-box.y0-wimpt_dy());
+      break;
+
+    /* --- Guidelines moving -- draw all the guides which are moving --- */
+
+    case window__HORGUIDE:
+      for (i=0;i<glass_GUIDELIMIT;i++)
+      {
+        if (w->guide[i].active && w->guide[i].selected && w->guide[i].horiz)
+        {
+          bbc_plot(bbc_DottedBoth+bbc_MoveCursorAbs,
+                   ox+w->def->desc.w.ex.x0,
+                   oy+w->guide[i].coord+y-sy);
+          bbc_plot(bbc_DottedBoth+bbc_DrawAbsFore,
+                   ox+w->def->desc.w.ex.x1,
+                   oy+w->guide[i].coord+y-sy);
+        }
+      }
+      break;
+    case window__VERGUIDE:
+      for (i=0;i<glass_GUIDELIMIT;i++)
+      {
+        if (w->guide[i].active && w->guide[i].selected && !w->guide[i].horiz)
+        {
+          bbc_plot(bbc_DottedBoth+bbc_MoveCursorAbs,
+                   ox+w->guide[i].coord+x-sx,
+                   oy+w->def->desc.w.ex.y0);
+          bbc_plot(bbc_DottedBoth+bbc_DrawAbsFore,
+                   ox+w->guide[i].coord+x-sx,
+                   oy+w->def->desc.w.ex.y1);
+        }
+      }
+      break;
+
+    /* --- Normal icon moves/resizes --- *
+     *
+     * We find out where the box is according to the drag-type bitfield,
+     * and draw that for each selected icon.
+     */
+
+    default:
+      for (i=0;i<w->def->desc.w.nicons;i++)
+      {
+        if (w->def->i[i].selected)
+        {
+          window_boundingBox(w,i,&box);
+          bw=(w->def->i[i].i.box.x0-box.x0) + (box.x1-w->def->i[i].i.box.x1);
+          bh=(w->def->i[i].i.box.y0-box.y0) + (box.y1-w->def->i[i].i.box.y1);
+
+          /* --- Adjust coordinates according to drag type --- */
+
+          if (type & window__TOP)
+            box.y1+=y-sy;
+          if (type & window__BOTTOM)
+            box.y0+=y-sy;
+          if (type & window__LEFT)
+            box.x0+=x-sx;
+          if (type & window__RIGHT)
+            box.x1+=x-sx;
+
+          /* --- Ensure that the box is not inside-out --- */
+
+          if (type & window__TOP)
+          {
+            if (box.y1-box.y0<bh)
+              box.y1=box.y0+bh;
+          }
+          if (type & window__BOTTOM)
+          {
+            if (box.y1-box.y0<bh)
+              box.y0=box.y1-bh;
+          }
+          if (type & window__LEFT)
+          {
+            if (box.x1-box.x0<bw)
+              box.x0=box.x1-bw;
+          }
+          if (type & window__RIGHT)
+          {
+            if (box.x1-box.x0<bw)
+              box.x1=box.x0+bw;
+          }
+
+          window__rectangle(ox+box.x0,
+                            oy+box.y0,
+                            box.x1-box.x0-wimpt_dx(),
+                            box.y1-box.y0-wimpt_dy());
+        }
+      }
+      break;
+  }
+}
+
+/*
+ * void window__redraw(glass_windPointer *w,wimp_redrawstr *r,BOOL *more)
+ *
+ * Use
+ *  Redraws a window following a call to Wimp_UpdateWindow or
+ *  Wimp_RedrawWindow.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to draw
+ *  wimp_redrawstr *r == stuff about the redraw
+ *  BOOL *more == whether there is more to do
+ */
+
+void window__redraw(glass_windPointer *w,wimp_redrawstr *r,BOOL *more)
+{
+  int i;
+  os_regset reg;
+  int xx;
+  int yy;
+  int XX;
+  int YY;
+  int xd;
+  int x;
+  int y;
+  int ox=r->box.x0-r->scx;
+  int oy=r->box.y1-r->scy;
+
+  /* --- Make Sculptrix use the right sprite area --- */
+
+  sculptrix_setSpriteArea(w->t->s);
+
+  /* --- Do the redraw for each rectangle the WIMP gives us --- */
+
+  while (*more)
+  {
+
+    /* --- Draw the grid --- */
+
+    if (w->gridShow
+  #ifndef glass_DEMO
+    && !w->testMode
+  #endif
+    )
+    {
+      xx=((r->g.x0-ox)/w->gridx)*w->gridx-w->gridx;
+      yy=((r->g.y0-oy)/w->gridy)*w->gridy-w->gridy;
+      XX=((r->g.x1-ox)/w->gridx)*w->gridx+w->gridx;
+      YY=((r->g.y1-oy)/w->gridy)*w->gridy+w->gridy;
+      wimp_setcolour(gPrefs_current()->gGridCol);
+      if (gPrefs_current()->gLines)
+      {
+        for (x=xx;x<=XX;x+=w->gridx)
+        {
+          bbc_move(x+ox,yy+oy);
+          bbc_draw(x+ox,YY+oy);
+        }
+        for (y=yy;y<=YY;y+=w->gridy)
+        {
+          bbc_move(xx+ox,y+oy);
+          bbc_draw(XX+ox,y+oy);
+        }
+      }
+      else
+      {
+        for (x=xx;x<=XX;x+=w->gridx)
+        {
+          for (y=yy;y<=YY;y+=w->gridy)
+            bbc_plot(bbc_Point+bbc_DrawAbsFore,x+ox,y+oy);
+        }
+      }
+    }
+
+    /* --- Draw guidelines --- */
+
+  #ifndef glass_DEMO
+    if (!w->testMode)
+  #endif
+    {
+      for (i=0;i<glass_GUIDELIMIT;i++)
+      {
+        if (w->guide[i].active)
+        {
+          if (w->guide[i].selected)
+          {
+            wimp_setcolour(window__GDESELCOL);
+            window__makeDashPattern(0xff);
+          }
+          else
+          {
+            wimp_setcolour(window__GUIDECOL);
+            window__makeDashPattern(0x33);
+          }
+          if (w->guide[i].horiz)
+          {
+            bbc_plot(bbc_DottedBoth+bbc_MoveCursorAbs,
+                     ox+w->def->desc.w.ex.x0,
+                     oy+w->guide[i].coord);
+            bbc_plot(bbc_DottedBoth+bbc_DrawAbsFore,
+                     ox+w->def->desc.w.ex.x1,
+                     oy+w->guide[i].coord);
+          }
+          else
+          {
+            bbc_plot(bbc_DottedBoth+bbc_MoveCursorAbs,
+                     ox+w->guide[i].coord,
+                     oy+w->def->desc.w.ex.y0);
+            bbc_plot(bbc_DottedBoth+bbc_DrawAbsFore,
+                     ox+w->guide[i].coord,
+                     oy+w->def->desc.w.ex.y1);
+          }
+        }
+      }
+    }
+
+    /* --- Draw the hatch pattern, if applicable --- */
+
+    if (gPrefs_current()->mDrawHatch &&
+        !(w->def->desc.w.flags & wimp_REDRAW_OK))
+    {
+      wimpt_noerr(wimp_setcolour(w->def->desc.w.colours[2]));
+      xx=((r->g.x0-ox)/48)*48-48;
+      yy=((r->g.y0-oy)/48)*48-48;
+      XX=((r->g.x1-ox)/48)*48+48;
+      YY=((r->g.y1-oy)/48)*48+48;
+      xd=YY-yy;
+      for (x=xx-xd;x<=XX;x+=48)
+      {
+        bbc_move(x+ox,yy+oy);
+        bbc_draw(x+ox+xd,YY+oy);
+        bbc_move(x+ox+xd,yy+oy);
+        bbc_draw(x+ox,YY+oy);
+      }
+    }
+
+    /* --- If in test mode, draw 3D bits, and skip icon rendering --- */
+
+  #ifndef glass_DEMO
+    if (w->testMode)
+    {
+      if (gPrefs_current()->sDispBorders)
+        sculptrix_redrawWindow(r);
+      if (gPrefs_current()->iDispBorders)
+        interface_render3dWindow(r);
+      if (gPrefs_current()->wDispBorders)
+      {
+        reg.r[1]=(int)r;
+        os_swix(XWimpExt_Redraw,&reg);
+      }
+      wimpt_noerr(wimp_get_rectangle(r,more));
+      continue;
+    }
+  #endif
+
+    /* --- Otherwise, translate coordinates for optimisation --- *
+     *
+     * We also bodge the rectangle a bit to include 3D borders.  This is
+     * to avoid really very slow redrawing in big windows, where we have to
+     * pass each validation string to each of 3 modules to be parsed before
+     * rendering...
+     *
+     * If this goes seriously wrong, blame someone else.  The worst that is
+     * likely to happen is that some *seriously* large borders don't get
+     * drawn all the time.
+     */
+
+    coords_box_toworkarea(&r->g,(coords_cvtstr *)&(r->box));
+    r->g.x0-=16;
+    r->g.y0-=32;
+    r->g.x1+=16;
+    r->g.y1+=16;
+
+    /* --- Plot 3D borders --- */
+
+    if (gPrefs_current()->iDispBorders ||
+        gPrefs_current()->wDispBorders ||
+        gPrefs_current()->sDispBorders)
+    {
+      for (i=0;i<w->def->desc.w.nicons;i++) /* Plot 3D borders first     */
+      {
+        if (!(w->def->i[i].i.flags & wimp_IDELETED) &&
+            coords_boxesoverlap(&w->def->i[i].i.box,&r->g))
+        {
+          if (gPrefs_current()->sDispBorders)
+            sculptrix_plotIcon(&w->def->i[i].i,r);
+          if (gPrefs_current()->iDispBorders)
+          {
+            reg.r[1]=(int)&(w->def->i[i].i);
+            reg.r[0]=(int)r;
+            os_swix(XInterface_Plot3dIcon,&reg);
+          }
+          if (gPrefs_current()->wDispBorders)
+          {
+            reg.r[1]=(int)&(w->def->i[i].i);
+            reg.r[0]=0;
+            reg.r[2]=w->h;
+            os_swix(XWimpExt_PlotBorder,&reg);
+          }
+        }
+      }
+    }
+
+    /* --- Plot the actual icons on top of everything --- */
+
+    for (i=0;i<w->def->desc.w.nicons;i++) /* And then the icons            */
+    {
+      if (!(w->def->i[i].i.flags & wimp_IDELETED) &&
+          coords_boxesoverlap(&w->def->i[i].i.box,&r->g))
+        wimp_ploticon(&(w->def->i[i].i));
+    }
+
+    /* --- Now temporary things (drawn in XOR mode) --- *
+     *
+     * The actual order of these is not important, seeing as the XOR nicely
+     * over each other, and XOR as we all know is commutative.
+     */
+
+    /* --- Bodge the graphics box to fit in the selection boxen --- */
+
+    r->g.x0-=window__HANDLEWIDTH+8;
+    r->g.y0-=window__HANDLEWIDTH+8;
+    r->g.x1+=window__HANDLEWIDTH+8;
+    r->g.y1+=window__HANDLEWIDTH+8;
+
+    /* --- Draw select boxes --- */
+
+    for (i=0;i<w->def->desc.w.nicons;i++) /* Select boxes...               */
+    {
+      if (w->def->i[i].selected)
+      {
+        if (coords_boxesoverlap(&w->def->i[i].i.box,&r->g))
+          window__drawSelectBox(w,i,FALSE,r);
+      }
+    }
+
+    /* --- Any drag boxen --- */
+
+    if (window__qDragType()!=-1 && w==window__dragWind())
+    {
+      window__rotate(0);
+      window__dragCoords(&x,&y);
+      window__redrawDragBox(w,r,x,y);
+    }
+
+    /* --- Get more rectangles from the WIMP --- */
+
+    wimpt_noerr(wimp_get_rectangle(r,more)); /* Get next bit to draw       */
+  }
+}
+
+/*
+ * void window_redrawIcon(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Sets the WIMP up to call for a redraw of the spcified icon (i.e. it
+ *  uses Wimp_ForceRedraw).
+ *
+ * Parameters
+ *  glass_windPointer *w == pointer to the window owning the icon
+ *  int icon == the icon to redraw
+ */
+
+void window_redrawIcon(glass_windPointer *w,int icon)
+{
+  wimp_redrawstr r;
+  if (!w->h)
+    return;
+  r.w=w->h;
+  window__bound(&w->def->i[icon].i,&r.box,TRUE);
+  r.box.x0-=window__HANDLEWIDTH+4;
+  r.box.x1+=window__HANDLEWIDTH+4;
+  r.box.y0-=window__HANDLEWIDTH+4;
+  r.box.y1+=window__HANDLEWIDTH+4;
+  wimpt_noerr(wimp_force_redraw(&r));
+  if (w==window_selectionOwner() && icon==window__selectedIcon())
+    tearEdit_update(w,icon);
+  window__updateMenu(w);
+}
+
+/*
+ * void window__redrawGuide(glass_windPointer *w,int guide)
+ *
+ * Use
+ *  Forces a redraw of the specified guideline.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the guideline
+ *  int guide == the number of the guideline.
+ */
+
+void window__redrawGuide(glass_windPointer *w,int guide)
+{
+  wimp_wstate s;
+  wimp_redrawstr r;
+
+  /* --- Force a redraw of the guideline --- *
+   *
+   * We can't realistically use Wimp_UpdateWindow because the guidelines are
+   * drawn over by everything else.  So all we do is leave a bit of the
+   * window marked as invalid, and wait for the redraw event a bit later.
+   */
+
+  wimpt_noerr(wimp_get_wind_state(w->h,&s));
+  r.w=w->h;
+  if (w->guide[guide].horiz)
+  {
+    r.box.x0=s.o.x;
+    r.box.y0=w->guide[guide].coord;
+    r.box.x1=s.o.x+s.o.box.x1-s.o.box.x0;
+    r.box.y1=w->guide[guide].coord+wimpt_dy();
+  }
+  else
+  {
+    r.box.y1=s.o.y;
+    r.box.x0=w->guide[guide].coord;
+    r.box.y0=s.o.y-s.o.box.y1+s.o.box.y0;
+    r.box.x1=w->guide[guide].coord+wimpt_dx();
+  }
+  wimpt_noerr(wimp_force_redraw(&r));
+}
diff --git a/StraySrc/Glass/!Glass/c/wSelect b/StraySrc/Glass/!Glass/c/wSelect
new file mode 100644 (file)
index 0000000..624e006
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * wSelect.c
+ *
+ * Handling a selection in a template window
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "window.h"
+#include "_window.h"
+#include "intMsgs.h"
+#include "toolbox.h"
+#include "editIcon.h"
+#include "editWin.h"
+#include "indir.h"
+#include "align.h"
+#include "iconData.h"
+#include "tearEdit.h"
+
+
+
+/*----- Private variables -------------------------------------------------*/
+
+static glass_windPointer *window__selOwner;   /* The window that owns the  */
+                                 /* current selection.                     */
+static int window__selIcon=-1;   /* The main currently selected icon       */
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * void window__updateSelectBox(glass_windPointer *w,int icon,BOOL makesi)
+ *
+ * Use
+ *  Updates the select box around the specified icon.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number whose selection border we change
+ *  BOOL makesi == whether to change the border from main sel to normal sel
+ */
+
+static void window__updateSelectBox(glass_windPointer *w,
+                                    int icon,
+                                    BOOL makesi)
+{
+  wimp_redrawstr r;
+  BOOL more;
+
+  r.w=w->h;
+  window_boundingBox(w,icon,&r.box);
+  r.box.x0-=window__HANDLEWIDTH+16;
+  r.box.x1+=window__HANDLEWIDTH+16;
+  r.box.y0-=window__HANDLEWIDTH+16;
+  r.box.y1+=window__HANDLEWIDTH+16;
+  wimpt_noerr(wimp_update_wind(&r,&more));
+  while (more)
+  {
+    window__drawSelectBox(w,icon,makesi,&r);
+    wimpt_noerr(wimp_get_rectangle(&r,&more));
+  }
+}
+
+/*
+ * void window__select(glass_windPointer *w,int icon,BOOL sel)
+ *
+ * Use
+ *  Selects or deselects the given icon.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window we're talking about
+ *  int icon == the icon to select (or not)
+ *  BOOL sel == TRUE to select, FALSE to deslect
+ */
+
+void window__select(glass_windPointer *w,int icon,BOOL sel)
+{
+  /* --- Make sure there's something sensible to do --- */
+
+  if (icon==-1)
+    return;
+  if (w->def->i[icon].selected==sel)
+    return;
+  if (w->def->i[icon].i.flags & wimp_IDELETED)
+    return;
+
+  /* --- Update the selection counter --- */
+
+  if (sel)
+    w->selno++;
+  else
+    w->selno--;
+  w->def->i[icon].selected=sel;
+
+  /* --- In test mode you can't see the selection rectangles --- */
+
+#ifndef glass_DEMO
+  if (w->testMode)
+  {
+    if (icon==window__selIcon && w==window__selOwner && !sel)
+      window__selIcon=-1;
+    return;
+  }
+#endif
+
+  /* --- Draw the selection boxes around the icons --- *
+   *
+   * It doesn't matter whether we're drawing or undrawing -- seeing as we're
+   * using XOR plotting for the rectangles, and we know that the seleciton
+   * state has changed, we just draw the selection boxes straight over the
+   * top.
+   */
+
+  window__updateSelectBox(w,icon,FALSE);
+
+  if (icon==window__selIcon && w==window__selOwner && !sel)
+  {
+    window__selIcon=-1;
+    tearEdit_update(w,-1);
+  }
+}
+
+/*
+ * void window__setSelectedIcon(int i)
+ *
+ * Use
+ *  Makes the specified icon in the current selection owner highlighted.
+ *
+ * Parameters
+ *  int i == the icon number to highlight
+ */
+
+void window__setSelectedIcon(int i)
+{
+  int o=window__selIcon;
+
+  if (i==o)
+    return;
+
+  if (o!=-1)
+    window__updateSelectBox(window__selOwner,o,TRUE);
+
+  window__selIcon=i;
+
+  if (i!=-1)
+  {
+    if (window__selOwner->def->i[i].selected)
+      window__updateSelectBox(window__selOwner,i,TRUE);
+    else
+      window__select(window__selOwner,i,TRUE);
+  }
+  tearEdit_update(window__selOwner,i);
+}
+
+/*
+ * void window__setSelectedIconDeselecting(int i)
+ *
+ * Use
+ *  Sets up the currently selected icon, deselecting the old one.
+ *
+ * Parameters
+ *  int i == the new icon to select
+ */
+
+void window__setSelectedIconDeselecting(int i)
+{
+  int o=window__selIcon;
+
+  if (o==i)
+    return;
+  else if (o==-1 || i==-1)
+    window__setSelectedIcon(i);
+  else
+  {
+    /* --- To prevent flickering, we must do all the work here --- */
+
+    window__updateSelectBox(window__selOwner,o,FALSE);
+    window__selOwner->def->i[o].selected=FALSE;
+    window__selIcon=i;
+    if (window__selOwner->def->i[i].selected)
+      window__updateSelectBox(window__selOwner,i,TRUE);
+    else
+      window__updateSelectBox(window__selOwner,i,FALSE);
+    window__selOwner->def->i[i].selected=TRUE;
+    tearEdit_update(window__selOwner,i);
+  }
+}
+
+/*
+ * int window__lowestSelected(glass_windPointer *w)
+ *
+ * Use
+ *  Returns the selected icon with the lowest number in the specified window.
+ */
+
+int window__lowestSelected(glass_windPointer *w)
+{
+  int i;
+  for (i=0;i<w->def->desc.w.nicons;i++)
+  {
+    if (w->def->i[i].selected)
+      return (i);
+  }
+  return (-1);
+}
+
+/*
+ * void window__gainSelection(glass_windPointer *w)
+ *
+ * Use
+ *  Gives the specified window the input focus, tool and info bars, and the
+ *  selection.  If 0 is specified, then the tool bars are taken down, and no
+ *  selection is set.
+ *
+ * Parameters
+ *  glass_windPointer *w == the new selection owner
+ */
+
+void window__gainSelection(glass_windPointer *w)
+{
+  int i;
+  wimp_caretstr c;
+  if (w)
+  {
+    c.w=w->h;
+    c.i=-1;
+    c.x=w->def->desc.w.ex.x0-50;
+    c.y=0;
+    c.height=0x02000000;
+    c.index=-1;
+    wimpt_noerr(wimp_set_caret_pos(&c));
+  }
+  if (window__selOwner==w)
+    return;
+  if (w)
+    window__renumber(w,FALSE);
+  if (window__selOwner!=0)
+  {
+    for (i=0;i<window__selOwner->def->desc.w.nicons;i++)
+      window__select(window__selOwner,i,FALSE);
+    for (i=0;i<glass_GUIDELIMIT;i++)
+    {
+      if (window__selOwner->guide[i].selected)
+      {
+        window__selOwner->guide[i].selected=FALSE;
+        window__redrawGuide(window__selOwner,i);
+      }
+    }
+  }
+  window__selOwner=w;
+  window__moveToolbars(w);
+}
+
+/*
+ * glass_windPointer *window_selectionOwner(void)
+ *
+ * Use
+ *  Returns the window currently owning the selection.
+ */
+
+glass_windPointer *window_selectionOwner(void)
+{
+  return (window__selOwner);
+}
+
+/*
+ * int window__selectedIcon(void)
+ *
+ * Use
+ *  Returns the currently selected icon
+ */
+
+int window__selectedIcon(void)
+{
+  return (window__selIcon);
+}
+
+/*
+ * void window__renumberSelectedIcon(int nsel)
+ *
+ * Use
+ *  To be called when the selected icon is renumbered.
+ */
+
+void window__renumberSelectedIcon(int nsel)
+{
+  window__selIcon=nsel;
+  tearEdit_update(window__selOwner,window__selIcon);
+}
diff --git a/StraySrc/Glass/!Glass/c/wToolbars b/StraySrc/Glass/!Glass/c/wToolbars
new file mode 100644 (file)
index 0000000..5b6b6c8
--- /dev/null
@@ -0,0 +1,778 @@
+/*
+ * wToolbars.c
+ *
+ * Handling of the tool and info bars
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/interface.h"
+#include "steel/sculptrix.h"
+#include "steel/buttons.h"
+#include "steel/caretPtr.h"
+#include "steel/flex.h"
+#include "steel/akbd.h"
+#include "steel/coords.h"
+#include "steel/pointer.h"
+#include "steel/bbc.h"
+#include "steel/colourtran.h"
+#include "steel/font.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "tfile.h"
+#include "window.h"
+#include "_window.h"
+#include "intMsgs.h"
+#include "toolbox.h"
+#include "editIcon.h"
+#include "editWin.h"
+#include "indir.h"
+#include "align.h"
+#include "iconData.h"
+#include "tearEdit.h"
+
+/*----- Private variables -------------------------------------------------*/
+
+static dbox window__toolbar;     /* Dialogue box handle for the tool bar   */
+static dbox window__infobar;     /* Dialogue box handle for the info bar   */
+static window__infoWidth;        /* The natural width of the info bar      */
+static window__infoMax;          /* The maximum width of the info bar      */
+static int window__toolX=98;
+static int window__toolY=912;
+static int window__infoX=234;
+static int window__infoY=260;
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * void window__setToolBarPositions(wimp_openstr *o)
+ *
+ * Use
+ *  Displays the tool and info bars according to current settings etc.
+ *
+ * Parameters
+ *  wimp_openstr *o == the position of the selection owner window, or 0.
+ *    This is updated to put the window somewhere nice without flicker.
+ */
+
+void window__setToolBarPositions(wimp_openstr *o)
+{
+  wimp_wstate s;
+  wimp_wstate t;
+  wimp_redrawstr r;
+  int width;
+  int height;
+  int tgap,bgap,lgap,rgap;
+  glass_windPointer *w=window_selectionOwner();
+
+  /* --- More WindowManager cunningness --- *
+   *
+   * When you click on the scroll arrows, the Wimp decides it'd be a good
+   * plan to ask you to open the window behind *itself*.  This gets nobbled
+   * here, and so the whole window frame flickes disgustingly.  We bodge.
+   * We also try to do absolutely nothing if the window isn't going anywhere.
+   */
+
+  if (o &&
+      !wimpt_justChangedMode() &&
+     (o->behind==o->w ||
+       (!memcmp(&o->box,&w->def->desc.w.box,sizeof(wimp_box)) &&
+       o->behind==w->def->desc.w.behind)))
+  {
+    wimpt_noerr(wimp_open_wind(o));
+    return;
+  }
+
+  wimpt_noerr(wimp_get_wind_state(w->h,&t));
+  r.w=t.o.w;
+  wimpt_noerr(wimp_getwindowoutline(&r));
+  lgap=t.o.box.x0-r.box.x0;
+  rgap=r.box.x1-t.o.box.x1;
+  tgap=r.box.y1-t.o.box.y1;
+  bgap=t.o.box.y0-r.box.y0;
+  if (o)
+  {
+    t.o=*o;
+    if (o->behind==-2)
+    {
+      wimpt_noerr(wimp_open_wind(o));
+      wimpt_noerr(wimp_get_wind_state(w->h,&t));
+    }
+  }
+  if (window__infobar && !gPrefs_current()->iFloating)
+  {
+    if (t.o.behind==dbox_syshandle(window__infobar))
+    {
+      wimpt_noerr(wimp_get_wind_state(dbox_syshandle(window__infobar),&s));
+      t.o.behind=s.o.behind;
+    }
+  }
+  if (window__toolbar && !gPrefs_current()->tFloating)
+  {
+    if (t.o.behind==dbox_syshandle(window__toolbar))
+    {
+      wimpt_noerr(wimp_get_wind_state(dbox_syshandle(window__toolbar),&s));
+      t.o.behind=s.o.behind;
+    }
+  }
+  if (t.flags & wimp_WCLICK_TOGGLE && o)
+  {
+    wimpt_noerr(wimp_open_wind(o));
+    wimpt_noerr(wimp_get_wind_state(w->h,&t));
+  }
+
+  if (window__toolbar)
+  {
+    wimpt_noerr(wimp_get_wind_state(dbox_syshandle(window__toolbar),&s));
+    width=s.o.box.x1-s.o.box.x0;
+    height=s.o.box.y1-s.o.box.y0;
+    if (!gPrefs_current()->tFloating)
+    {
+      if (gPrefs_current()->tLeft)
+        s.o.box.x0=gPrefs_current()->tPosn.x-width+t.o.box.x0-lgap;
+      else
+        s.o.box.x0=gPrefs_current()->tPosn.x-width+t.o.box.x1+rgap;
+      s.o.box.x1=s.o.box.x0+width;
+      s.o.box.y1=gPrefs_current()->tPosn.y+t.o.box.y1+tgap-wimpt_dy();
+      s.o.box.y0=s.o.box.y1-height;
+      window__toolX=s.o.box.x1;
+      window__toolY=s.o.box.y1;
+      s.o.behind=t.o.behind;
+      t.o.behind=s.o.w;
+    }
+    else
+    {
+      s.o.box.x0=window__toolX-width;
+      s.o.box.x1=s.o.box.x0+width;
+      s.o.box.y1=window__toolY;
+      s.o.box.y0=s.o.box.y1-height;
+    }
+    win_adjustBox(&s.o);
+    wimpt_noerr(wimp_open_wind(&s.o));
+  }
+  if (window__infobar)
+  {
+    wimpt_noerr(wimp_get_wind_state(dbox_syshandle(window__infobar),&s));
+    height=s.o.box.y1-s.o.box.y0;
+    width=(w->renumber ? window__infoMax : window__infoWidth);
+    if (!gPrefs_current()->iFloating)
+    {
+      s.o.box.x0=gPrefs_current()->iPosn.x+t.o.box.x0-lgap+wimpt_dx();
+      s.o.box.x1=s.o.box.x0+width;
+      if (gPrefs_current()->iUnder)
+        s.o.box.y1=gPrefs_current()->iPosn.y+t.o.box.y0-bgap;
+      else
+        s.o.box.y1=gPrefs_current()->iPosn.y+t.o.box.y1+tgap;
+      s.o.box.y0=s.o.box.y1-height;
+      window__infoX=s.o.box.x0;
+      window__infoY=s.o.box.y1;
+      s.o.behind=t.o.behind;
+      t.o.behind=s.o.w;
+    }
+    else
+    {
+      s.o.box.x0=window__infoX;
+      s.o.box.x1=s.o.box.x0+width;
+      s.o.box.y1=window__infoY;
+      s.o.box.y0=s.o.box.y1-height;
+    }
+    win_adjustBox(&s.o);
+    wimpt_noerr(wimp_open_wind(&s.o));
+  }
+  if (o)
+  {
+    o->behind=t.o.behind;
+    wimpt_noerr(wimp_open_wind(o));
+  }
+}
+
+/*
+ * void window__updateInfoBar(void)
+ *
+ * Use
+ *  Updates the settings on the info bar.  If a setting hasn't changed, then
+ *  it isn't updated (reducing flicker).
+ *
+ * Parameters
+ *  BOOL force == whether to force an update of everything.
+ */
+
+void window__updateInfoBar(BOOL force)
+{
+  static int ox=-1;
+  static int oy=-1;
+  static glass_windPointer *ow;
+  static int oi=-2;
+  static int orenum=-1;
+  int x,y;
+  int ni;
+  glass_windPointer *wso=window_selectionOwner();
+  wimp_mousestr m;
+  unused(orenum);
+
+  if (force)
+  {
+    ox=-1;
+    oy=-1;
+    ow=0;
+    oi=-2;
+    orenum=-1;
+  }
+  if (!window__infobar)
+    return;
+  if (wso!=ow)
+    dbox_setfield(window__infobar,glass_IBWIND,"%s",wso->id);
+  ow=wso;
+  wimpt_noerr(wimp_get_point_info(&m));
+  x=ow->def->desc.w.box.x0-ow->def->desc.w.scx;
+  y=ow->def->desc.w.box.y1-ow->def->desc.w.scy;
+  m.x-=x;
+  m.y-=y;
+  if (m.w!=ow->h || m.i<-1)
+  {
+    m.x=-3;
+    m.y=-3;
+  }
+  if (m.x!=ox)
+  {
+    switch (m.x)
+    {
+      case -3:
+        dbox_setfield(window__infobar,glass_IBX,"");
+        break;
+      default:
+        dbox_setfield(window__infobar,glass_IBX,"%i",m.x);
+        break;
+    }
+  }
+  if (m.y!=oy)
+  {
+    switch (m.y)
+    {
+      case -3:
+        dbox_setfield(window__infobar,glass_IBY,"");
+        break;
+      default:
+        dbox_setfield(window__infobar,glass_IBY,"%i",m.y);
+        break;
+    }
+  }
+  ox=m.x;
+  oy=m.y;
+  if (m.x==-3)
+    ni=-3;
+#ifndef glass_DEMO
+  else if (wso->testMode)
+    ni=m.i;
+#endif
+  else
+  {
+    ni=window__pointerInfo(ow,-1,FALSE);
+    if (ni & window__ZONEMASK)
+      ni=-1;
+  }
+  if (ni!=oi)
+  {
+    switch (ni)
+    {
+      case -3:
+        dbox_setfield(window__infobar,glass_IBICON,"");
+        break;
+      case -1:
+        dbox_setfield(window__infobar,glass_IBICON,msgs_lookup("wdBACKG"));
+        break;
+      default:
+        dbox_setfield(window__infobar,glass_IBICON,"%i",ni);
+        break;
+    }
+    oi=ni;
+  }
+}
+
+/*
+ * BOOL window__toolRaw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles odd events for tool and info boxes (mainly moves - getting the
+ *  positioning right, updating the preferences entries and so on).
+ *
+ * Parameters
+ *  dbox d == the dialogue box handle
+ *  wimp_eventstr *e == the event that happened
+ *  void *handle == a pointer (ignored)
+ *
+ * Returns
+ *  TRUE if the event has been processed.
+ */
+
+static BOOL window__toolRaw(dbox d,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  wimp_wstate s;
+  wimp_wstate t;
+  wimp_redrawstr r;
+  int tgap,bgap,lgap,rgap;
+  BOOL more;
+  glass_windPointer *wso=window_selectionOwner();
+  unused(handle);
+
+  switch (e->e)
+  {
+    case wimp_EREDRAW:
+      if (d==window__infobar)
+      {
+        r.w=e->data.o.w;
+        wimpt_noerr(wimp_redraw_wind(&r,&more));
+        while (more)
+        {
+          wimp_setcolour(0x81);
+          bbc_clg();
+          sculptrix_redrawWindow(&r);
+          wimpt_noerr(wimp_get_rectangle(&r,&more));
+        }
+        handled=TRUE;
+      }
+      break;
+    case wimp_EOPEN:
+      if (wimpt_justChangedMode()) /* We've already moved them with the */
+      {                            /* main window, so the WIMP just messes */
+        handled=TRUE;              /* it all up */
+        break;
+      }
+      win_adjustBox(&e->data.o);
+      wimpt_noerr(wimp_get_wind_state(wso->h,&s));
+      r.w=s.o.w;
+      wimpt_noerr(wimp_getwindowoutline(&r));
+      lgap=s.o.box.x0-r.box.x0;
+      rgap=r.box.x1-s.o.box.x1;
+      tgap=r.box.y1-s.o.box.y1;
+      bgap=s.o.box.y0-r.box.y0;
+      wimpt_noerr(wimp_get_wind_state(e->data.o.w,&t));
+      if (d==window__toolbar)
+      {
+        if (!gPrefs_current()->tFloating)
+        {
+          gPrefs_current()->tLeft=abs(e->data.o.box.x1-s.o.box.x0)<
+                                   abs(e->data.o.box.x0-s.o.box.x1);
+          if (gPrefs_current()->tLeft)
+            gPrefs_current()->tPosn.x=e->data.o.box.x1-s.o.box.x0+lgap;
+          else
+            gPrefs_current()->tPosn.x=e->data.o.box.x1-s.o.box.x1-rgap;
+          gPrefs_current()->tPosn.y=e->data.o.box.y1-s.o.box.y1-tgap+
+                                                                  wimpt_dy();
+          e->data.o.behind=t.o.behind;
+        }
+        window__toolX=e->data.o.box.x1;
+        window__toolY=e->data.o.box.y1;
+      }
+      else if (d==window__infobar)
+      {
+        if (!gPrefs_current()->iFloating)
+        {
+          gPrefs_current()->iUnder=abs(e->data.o.box.y1-s.o.box.y0)<
+                                    abs(e->data.o.box.y0-s.o.box.y1);
+          gPrefs_current()->iPosn.x=e->data.o.box.x0-s.o.box.x0;
+          if (gPrefs_current()->iUnder)
+            gPrefs_current()->iPosn.y=e->data.o.box.y1-s.o.box.y0+bgap;
+          else
+            gPrefs_current()->iPosn.y=e->data.o.box.y1-s.o.box.y1-tgap;
+          e->data.o.behind=t.o.behind;
+        }
+        window__infoX=e->data.o.box.x0;
+        window__infoY=e->data.o.box.y1;
+      }
+      wimpt_noerr(wimp_open_wind(&e->data.o));
+      handled=TRUE;
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void window__infoEvents(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles events on the info bar.
+ *
+ * Parameters
+ *  dbox d == the dialogue box handle
+ *  dbox_field f == the event that happened
+ *  void *handle == a pointer (ignored)
+ */
+
+static void window__infoEvents(dbox d,dbox_field f,void *handle)
+{
+  wimp_dragstr dr;
+#ifndef glass_DEMO
+  glass_windPointer *wso=window_selectionOwner();
+#endif
+  unused(handle);
+
+  switch (f)
+  {
+    case glass_IBDRAG:
+      dr.window=dbox_syshandle(d);
+      dr.type=wimp_MOVE_WIND;
+      wimp_drag_box(&dr);
+      break;
+  #ifndef glass_DEMO
+    case glass_IBEDIT:
+      if (wso->testMode)
+        window__simMenu(wso,glass_TWMISC,glass_TWMTEST);
+      break;
+    case glass_IBTEST:
+      if (!wso->testMode)
+        window__simMenu(wso,glass_TWMISC,glass_TWMTEST);
+      break;
+  #endif
+    case dbox_HELP:
+      help_startHelp();
+      help_addLine(msgs_lookup("wdhIB"));
+      help_readFromIcon();
+      help_endHelp();
+      break;
+  }
+}
+
+/*
+ * void window__toolEvents(dbox d,dbox_field f,void *handle)
+ *
+ * Use
+ *  Handles events on the tool bar.
+ *
+ * Parameters
+ *  dbox d == the dialogue box handle
+ *  dbox_field f == the event that happened
+ *  void *handle == a pointer (ignored)
+ */
+
+static void window__toolEvents(dbox d,dbox_field f,void *handle)
+{
+  wimp_dragstr dr;
+  glass_windPointer *wso=window_selectionOwner();
+  static int hit1[]=
+  {
+    0,
+    glass_TWMISC,
+    glass_TWICON,
+    glass_TWSELECT,
+    glass_TWSELECT,
+    glass_TWMISC,
+    glass_TWSELECT,
+    glass_TWSELECT,
+  };
+  static int hit2[]=
+  {
+    0,
+    glass_TWMCLOSE,
+    glass_TWINEW,
+    glass_TWSDEL,
+    glass_TWSCOPY,
+    glass_TWMEDITWIN,
+    glass_TWSEDIT,
+    glass_TWSORDER,
+  };
+  unused(handle);
+
+  switch (f)
+  {
+    case glass_TBDRAG:
+      dr.window=dbox_syshandle(d);
+      dr.type=wimp_MOVE_WIND;
+      wimp_drag_box(&dr);
+      break;
+    case dbox_HELP:
+      help_startHelp();
+      help_addLine(msgs_lookup("wdhTB"));
+      help_readFromIcon();
+      help_endHelp();
+      break;
+    default:
+      if (f>=0 && f<=(sizeof(hit1)/sizeof(int)))
+      {
+        dbox_clickicon(d,f);
+        window__simMenu(wso,hit1[f],hit2[f]);
+        dbox_unclick();
+      }
+      break;
+  }
+}
+
+/*
+ * void window_updateToolbar(void)
+ *
+ * Use
+ *  Updates the display of toolbars as necessary in line with new
+ *  Preferences settings.  It is assumed that Preferences is intelligent
+ *  enough to only call this if something actually needs to be done!
+ */
+
+void window_updateToolbar(void)
+{
+  glass_windPointer *wso=window_selectionOwner();
+  if (!wso)         /* Nothing doing if no current window     */
+    return;
+  if (gPrefs_current()->tDisplay)
+  {
+    if (!window__toolbar)
+    {
+      window__toolbar=dbox_create("toolbar");
+      if (window__toolbar)
+      {
+        dbox_eventHandler(window__toolbar,window__toolEvents,0);
+        dbox_rawEventHandler(window__toolbar,window__toolRaw,0);
+      }
+    }
+  }
+  else
+  {
+    if (window__toolbar)
+      dbox_delete(window__toolbar);
+    window__toolbar=0;
+  }
+  if (gPrefs_current()->iDisplay)
+  {
+    if (!window__infobar)
+    {
+      window__infobar=dbox_create("infobar");
+      if (window__infobar)
+      {
+        dbox_eventHandler(window__infobar,window__infoEvents,0);
+        dbox_rawEventHandler(window__infobar,window__toolRaw,0);
+      #ifdef glass_DEMO
+        dbox_shadeicon(window__infobar,glass_IBEDIT,TRUE);
+        dbox_shadeicon(window__infobar,glass_IBTEST,TRUE);
+        dbox_selecticon(window__infobar,glass_IBEDIT,TRUE);
+        dbox_selecticon(window__infobar,glass_IBTEST,FALSE);
+      #else
+        dbox_selecticon(window__infobar,glass_IBEDIT,!wso->testMode);
+        dbox_selecticon(window__infobar, glass_IBTEST,wso->testMode);
+        dbox_shadeicon(window__infobar,glass_IBEDIT,wso->renumber);
+        dbox_shadeicon(window__infobar,glass_IBTEST,wso->renumber);
+      #endif
+        if (wso->renumber)
+        {
+          dbox_setfield(window__infobar,
+                        glass_IBRENUM,"%i",
+                        window__lowestSelected(wso));
+        }
+      }
+    }
+    window__updateInfoBar(TRUE);
+  }
+  else
+  {
+    if (window__infobar)
+      dbox_delete(window__infobar);
+    window__infobar=0;
+  }
+  window__setToolBarPositions(0);
+}
+
+/*
+ * void window__toggleRenumber(glass_windPointer *w)
+ *
+ * Use
+ *  Updates the info bar after entering or leaving renumber-mode.  w is
+ *  the currently selected window.
+ */
+
+void window__toggleRenumber(glass_windPointer *w)
+{
+  if (window__infobar)
+  {
+    if (w->renumber)
+    {
+      dbox_setfield(window__infobar,
+                    glass_IBRENUM,
+                    "%i",
+                    window__lowestSelected(w));
+    }
+
+  #ifndef glass_DEMO
+    dbox_shadeicon(window__infobar,glass_IBEDIT,w->renumber);
+    dbox_shadeicon(window__infobar,glass_IBTEST,w->renumber);
+  #else
+    dbox_shadeicon(window__infobar,glass_IBEDIT,TRUE);
+    dbox_shadeicon(window__infobar,glass_IBTEST,TRUE);
+  #endif
+
+    window__setToolBarPositions(0);
+  }
+}
+
+/*
+ * void window__toggleTest(glass_windPointer *w)
+ *
+ * Use
+ *  Updates the info bar after entering or leaving test-mode.  w is the
+ *  currently selected window.
+ */
+
+#ifndef glass_DEMO
+void window__toggleTest(glass_windPointer *w)
+{
+  if (window__infobar)
+  {
+    dbox_selecticon(window__infobar,glass_IBEDIT,!w->testMode);
+    dbox_selecticon(window__infobar,glass_IBTEST,w->testMode);
+  }
+}
+#endif
+
+/*
+ * void window__updateInfoName(char *newname)
+ *
+ * Use
+ *  Updates the name in the info bar
+ */
+
+void window__updateInfoName(char *newname)
+{
+  if (window__infobar)
+    dbox_setfield(window__infobar,glass_IBWIND,"%s",newname);
+}
+
+/*
+ * void window__nextRenumber(glass_windPointer *w)
+ *
+ * Use
+ *  Updates the next renumber icon number display.
+ */
+
+void window__nextRenumber(glass_windPointer *w)
+{
+  if (window__infobar)
+  {
+    dbox_setfield(window__infobar,glass_IBRENUM,"%i",
+                  window__lowestSelected(w));
+  }
+}
+
+/*
+ * void window__moveToolbars(glass_windPointer *w)
+ *
+ * Use
+ *  Moves the toolbars and attaches them to a new window
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to attach the bars to
+ */
+
+void window__moveToolbars(glass_windPointer *w)
+{
+  if (w)
+  {
+    if (!window__toolbar && gPrefs_current()->tDisplay)
+    {
+      window__toolbar=dbox_create("toolbar");
+      if (window__toolbar)
+      {
+        dbox_eventHandler(window__toolbar,window__toolEvents,0);
+        dbox_rawEventHandler(window__toolbar,window__toolRaw,0);
+      }
+    }
+    if (!window__infobar && gPrefs_current()->iDisplay)
+    {
+      window__infobar=dbox_create("infobar");
+      if (window__infobar)
+      {
+        dbox_eventHandler(window__infobar,window__infoEvents,0);
+        dbox_rawEventHandler(window__infobar,window__toolRaw,0);
+      }
+    }
+    window__updateInfoBar(TRUE);
+    window__setToolBarPositions(0);
+    if (window__infobar)
+    {
+    #ifdef glass_DEMO
+      dbox_shadeicon(window__infobar,glass_IBEDIT,TRUE);
+      dbox_shadeicon(window__infobar,glass_IBTEST,TRUE);
+      dbox_selecticon(window__infobar,glass_IBEDIT,TRUE);
+      dbox_selecticon(window__infobar,glass_IBTEST,FALSE);
+    #else
+      dbox_selecticon(window__infobar,glass_IBEDIT,!w->testMode);
+      dbox_selecticon(window__infobar,glass_IBTEST,w->testMode);
+      dbox_shadeicon(window__infobar,glass_IBEDIT,w->renumber);
+      dbox_shadeicon(window__infobar,glass_IBTEST,w->renumber);
+    #endif
+      if (w->renumber)
+      {
+        dbox_setfield(window__infobar,
+                      glass_IBRENUM,
+                      "%i",
+                      window__lowestSelected(w));
+      }
+    }
+  }
+  else
+  {
+    if (window__toolbar)
+      dbox_delete(window__toolbar);
+    if (window__infobar)
+      dbox_delete(window__infobar);
+    window__toolbar=0;
+    window__infobar=0;
+  }
+}
+
+/*
+ * void window__tbarInit(void)
+ *
+ * Use
+ *  Initialises the toolbar system
+ */
+
+void window__tbarInit(void)
+{
+  wimp_wind *wdef;
+  wdef=&template_find("infobar")->window;
+  window__infoWidth=wdef->box.x1-wdef->box.x0;
+  window__infoMax=wdef->ex.x1-wdef->ex.x0;
+}
diff --git a/StraySrc/Glass/!Glass/c/wWinEvent b/StraySrc/Glass/!Glass/c/wWinEvent
new file mode 100644 (file)
index 0000000..dcb851b
--- /dev/null
@@ -0,0 +1,930 @@
+/*
+ * wWinEvent.c
+ *
+ * Handling events for template windows
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/interface.h"
+#include "steel/sculptrix.h"
+#include "steel/caretPtr.h"
+#include "steel/akbd.h"
+#include "steel/bbc.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "gPrefs.h"
+#include "tfile.h"
+#include "window.h"
+#include "_window.h"
+#include "intMsgs.h"
+#include "toolbox.h"
+#include "editIcon.h"
+#include "editWin.h"
+#include "tearEdit.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * void window__winIdles(void *handle)
+ *
+ * Use
+ *  Changes the pointer shape to something appropriate for what its over.
+ *
+ * Parameters
+ *  void *handle == pointer to window containing pointer
+ */
+
+void window__winIdles(void *handle)
+{
+  glass_windPointer *w=handle;
+  int i=window__pointerInfo(w,-1,TRUE);
+#ifndef glass_DEMO
+  if (w->testMode)
+    i=window__SELECT;
+#endif
+  window__setPtrShape(i);
+  window__updateInfoBar(FALSE);
+}
+
+/*
+ * int window__keyAhead(int k,int *nk)
+ *
+ * Use
+ *  Counts how many times the given key k is pressed, and returns the next
+ *  key in *nk (or -1 if no next key).
+ *
+ * Parameters
+ *  int k == the key to check for
+ *  int *nk == where to store next key value
+ *
+ * Returns
+ *  Number of times key was buffered.
+ */
+
+static int window__keyAhead(int k,int *nk)
+{
+  int count=0;
+  *nk=k;
+  while (*nk==k)
+  {
+    count++;
+    if (!akbd_pollkey(nk))
+      *nk=-1;
+    else
+      *nk=akbd_translate(*nk);
+  }
+  return (count);
+}
+
+/*
+ * void window__testEvents(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles all events for windows running in Test mode.  Events handled
+ *  are:
+ *
+ *  Redraw   Redraws the window using Interface/hatch pattern as requested.
+ *  Open     Moves the window around.
+ *  Close    Closes the window(!)
+ *  Leave    Ignored
+ *  Enter    Turn off STEEL pointer changing
+ *  Click    Handled by WIMP or Interface, except for menu, which opens
+ *           the menu(!)
+ *  Key      Handled by WIMP, WimpExtension, or ignored
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event
+ *  void *handle == pointer to window info
+ */
+
+#ifndef glass_DEMO
+
+void window__testEvents(wimp_eventstr *e,void *handle)
+{
+  glass_windPointer *w=handle; /* Extract my data from the handle       */
+  wimp_wstate s;
+  int ox,oy;
+  wimp_redrawstr r;              /* For the redraw event                   */
+  BOOL more;                     /* To tell me when I've finished          */
+  wimp_w wnd;
+  os_regset reg;
+  wimp_icon icon;
+  sculptrix_slabDescriptor d;
+
+  switch (e->e)
+  {
+    case wimp_EREDRAW:
+      r.w=w->h;
+      wimpt_noerr(wimp_redraw_wind(&r,&more)); /* Start the redraw         */
+      window__redraw(w,&r,&more);
+      break;
+    case wimp_EOPEN:
+      if (e->data.o.x<=w->def->desc.w.scx &&
+          e->data.o.y>=w->def->desc.w.scy)
+      {
+        r.w=e->data.o.w;
+        r.box=w->tex;
+        if (tst(w->def->desc.w.flags,14))
+        {
+          r.box.x0=w->def->desc.w.ex.x0;
+          r.box.x1=max2(w->def->desc.w.ex.x1,e->data.o.x+e->data.o.box.x1-
+                                                         e->data.o.box.x0);
+        }
+        if (tst(w->def->desc.w.flags,15))
+        {
+          r.box.y1=w->def->desc.w.ex.y1;
+          r.box.y0=min2(w->def->desc.w.ex.y0,e->data.o.y-e->data.o.box.y1+
+                                                         e->data.o.box.y0);
+        }
+        if (memcmp(&r.box,&w->tex,sizeof(wimp_box)))
+        {
+          wimpt_noerr(wimp_set_extent(&r));
+          w->tex=r.box;
+        }
+      }
+
+      if (window_selectionOwner()==w)
+        window__setToolBarPositions(&e->data.o);
+      else
+        wimpt_noerr(wimp_open_wind(&e->data.o));
+      w->def->desc.w.box=e->data.o.box; /* Copy the information down       */
+      w->def->desc.w.scx=e->data.o.x;
+      w->def->desc.w.scy=e->data.o.y;
+      w->def->desc.w.behind=e->data.o.behind;
+      if (!w->t->alts)           /* Moving the window alters the template  */
+        tfile_markAsAltered(w->t); /* But only if not already altered      */
+      if (wimpt_justChangedMode() && w->antiAliased)
+      {
+        if (wnd=window__recreate(w),!wnd)
+          return;
+        win_register_event_handler(wnd,window__testEvents,w);
+        wimpt_noerr(wimp_get_wind_state(w->h,&s));
+        wimpt_noerr(wimp_delete_wind(w->h));
+        win_register_event_handler(w->h,0,0);
+        win_activedec();
+        w->h=wnd;
+        s.o.w=w->h;
+        wimpt_noerr(wimp_open_wind(&s.o));
+      }
+      break;
+    case wimp_ECLOSE:
+      window_close(w);
+      break;
+    case wimp_EBUT:
+      e=wimpt_last_event();      /* Get the real event                     */
+      switch (e->data.but.m.bbits)
+      {
+        case wimp_BMID:
+          if (gPrefs_current()->sSlabMenu && e->data.but.m.i!=-1)
+            sculptrix_slabIcon(e->data.but.m.w,e->data.but.m.i,&d);
+          if (gPrefs_current()->iSlabMenu && e->data.but.m.i!=-1)
+          {
+            wimpt_noerr(wimp_get_icon_info(w->h,e->data.but.m.i,&icon));
+            interface_slabButton(&e->data.but.m);
+          }
+          wimpt_noerr(wimp_get_wind_state(w->h,&s));
+          ox=s.o.box.x0-s.o.x;
+          oy=s.o.box.y1-s.o.y;
+          window__showMenu(e->data.but.m.x-ox,e->data.but.m.y-oy,w);
+          e->data.but.m.bbits=0;
+          if (gPrefs_current()->iSlabMenu && e->data.but.m.i!=-1)
+          {
+            interface_slabButton(&e->data.but.m);
+            if (icon.flags & wimp_IFONT)
+            {
+              wimpt_noerr(wimp_set_icon_state(w->h,
+                                              e->data.but.m.i,
+                                              icon.flags & 0xff000000,
+                                              0xff000000));
+            }
+          }
+          if (gPrefs_current()->sSlabMenu && e->data.but.m.i!=-1)
+            sculptrix_unslabIcon(&d);
+          break;
+        case wimp_BDRAGLEFT:
+        case wimp_BDRAGRIGHT:
+          break;
+        default:
+          if (gPrefs_current()->sSlabIcons && e->data.but.m.i!=-1)
+            sculptrix_slabIcon(e->data.but.m.w,e->data.but.m.i,&d);
+
+          if (gPrefs_current()->iSlabIcons && e->data.but.m.i!=-1)
+          {
+            wimpt_noerr(wimp_get_icon_info(w->h,e->data.but.m.i,&icon));
+            interface_slabButton(&e->data.but.m);
+            e->data.but.m.bbits=0;
+            interface_slabButton(&e->data.but.m);
+            if (icon.flags & wimp_IFONT)
+            {
+              wimpt_noerr(wimp_set_icon_state(w->h,
+                                              e->data.but.m.i,
+                                              icon.flags & 0xff000000,
+                                              0xff000000));
+            }
+          }
+
+          if (gPrefs_current()->sSlabIcons && e->data.but.m.i!=-1)
+            sculptrix_unslabIcon(&d);
+          break;
+      }
+      break;
+    case wimp_EPTRLEAVE:
+      w->ownPointer=FALSE;
+      win_removeIdleClaimer(window__winIdles,w);
+      window__updateInfoBar(FALSE);
+      window__setPtrShape(window__SELECT);
+      interface_spritearea((sprite_area *)1);
+      break;
+    case wimp_EPTRENTER:
+      w->ownPointer=TRUE;
+      win_addIdleClaimer(window__winIdles,win_DONTCARE,w);
+      caretPtr__pointer(FALSE); /* Don't change pointer in this window */
+      interface_spritearea(w->t->s);
+      break;
+    case wimp_EKEY:
+      if (gPrefs_current()->wKeyPress)
+      {
+        reg.r[0]=e->data.key.chcode;
+        reg.r[2]=w->h;
+        reg.r[3]=e->data.key.c.i;
+        os_swix(XWimpExt_MoveCaret,&reg);
+        if (reg.r[0])
+          wimpt_noerr(wimp_processkey(e->data.key.chcode));
+        else
+        {
+          reg.r[0]=2;
+          reg.r[2]=-1;
+          os_swix(XWimpExt_ViewIcon,&reg);
+
+          /* --- That may have moved the window, so... --- */
+
+          wimpt_noerr(wimp_get_wind_state(w->h,&s));
+          if (s.o.x!=w->def->desc.w.scx || s.o.y!=w->def->desc.w.scy)
+          {
+            w->def->desc.w.scx=s.o.x;
+            w->def->desc.w.scy=s.o.y;
+            if (!w->t->alts)
+              tfile_markAsAltered(w->t);
+          }
+        }
+      }
+      else
+        wimpt_noerr(wimp_processkey(e->data.key.chcode));
+      break;
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      window__events(e,w);
+      break;
+  }
+}
+
+#endif
+
+/*
+ * void window__events(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles all events for template windows (this is the first chance I've
+ *  had to get my fingers *REALLY* mucky on this whole project!)
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event that I am meant to be inerested in
+ *  void *handle == a pointer to the structural information for this window
+ */
+
+void window__events(wimp_eventstr *e,void *handle)
+{
+  glass_windPointer *w=handle;   /* Extract my data from the handle        */
+  wimp_redrawstr r;              /* For the redraw event                   */
+  BOOL more;                     /* To tell me when I've finished          */
+  int i;
+  int zone;
+  glass_intMsgstr *m;
+  wimp_wstate s;
+  wimp_w wnd;
+  wimp_caretstr c;
+  int ox=0,oy=0;
+  int set=FALSE;
+  wimp_box b;
+  BOOL started=FALSE;
+  static BOOL dontDrag;           /* Disable/ignore next drag event        */
+  glass_iconDescription icd;
+  wimp_box bound;
+  int dragType;
+  int key,okey;
+
+  switch (e->e)
+  {
+    case wimp_EREDRAW:
+      r.w=w->h;
+      wimpt_noerr(wimp_redraw_wind(&r,&more)); /* Start the redraw         */
+      window__redraw(w,&r,&more);
+      break;
+    case wimp_EOPEN:
+
+      /* --- Handle rubbery extents --- *
+       *
+       * We've got to make sure the window's not scrolling here, otherwise
+       * very strange things start happening.
+       */
+
+      if (e->data.o.x<=w->def->desc.w.scx &&
+          e->data.o.y>=w->def->desc.w.scy)
+      {
+        r.w=e->data.o.w;
+        r.box=w->tex;
+        if (tst(w->def->desc.w.flags,14))
+        {
+          r.box.x0=w->def->desc.w.ex.x0;
+          r.box.x1=max2(w->def->desc.w.ex.x1,e->data.o.x+e->data.o.box.x1-
+                                                         e->data.o.box.x0);
+        }
+        if (tst(w->def->desc.w.flags,15))
+        {
+          r.box.y1=w->def->desc.w.ex.y1;
+          r.box.y0=min2(w->def->desc.w.ex.y0,e->data.o.y-e->data.o.box.y1+
+                                                         e->data.o.box.y0);
+        }
+        if (memcmp(&r.box,&w->tex,sizeof(wimp_box)))
+        {
+          wimpt_noerr(wimp_set_extent(&r));
+          w->tex=r.box;
+        }
+      }
+
+      if (window_selectionOwner()==w)
+        window__setToolBarPositions(&e->data.o);
+      else
+        wimpt_noerr(wimp_open_wind(&e->data.o));
+      w->def->desc.w.box=e->data.o.box; /* Copy the information down       */
+      w->def->desc.w.scx=e->data.o.x;
+      w->def->desc.w.scy=e->data.o.y;
+      w->def->desc.w.behind=e->data.o.behind;
+      if (!w->t->alts)           /* Moving the window alters the template  */
+        tfile_markAsAltered(w->t); /* But only if not already altered      */
+      editWindow_windowMoved(w);
+      if (wimpt_justChangedMode() && w->antiAliased)
+      {
+        if (wnd=window__recreate(w),!wnd)
+          return;
+        win_register_event_handler(wnd,window__events,w);
+        wimpt_noerr(wimp_get_wind_state(w->h,&s));
+        wimpt_noerr(wimp_delete_wind(w->h));
+        win_register_event_handler(w->h,0,0);
+        win_activedec();
+        w->h=wnd;
+        s.o.w=w->h;
+        wimpt_noerr(wimp_open_wind(&s.o));
+      }
+      break;
+    case wimp_ECLOSE:
+      window_close(w);
+      break;
+    case wimp_EBUT:
+      if (window__qDragType()!=-1)
+        break;
+      switch (e->data.but.m.bbits)
+      {
+         case wimp_BMID:
+          wimpt_noerr(wimp_get_wind_state(w->h,&s));
+          ox=s.o.box.x0-s.o.x;
+          oy=s.o.box.y1-s.o.y;
+          window__showMenu(e->data.but.m.x-ox,e->data.but.m.y-oy,w);
+          break;
+        case wimp_BLEFT:
+          if (!(akbd_pollsh() && (w->lastClicked!=-1)) &&
+              !w->renumber &&
+              (!gPrefs_current()->mCtrlEdit || akbd_pollctl()))
+          {
+            i=window__pointerInfo(w,-1,TRUE);
+            if ((i & window__ZONEMASK)==window__HORGUIDE ||
+                (i & window__ZONEMASK)==window__VERGUIDE)
+              break;
+            if (i!=-1)
+              editIcon(w,i&window__ICONMASK);
+            else
+            {
+              i=window__pointerInfo(w,-1,FALSE);
+              if (i!=-1)
+                editIcon(w,i);
+              else
+                editWindow(w);
+            }
+            break;
+          }
+          /* Otherwise drop through to select... */
+        case wimp_BRIGHT:
+          /* Treat this as a normal click - drop to select */
+        case wimp_BCLICKLEFT:
+        case wimp_BCLICKRIGHT:
+
+          /* --- if we're in the toolbox, or grab mode, ignore click --- */
+
+          if (toolbox_toolSelected() || window_grabbing())
+          {
+            dontDrag=TRUE;      /* The WIMP gives a drag on grab sprites!  */
+            break;
+          }
+
+          /* --- give this window the selection, tool bars, and caret --- */
+
+          window__gainSelection(w);
+
+          /* --- special case for renumbering --- */
+
+          if (w->renumber)
+          {
+            i=window__pointerInfo(w,-1,FALSE);
+            if (!(i & window__ZONEMASK) && w->def->i[i].selected)
+            {
+              set=window__lowestSelected(w);
+              window__select(w,i,FALSE);
+              icd=w->def->i[i];
+              w->def->i[i]=w->def->i[set];
+              w->def->i[set]=icd;
+              window_redrawIcon(w,i);
+              window_redrawIcon(w,set);
+              tfile_markAsAltered(w->t);
+              if (w->selno)
+                window__nextRenumber(w);
+              else
+                window__renumber(w,FALSE);
+            }
+            window__updateMenu(w); /* May have changed focus */
+            break;
+          }
+
+          /* --- handle depthwise selection - no problem with guides --- */
+          /* --- because we know the pointer is over an icon --- */
+
+          if (akbd_pollsh() &&
+              w->lastClicked!=-1 &&
+              window__pointerOverIcon(w,w->lastClicked))
+          {
+            i=w->lastClicked;
+            w->lastClicked=window__pointerInfo(w,w->lastClicked,FALSE);
+            if (i!=w->lastClicked)
+            {
+              if (i==window__selectedIcon())
+                window__setSelectedIconDeselecting(w->lastClicked);
+              else
+              {
+                window__select(w,i,FALSE);
+                window__select(w,w->lastClicked,TRUE);
+              }
+            }
+            dontDrag=TRUE;
+            window__updateMenu(w);
+            break;
+          }
+
+          /* --- this is the complicated bit.  ADJUST should just --- */
+          /* --- toggle the object.  So do this, but remember, it --- */
+          /* --- could have been a double-click --- */
+
+          if (e->data.but.m.bbits==wimp_BCLICKRIGHT ||
+              e->data.but.m.bbits==wimp_BRIGHT)
+          {
+            i=window__pointerInfo(w,-1,FALSE);
+            if (i != -1 && (i & window__ZONEMASK)) {
+              i &= window__ICONMASK;
+              w->guide[i].selected=!w->guide[i].selected;
+              window__redrawGuide(w,i);
+              dontDrag=TRUE;
+            } else {
+              if (i!=-1)
+              {
+                window__select(w,i,!w->def->i[i].selected);
+                w->lastClicked=i;
+                dontDrag=TRUE;
+              }
+              else
+                dontDrag=FALSE;
+            }
+            window__updateMenu(w);
+            break;
+          }
+
+          /* --- now we're left with a SELECT click.  If this is the --- */
+          /* --- start of a drag, then ignore it, otherwise do normal --- */
+          /* --- SELECT-type things (deselecting other icons etc.) --- */
+
+          i=window__pointerInfo(w,-1,TRUE);
+          if (i==-1)
+          {
+            i=window__pointerInfo(w,-1,FALSE);
+            zone=-1;
+          }
+          else
+          {
+            zone=i & window__ZONEMASK;
+            i&=window__ICONMASK;
+          }
+          w->lastClicked=i;
+
+          switch (zone)
+          {
+            case -1:             /* Not previously selected                */
+              if (w->lastClicked!=-1)
+                window__setSelectedIconDeselecting(w->lastClicked);
+              for (i=0;i<w->def->desc.w.nicons;i++)
+              {
+                if (i!=w->lastClicked)
+                  window__select(w,i,FALSE);
+              }
+              dontDrag=FALSE;
+              break;
+            case window__HORGUIDE:
+            case window__VERGUIDE:
+              if (!w->guide[i].selected)
+              {
+                for (i=0;i<glass_GUIDELIMIT;i++)
+                {
+                  if (w->guide[i].selected)
+                  {
+                    w->guide[i].selected=FALSE;
+                    window__redrawGuide(w,i);
+                  }
+                }
+                w->guide[w->lastClicked].selected=TRUE;
+                window__redrawGuide(w,w->lastClicked);
+              }
+              dontDrag=FALSE;
+              break;
+            default:
+              /* --- Any other zones we ignore - these are for drag --- */
+              /* --- operations --- */
+              window__setSelectedIcon(w->lastClicked);
+              dontDrag=FALSE;
+              break;
+          }
+          window__updateMenu(w);
+          break;
+        case wimp_BDRAGLEFT:
+        case wimp_BDRAGRIGHT:
+          if (dontDrag ||
+              toolbox_toolSelected() ||
+              window_grabbing() ||
+              w->renumber)
+            break;
+
+          /* --- YARB -- Yet Another RISC OS Bug --- *
+           *
+           * In a terribly cunning way, the WIMP gives me drag events even
+           * when the mouse button is up and the user didn't drag at all.
+           * This is phenomenally irritating, and so, hi-ho, a bodging we
+           * will go...
+           */
+
+          bbc_mouse(0,0,&i,0);
+          if (!i)
+            return;
+
+          if (e->data.but.m.bbits==wimp_BDRAGLEFT)
+          {
+            i=window__pointerInfo(w,-1,TRUE);
+            if (i == -1)
+              dragType = window__SELECT;
+            else
+              dragType=i & window__ZONEMASK;
+          }
+          else
+            dragType=window__SELECT;
+          switch (dragType)
+          {
+            case window__SELECT:
+            case window__HORGUIDE:
+            case window__VERGUIDE:
+              break;
+            default:
+              for (i=0;i<w->def->desc.w.nicons;i++)
+              {
+                if (w->def->i[i].selected)
+                {
+                  window_boundingBox(w,i,&b);
+                  if (!started)
+                  {
+                    bound=b;
+                    started=TRUE;
+                  }
+                  else
+                  {
+                    if (bound.x0>b.x0)
+                      bound.x0=b.x0;
+                    if (bound.x1<b.x1)
+                      bound.x1=b.x1;
+                    if (bound.y0>b.y0)
+                      bound.y0=b.y0;
+                    if (bound.y1<b.y1)
+                      bound.y1=b.y1;
+                  }
+                }
+              }
+              bound.x1-=wimpt_dx();
+              bound.y1-=wimpt_dy();
+              break;
+          }
+          wimpt_noerr(wimp_get_wind_state(w->h,&s));
+          ox=s.o.box.x0-s.o.x;
+          oy=s.o.box.y1-s.o.y;
+          window__startDrag(dragType,
+                            &bound,
+                            w,
+                            e->data.but.m.x-ox,
+                            e->data.but.m.y-oy);
+          break;
+      }
+      break;
+    case wimp_EPTRLEAVE:
+      w->ownPointer=FALSE;
+      win_removeIdleClaimer(window__winIdles,w);
+      window__updateInfoBar(FALSE);
+      window__setPtrShape(window__SELECT);
+      break;
+    case wimp_EPTRENTER:
+      w->ownPointer=TRUE;
+      win_addIdleClaimer(window__winIdles,win_DONTCARE,w);
+      if (window__qDragType()==window__GRABICON && !window__dragWind())
+        window__setDragWind(w);
+      break;
+    case wimp_EKEY:
+      key=akbd_translate(e->data.key.chcode);
+      while (key!=-1)
+      {
+        okey=key;
+        key=-1;
+        switch (okey)
+        {
+
+          /* --- Normal short-cuts, simulate menu entries --- */
+
+          case key_cF1:
+            window__simMenu(w,glass_TWMISC,glass_TWMINFO);
+            break;
+          case key_cW:
+            window__simMenu(w,glass_TWMISC,glass_TWMEDITWIN);
+            break;
+          case key_cT:
+            window__simMenu(w,glass_TWMISC,glass_TWMTEST);
+            break;
+          case key_cF2:
+            window__simMenu(w,glass_TWMISC,glass_TWMCLOSE);
+            break;
+          case key_F3:
+            window__simMenu(w,glass_TWSAVE,0);
+            break;
+          case key_cA:
+            window__simMenu(w,glass_TWSELECT,glass_TWSALL);
+            break;
+          case key_cZ:
+            window__simMenu(w,glass_TWSELECT,glass_TWSCLR);
+            break;
+          case key_cC:
+            window__simMenu(w,glass_TWSELECT,glass_TWSCOPY);
+            break;
+          case key_cX:
+            window__simMenu(w,glass_TWSELECT,glass_TWSDEL);
+            break;
+          case key_cR:
+            window__simMenu(w,glass_TWSELECT,glass_TWSORDER);
+            break;
+          case key_scF:
+            window__simMenu(w,glass_TWSELECT,glass_TWSFRONT);
+            break;
+          case key_cF:
+            window__simMenu(w,glass_TWSELECT,glass_TWSRAISE);
+            break;
+          case key_cB:
+            window__simMenu(w,glass_TWSELECT,glass_TWSLOWER);
+            break;
+          case key_scB:
+            window__simMenu(w,glass_TWSELECT,glass_TWSBACK);
+            break;
+          case key_cP:
+            window__simMenu(w,glass_TWSELECT,glass_TWSPULL);
+            break;
+          case key_cL:
+            window__simMenu(w,glass_TWSELECT,glass_TWSALIGN);
+            break;
+          case key_scE:
+            tearEdit_open();
+            break;
+          case key_cE:
+            window__simMenu(w,glass_TWSELECT,glass_TWSEDIT);
+            break;
+        #ifdef glass_NOTLAZY
+          case key_cD:
+            window__simMenu(w,glass_TWSELECT,glass_TWSDATA);
+            break;
+        #endif
+          case key_cN:
+            window__simMenu(w,glass_TWICON,glass_TWINEW);
+            break;
+          case key_cG:
+            window__simMenu(w,glass_TWICON,glass_TWIGRAB);
+            break;
+
+          /* --- Cursor keys -- move icons around --- */
+
+          /* No modifiers -- move the whole icon */
+
+          case key_Up:
+            b.y0=b.y1=window__keyAhead(okey,&key);
+            b.x0=b.x1=0;
+            window__nudgeIcons(w,&b);
+            break;
+          case key_Down:
+            b.y0=b.y1=-window__keyAhead(okey,&key);
+            b.x0=b.x1=0;
+            window__nudgeIcons(w,&b);
+            break;
+          case key_Left:
+            b.y0=b.y1=0;
+            b.x0=b.x1=-window__keyAhead(okey,&key);
+            window__nudgeIcons(w,&b);
+            break;
+          case key_Right:
+            b.y0=b.y1=0;
+            b.x0=b.x1=window__keyAhead(okey,&key);
+            window__nudgeIcons(w,&b);
+            break;
+
+          /* Control pressed -- move the most significant edge */
+
+          case key_cUp:
+            b.y1=window__keyAhead(okey,&key);
+            b.x0=b.x1=b.y0=0;
+            window__nudgeIcons(w,&b);
+            break;
+          case key_cDown:
+            b.y1=-window__keyAhead(okey,&key);
+            b.x0=b.x1=b.y0=0;
+            window__nudgeIcons(w,&b);
+            break;
+          case key_cLeft:
+            b.x1=-window__keyAhead(okey,&key);
+            b.y0=b.y1=b.x0=0;
+            window__nudgeIcons(w,&b);
+            break;
+          case key_cRight:
+            b.x1=window__keyAhead(okey,&key);
+            b.y0=b.y1=b.x0=0;
+            window__nudgeIcons(w,&b);
+            break;
+
+          /* Shift pressed -- move the least significant edge */
+
+          case key_sUp:
+            b.y0=window__keyAhead(okey,&key);
+            b.x0=b.x1=b.y1=0;
+            window__nudgeIcons(w,&b);
+            break;
+          case key_sDown:
+            b.y0=-window__keyAhead(okey,&key);
+            b.x0=b.x1=b.y1=0;
+            window__nudgeIcons(w,&b);
+            break;
+          case key_sLeft:
+            b.x0=-window__keyAhead(okey,&key);
+            b.y0=b.y1=b.x1=0;
+            window__nudgeIcons(w,&b);
+            break;
+          case key_sRight:
+            b.x0=window__keyAhead(okey,&key);
+            b.y0=b.y1=b.x1=0;
+            window__nudgeIcons(w,&b);
+            break;
+
+          /* Shift and control pressed -- scroll the window --- */
+
+          case key_scUp:
+            window__nudgeScroll(w,0,window__keyAhead(okey,&key));
+            break;
+          case key_scDown:
+            window__nudgeScroll(w,0,-window__keyAhead(okey,&key));
+            break;
+          case key_scLeft:
+            window__nudgeScroll(w,-window__keyAhead(okey,&key),0);
+            break;
+          case key_scRight:
+            window__nudgeScroll(w,window__keyAhead(okey,&key),0);
+            break;
+
+          /* --- No match -- pass on keypress --- */
+
+          default:
+            wimp_processkey(e->data.key.chcode);
+            break;
+        }
+      }
+      break;
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MHELPREQUEST:
+          help_startHelp();
+          help_addLine(msgs_lookup("wdhWIN"),w->id);
+          if (i=window__pointerInfo(w,-1,FALSE),i!=-1)
+            help_addLine(msgs_lookup("wdhICN"),i);
+          else
+            help_addLine(msgs_lookup("wdhBKG"));
+          help_endHelp();
+          break;
+        case wimp_MINTERNAL:
+          m=intMsgs_receive(e);
+          switch (e->data.msg.data.words[0])
+          {
+            case glass_REDRAW:
+              if (m->rdr.t==w->t || m->rdr.t==0)
+              {
+                wimpt_noerr(wimp_get_wind_state(w->h,&s));
+                r.w=w->h;
+                r.box.x0=s.o.x;
+                r.box.x1=r.box.x0+s.o.box.x1-s.o.box.x0;
+                r.box.y1=s.o.y;
+                r.box.y0=r.box.y1+s.o.box.y0-s.o.box.y1;
+                wimpt_noerr(wimp_force_redraw(&r));
+              }
+              break;
+            case glass_RENAME:
+              if (m->rn.w==w && w==window_selectionOwner())
+                window__updateInfoName(w->id);
+              break;
+            case glass_SPRITECHANGE:
+              if (m->sc.t==w->t)
+              {
+                wimpt_noerr(wimp_get_caret_pos(&c));
+                if (wnd=window__recreate(w),!wnd)
+                  return;
+                if (c.w==w->h)
+                  c.w=wnd;
+              #ifndef glass_DEMO
+                win_register_event_handler(wnd,
+                        w->testMode ? window__testEvents : window__events,w);
+              #else
+                win_register_event_handler(wnd,window__events,w);
+              #endif
+                wimpt_noerr(wimp_get_wind_state(w->h,&s));
+                wimpt_noerr(wimp_delete_wind(w->h));
+                win_register_event_handler(w->h,0,0);
+                win_activedec();
+                w->h=wnd;
+                s.o.w=w->h;
+                wimpt_noerr(wimp_open_wind(&s.o));
+                if (c.w==wnd)
+                  wimp_set_caret_pos(&c);
+              }
+              break;
+          }
+          break;
+      }
+      break;
+  }
+}
diff --git a/StraySrc/Glass/!Glass/c/wWindows b/StraySrc/Glass/!Glass/c/wWindows
new file mode 100644 (file)
index 0000000..b73d361
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * wWindows.c
+ *
+ * Manipulation of template windows
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * Steel headers
+ */
+
+#define _STDAPP
+#define _LOWLVL
+#include "steel/Steel.h"
+
+#include "steel/flex.h"
+
+/*
+ * Glass headers
+ */
+
+#include "gStruct.h"
+#include "gMenus.h"
+#include "gIcons.h"
+
+#include "glass.h"
+#include "tfile.h"
+#include "window.h"
+#include "_window.h"
+#include "editWin.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * wimp_w window__recreate(glass_windPointer *w)
+ *
+ * Use
+ *  Recreates a window, getting all the fiddly bits right.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window
+ *
+ * Returns
+ *  The window handle, or 0 for failure
+ */
+
+wimp_w window__recreate(glass_windPointer *w)
+{
+  wimp_iconflags icf;
+  wimp_w wh;
+  int i;
+
+  /* --- Update all the sprite areas for the title bar and icons --- */
+
+  icf=w->def->desc.w.titleflags;
+  if ((icf & wimp_INDIRECT) && (icf & wimp_ISPRITE) && !(icf & wimp_ITEXT))
+    w->def->desc.w.title.indirectsprite.spritearea=w->t->s;
+  for (i=0;i<w->def->desc.w.nicons;i++)
+  {
+    icf=w->def->i[i].i.flags;
+    if ((icf & wimp_INDIRECT) && (icf & wimp_ISPRITE) && !(icf & wimp_ITEXT))
+      w->def->i[i].i.data.indirectsprite.spritearea=w->t->s;
+  }
+
+  /* --- If we're in test mode, allocate space for all the icons --- */
+
+#ifndef glass_DEMO
+  if (w->testMode)
+  {
+    wimp_wind *wp;
+    wimp_icon *ip;
+
+    if (!flex_alloc((flex_ptr)&wp,
+                    sizeof(wimp_wind)+
+                    w->def->desc.w.nicons*sizeof(wimp_icon)))
+      return (0);
+
+    /* --- Copy the window data across from our main structure --- */
+
+    *wp=w->def->desc.w;
+    ip=(wimp_icon *)(wp+1);
+    for (i=0;i<w->def->desc.w.nicons;i++)
+      ip[i]=w->def->i[i].i;
+    wp->spritearea=w->t->s;
+
+    /* --- Mangle the flags a little --- */
+
+    wp->flags&=~wimp_WPANE;     /* Strange things occur if we don't...    */
+    wp->flags&=~wimp_BACK_WINDOW; /* Don't let Pinboard hide my windows   */
+    wp->flags&=~wimp_HOT_KEYS;  /* Don't grab hot keys -- no use for them */
+
+    /* --- Bodge the window extent --- *
+     *
+     * Since the visible area can now `stretch' the window extent, we may
+     * need to bodge the extent for a bit
+     */
+
+    wp->ex.x1=max2(wp->ex.x1,wp->scx+wp->box.x1-wp->box.x0);
+    wp->ex.y0=min2(wp->ex.y0,wp->scy-wp->box.y1+wp->box.y0);
+    w->tex=wp->ex;
+
+    /* --- Try to create the window --- */
+
+    if (wimpt_complain(wimp_create_wind(wp,&wh)))
+    {
+      flex_free((flex_ptr)&wp);
+      return (0);
+    }
+    flex_free((flex_ptr)&wp);
+
+    /* --- Bodge for WimpExtension being buggy --- *
+     *
+     * WimpExtension doesn't accept NULL-terminated strings for all its
+     * validation strings, so we have to go through them all and return-
+     * terminate them :-(.  Hopefully we won't have to do this when
+     * WimpExtension II is ready.
+     */
+
+  #ifndef window__WimpExtension_works_with_null_terminated_strings
+    for (i=0;i<w->def->desc.w.nicons;i++)
+    {
+      if ( (w->def->i[i].i.flags & wimp_INDIRECT) &&
+           (w->def->i[i].i.flags & wimp_ITEXT) &&
+           (w->def->i[i].i.data.indirecttext.validstring!=(char *)-1) )
+      {
+        char *j;
+        for (j=w->def->i[i].i.data.indirecttext.validstring;*j>=32;j++)
+          /* thing */;
+        *j=0x0d;
+      }
+    }
+  #endif
+
+  }
+  else
+#endif
+
+  /* --- We're creating the window for editing -- don't make icons --- */
+
+  {
+    wimp_wind wdef;
+
+    wdef=w->def->desc.w;
+
+    wdef.ex.x1=max2(wdef.ex.x1,wdef.scx+wdef.box.x1-wdef.box.x0);
+    wdef.ex.y0=min2(wdef.ex.y0,wdef.scy-wdef.box.y1+wdef.box.y0);
+    w->tex=wdef.ex;
+
+    wdef.nicons=0;               /* We draw the icons ourselves            */
+    wdef.spritearea=w->t->s;     /* Set up sprite area                     */
+    wdef.workflags=wimp_BCLICKDRAGDOUBLE<<12;
+    wdef.flags|=wimp_WMOVEABLE;  /* Make window movable (Acorn karnt spel) */
+    wdef.flags&=~wimp_REDRAW_OK; /* We need to draw the icons!             */
+    wdef.flags&=~wimp_WPANE;     /* Show the highlight on the actual window*/
+    wdef.flags&=~wimp_BACK_WINDOW; /* Let it come to the front nicely      */
+    wdef.flags&=~wimp_HOT_KEYS;  /* Don't grab hot keys -- no use for them */
+    if (wimpt_complain(wimp_create_wind(&wdef,&wh)))
+      return(0);                 /* Don't be too unhappy if it failed      */
+  }
+
+  win_activeinc();               /* Pointless convention, but there you go */
+  return (wh);
+}
+
+/*
+ * void window__nudgeScroll(glass_windPointer *w,int x,int y)
+ *
+ * Use
+ *  Scrolls the window a bit, by adding the x and y values given to the
+ *  scroll offsets of the window.  The values are multiplied up to give a
+ *  sensible sized scroll.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to scroll
+ *  int x == the x scroll offset to add
+ *  int y == the y scroll offset to add
+ */
+
+void window__nudgeScroll(glass_windPointer *w,int x,int y)
+{
+  wimp_wstate s;
+
+  /* --- Scroll the window --- */
+
+  wimpt_noerr(wimp_get_wind_state(w->h,&s));
+  s.o.x+=x*32;
+  s.o.y+=y*32;
+  wimpt_noerr(wimp_open_wind(&s.o));
+  wimpt_noerr(wimp_get_wind_state(w->h,&s));
+
+  /* --- Write the new scroll values back to the window block --- */
+
+  if (s.o.x!=w->def->desc.w.scx || s.o.y!=w->def->desc.w.scy)
+  {
+    w->def->desc.w.scx=s.o.x;
+    w->def->desc.w.scy=s.o.y;
+    if (!w->t->alts)             /* Moving the window alters the template  */
+      tfile_markAsAltered(w->t); /* But only if not already altered        */
+    editWindow_windowMoved(w);
+  }
+}
+
+/*
+ * void window_hasBeenDeleted(glass_windPointer *w)
+ *
+ * Use
+ *  Informs the window system that a window is about to be deleted.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window that bites the dust
+ */
+
+void window_hasBeenDeleted(glass_windPointer *w)
+{
+  if (window_selectionOwner()==w)
+    window__gainSelection(0);
+  if (window__menuOwner()==w)
+    window__updateMenu(0);
+  if (w->ownPointer)
+  {
+    win_removeIdleClaimer(window__winIdles,w);
+    window__setPtrShape(window__SELECT);
+  }
+}
+
+/*
+ * void window_recreate(glass_windPointer *w)
+ *
+ * Use
+ *  Recreates a window after editing.  Nothing happens if the window is not
+ *  open already.  If an error occurs, the open window is removed and left
+ *  that way.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to recreate
+ */
+
+void window_recreate(glass_windPointer *w)
+{
+  wimp_wstate s;
+  wimp_w wnd;
+  if (!w->h)
+    return;
+  wimpt_noerr(wimp_get_wind_state(w->h,&s));
+  wimpt_noerr(wimp_delete_wind(w->h));
+  win_register_event_handler(w->h,0,0);
+  win_activedec();
+  if (wnd=window__recreate(w),!wnd)
+    return;
+  win_register_event_handler(wnd,window__events,w);
+  w->h=wnd;
+  s.o.w=w->h;
+  wimpt_noerr(wimp_open_wind(&s.o));
+  window_updateToolbar();
+}
+
+/*
+ * void window_close(glass_windPointer *w)
+ *
+ * Use
+ *  Closes the specified window.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window wot we 'ave to close
+ */
+
+void window_close(glass_windPointer *w)
+{
+#ifndef glass_DEMO
+  int i;
+  wimp_icon icn;
+#endif
+
+  wimpt_noerr(wimp_close_wind(w->h)); /* Closed, guv'nor                   */
+  if (window_selectionOwner()==w)
+    window__gainSelection(0);
+
+#ifndef glass_DEMO
+  if (w->testMode)
+  {
+    for (i=0;i<w->def->desc.w.nicons;i++)
+    {
+      wimpt_noerr(wimp_get_icon_info(w->h,i,&icn));
+      if (memcmp(&icn,&w->def->i[i].i,sizeof(wimp_icon)))
+      {
+        tfile_markAsAltered(w->t);
+        w->def->i[i].i=icn;
+      }
+    }
+  }
+  else
+#endif
+
+  if (w->ownPointer)
+  {
+    win_removeIdleClaimer(window__winIdles,w);
+    window__setPtrShape(window__SELECT);
+  }
+  win_register_event_handler(w->h,0,0); /* Window won't need this now      */
+  wimpt_noerr(wimp_delete_wind(w->h)); /* Delete the window                */
+  w->h=0;                        /* Make sure nobody does anything stupid  */
+
+  if (window__menuOwner()==w)
+    window__updateMenu(0);
+}
+
+/*
+ * void window_open(glass_windPointer *w,BOOL test)
+ *
+ * Use
+ *  Opens the specified window.  If the window is off-screen, it is moved
+ *  back.  This routine also registers all handlers required for editing the
+ *  window etc.  If the window is already open, it is brought to the front.
+ *
+ * Parameters
+ *  glass_windPointer *w == pointer to basic window information.
+ *  BOOL test == open in test mode or not
+ */
+
+void window_open(glass_windPointer *w,BOOL test)
+{
+  wimp_wstate s;
+  int i;
+
+  /* --- Create the window if it doesn't exist yet --- */
+
+  if (!w->h)
+  {
+    /* --- Allow tfile to set the test flag --- */
+
+  #ifndef glass_DEMO
+    w->testMode=test;
+  #else
+    unused(test);
+  #endif
+
+    /* --- Unselect all the window's icons and guides --- */
+
+    for (i=0;i<w->def->desc.w.nicons;i++)
+    {
+      w->def->i[i].selected=FALSE;
+      w->def->i[i].copied=FALSE;
+    }
+
+    for (i=0;i<glass_GUIDELIMIT;i++)
+      w->guide[i].selected=FALSE;
+    w->lastClicked=-1;
+    w->selno=0;
+    w->ownPointer=FALSE;
+    w->renumber=FALSE;
+
+    /* --- Finally, create the window and attach the event handler --- */
+
+    if (w->h=window__recreate(w),!w->h)
+      return;
+  #ifndef glass_DEMO
+    if (test)
+      win_register_event_handler(w->h,window__testEvents,w);
+    else
+  #endif
+      win_register_event_handler(w->h,window__events,w);
+  }
+  /* --- Now we can open the window --- */
+
+  wimpt_noerr(wimp_get_wind_state(w->h,&s));
+  s.o.behind=-1;                 /* Open the window on top of the screen   */
+  win_adjustBox(&s.o);           /* Make sure it goes on the screen!       */
+  wimpt_noerr(wimp_open_wind(&s.o)); /* Go!                                */
+  wimpt_noerr(wimp_get_wind_state(w->h,&s)); /* Find out where it went     */
+  w->def->desc.w.box=s.o.box;
+  w->def->desc.w.scx=s.o.x;
+  w->def->desc.w.scy=s.o.y;
+  w->def->desc.w.behind=s.o.behind;
+  editWindow_windowMoved(w);
+  if (window_selectionOwner()==w)
+    window_updateToolbar();
+}
diff --git a/StraySrc/Glass/!Glass/c/window b/StraySrc/Glass/!Glass/c/window
new file mode 100644 (file)
index 0000000..3453a23
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * window.c
+ *
+ * Manipulation of window templates
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*
+ * ANSI standard headers
+ */
+
+/*
+ * Steel headers
+ */
+
+/*
+ * Glass headers
+ */
+
+#include "window.h"
+#include "_window.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * void window_init(void)
+ *
+ * Use
+ *  Reads the default template file and ceates the menu etc.
+ */
+
+void window_init(void)
+{
+  window__menuInit();
+  window__tbarInit();
+}
diff --git a/StraySrc/Glass/!Glass/h/_window b/StraySrc/Glass/!Glass/h/_window
new file mode 100644 (file)
index 0000000..b03849f
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ * _window.h
+ *
+ * Private window definitions
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ___window_h
+#define ___window_h
+
+#ifndef __gPrefs_h
+  #include "gPrefs.h"
+#endif
+
+#ifndef __gStruct
+  #include "gStruct.h"
+#endif
+
+/*----- Common macros -----------------------------------------------------*/
+
+/*
+ * Macros describing parts of icons (as returned by window__pointerInfo)
+ */
+
+/*
+ * These have been redefined to be a bitfield (24/5/93):
+ * And then re-redefined to be a different bitfield (3/2/98):
+ *
+ *  bit 24 set == drag moves top of icon
+ *  bit 25 set == drag moves bottom of icon
+ *  bit 26 set == drag moves left of icon
+ *  bit 27 set == drag moves right of icon
+ *
+ * The values 3, b and c are not defined - They may be used for future
+ *  expansion, but I doubt it somehow.  d and e are used to describe
+ *  guidelines - the magic number is ORred with the guide number.
+ */
+
+#define window__TOP         0x01000000 /* The top edge drag box            */
+#define window__BOTTOM      0x02000000 /* The bottom edge drag box         */
+#define window__LEFT        0x04000000 /* The left edge drag box           */
+#define window__RIGHT       0x08000000 /* The right edge drag box          */
+#define window__MAIN        0x0f000000 /* The main part of the icon        */
+#define window__TOPLEFT     0x05000000 /* The top left corner drag box     */
+#define window__TOPRIGHT    0x09000000 /* The top right corner drag box    */
+#define window__BOTTOMLEFT  0x06000000 /* The bottom left corner drag box  */
+#define window__BOTTOMRIGHT 0x0a000000 /* The bottom right corner drag box */
+
+#define window__HORGUIDE    0x0d000000 /* A horizontal guide               */
+#define window__VERGUIDE    0x0e000000 /* A vertical guide                 */
+#define window__GRABICON    0x07000000 /* This is a drag of a grabbed icon */
+#define window__SELECT      0x00000000 /* This is a drag to select icons   */
+
+#define window__ZONEMASK    0x0F000000 /* Mask for drag zones              */
+#define window__ICONMASK    0x00FFFFFF /* Mask for icon numbers            */
+
+/*
+ * Colours for things
+ */
+
+#define window__SELBOXCOL (gPrefs_current()->sBColour)
+#define window__HANDCOL (gPrefs_current()->sHColour)
+#define window__MSELBOXCOL (gPrefs_current()->sSColour)
+#define window__DRAGCOL 0x0b
+#define window__GUIDECOL (gPrefs_current()->gGdeCol)
+#define window__GDESELCOL (gPrefs_current()->gGdeSelCol)
+
+/*
+ * Other things
+ */
+
+#define window__HANDLEWIDTH gPrefs_current()->sHandSize
+#define window__SNAPDIST 16
+#define window__DRAGTIME 0
+
+#define max2(a,b) ((a)>(b) ? (a) : (b))
+#define min2(a,b) ((a)<(b) ? (a) : (b))
+
+/*----- Low level graphics handling ---------------------------------------*/
+
+/*
+ * void window__colourChange(int col1,int col2)
+ *
+ * Use
+ *  Sets up the current foreground colour so that when plotted over colour
+ *  col1 it looks like col2 and vice-versa.  The effects of plotting over
+ *  other colours is defined to be psychedelically interesting, but not
+ *  pretty.
+ *
+ *  Basically, all it does is suss out what the colours really mean and XOR
+ *  them together.
+ *
+ * Parameters
+ *  int col1,int col2 == the Wimp colour numbers to swap between
+ */
+
+void window__colourChange(int col1,int col2);
+
+/*
+ * void window__setXORColour(glass_windPointer *w,int col)
+ *
+ * Use
+ *  Sets up the current foreground colour so that it appears to be WIMP
+ *  colour col on the specified window background.  Lots of tedious
+ *  ColourTransing to do on this, with no real reward, but at least it will
+ *  look vaguely right in 256 colour modes.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window in which to set the colour
+ *  int col == the colour to set
+ */
+
+void window__setXORColour(glass_windPointer *w,int col);
+
+/*
+ * void window__makeDashPattern(int ptn)
+ *
+ * Use
+ *  Sets the OS dash pattern to the given pattern (only the lowest byte
+ *  is considered).
+ *
+ * Parameters
+ *  int ptn == the LSB of this word contains the dash pattern as a bit
+ *   pattern
+ */
+
+void window__makeDashPattern(int ptn);
+
+/*
+ * void window__setDash(void)
+ *
+ * Use
+ *  Sets the dashed pattern so that it looks as if a 'rotating' box is being
+ *  dragged, like the WIMP's, only better...  The box is set up so that a
+ *  SINGLE exclusive-or plot will move the dash round.
+ */
+
+void window__setDash(void);
+
+/*
+ * void window__rotate(int by)
+ *
+ * Use
+ *  Rotates the current rotating-dash pattern by a given amount.  This is
+ *  used to rotate the dash box while the box is moving.
+ *
+ * Parameters
+ *  int by == the number of steps to rotate the dash pattern.
+ */
+
+void window__rotate(int by);
+
+/*
+ * void window__rectangle(int x,int y,int w,int h)
+ *
+ * Use
+ *  Draws a rectangle, using the current dotted line pattern
+ *
+ * Parameters
+ *  int x == the left side of the rectangle
+ *  int y == the right side of the rectangle
+ *  int w == the width of the rectangle (may be <0)
+ *  int h == the height of the rectangle (may be <0)
+ */
+
+void window__rectangle(int x,int y,int w,int h);
+
+/*----- Redrawing windows -------------------------------------------------*/
+
+/*
+ * void window__drawSelectBox(glass_windPointer *w,
+ *                            int icon,
+ *                           BOOL makesi,
+ *                            wimp_redrawstr *r)
+ *
+ * Use
+ *  Draws the selection box around an icon
+ *
+ * Parameters
+ *  glass_windPointer *w == the window
+ *  int icon == the icon
+ *  BOOL makesi == whether we're going between a selected and main selected
+ *    icon.
+ *  wimp_redrawstr *r == the redraw structure
+ */
+
+void window__drawSelectBox(glass_windPointer *w,
+                           int icon,
+                           BOOL makesi,
+                           wimp_redrawstr *r);
+
+/*
+ * void window__redrawDragBox(glass_windPointer *w,
+ *                            wimp_redrawstr *r,
+ *                            int x,
+ *                            int y)
+ *
+ * Use
+ *  Redraws the screen during a drag operation, either to update the window
+ *  during the drag, or to redraw the window should something silly happen
+ *  to it.
+ *
+ * Parameters
+ *  glass_windPointer *w == pointer to the window owning drag
+ *  wimp_redrawstr *r == pointer to current redraw
+ *  int x,int y == coordinates to draw drag relative to...
+ */
+
+void window__redrawDragBox(glass_windPointer *w,wimp_redrawstr *r,
+                           int x,int y);
+
+/*
+ * void window__redraw(glass_windPointer *w,wimp_redrawstr *r,BOOL *more)
+ *
+ * Use
+ *  Redraws a window following a call to Wimp_UpdateWindow or
+ *  Wimp_RedrawWindow.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to draw
+ *  wimp_redrawstr *r == stuff about the redraw
+ *  BOOL *more == whether there is more to do
+ */
+
+void window__redraw(glass_windPointer *w,wimp_redrawstr *r,BOOL *more);
+
+/*
+ * void window__redrawGuide(glass_windPointer *w,int guide)
+ *
+ * Use
+ *  Forces a redraw of the specified guideline.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the guideline
+ *  int guide == the number of the guideline.
+ */
+
+void window__redrawGuide(glass_windPointer *w,int guide);
+
+/*----- Grabbing icons ----------------------------------------------------*/
+
+/*
+ * void window__grabIcon(wimp_mousestr *m,void *handle)
+ *
+ * Use
+ *  Grabs an icon from another application.
+ *
+ * Parameters
+ *  wimp_mousestr *m == pointer to info about which icon to get
+ *  void *handle == pointer to destination window
+ */
+
+void window__grabIcon(wimp_mousestr *m,void *handle);
+
+/*
+ * void window__doGrabIcon(wimp_box *b,glass_windPointer *w)
+ *
+ * Use
+ *  Actually does a window grab job after all the pallaver.
+ *
+ * Parameters
+ *  wimp_box *b == the box in which the icon is contained
+ *  glass_windPointer *w == the window into which the icon is to be created
+ *
+ * Returns
+ *  TRUE if the evtn has been successfully handled.
+ */
+
+void window__doGrabIcon(wimp_box *b,glass_windPointer *w);
+
+/*
+ * wimp_icon *window__qGrabbedIcon(void)
+ *
+ * Use
+ *  Returns a pointer to the icon being grabbed
+ */
+
+wimp_icon *window__qGrabbedIcon(void);
+
+/*----- Dragging icons around ---------------------------------------------*/
+
+/*
+ * void window__align(glass_windPointer *w,int *x,int *y)
+ *
+ * Use
+ *  Aligns the given point to the *nearest* grid point.  The point is
+ *  fiddled in-situ.  It does the Right Thing with negative points.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window we're using
+ *  int *x == pass-by-reference x coord of point
+ *  int *y == pass-by-reference y coord of point
+ */
+
+void window__align(glass_windPointer *w,int *x,int *y);
+
+/*
+ * void window__startDrag(int type,
+ *                        wimp_box *box,
+ *                        glass_windPointer *w,
+ *                        int x,int y)
+ *
+ * Use
+ *  Starts a drag operation in the specified window
+ *
+ * Parameters
+ *  int type == what sort of drag this is
+ *  wimp_box *box == the bounding box of the object we're dragging
+ *  glass_windPointer *w == the window in which the drag is taking place
+ *  int x,int y == the mouse position the drag will start from
+ */
+
+void window__startDrag(int type,
+                       wimp_box *box,
+                       glass_windPointer *w,
+                       int x,int y);
+
+/*
+ * glass_windPointer *window__dragWind(void)
+ *
+ * Use
+ *  Returns the current dragging window
+ */
+
+glass_windPointer *window__dragWind(void);
+
+/*
+ * void window__setDragWind(glass_windPointer *w)
+ *
+ * Use
+ *  Claims the current drag operation for the given window
+ */
+
+void window__setDragWind(glass_windPointer *w);
+
+/*
+ * int window__qDragType(void)
+ *
+ * Use
+ *  Returns the current drag type
+ */
+
+int window__qDragType(void);
+
+/*
+ * wimp_box window__qDragBox(void)
+ *
+ * Use
+ *  Returns the bounding box of the things being dragged
+ */
+
+wimp_box window__qDragBox(void);
+
+/*
+ * void window__dragCoords(int *x,int *y)
+ *
+ * Use
+ *  Returns the current drag position
+ */
+
+void window__dragCoords(int *x,int *y);
+
+/*
+ * void window__dragStart(int *x,int *y)
+ *
+ * Use
+ *  Returns the initial drag position
+ */
+
+void window__dragStart(int *x,int *y);
+
+/*----- Mouse pointer shape and position ----------------------------------*/
+
+/*
+ * int window__pointerInfo(glass_windPointer *w,int from,BOOL zones)
+ *
+ * Use
+ *  Returns the icon number of the icon which the pointer is over.  Guides
+ *  are also checked for.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to use info from
+ *  int from == number to search down from (or -1 for the top).  This is
+ *   useful for selection, multiple clicks moving down overlapping icons.
+ *  BOOL zones == search for drag zones.  If this is set, the routine
+ *   searches for selected icons only.  If it is clear, zones are not
+ *   checked.
+ *
+ * Returns
+ *  An icon number, or -1 for the background.
+ */
+
+int window__pointerInfo(glass_windPointer *w,int from,BOOL zones);
+
+/*
+ * BOOL window__pointerOverIcon(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Informs the caller if the pointer is over the bounding box of the icon
+ *  specified.
+ *
+ * Parameters
+ *  glass_windPointer *w == window containing icon
+ *  int icon == icon to check for
+ */
+
+BOOL window__pointerOverIcon(glass_windPointer *w,int icon);
+
+/*
+ * void window__setPtrShape(int icon)
+ *
+ * Use
+ *  Sets the pointer shape accoding to the 'drag zone' part of the given
+ *  icon number.
+ *
+ * Parameters
+ *  int icon == the icon number
+ */
+
+void window__setPtrShape(int icon);
+
+/*----- Selection handling ------------------------------------------------*/
+
+/*
+ * void window__select(glass_windPointer *w,int icon,BOOL sel)
+ *
+ * Use
+ *  Selects or deselects the given icon.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window we're talking about
+ *  int icon == the icon to select (or not)
+ *  BOOL sel == TRUE to select, FALSE to deslect
+ */
+
+void window__select(glass_windPointer *w,int icon,BOOL sel);
+
+/*
+ * void window__setSelectedIcon(int i)
+ *
+ * Use
+ *  Makes the specified icon in the current selection owner highlighted.
+ *
+ * Parameters
+ *  int i == the icon number to highlight
+ */
+
+void window__setSelectedIcon(int i);
+
+/*
+ * void window__setSelectedIconDeselecting(int i)
+ *
+ * Use
+ *  Sets up the currently selected icon, deselecting the old one.
+ *
+ * Parameters
+ *  int i == the new icon to select
+ */
+
+void window__setSelectedIconDeselecting(int i);
+
+/*
+ * int window__lowestSelected(glass_windPointer *w)
+ *
+ * Use
+ *  Returns the selected icon with the lowest number in the specified window.
+ */
+
+int window__lowestSelected(glass_windPointer *w);
+
+/*
+ * void window__gainSelection(glass_windPointer *w)
+ *
+ * Use
+ *  Gives the specified window the input focus, tool and info bars, and the
+ *  selection.  If 0 is specified, then the tool bars are taken down, and no
+ *  selection is set.
+ *
+ * Parameters
+ *  glass_windPointer *w == the new selection owner
+ */
+
+void window__gainSelection(glass_windPointer *w);
+
+/*
+ * int window__selectedIcon(void)
+ *
+ * Use
+ *  Returns the currently selected icon
+ */
+
+int window__selectedIcon(void);
+
+/*
+ * void window__renumberSelectedIcon(int nsel)
+ *
+ * Use
+ *  To be called when the selected icon is renumbered.
+ */
+
+void window__renumberSelectedIcon(int nsel);
+
+/*----- Icon manipulation -------------------------------------------------*/
+
+/*
+ * void window__bound(wimp_icon *i,wimp_box *box,BOOL force)
+ *
+ * Use
+ *  Works out the bounding box (including 3D border) of the given pseudoicon.
+ *
+ * Parameters
+ *  wimp_icon *i == pointer to an icon definition
+ *  wimp_box *box == where to put the result
+ *  BOOL force == force reading of the border, even if disabled in prefs
+ */
+
+void window__bound(wimp_icon *i,wimp_box *box,BOOL force);
+
+/*
+ * void window__removeTrailingDeleted(glass_windPointer *w)
+ *
+ * Use
+ *  Removes trailing deleted icons from a window (i.e. ones that can be
+ *  safely deleted properly without messing up icon numbers).
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to blitz
+ */
+
+void window__removeTrailingDeleted(glass_windPointer *w);
+
+/*
+ * int window__createIcon(glass_windPointer *w)
+ *
+ * Use
+ *  Creates a slot for an icon in the window specified, according to current
+ *  preferences.  The contents of the icon array are unspecified (and
+ *  probably not too useful).
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to create the icon in
+ *
+ * Returns
+ *  Icon number that can be used, or -1 if the operation failed.
+ */
+
+int window__createIcon(glass_windPointer *w);
+
+/*
+ * void window__renumber(glass_windPointer *w,BOOL renum)
+ *
+ * Use
+ *  Sets the renumber flag of the given window to the given state.
+ *  Everything is set up properly according to the new state.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to renumber
+ *  BOOL renum == the new state of the flag
+ */
+
+void window__renumber(glass_windPointer *w,BOOL renum);
+
+/*
+ * void window__copyIcons(glass_windPointer *w)
+ *
+ * Use
+ *  Copies the selected icons into the given window.  If the icons are
+ *  already in the given window, they are duplicated and offset by a small
+ *  quantity.  If the icons are in a different window, then they are
+ *  centred over the current visible area.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to put the icons
+ */
+
+void window__copyIcons(glass_windPointer *w);
+
+/*
+ * void window__nudgeIcons(glass_windPointer *w,wimp_box *nudge)
+ *
+ * Use
+ *  Nudges the selected icons in the specified window, by adding the box
+ *  given to each icon's bounding box.  The nudge box is multiplied either by
+ *  the current grid size (if grid lock is enabled) or by the pixel size (if
+ *  it isn't) before addition.  A nudge is considered to be a single
+ *  alteration for the purposes of autosave-counting.  If no icons are moved
+ *  then the selected guidelines are moved instead.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icons to nudge
+ *  wimp_box *nudge == the box to add to the coordinates of the icons
+ */
+
+void window__nudgeIcons(glass_windPointer *w,wimp_box *nudge);
+
+/*----- Window manipulation -----------------------------------------------*/
+
+/*
+ * wimp_w window__recreate(glass_windPointer *w)
+ *
+ * Use
+ *  Recreates a window, getting all the fiddly bits right.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window
+ *
+ * Returns
+ *  The window handle, or 0 for failure
+ */
+
+wimp_w window__recreate(glass_windPointer *w);
+
+/*
+ * void window__nudgeScroll(glass_windPointer *w,int x,int y)
+ *
+ * Use
+ *  Scrolls the window a bit, by adding the x and y values given to the
+ *  scroll offsets of the window.  The values are multiplied up to give a
+ *  sensible sized scroll.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to scroll
+ *  int x == the x scroll offset to add
+ *  int y == the y scroll offset to add
+ */
+
+void window__nudgeScroll(glass_windPointer *w,int x,int y);
+
+/*----- The main menu -----------------------------------------------------*/
+
+/*
+ * glass_windPointer *window__menuOwner(void)
+ *
+ * Use
+ *  Returns which window currently owns the menu.
+ *
+ * Returns
+ *  A pointer to the window's anchor block.
+ */
+
+glass_windPointer *window__menuOwner(void);
+
+/*
+ * void window__updateMenu(glass_windPointer *w)
+ *
+ * Use
+ *  Updates the menu attached to the main window.
+ *
+ * Parameters
+ *  glass_windPointer *w == pointer to owning menu
+ */
+
+void window__updateMenu(glass_windPointer *w);
+
+/*
+ * void window__simMenu(glass_windPointer *w,int hit1,int hit2)
+ *
+ * Use
+ *  Simulates a menu hit on the specified item.  Gives a beep if the item
+ *  is unavailable.  Otherwise, the hit is sent to the current selection
+ *  owner.  [fixed to allow which window is used rather than only the
+ *  selection owner, 1 November 1993]
+ *
+ * Use
+ *  glass_windPointer *w == the window in which to simulate the event
+ *  int hit1 == first hit in the sequence
+ *  int hit2 == second hit in the sequence
+ */
+
+void window__simMenu(glass_windPointer *w,int hit1,int hit2);
+
+/*
+ * void window__showMenu(int x,int y,glass_windPointer *w)
+ *
+ * Use
+ *  Displays the Template Window Menu
+ *
+ * Parameters
+ *  int x,int y == the (window) position to display the menu
+ *  glass_windPointer *w == the window to display the menu for
+ */
+
+void window__showMenu(int x,int y,glass_windPointer *w);
+
+/*
+ * void window__menuInit(void)
+ *
+ * Use
+ *  Initialises the create icon menu
+ */
+
+void window__menuInit(void);
+
+/*----- Handling the toolbars ---------------------------------------------*/
+
+/*
+ * void window__setToolBarPositions(wimp_openstr *o)
+ *
+ * Use
+ *  Displays the tool and info bars according to current settings etc.
+ *
+ * Parameters
+ *  wimp_openstr *o == the position of the selection owner window, or 0.
+ *    This is updated to put the window somewhere nice without flicker.
+ */
+
+void window__setToolBarPositions(wimp_openstr *o);
+
+/*
+ * void window__updateInfoBar(void)
+ *
+ * Use
+ *  Updates the settings on the info bar.  If a setting hasn't changed, then
+ *  it isn't updated (reducing flicker).
+ *
+ * Parameters
+ *  BOOL force == whether to force an update of everything.
+ */
+
+void window__updateInfoBar(BOOL force);
+
+/*
+ * void window__toggleRenumber(glass_windPointer *w)
+ *
+ * Use
+ *  Updates the info bar after entering or leaving renumber-mode.  w is
+ *  the currently selected window.
+ */
+
+void window__toggleRenumber(glass_windPointer *w);
+
+/*
+ * void window__toggleTest(glass_windPointer *w)
+ *
+ * Use
+ *  Updates the info bar after entering or leaving test-mode.  w is the
+ *  currently selected window.
+ */
+
+#ifndef glass_DEMO
+void window__toggleTest(glass_windPointer *w);
+#endif
+
+/*
+ * void window__updateInfoName(char *newname)
+ *
+ * Use
+ *  Updates the name in the info bar
+ */
+
+void window__updateInfoName(char *newname);
+
+/*
+ * void window__nextRenumber(glass_windPointer *w)
+ *
+ * Use
+ *  Updates the next renumber icon number display.
+ */
+
+void window__nextRenumber(glass_windPointer *w);
+
+/*
+ * void window__moveToolbars(glass_windPointer *w)
+ *
+ * Use
+ *  Moves the toolbars and attaches them to a new window
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to attach the bars to
+ */
+
+void window__moveToolbars(glass_windPointer *w);
+
+/*
+ * void window__tbarInit(void)
+ *
+ * Use
+ *  Initialises the toolbar system
+ */
+
+void window__tbarInit(void);
+
+/*----- The icon palette --------------------------------------------------*/
+
+/*
+ * void window__showPalette(void)
+ *
+ * Use
+ *  Displays the palette window, as set up in the Defaults template file.
+ */
+
+void window__showPalette(void);
+
+/*----- The main event handlers -------------------------------------------*/
+
+/*
+ * void window__winIdles(void *handle)
+ *
+ * Use
+ *  Changes the pointer shape to something appropriate for what its over.
+ *
+ * Parameters
+ *  void *handle == pointer to window containing pointer
+ */
+
+void window__winIdles(void *handle);
+
+/*
+ * void window__testEvents(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles all events for windows running in Test mode.  Events handled
+ *  are:
+ *
+ *  Redraw   Redraws the window using Interface/hatch pattern as requested.
+ *  Open     Moves the window around.
+ *  Close    Closes the window(!)
+ *  Leave    Ignored
+ *  Enter    Turn off STEEL pointer changing
+ *  Click    Handled by WIMP or Interface, except for menu, which opens
+ *           the menu(!)
+ *  Key      Handled by WIMP, WimpExtension, or ignored
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event
+ *  void *handle == pointer to window info
+ */
+
+#ifndef glass_DEMO
+void window__testEvents(wimp_eventstr *e,void *handle);
+#endif
+
+/*
+ * void window__events(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles all events for template windows (this is the first chance I've
+ *  had to get my fingers *REALLY* mucky on this whole project!)
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event that I am meant to be inerested in
+ *  void *handle == a pointer to the structural information for this window
+ */
+
+void window__events(wimp_eventstr *e,void *handle);
+
+/*----- THE END -----------------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/align b/StraySrc/Glass/!Glass/h/align
new file mode 100644 (file)
index 0000000..3c8fcb4
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * align.c
+ *
+ * The alignment dialogue box
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __align_h
+#define __align_h
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void align(void)
+ *
+ * Use
+ *  Opens the align dialogue box.  There can only be one selection, ergo
+ *  there can only be one align box.
+ */
+
+void align(void);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/colSelect b/StraySrc/Glass/!Glass/h/colSelect
new file mode 100644 (file)
index 0000000..c7c28eb
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * colSelect.c
+ *
+ * Handling of a colour button
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Background information ----------------------------------------------
+
+  A colour button is a small (36x36 OS unit) button, pressed into a
+  dialogue, which allows the user to select a WIMP colour.  Clicks on the
+  button are handled as follows:
+
+    SELECT    Cycle through colours in ascending number order.  If
+              transparent is allowed, this comes between colours 15 and 0.
+              Holding down the button auto-repeats.
+    ADJUST    Cycle through colours in reverse order to SELECT.
+    MENU      Display a colour selector dialogue.
+
+Specifications for a colour button
+
+  Size        36x36 OS units
+  Border      Z3 type 3D, no WIMP border
+
+  If colour can be transparent, validation string must include an 'Strans'
+  instruction.  The icon must have a background set.
+
+---------------------------------------------------------------------------*/
+
+#ifndef __colSelect_h
+#define __colSelect_h
+
+/*----- Required header files ---------------------------------------------*/
+
+#ifndef __dbox_h
+  #include "steel/dbox.h"
+#endif
+
+/*----- Type definitions --------------------------------------------------*/
+
+typedef void (*colSelect_proc)(dbox d,dbox_field f,int colour,void *handle);
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void colSelect_setColourButton(dbox d,dbox_field f,int colour)
+ *
+ * Use
+ *  Sets a colour button to show a colour
+ *
+ * Parameters
+ *  dbox d == dbox containing button
+ *  dbox_field f == the icon which is the button
+ *  int colour == colour to set the button.  255 means transparent
+ */
+
+void colSelect_setColourButton(dbox d,dbox_field f,int colour);
+
+/*
+ * void colSelect(dbox d,dbox_field f,wimp_bbits bbits,char *editing,
+ *                          BOOL allowTrans,colSelect_proc proc,void *handle)
+ *
+ * Use
+ *  Handles mouse events on a colour button.
+ *
+ * Parameters
+ *  dbox d == the dialogue containing the colour button
+ *  dbox_field f == the icon which is the colour button
+ *  wimp_bbits bbits == button status that prompted this
+ *  char *editing == what we're editing (for dialogue)
+ *  BOOL allowTrans == whether we're allowed transparent colour
+ *  colSelect_proc proc == routine to take notice of any changes
+ *  void *handle == pointer to pass to the proc
+ */
+
+void colSelect(dbox d,dbox_field f,wimp_bbits bbits,char *editing,
+                           BOOL allowTrans,colSelect_proc proc,void *handle);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/editIcon b/StraySrc/Glass/!Glass/h/editIcon
new file mode 100644 (file)
index 0000000..85c6433
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * editIcon.c
+ *
+ * Edit icon dialigue box
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __editIcon_h
+#define __editIcon_h
+
+/*----- Required header files ---------------------------------------------*/
+
+#ifndef __gStruct_h
+  #include "gStruct.h"
+#endif
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void editIcon_renumber(glass_windPointer *w,int icon,int new)
+ *
+ * Use
+ *  Informs an edit dialogue that an icon has been renumbered.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number
+ *  int new == the new number for the icon
+ */
+
+void editIcon_renumber(glass_windPointer *w,int icon,int new);
+
+/*
+ * void editIcon_iconMoved(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Informs an edit dialogue that an icon has been moved.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number.  This may not be the same during the edit...
+ */
+
+void editIcon_iconMoved(glass_windPointer *w,int icon);
+
+/*
+ * void editIcon_readData(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Forces a re-read of the icon data for the given icon edit
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number.  This may not be the same during the edit...
+ */
+
+void editIcon_readData(glass_windPointer *w,int icon);
+
+/*
+ * void editIcon_close(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Closes an edit window
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number.  This may not be the same during the edit...
+ */
+
+void editIcon_close(glass_windPointer *w,int icon);
+
+/*
+ * void editIcon(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Edits the given icon in a dialogue box.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number.  This may not be the same during the edit...
+ */
+
+void editIcon(glass_windPointer *w,int icon);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/editWin b/StraySrc/Glass/!Glass/h/editWin
new file mode 100644 (file)
index 0000000..ddf1f37
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * editWindow.c
+ *
+ * Edit icon dialigue box
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __editWin_h
+#define __editWin_h
+
+/*----- Required header files ---------------------------------------------*/
+
+#ifndef __gStruct_h
+  #include "gStruct.h"
+#endif
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void editWindow_windowMoved(glass_windPointer *w)
+ *
+ * Use
+ *  Informs an edit dialogue that a window has been moved.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ */
+
+void editWindow_windowMoved(glass_windPointer *w);
+
+/*
+ * void editWindow_readData(glass_windPointer *w)
+ *
+ * Use
+ *  Forces a re-read of the title data for the given window edit
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ */
+
+void editWindow_readData(glass_windPointer *w);
+
+/*
+ * void editWindow_close(glass_windPointer *w)
+ *
+ * Use
+ *  Closes an edit window
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ */
+
+void editWindow_close(glass_windPointer *w);
+
+/*
+ * void editWindow(glass_windPointer *w)
+ *
+ * Use
+ *  Edits the given window in a dialogue box.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to edit
+ */
+
+void editWindow(glass_windPointer *w);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/gIcons b/StraySrc/Glass/!Glass/h/gIcons
new file mode 100644 (file)
index 0000000..e36990a
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * gIcons.h
+ *
+ * Symbolic definitions of icon numbers
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __gIcons_h
+#define __gIcons_h
+
+/*----- Toolbox -----------------------------------------------------------*/
+
+#define glass_TBCLOSE 0       /* Close window tool                      */
+#define glass_TBBACK 1        /* Send to back tool                      */
+#define glass_TBSIZE 2        /* Resize window tool                     */
+#define glass_TBHSCR 3        /* Horizontal scroll tool                 */
+#define glass_TBVSCR 4        /* Vertical scroll tool                   */
+#define glass_TBMOVE 5        /* Move window tool                       */
+
+/*----- Loading window ----------------------------------------------------*/
+
+#define glass_CRVERSION 4     /* Version display                        */
+#define glass_CRGPLNOTE 6     /* General public license display         */
+#define glass_CRNOWARRANTY 7  /* Notice about lack of warranty          */
+#define glass_CRSLIDER 10     /* Progress slider                        */
+#define glass_CRPERCENT 11    /* Percentage display                     */
+#define glass_CRDOING 13      /* What the system is doing               */
+
+/*----- Window info monologue boxes ---------------------------------------*/
+
+/*
+ * Template file info
+ */
+
+#define glass_FINAME 1        /* Name of the file                       */
+#define glass_FISIZE 3        /* File size (OS_ConvertFileSize)         */
+#define glass_FIINDSZ 5              /* Indirected data size                   */
+#define glass_FIWINDOWS 7     /* Number of windows in the file          */
+#define glass_FIMODIFIED 9    /* Has the file been modified?            */
+
+/*
+ * Window info
+ */
+
+#define glass_WINAME 1        /* Name of the window                     */
+#define glass_WISIZE 3        /* Size of the window                     */
+#define glass_WIINDSZ 5              /* Indirected data size                   */
+#define glass_WIICONS 7       /* Number of icons in the window          */
+
+/*
+ * Selection info
+ */
+
+#define glass_SINUM 1         /* Number of windows selected             */
+#define glass_SISIZE 3        /* Size of the selection                  */
+#define glass_SIINDSZ 5              /* Indirected data size                   */
+#define glass_SIICONS 7       /* Number of icons in the selection       */
+
+/*----- Sprite info monologue boxes ---------------------------------------*/
+
+/*
+ * Sprite area info
+ */
+
+#define glass_SAOWNER 1       /* Name of the owning template file       */
+#define glass_SASIZE 4        /* File size (OS_ConvertFileSize)         */
+#define glass_SASPRITES 2     /* Number of sprites in the file          */
+
+/*
+ * Sprite info
+ */
+
+#define glass_SPNAME 1        /* Name of the sprite                     */
+#define glass_SPMODE 5        /* Mode the sprite was defined in         */
+#define glass_SPWIDTH 6       /* Width of the sprite                    */
+#define glass_SPHEIGHT 7      /* Height of the sprite                   */
+#define glass_SPSIZE 3        /* Size of the sprite                     */
+#define glass_SPMASK 10       /* Does it have a mask?                   */
+#define glass_SPPALETTE 12    /* Does it have a palette?                */
+
+/*
+ * Selection info
+ */
+
+#define glass_SSNUM 1         /* Number of sprites selected             */
+#define glass_SSSIZE 3        /* Size of the selection                  */
+
+/*----- Heap info ---------------------------------------------------------*/
+
+#define glass_HEAPSIZE 1      /* Current size of the heap               */
+#define glass_FREESIZE 2      /* Size of free area                      */
+#define glass_LARGEST 4       /* Size of the largest free block         */
+#define glass_HEAPSLIDE 6     /* Slider showing all this info           */
+
+/*----- Colour selector ---------------------------------------------------*/
+
+#define glass_CSOK 0          /* OK button                              */
+#define glass_CSCANCEL 1      /* Cancel button                          */
+#define glass_CSEDITING 2     /* Display field - what we're editing     */
+#define glass_CSCOLOURS 4     /* The first colour icon - others seq.    */
+#define glass_CSTRANS 22      /* Transparent switch                     */
+
+/*----- Grid --------------------------------------------------------------*/
+
+#define glass_GOK 0           /* OK button                              */
+#define glass_GDISP 1         /* Display switch                         */
+#define glass_GLOCK 2         /* Grid lock switch                       */
+#define glass_GWUP 4          /* Grid width up arrow                    */
+#define glass_GWDOWN 5        /* Grid width down arrow                  */
+#define glass_GWWRITE 6       /* Grid width writable area               */
+#define glass_GHUP 8          /* Grid height up arrow                   */
+#define glass_GHDOWN 9        /* Grid height down arrow                 */
+#define glass_GHWRITE 10      /* Grid height writable area              */
+
+/*----- Sprite zoom -------------------------------------------------------*/
+
+#define glass_ZOK 0           /* OK button                             */
+#define glass_ZUP 3          /* Up arrow button                        */
+#define glass_ZDOWN 4        /* Down arrow button                      */
+#define glass_ZWRITE 1       /* Writable area for zoom percentage      */
+#define glass_ZDEFAULTS 6     /* Default zoom percentage buttons       */
+
+/*----- Align -------------------------------------------------------------*/
+
+#define glass_AOK 0           /* Align OK button                        */
+#define glass_ACANCEL 1       /* Align Cancel button                    */
+#define glass_AHNONE 3        /* Horizontal no change radio             */
+#define glass_AHALIGN 4       /* Horizontal align radio                 */
+#define glass_AHDISTRIB 5     /* Horizontal distribute radio            */
+#define glass_AHLEFT 7        /* Horizontal left radio                  */
+#define glass_AHRIGHT 8       /* Horizontal right radio                 */
+#define glass_AHCENTRE 9      /* Horizontal centre radio                */
+#define glass_AHWIDTH 10      /* Horizontal width radio                 */
+#define glass_AHBOUND 12      /* Horizontal bounding box radio          */
+#define glass_AHVISAREA 13    /* Horizontal visible area radio          */
+#define glass_AHCONTAIN 14    /* Horizontal container constraint        */
+#define glass_AVNONE 16       /* Vertical no change radio               */
+#define glass_AVALIGN 17      /* Vertical align radio                   */
+#define glass_AVDISTRIB 18    /* Vertical distribute radio              */
+#define glass_AVTOP 20        /* Vertical top radio                     */
+#define glass_AVBOTTOM 21     /* Vertical bottom radio                  */
+#define glass_AVCENTRE 22     /* Vertical centre radio                  */
+#define glass_AVHEIGHT 23     /* Vertical height radio                  */
+#define glass_AVBOUND 25      /* Vertical bounding box radio            */
+#define glass_AVVISAREA 26    /* Vertical visible area radio            */
+#define glass_AVCONTAIN 27    /* Vertical container constraint          */
+
+/*----- Tool bar ----------------------------------------------------------*/
+
+#define glass_TBDRAG 0        /* Tool bar drag bar                      */
+#define glass_TBCLOSEW 1      /* Tool bar close window icon             */
+#define glass_TBCREATE 2      /* Tool bar create icon                   */
+#define glass_TBDELETE 3      /* Tool bar delete icon                   */
+#define glass_TBCOPY 4        /* Tool bar copy icon                     */
+#define glass_TBEDITW 5       /* Tool bar edit window icon              */
+#define glass_TBEDITI 6       /* Tool bar edit icon icon (!)            */
+#define glass_TBRENUMBER 7    /* Tool bar renumber icon                 */
+
+/*----- Info bar ----------------------------------------------------------*/
+
+#define glass_IBDRAG 0        /* Info bar drag bar                      */
+#define glass_IBWIND 2        /* Info bar window display                */
+#define glass_IBICON 4        /* Info bar icon display                  */
+#define glass_IBX 6           /* Info bar x coord display               */
+#define glass_IBY 8           /* Info bar y coord display               */
+#define glass_IBEDIT 9        /* Info bar edit mode radio               */
+#define glass_IBTEST 10       /* Info bar test mode radio               */
+#define glass_IBRENUM 12      /* Info bar next renumber display         */
+
+/*----- Autosave dialogues ------------------------------------------------*/
+
+/*
+ * Autosave prompt dialogue
+ */
+
+#define glass_APSAVE 0        /* Save file action button                */
+#define glass_APCANCEL 1      /* Cancel action button                   */
+#define glass_APSAVEAS 2      /* Save as action button                  */
+#define glass_APNAME 4        /* Where to put the file's name           */
+
+/*
+ * Autosave message dialogue
+ */
+
+#define glass_AMNAME 2        /* Where to put the name                  */
+
+/*----- Preferences -------------------------------------------------------*/
+
+/*
+ * The main window
+ */
+
+#define glass_PMOK 0          /* OK button                              */
+#define glass_PMCANCEL 1      /* Cancel button                          */
+#define glass_PMSAVE 3        /* Save button                            */
+#define glass_PMAUTOSAVE 5    /* Autosave radio                         */
+#define glass_PMINTERFACE 6   /* Interface radio                        */
+#define glass_PMSPRITES 7     /* Sprites radio                          */
+#define glass_PMFILEDISP 8    /* File dislay radio                      */
+#define glass_PMGRID 9        /* Grid radio                             */
+#define glass_PMSELECTION 10  /* Selection radio                        */
+#define glass_PMCONFIRM 11    /* Confirm radio                          */
+#define glass_PMTOOLINFO 12   /* Tool and info bar radio                */
+#define glass_PMMISC 13       /* Miscellaneous radio                    */
+#define glass_PMPOSN 14       /* Pane positioning icon                  */
+
+/*
+ * Autosave
+ */
+
+#define glass_PATIMED 3       /* Timed autosave switch                  */
+#define glass_PATIMEDOWN 5    /* Time down arrow                        */
+#define glass_PATIMEWRITE 6   /* Time writable area                     */
+#define glass_PATIMEUP 7      /* Time up arrow                          */
+#define glass_PAUNITSDISP 8   /* Display area for units menu            */
+#define glass_PAUNITSMENU 9   /* Menu button for units menu             */
+#define glass_PACOUNTED 11    /* Counted autosave switch                */
+#define glass_PACOUNTDOWN 13  /* Count down arrow                       */
+#define glass_PACOUNTWRITE 14 /* Count writable area                    */
+#define glass_PACOUNTUP 15    /* Count up arrow                         */
+#define glass_PAPROMPT 17     /* Prompt for autosave switch             */
+
+/*
+ * Interface (3D module support)
+ */
+
+/* --- Interface --- */
+
+#define glass_PIDISPBORDER 3  /* Display 3D borders switch              */
+#define glass_PIMOUSECLICK 4  /* Respond to mouse clicks on 3D icons    */
+#define glass_PIMENUCLICK 5   /* Respond to menu clicks on 3D icons     */
+#define glass_PIINCBORDER 6   /* Include Interface border in bdd box    */
+
+/* --- WimpExtension --- */
+
+#define glass_PWDISPBORDER 8  /* Display 3D borders switch              */
+#define glass_PWKEYPRESS 9    /* Respond to mouse clicks on 3D icons    */
+#define glass_PWINCBORDER 10  /* Include WimpExtension border in bdd box*/
+
+/* --- Sculptrix --- */
+
+#define glass_PSDISPBORDER 12 /* Display 3D borders switch              */
+#define glass_PSMOUSECLICK 13 /* Respond to mouse clicks on 3D icons    */
+#define glass_PSMENUCLICK 14  /* Respond to menu clicks on 3D icons     */
+#define glass_PSINCBORDER 15  /* Include Sculptrix border in bdd box    */
+
+/*
+ * Sprites
+ */
+
+#define glass_PSSPRITES 2     /* Load Sprites switch                    */
+#define glass_PSPSPRITES 3    /* Load !Sprites switch                   */
+#define glass_PSDEFAULTS 4    /* Load Glass default sprites          */
+
+/*
+ * File display panel
+ */
+
+#define glass_PFLARGE 3       /* Large icons radio                      */
+#define glass_PFSMALL 4       /* Small icons radio                      */
+#define glass_PFNAME 6        /* Sort by name radio                     */
+#define glass_PFSIZE 7        /* Sort by size radio                     */
+#define glass_PFICONS 8       /* Sort by number of icons radio          */
+#define glass_PFNOSORT 9      /* Don't sort radio                       */
+
+/*
+ * Grid panel
+ */
+
+#define glass_PGDISP 3        /* Display grid switch                    */
+#define glass_PGLOCK 4        /* Snap to grid switch                    */
+#define glass_PGWUP 6         /* Width up arrow                         */
+#define glass_PGWDOWN 7       /* Width down arrow                       */
+#define glass_PGWWRITE 8      /* Width writable area                    */
+#define glass_PGHUP 10        /* Height up arrow                        */
+#define glass_PGHDOWN 11      /* Height down arrow                      */
+#define glass_PGHWRITE 12     /* Height writable area                   */
+#define glass_PGLINES 21      /* Lines radio                            */
+#define glass_PGPOINTS 22     /* Points radio                           */
+#define glass_PGGRIDCOL 15    /* Grid colour button                     */
+#define glass_PGGUIDECOL 17   /* Guide colour button                    */
+#define glass_PGGDESELCOL 19  /* Selected guide colour button           */
+
+/*
+ * Selection panel
+ */
+
+#define glass_PSBORDER 3      /* Select border switch                   */
+#define glass_PSDOTTED 4      /* Dotted border switch                   */
+#define glass_PSBCOLLABEL 5   /* Border colour label (for shading)      */
+#define glass_PSBCOLOUR 6     /* Border colour button                   */
+#define glass_PSCORNEDGE 9    /* Corners and edges radio                */
+#define glass_PSCORNONLY 10   /* Corners only radio                     */
+#define glass_PSSIZEUP 12     /* Handle size up arrow                   */
+#define glass_PSSIZEDOWN 13   /* Handle size down arrow                 */
+#define glass_PSSIZEWRITE 14  /* Handle size writable area              */
+#define glass_PSHCOLOUR 16    /* Handle colour button                   */
+#define glass_PSSCOLOUR 18    /* Special icon handle colour button      */
+
+/*
+ * Confirm panel
+ */
+
+#define glass_PCQUIT 2        /* Quit with unsaved files switch         */
+#define glass_PCCLOSE 3       /* Close unsaved file switch              */
+#define glass_PCDELWIN 4      /* Delete windows switch                  */
+#define glass_PCDELICON 5     /* Delete icons switch                    */
+#define glass_PCTEST 6        /* Close edits for test mode              */
+#define glass_PCOVERWRITE 7   /* Overwrite existing files switch        */
+
+/*
+ * Tool/Info bars
+ */
+
+#define glass_PTTOOLDISP 3    /* Tool bar display switch                */
+#define glass_PTTOOLFLOAT 4   /* Tool bar floating switch               */
+#define glass_PTINFODISP 6    /* Info bar display switch                */
+#define glass_PTINFOFLOAT 7   /* Info bar floating switch               */
+
+/*
+ * Miscellaneous
+ */
+
+#define glass_PMHATCH 2       /* Fill redrawable windows with hatching  */
+#define glass_PMBLINK 3       /* Blinking cursor switch                 */
+#define glass_PMVISINWORK 4   /* Keep visible area in work area switch  */
+#define glass_PMNEWONTOP 5    /* Create new icons on top switch         */
+#define glass_PMRENDEL 6      /* Renumber icons on delete switch        */
+#define glass_PMCTRLEDIT 7    /* Require control key pressed to edit    */
+
+/*----- Edit icon ---------------------------------------------------------*/
+
+/*
+ * The main window
+ */
+
+#define glass_EIOK 0          /* OK action button                       */
+#define glass_EICAN 1         /* Cancel action button                   */
+#define glass_EIDELETE 2      /* Delete action button                   */
+#define glass_EIDATA 4        /* Data panel selector                    */
+#define glass_EIAPPEARANCE 5  /* Appearance panel selector              */
+#define glass_EIACTIONS 6     /* Actions panel selector                 */
+#define glass_EICOLOURS 7     /* Colours panel selector                 */
+#define glass_EIPOSITION 8    /* Position panel selector                */
+#define glass_EISIZE 9        /* Size panel selector                    */
+#define glass_EINUMUP 11      /* Icon number up arrow                   */
+#define glass_EINUMDOWN 12    /* Icon number down arrow                 */
+#define glass_EINUMWRITE 13   /* Icon number writable area              */
+#define glass_EIWINDISP 15    /* Window owner identity display area     */
+#define glass_EIPOSN 16       /* Where to put the pane window           */
+
+/*
+ * Icon data panel
+ */
+
+#define glass_EIDDATA 2       /* Data string writable area              */
+#define glass_EIDTEXT 4       /* Text switch                            */
+#define glass_EIDSPRITE 5     /* Sprite switch                          */
+#define glass_EIDINDIR 7      /* Indirected switch                      */
+#define glass_EIDINDSIZE 9    /* Indirected data size                   */
+#define glass_EIDINDUP 10     /* Indirect size up arrow                 */
+#define glass_EIDINDDOWN 11   /* Indirect size down arrow               */
+#define glass_EIDMINIMISE 12  /* Indirect size minimise button          */
+#define glass_EIDINDPART 13   /* The partition icon                    */
+#define glass_EIDVALID 14     /* Validation string switch               */
+#define glass_EIDVALSTRING 15 /* Validation string writable area        */
+
+/*
+ * Icon appearance panel
+ */
+
+#define glass_EIAFONT 7       /* Antialiased switch                     */
+#define glass_EIAFONTNAME 8   /* Font name display area                 */
+#define glass_EIAFONTMENU 9   /* Font name menu button                  */
+#define glass_EIAFSIZEUP 11   /* Font size up arrow                     */
+#define glass_EIAFSIZEDOWN 12 /* Font size down arrow                   */
+#define glass_EIAFSIZEWRITE 13 /* Font size writable area               */
+#define glass_EIAHCENTRE 3    /* Horizotally centred switch             */
+#define glass_EIAVCENTRE 4    /* Vertically centred switch              */
+#define glass_EIARALIGN 5     /* Right aligned switch                   */
+#define glass_EIABORDER 16    /* WIMP-drawn border switch               */
+#define glass_EIAFILL 17      /* Filled background switch               */
+#define glass_EIAHALFSIZE 18  /* Sprite at half size switch             */
+#define glass_EIANEEDSHELP 19 /* Needs help to be redrawn switch        */
+
+/*
+ * Icon actions panel
+ */
+
+#define glass_EIABTYPE 3      /* Button type display area               */
+#define glass_EIABTMENU 4     /* Button type menu button                */
+#define glass_EIAESGUP 6      /* ESG up arrow                           */
+#define glass_EIAESGDOWN 7    /* ESG down arrow                         */
+#define glass_EIAESGWRITE 8   /* ESG writable area                      */
+#define glass_EIAADJUST 9     /* Adjust clicks use ESG 0 switch         */
+#define glass_EIASELECT 10    /* Selected switch                        */
+#define glass_EIASHADE 11     /* Shaded switch                          */
+
+/*
+ * Icon colours panel
+ */
+
+#define glass_EICFORE 4       /* Foreground colour button               */
+#define glass_EICBACK 5       /* Background colour button               */
+
+/*
+ * Position/size panel
+ */
+
+#define glass_EIPUP 3         /* Rectangle up button                    */
+#define glass_EIPDOWN 4       /* Rectangle down button                  */
+#define glass_EIPLEFT 5       /* Rectangle left button                  */
+#define glass_EIPRIGHT 6      /* Rectangle right button                 */
+#define glass_EIPWRITE 7      /* Writable coords area                   */
+
+#define glass_EIPSETSIZE 8    /* Set icon size correctly                */
+
+/*----- Edit window -------------------------------------------------------*/
+
+/*
+ * The main window
+ */
+
+#define glass_EWOK 0          /* The OK button                          */
+#define glass_EWCAN 1         /* The Cancel button                      */
+#define glass_EWDEL 2         /* Delete window action button            */
+#define glass_EWSAVE 3        /* Save window action button              */
+#define glass_EWCHARS 5       /* Characteristics panel selector         */
+#define glass_EWGADGETS 6     /* Gadgets panel selector                 */
+#define glass_EWBTYPE 7       /* Button type                            */
+#define glass_EWTDATA 8       /* Title data panel selector              */
+#define glass_EWTAPPEAR 9     /* Title appearance panel selector        */
+#define glass_EWCOLOURS 10    /* Colours panel selector                 */
+#define glass_EWWORKAREA 11   /* Work area sizes panel selector         */
+#define glass_EWIDWRITE 13    /* Identifier writable area               */
+#define glass_EWFILEDISP 15   /* Template file name display area        */
+#define glass_EWPOSN 16       /* Pane positioning icon                  */
+
+/*
+ * Window characteristics panel
+ */
+
+#define glass_EWCMOVE 2       /* Window may be moved switch             */
+#define glass_EWCREDRAW 3     /* Window is redrawn by the WIMP          */
+#define glass_EWCPANE 4       /* Window is a pain switch                */
+#define glass_EWCNOBOUNDS 5   /* Window may be moved off-screen switch  */
+#define glass_EWCONSCREEN 6   /* Always force window on screen                 */
+#define glass_EWCSCRLQ 8      /* Window generates scroll requests switch*/
+#define glass_EWCSCRLREP 9    /* Scroll requests auto-repeat radio      */
+#define glass_EWCSCRLDEB 10   /* Scroll requests debounced radio        */
+#define glass_EWCGCOL 11      /* Window uses normal mode colours switch */
+#define glass_EWCBACK 12      /* Window stays at the back switch        */
+#define glass_EWCHOTKEYS 13   /* Window grabs hotkeys switch            */
+
+/*
+ * Window gadgets panel
+ */
+
+#define glass_EWGOLD 3        /* Old style gadgets radio                */
+#define glass_EWGOTITLE 4     /* Old style title bar switch             */
+#define glass_EWGOCLOSEBACK 5 /* Old style close/back box switch        */
+#define glass_EWGOHORIZ 6     /* Old style horizontal scroll bar switch */
+#define glass_EWGOVERT 7      /* Old style vertical scroll bar switch   */
+#define glass_EWGNEW 9        /* New style gadgets radio                */
+#define glass_EWGNTITLE 10    /* New style title bar switch             */
+#define glass_EWGNCLOSE 11    /* New style close box switch             */
+#define glass_EWGNRESIZE 12   /* New style resize box switch            */
+#define glass_EWGNBACK 13     /* New style send-to-back box switch      */
+#define glass_EWGNTOGGLE 14   /* New style max-min box switch           */
+#define glass_EWGNHORIZ 15    /* New style horizontal scroll bar switch */
+#define glass_EWGNVERT 16     /* New style vertical scroll bar switch   */
+
+/*
+ * Window button type panel
+ */
+
+#define glass_EWBBTDISP 3     /* Button type display area               */
+#define glass_EWBBTMENU 4     /* Button type menu button                */
+
+/*
+ * Window title data and window title appearance
+ *
+ * Since these are presented using the same templates as the corresponding
+ * icon panels, I think it's fair to use the same icon number definitions
+ * above.
+ */
+
+/*
+ * Window colours panel
+ */
+
+#define glass_EWCTBFORE 8     /* Title bar foreground colour button     */
+#define glass_EWCTBBACK 9     /* Title bar background colour button     */
+#define glass_EWCWAFORE 10    /* Work area foreground colour button     */
+#define glass_EWCWABACK 11    /* Work area background colour button     */
+#define glass_EWCSCFORE 12    /* Scroll bar foreground colour button    */
+#define glass_EWCSCBACK 13    /* Scroll bar background colour button    */
+#define glass_EWCHIGH 14      /* Input focus highlight colour           */
+
+/*
+ * Window work area sizes panel
+ */
+
+#define glass_EWSTLLARGE 2    /* Move top left outwards button          */
+#define glass_EWSTOPRIGHT 4   /* Top right extent writable area         */
+#define glass_EWSTOPUP 5      /* Top extent up arrow                    */
+#define glass_EWSTOPDOWN 6    /* Top extent down arrow                  */
+#define glass_EWSLEFTLEFT 7   /* Left extent left arrow                 */
+#define glass_EWSLEFTRIGHT 8  /* Left extent right arrow                */
+#define glass_EWSEXTLOCK 9    /* Set to visible size button             */
+#define glass_EWSRIGHTLEFT 10 /* Right extent left arrow                */
+#define glass_EWSRIGHTRIGHT 11 /* Right extent right arrow              */
+#define glass_EWSBOTTOMUP 12  /* Bottom extent up arrow                 */
+#define glass_EWSBOTTOMDOWN 13 /* Bottom extent down arrow              */
+#define glass_EWSBOTTOMLEFT 14 /* Bottom left extent writable area      */
+#define glass_EWSBRLARGE 15   /* Move bottom right outwards button      */
+#define glass_EWSMINWIDTH 17  /* Minimum width writable area            */
+#define glass_EWSMINWSET 18   /* Min width set to current width button  */
+#define glass_EWSMINHEIGHT 20 /* Minimum height writable area           */
+#define glass_EWSMINHSET 21   /* Min height set to current height button*/
+#define glass_EWSRUBBERH 23   /* Rubber horizontal extent switch        */
+#define glass_EWSRUBBERV 24   /* Rubber vertical extent switch         */
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/gMenus b/StraySrc/Glass/!Glass/h/gMenus
new file mode 100644 (file)
index 0000000..301e63c
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * gMenus.h
+ *
+ * Symbolic definitions of menus
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __gMenus_h
+#define __gMenus_h
+
+/*----- Icon bar menu -----------------------------------------------------*/
+
+enum
+{
+  glass_IBARINFO=1,           /* Info...        >                       */
+  glass_IBARPREFS,            /* Preferences...                         */
+  glass_IBARTBOX,             /* Toolbox...                             */
+  glass_IBARHEAPINFO,         /* Heap info...                           */
+  glass_IBARQUIT              /* Quit                                   */
+};
+
+/*----- Template file menu ------------------------------------------------*/
+
+enum
+{
+  glass_TFINFO=1,             /* Info...         >                      */
+  glass_TFDISP,               /* Display         >                      */
+  glass_TFSEL,                /* Window 'name'   >                      */
+  glass_TFSELALL,             /* Select all                             */
+  glass_TFCLRSEL,             /* Clear selection                        */
+  glass_TFSAVE,               /* Save...         >                      */
+  glass_TFCREATE,             /* Create...       >                      */
+  glass_TFGRAB,               /* Grab window...  >                      */
+  glass_TFSHWSPR              /* Show sprites    >                      */
+#ifdef glass_NOTLAZY
+  glass_TFSTYLES              /* Icon styles     >                      */
+#endif
+};
+
+enum
+{
+  glass_TFDLARGE=1,           /* Large icons                            */
+  glass_TFDSMALL,             /* Small icons                            */
+  glass_TFDSORTNAME,          /* Sort by name                           */
+  glass_TFDSORTSIZE,          /* Sort by size                           */
+  glass_TFDSORTICONS,         /* Sort by no. of icons                   */
+  glass_TFDNOSORT             /* Don't sort                             */
+};
+
+enum
+{
+  glass_TFSELINFO=1,          /* Info...   >                            */
+  glass_TFSELEDIT,            /* Edit...                                */
+  glass_TFSELCOPY,            /* Copy...   >                            */
+  glass_TFSELRENAME,          /* Rename... >                            */
+  glass_TFSELSAVE,            /* Save...   >                            */
+  glass_TFSELDELETE           /* Delete                                 */
+};
+
+#ifdef glass_NOTLAZY
+enum
+{
+  glass_TFSTYLESEDIT=1,       /* Edit style...                          */
+  glass_TFSTYLESNEW,          /* New style...                           */
+  glass_TFSTYLESSAVE          /* Save...       >                        */
+};
+#endif
+
+/*----- Sprite viewer menu ------------------------------------------------*/
+
+enum
+{
+  glass_SPINFO=1,             /* Info...         >                      */
+  glass_SPSEL,                /* Sprite 'name'   >                      */
+  glass_SPSELALL,             /* Select all                             */
+  glass_SPCLRSEL,             /* Clear selection                        */
+  glass_SPSAVE,               /* Save...         >                      */
+  glass_SPGRAB                /* Grab sprite...                         */
+};
+
+enum
+{
+  glass_SPSELINFO=1,          /* Info...   >                            */
+  glass_SPSELCOPY,            /* Copy...   >                            */
+  glass_SPSELRENAME,          /* Rename... >                            */
+  glass_SPSELSAVE,            /* Save...   >                            */
+  glass_SPSELDELETE           /* Delete                                 */
+};
+
+/*----- Template window menu ----------------------------------------------*/
+
+enum
+{
+  glass_TWMISC=1,             /* Misc        >                          */
+  glass_TWSAVE,               /* Save...  F3 >                          */
+  glass_TWSELECT,             /* Select      >                          */
+  glass_TWICON,               /* Create icon >                          */
+  glass_TWEDIT,               /* Edit icon   >                          */
+  glass_TWGRID,               /* Grid...     >                          */
+  glass_TWGDE                 /* Guides      >                          */
+};
+
+enum
+{
+  glass_TWMINFO=1,            /* Info...          ^F1 >                 */
+  glass_TWMEDITWIN,           /* Edit window...    ^W                   */
+  glass_TWMTEST,              /* Test mode         ^T                   */
+  glass_TWMREMDEL,            /* Remove deleted icons                   */
+  glass_TWMBRINGBK,           /* Bring back icons                       */
+  glass_TWMCLOSE              /* Close window     ^F2                   */
+};
+
+enum
+{
+  glass_TWSALL=1,             /* Select all      ^A                     */
+  glass_TWSCLR,               /* Clear selection ^Z                     */
+  glass_TWSCOPY,              /* Copy            ^C                     */
+  glass_TWSDEL,               /* Delete          ^X                     */
+  glass_TWSORDER,             /* Reorder         ^R                     */
+  glass_TWSFRONT,             /* Bring to front s^F                     */
+  glass_TWSRAISE,             /* Raise           ^F                     */
+  glass_TWSLOWER,             /* Lower           ^B                     */
+  glass_TWSBACK,              /* Put to back    s^B                     */
+  glass_TWSPULL,              /* Pull onto grid  ^P                     */
+  glass_TWSALIGN,             /* Align...        ^A                     */
+  glass_TWSEDIT,              /* Edit...         ^E                     */
+#ifdef glass_NOTLAZY
+  glass_TWSDATA,              /* Icon data       ^D >                   */
+#endif
+  glass_TWSBTYPE              /* Button type        >                   */
+#ifdef glass_NOTLAZY
+  glass_TWSSTYLE              /* Apply style        >                   */
+#endif
+};
+
+enum
+{
+  glass_TWINEW=1,             /* New icon  ^N                           */
+  glass_TWIPAL,               /* Show palette                           */
+  glass_TWIGRAB               /* Grab icon ^G                           */
+};
+
+enum
+{
+  glass_TWGSELALL=1,          /* Select all                             */
+  glass_TWGCLRSEL,            /* Clear selection                        */
+  glass_TWGDEL,               /* Delete selection                       */
+  glass_TWGHORIZ,             /* Create horizontal                      */
+  glass_TWGVERT               /* Create vertical                        */
+};
+
+/*----- Preferences -------------------------------------------------------*/
+
+/*
+ * The very small Units menu
+ */
+
+enum
+{
+  glass_PUHOURS=1,            /* Hours                                  */
+  glass_PUMINUTES,            /* Minutes                                */
+  glass_PUSECONDS             /* Seconds                                */
+};
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/gPrefs b/StraySrc/Glass/!Glass/h/gPrefs
new file mode 100644 (file)
index 0000000..ffc1b9e
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * gPrefs.h
+ *
+ * Loading, saving, alteration and setting of preferences
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __gPrefs_h
+#define __gPrefs_h
+
+/*----- Required headers --------------------------------------------------*/
+
+#ifndef __glass_h
+  #include "glass.h"
+#endif
+
+/*----- Structure definitions ---------------------------------------------*/
+
+typedef enum
+{
+  gPrefs_SECONDS=3,
+  gPrefs_MINUTES=2,
+  gPrefs_HOURS=1
+}
+gPrefs_autoUnits;
+
+typedef enum
+{
+  gPrefs_LARGE=1,
+  gPrefs_SMALL
+}
+gPrefs_iconSize;
+
+typedef enum
+{
+  gPrefs_NAME=1,
+  gPrefs_SIZE,
+  gPrefs_ICONS,
+  gPrefs_NOSORT
+}
+gPrefs_sortType;
+
+typedef struct
+{
+  int x;
+  int y;
+}
+gPrefs_coords;
+
+typedef struct
+{
+  gPrefs_autoUnits aUnit;        /* Autosave time unit                     */
+  int aTime;                     /* Timed autosave                         */  int aAlts;                     /* Alteration-driven autosave             */
+  BOOL aPrompt;                  /* Prompt on autosave                     */
+
+  BOOL iDispBorders;             /* Display Interface borders              */
+  BOOL iSlabIcons;               /* Slab icons on click                    */
+  BOOL iIncBorder;               /* Include interface borders in drags     */
+  BOOL iSlabMenu;                /* Slab buttons on menu click             */
+
+  BOOL wDispBorders;             /* Display WimpExtension borders          */
+  BOOL wKeyPress;                /* Slab icons on click                    */
+  BOOL wIncBorder;               /* Include WimpExtension borders in drags */
+
+  BOOL sDispBorders;             /* Display Skulpted borders               */
+  BOOL sSlabIcons;               /* Slab icons on click                    */
+  BOOL sIncBorder;               /* Include Skulpted borders in drags      */
+  BOOL sSlabMenu;                /* Slab buttons on menu click             */
+
+  BOOL sLoadSpr;                 /* Load Sprites file                      */
+  BOOL sLoadPSpr;                /* Load !Sprites file                     */
+  BOOL sLoadDef;                 /* Load default Glass file                */
+
+  gPrefs_iconSize fIcons;        /* Template file viewer icon size         */
+  gPrefs_sortType fSort;         /* Template file viewer sort system       */
+
+  BOOL gDisp;                    /* Grid display                           */
+  BOOL gLock;                    /* Grid lock                              */
+  int gWidth;                    /* Grid width                             */
+  int gHeight;                   /* Grid height                            */
+  BOOL gLines;                   /* Draw grid lines (rather than points)   */
+  int gGridCol;                  /* Grid colour                            */
+  int gGdeCol;                   /* Guide colour                           */
+  int gGdeSelCol;                /* Selected guide colour                  */
+
+  BOOL sBorder;                  /* Draw selection border                  */
+  BOOL sDotted;                  /* Selection border dotted line           */
+  int sBColour;                  /* Border colour                          */
+  BOOL sEdgeHandles;             /* Include edge drag handles              */
+  int sHandSize;                 /* Handle size                            */
+  int sHColour;                  /* Handle colour                          */
+  int sSColour;                  /* Special handle colour                  */
+
+  BOOL cQuit;                    /* Confirm quit with unsaved files        */
+  BOOL cClose;                   /* Confirm close unsaved file             */
+  BOOL cDelWind;                 /* Confirm delete window                  */
+  BOOL cDelIcon;                 /* Confirm delete icon                    */
+  BOOL cTest;                    /* Confirm closing edits on test mode     */
+  BOOL cSave;                    /* Confirm overwriting files              */
+
+  BOOL tDisplay;                 /* Display the toolbar                    */
+  BOOL tFloating;                /* Free-floating toolbar                  */
+  gPrefs_coords tPosn;           /* Toolbar position on screen             */
+  BOOL tLeft;                    /* Is the tool bar on the left of window  */
+
+  BOOL iDisplay;                 /* Display the infobar                    */
+  BOOL iFloating;                /* Free-floating infobar                  */
+  gPrefs_coords iPosn;           /* Infobar position on screen             */
+  BOOL iUnder;                   /* Is the info bar under the window       */
+
+  BOOL mDrawHatch;               /* Draw a hatch pattern in windows        */
+  BOOL mBlink;                   /* Blink the cursor                       */
+  BOOL mVisInWork;               /* Keep visiable area in work area        */
+  BOOL mCreateTop;               /* Create icons on top                    */
+  BOOL mDeleteRenum;             /* Keep icon numbers on delete            */
+  BOOL mCtrlEdit;                /* Require control key on edit            */
+}
+gPrefs_prefs;
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void gPrefs_init(void)
+ *
+ * Use
+ *  Reads preferences file and initialises things accordingly
+ */
+
+void gPrefs_init(void);
+
+/*
+ * gPrefs_prefs *gPrefs_current(void)
+ *
+ * Use
+ *  Returns the current preferences settings.
+ *
+ * Returns
+ *  A pointer to the structure as defined above.
+ */
+
+gPrefs_prefs *gPrefs_current(void);
+
+/*
+ * int gPrefs_autoTiming(void)
+ *
+ * Use
+ *  Returns the current autosave time in centiseconds, or 0 for no timed
+ *  autosave.
+ */
+
+int gPrefs_autoTiming(void);
+
+/*
+ * void gPrefs_edit(void)
+ *
+ * Use
+ *  Opens the preferences dialogue box to allow editing of preferences.
+ */
+
+void gPrefs_edit(void);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/gSprite b/StraySrc/Glass/!Glass/h/gSprite
new file mode 100644 (file)
index 0000000..b5b3624
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * gSprite.c
+ *
+ * Handling of template file sprite windows and areas
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __gSprite_h
+#define __gSprite_h
+
+/*----- Required header files ---------------------------------------------*/
+
+#ifndef __gStruct_h
+  #include "gStruct.h"
+#endif
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void gSprite_kill(glass_tfile *t)
+ *
+ * Use
+ *  Closes the sprite viewer and frees the sprite area
+ *
+ * Parameters
+ *  glass_tfile *t == the template file that's closing
+ */
+
+void gSprite_kill(glass_tfile *t);
+
+/*
+ * void gSprite_display(glass_tfile *t)
+ *
+ * Use
+ *  Displays the sprite viewer for the specified template file.
+ *
+ * glass_tfile *t == the template file whose sprites we want to see
+ */
+
+void gSprite_display(glass_tfile *t);
+
+/*
+ * void gSprite_mergeFromMemory(glass_tfile *t,void **p)
+ *
+ * Use
+ *  Merges a sprite file which is stored in memory.  This is so I can do
+ *  in-memory transfer of sprites.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file owner of the sprite area
+ *  void **p == the flex block stroing the sprite file
+ */
+
+void gSprite_mergeFromMemory(glass_tfile *t,void **p);
+
+/*
+ * void gSprite_mergeFromFile(glass_tfile *t,char *name)
+ *
+ * Use
+ *  Merges the given file into the sprite area specified.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file that we're going to load for
+ *  char *name == the name of the file to load
+ */
+
+void gSprite_mergeFromFile(glass_tfile *t,char *name);
+
+/*
+ * void gSprite_new(glass_tfile *t)
+ *
+ * Use
+ *  Creates a sprite file for the given template file.  Initially, the file
+ *  is blank.  On failure, an error is generated and sprite area 1 (WIMP
+ *  pool) is used instead.  Note that at present, this section uses indir
+ *  for allocation of sprite areas.
+ *
+ * Parameters
+ *  glass_tfile *t == the file to use
+ */
+
+void gSprite_new(glass_tfile *t);
+
+/*
+ * sprite_area *gSprite_area(void)
+ *
+ * Use
+ *  Returns the address of the Glass default sprite file, or 1 for the
+ *  WIMP sprite area if no default sprites are loaded
+ */
+
+sprite_area *gSprite_area(void);
+
+/*
+ * void gSprite_init(void)
+ *
+ * Use
+ *  Loads the Glass default sprite area into memory.
+ */
+
+void gSprite_init(void);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/gStruct b/StraySrc/Glass/!Glass/h/gStruct
new file mode 100644 (file)
index 0000000..7b1ef71
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * gStruct.h
+ *
+ * Data structure definitions (annotated)
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __gStruct_h
+#define __gStruct_h
+
+#ifndef __gPrefs_h
+  #include "gPrefs.h"
+#endif
+
+#ifndef __wimp_h
+  #include "steel/wimp.h"
+#endif
+
+#ifndef __dbox_h
+  #include "steel/dbox.h"
+#endif
+
+#ifndef __viewer_h
+  #include "steel/viewer.h"
+#endif
+
+#ifndef __pane_h
+  #include "steel/pane.h"
+#endif
+
+typedef struct glass_tfile
+/*
+ * Structure contains information about template file in general.  Specifics
+ * are handled by viewer segment of Steel as handles for viewer icons.
+ */
+{
+  viewer v;                      /* The viewer window displaying this file */
+  sprite_area *s;                /* The sprite area for the template file  */
+  viewer vs;                     /* The viewer for the sprite area         */
+  int alts;                      /* Number of alterations since saving     */
+  int autoTime;                  /* Time of first alteration               */
+  int autoAlarm;                 /* Alarm time for next autosave           */
+  char filename[256];            /* What is the file's name?               */
+  dbox autod;                    /* Dialogue box for autosave              */
+  gPrefs_iconSize isz;           /* Icon size for displaying               */
+  gPrefs_sortType sort;          /* How to sort icons in the display       */
+  BOOL loaded               : 1; /* Does the file have a sensible name?    */
+  BOOL autoSaved            : 1; /* Has the file been autosaved?           */
+}
+glass_tfile;
+
+typedef struct glass_edit
+/*
+ * Contains common edit information (dbox handles, panel number and so on)
+ */
+{
+  dbox d;                        /* Dialogue box handle for the edit       */
+  pane p;                        /* Pane holding current panel in place    */
+  dbox pd;                       /* Dbox handle of the current panel       */
+  dbox_field panel;              /* The currently selcted panel            */
+}
+glass_edit;
+
+typedef struct glass_editWindow
+/*
+ * Contains complete information about an edit window window
+ */
+{
+  glass_edit e;                  /* Common edit information                */
+  struct glass_windPointer *w;   /* The window to edit                     */
+  wimp_wind wdef;                /* The window definition in the dbox      */
+  char data[256];                /* The title bar data text                */
+  char valid[256];               /* The title bar validation string        */
+  int indLen;                    /* Length of indirected data              */
+  BOOL hasValid;                 /* Short cut to whether vstring exists    */
+  char font[40];                 /* Font name for the title                */
+  int fontSize;                  /* Font size                              */
+}
+glass_editWindow;
+
+typedef struct glass_editIcon
+/*
+ * Contains complete information about an edit icon window
+ */
+{
+  glass_edit e;                  /* Common edit information                */
+  struct glass_windPointer *w;   /* The window containing the icon to edit*/
+  int i;                         /* The icon number to edit                */
+  wimp_icon idef;                /* The icon definition in the dbox        */
+  char data[256];                /* The icon data text                     */
+  char valid[256];               /* The icon validation string             */
+  int indLen;                    /* Length of indirected data              */
+  BOOL hasValid;                 /* Short cut to whether vstring exists    */
+  char font[40];                 /* Font name for the icon                 */
+  int fontSize;                  /* Font size                              */
+}
+glass_editIcon;
+
+typedef struct glass_guide
+/*
+ * Contains information on window guide lines.
+ */
+{
+  int coord;                     /* The guide's position                   */
+  BOOL active               : 1; /* Is it currently active?                */
+  BOOL horiz                : 1; /* TRUE == horizontal, FALSE == vertical  */
+  BOOL selected             : 1; /* Is the guideline selected?             */
+}
+glass_guide;
+
+#define glass_GUIDELIMIT 16      /* Allow 16 guides per window             */
+
+typedef struct glass_windPointer
+/*
+ * Contains mainly status information about a window, and points to the flex
+ * block containing the actual window definition in internal form.
+ */
+{
+  char id[15];                   /* The window identifier                  */
+  glass_tfile *t;                /* The template file                      */
+  viewer_icon i;                 /* The viewer icon handle                 */
+  struct glass_window *def;      /* Flex anchor point for definiton block  */
+  wimp_w h;                      /* Window handle if open (or 0)           */
+  int selno;                     /* Number of icons selected               */
+  int lastClicked;               /* Last icon clicked (for depthwise sel)  */
+  glass_editWindow *edit;        /* Pointer to edit information, or 0      */
+  int gridx;                     /* Grid width                             */
+  int gridy;                     /* Grid height                            */
+  int size;                      /* Memory taken up by the definition      */
+  int serial;                    /* Serial number of this window           */
+  glass_guide guide[glass_GUIDELIMIT]; /* Array of guide defs              */
+  wimp_box tex;                         /* Current temporary window extent        */
+  char fonts[256];               /* Font usage array for this window       */
+  BOOL ownPointer           : 1; /* TRUE if this window contains the ptr   */
+  BOOL renumber             : 1; /* TRUE if we're reordering icons         */
+  BOOL gridShow             : 1; /* Display the grid onsceeen?             */
+  BOOL gridLock             : 1; /* Snap to the grid?                      */
+  BOOL antiAliased          : 1; /* Quick check for fonts                  */
+#ifndef glass_DEMO
+  BOOL testMode             : 1; /* TRUE if the window is in test mode     */
+#endif
+}
+glass_windPointer;
+
+typedef struct glass_windDescription
+/*
+ * Defines how a window is laid out internally in Glass's workspace.
+ */
+{
+  wimp_wind w;                   /* The window definition                  */
+}
+glass_windDescription;
+
+typedef struct glass_iconDescription
+/*
+ * Icon description (internal format) used in flex block.
+ */
+{
+  glass_editIcon *edit;          /* Is the icon being edited?              */
+  wimp_icon i;                   /* The icon definition                    */
+  BOOL selected             : 1; /* Is the icon selected (for manipulation */
+                                 /*  in Glass, not in the WIMP sense)      */
+  BOOL copied               : 1; /* Is the icon a new copy (i.e. select it */
+                                 /*  after a copy op)                      */
+}
+glass_iconDescription;
+
+typedef struct glass_window
+/*
+ * Contains a complete window definiton.  This describes exactly what is
+ * contained in the window definiton flex block.
+ */
+{
+  glass_windDescription desc;    /* Description of window (not icons)      */
+  glass_iconDescription i[1];    /* Description of icons                   */
+}
+glass_window;
+
+/*
+ * Macros to allow indirection to a structure in a flex block
+ *
+ * flex == flex pointer (any pointer)
+ * offset == integer offset (in bytes)
+ *
+ * Example
+ *  iconptr(w->def,off)->flags.indirect=TRUE;
+ */
+
+#define intptr(flex,offset) \
+  ((int *)(((char *)(flex))+(offset)))
+#define charptr(flex,offset) \
+  (((char *)(flex))+(offset))
+#define winptr(flex,offset) \
+  ((glass_window *)(((char *)(flex))+(offset)))
+#define iconptr(flex,offset) \
+  ((glass_iconDescription *)(((char *)(flex))+(offset)))
+#define _ptr(type,flex,offset) \
+  ((type *)(((char *)(flex))+(offset)))
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/glass b/StraySrc/Glass/!Glass/h/glass
new file mode 100644 (file)
index 0000000..834bc9d
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * glass.h
+ *
+ * Central information header file
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __glass_h
+#define __glass_h
+
+/*----- Standard macros ---------------------------------------------------*/
+
+#define unused(x) ((x)=(x))      /* Prevents compiler complaints about     */
+                                 /* unused variables                       */
+
+#ifndef BOOL
+#define BOOL int                 /* Standard type definition, fits in with */
+#define TRUE 1                   /* the RISC_OSlib definition              */
+#define FALSE 0
+#endif
+
+/*----- Bitwise operators -------------------------------------------------*/
+
+#define bit(b) (1<<(b))          /* Returns the appropriate bit set        */
+#define tst(x,b) (((x)>>(b))&1)  /* Test bit and return TRUE or FALSE      */
+#define set(x,b) (x)|=bit(b);    /* Set appropriate bit                    */
+#define reset(x,b) (x)&=~bit(b); /* Reset appropriate bit                  */
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/iconData b/StraySrc/Glass/!Glass/h/iconData
new file mode 100644 (file)
index 0000000..145bc42
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * iconData.h
+ *
+ * Central handling for icon data
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __iconData_h
+#define __iconData_h
+
+/*----- Required header files ---------------------------------------------*/
+
+#ifndef __gStruct_h
+  #include "gStruct.h"
+#endif
+
+/*----- Type definitions --------------------------------------------------*/
+
+typedef char *(*iconData_proc)(char *ptr,void *handle);
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * BOOL iconData_processIcon
+ * (
+ *   glass_windPointer *w,
+ *   int i;
+ *   iconData_proc proc,
+ *   BOOL updateSize,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Processes one icon in the given window.  This routine will replace all
+ *  the indirection pointers with pointers to blocks from the indirection
+ *  heap.
+ *
+ * Parameters
+ *   glass_windPointer *w == the window data from which the icon is from
+ *   int i == the icon to update (-1 for the title)
+ *   BOOL updateSize == whether to update the window's size variable
+ *   iconData_proc proc == function to return a pointer to an indirected
+ *     string given what's in the data word.  Pass 0 if its actually a
+ *     valid pointer
+ *   void *handle == pointer to pass to 'proc'
+ *
+ * Returns
+ *  FALSE if it ran out of memory, or TRUE for success
+ */
+
+BOOL iconData_processIcon
+(
+  glass_windPointer *w,
+  int i,
+  iconData_proc proc,
+  BOOL updateSize,
+  void *handle
+);
+
+
+/*
+ * BOOL iconData_handleFont(glass_windPointer *w,wimp_iconflags *f)
+ *
+ * Use
+ *  Processes a font handle, refinding etc. and adding to font reference
+ *  array.  It assumes the icon is from an external source, and doesn't
+ *  attempt to free the font.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon/title to fiddle
+ *  wimp_iconflags *f == icon flags to fiddle with
+ *
+ * Returns
+ *  TRUE if all went well, or FALSE if the icon's font has been lost.  In
+ *  this case the icon has been deantialiased(!) leaving potentially very
+ *  strange colours.
+ */
+
+BOOL iconData_handleFont(glass_windPointer *w,wimp_iconflags *f);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/indir b/StraySrc/Glass/!Glass/h/indir
new file mode 100644 (file)
index 0000000..70b0da6
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * indir.h
+ *
+ * Control of indirected data allocation
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __indir_h
+#define __indir_h
+
+/*----- External routines -------------------------------------------------*/
+
+#ifndef __size_t
+#define __size_t 1
+typedef unsigned int size_t;   /* from <stddef.h> */
+#endif
+
+/*
+ * void indir_init(void)
+ *
+ * Use
+ *  Jumps in to ensure that indir gets the first flex block, so it doesn't
+ *  move.
+ */
+
+void indir_init(void);
+
+/*
+ * void *indir_alloc(int size)
+ *
+ * Use
+ *  Allocate memory from heap.
+ *
+ * Parameters
+ *  int size == the number of bytes the caller wants
+ */
+
+void *indir_alloc(size_t size);
+
+/*
+ * void indir_free(void *p)
+ *
+ * Use
+ *  Reclaims the memory from the block pointed to by p.  Some simple checks
+ *  are used to ensure that p is valid.
+ *
+ * Parameters
+ *  void *p == pointer to a block to free.
+ */
+
+void indir_free(void *p);
+
+/*
+ * void *indir_realloc(void *p,int newsize)
+ *
+ * Use
+ *  Resizes a heap block.
+ *
+ * Parameters
+ *  void *p == pointer to block to resize
+ *  int newsize == the new size to make it
+ *
+ * Returns
+ *  Pointer to the block (may have moved) or 0 (failure, block didn't move)
+ */
+
+void *indir_realloc(void *p,int newsize);
+
+/*
+ * void indir_heapInfo(void)
+ *
+ * Use
+ *  Displays a dialogue box showing current heap stats
+ */
+
+void indir_heapInfo(void);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/intMsgs b/StraySrc/Glass/!Glass/h/intMsgs
new file mode 100644 (file)
index 0000000..74c1550
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * intMsgs.h
+ *
+ * Definitions of Glass internal broadcasts
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Background information --------------------------------------------*
+ *
+ * Various operations require that many separate parts of the Glass
+ * program are informed of changes made to the state of the application
+ * (i.e. when windows are deleted, all Edit windows associated with the
+ * window must be removed).  The easiest way of doing this was deemed to be
+ * to use the new Steel broadcast system.  A new message has been
+ * created, called Message_StraylightInternal (message number &427FF, defined
+ * as wimp_MINTERNAL in wimp.h).  Messages should be passed to intMsgs_send,
+ * which constructs a message block, and then sends out the message via
+ * win_broadcast.  In raw event handlers, interested windows should scan for
+ * message wimp_MINTERNAL, and use intMsgs_receive to extract the
+ * information from the event block.  For speed, this has been implemented as
+ * a macro.  This may not always be the case.
+ */
+
+#ifndef __intMsgs_h
+#define __intMsgs_h
+
+/*----- Required header files ---------------------------------------------*/
+
+#ifndef __gStruct_h
+  #include "gStruct.h"
+#endif
+
+/*----- Message codes and meanings ----------------------------------------*/
+
+typedef enum
+{
+  glass_DELETEWINDOW,         /* Deleting a window                      */
+  glass_DELETEFILE,           /* Deleting a whole file                  */
+  glass_KILLFILES,            /* Close all open files, on PREQUIT       */
+  glass_CLOSEDOWN,            /* Closing down the application           */
+  glass_RENAME,               /* Renaming a window                      */
+  glass_SAVEFILE,             /* A file has been saved                  */
+  glass_REDRAW,               /* Request to redraw windows              */
+  glass_AUTOSAVE,             /* Autosave timings have changed          */
+  glass_SPRITECHANGE,         /* A template file's sprite area changed  */
+  glass_MODECHANGE            /* The screen mode has changed            */
+}
+glass_intMessage;
+
+/*----- Structure definitions ---------------------------------------------*/
+
+typedef union
+{
+  struct {
+    glass_windPointer *w;     /* The window being deleted               */
+  } dw;                          /* glass_DELETEWINDOW                  */
+
+  struct {
+    glass_tfile *t;           /* The file being deleted                 */
+  } df;                          /* glass_DELETEFILE                    */
+
+    struct {
+    glass_windPointer *w;     /* The window being renamed               */
+  } rn;                          /* glass_RENAME                        */
+
+  struct {
+    glass_tfile *t;           /* The file that was saved                */
+  } sf;                          /* glass_SAVEFILE                      */
+
+  struct {
+    glass_tfile *t;           /* The file to redraw, or 0 for all       */
+  } rdr;                         /* glass_REDRAW                        */
+
+  struct {
+      int newTime;               /* The new autosave time in centiseconds  */
+  } as;                          /* glass_AUTOSAVE                      */
+
+  struct {
+    glass_tfile *t;           /* The template file whose area changed   */
+  } sc;                          /* glass_SPRITECHANGE                  */
+}
+glass_intMsgstr;
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void intMsgs_send(glass_intMessage type,...)
+ *
+ * Use
+ *  Sends out an internal broadcast message.  The routine constructs a
+ *  Message_StraylightInternal block and sends it out via win_broadcast.
+ *  The parameters should be as for the entries in the appropriate
+ *  structure, in order (i.e one for glass_DELETEWINDOW, two for
+ *  glass_DELETEICON).
+ *
+ * Parameters
+ *  glass_intMessage type == the message type.  This is used to decide
+ *    how many and what type of parameters to accept.
+ */
+
+void intMsgs_send(glass_intMessage type,...);
+
+/*
+ * glass_intMsgstr *intMsgs_receive(wimp_eventstr *e)
+ *
+ * Use
+ *  Returns a pointer to an internal message structure type.  No checking is
+ *  done to ensure that the event is correct.  This routine is implemented
+ *  as a macro.  There is no guarantee that this will continue to be the
+ *  case.
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event to use
+ */
+
+#define intMsgs_receive(e) \
+  ((glass_intMsgstr *)(&(e)->data.msg.data.words[1]))
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/tearEdit b/StraySrc/Glass/!Glass/h/tearEdit
new file mode 100644 (file)
index 0000000..0c9bc24
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * tearEdit.c
+ *
+ * Editing icons in tearoff menus
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __tearEdit_h
+#define __tearEdit_h
+
+/*----- Required headers --------------------------------------------------*/
+
+#ifndef __gStruct
+  #include "gStruct.h"
+#endif
+
+/*----- External functions ------------------------------------------------*/
+
+/*
+ * void tearEdit_open(void)
+ *
+ * Use
+ *  Opens the edit icon menu, as a submenu if appropriate, otherwise as a
+ *  full menu.
+ */
+
+void tearEdit_open(void);
+
+/*
+ * void tearEdit_update(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Updates the edit icon menu from the specified window and icon.  If the
+ *  window handle is 0, or the icon is -1 then the menu is made unavailable
+ *  (i.e. its items are shaded).  Otherwise, the menu is updated to reflect
+ *  the state of the icon.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon to edit
+ *  int icon == the icon to be editing in the menu
+ */
+
+void tearEdit_update(glass_windPointer *w,int icon);
+
+/*
+ * void tearEdit_init(void)
+ *
+ * Use
+ *  Initialises the tearoff menus for editing icons and starts up the tearoff
+ *  menu manager.
+ */
+
+void tearEdit_init(void);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/tfile b/StraySrc/Glass/!Glass/h/tfile
new file mode 100644 (file)
index 0000000..40c8231
--- /dev/null
@@ -0,0 +1,234 @@
+/*
+ * tfile.c
+ *
+ * Control of template files
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __tfile_h
+#define __tfile_h
+
+/*----- Required headers --------------------------------------------------*/
+
+#ifndef __gStruct_h
+  #include "gStruct.h"
+#endif
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * BOOL tfile_okToQuit(BOOL ask)
+ *
+ * Use
+ *  Ensures that it is 'safe' for Glass to quit.
+ *
+ * Parameters
+ *  BOOL ask == should I open a dialogue to ask the user?
+ *
+ * Returns
+ *  TRUE if it is safe to quit, or FALSE if not.
+ */
+
+BOOL tfile_okToQuit(BOOL ask);
+
+/*
+ * void tfile_markAsAltered(glass_tfile *t)
+ *
+ * Use
+ *  Marks down another alteration for the template file, changing the window
+ *  title if required etc.  Also handles stuff for autosave etc.
+ *
+ * Parameters
+ *  glass_tfile *t == the template file to alter
+ */
+
+void tfile_markAsAltered(glass_tfile *t);
+
+/*
+ * void tfile_markAsSaved(glass_tfile *t,char *newName)
+ *
+ * Use
+ *  Marks a template file as having been saved.  Turns off autosave and
+ *  things.
+ *
+ * Parameters
+ *  glass_tfile *t == the file to mark
+ *  char *newName == the new name to give to the file
+ */
+
+void tfile_markAsSaved(glass_tfile *t,char *newName);
+
+/*
+ * void tfile_windowInfo(glass_windPointer *w)
+ *
+ * Use
+ *  Displays an info box for a single window
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to display info on
+ */
+
+void tfile_windowInfo(glass_windPointer *w);
+
+/*
+ * void tfile_deleteWindow(glass_windPointer *w)
+ *
+ * Use
+ *  Deletes a single window.
+ *
+ * Parameters
+ *  viewer_icon i == the icon to get
+ *  void *handle ==  the window to eliminate (as a glass_windPointer *)
+ */
+
+void tfile_deleteWindow(viewer_icon i,void *handle);
+
+/*
+ * BOOL tfile_rename(char *newName,void *handle)
+ *
+ * Use
+ *  Renames the specified window
+ *
+ * Parameters
+ *  char *newName == the new name of the window
+ *  void *handle == pointer to the window structure
+ */
+
+BOOL tfile_rename(char *newName,void *handle);
+
+/*
+ * void tfile_saveTemplates(glass_tfile *t)
+ *
+ * Use
+ *  Saves a template file using a standard dialogue box
+ *
+ * Parameters
+ *  glass_tfile *t == the template file to save
+ */
+
+void tfile_saveTemplates(glass_tfile *t);
+
+/*
+ * void tfile_saveWindow(glass_windPointer *w)
+ *
+ * Use
+ *  Saves a single window using a standard dialogue box
+ *
+ * Parameters
+ *  glass_windPointer *w == pointer to the window to save
+ */
+
+void tfile_saveWindow(glass_windPointer *w);
+
+/*
+ * void tfile_mergeFromMemory(void **p,glass_tfile *t)
+ *
+ * Use
+ *  Actually does a merge operation.  The target file is a glass_tfile in
+ *  memory (internal format) and the source file is a memory image of a
+ *  normal template file.
+ *
+ * Parameters
+ *  void **p == a flex anchor pointer to the source file
+ *  glass_tfile *t == a pointer to the destination file
+ */
+
+BOOL tfile_mergeFromMemory(void **p,glass_tfile *t);
+
+/*
+ * void tfile_mergeFromFile(char *file,glass_tfile *t)
+ *
+ * Use
+ *  Merges the template file given into the given template file structure.
+ *
+ * Parameters
+ *  char *file == the file to load
+ *  glass_tfile *t == the template file structure to merge with
+ */
+
+BOOL tfile_mergeFromFile(char *file,glass_tfile *t);
+
+/*
+ * glass_tfile *tfile_createTemplateFile(char *name)
+ *
+ * Use
+ *  Creates a template file with the given name, but doesn't open its viewer.
+ *
+ * Returns
+ *  A pointer to the file structure, or zero as failure.
+ */
+
+glass_tfile *tfile_createTemplateFile(char *name);
+
+/*
+ * glass_tfile *tfile_loadFromMemory(void **p,char *name)
+ *
+ * Use
+ *  Loads a file from memory, i.e. from another application via RAM
+ *  transfer.
+ *
+ * Parameters
+ *  void **p == the memory block that contains the file to load.
+ *  char *name == the name to give to the file.
+ *
+ * Returns
+ *  A pointer to the template file, or 0
+ */
+
+glass_tfile *tfile_loadFromMemory(void **p,char *name);
+
+/*
+ * glass_tfile *tfile_loadFromFile(char *file,char *name)
+ *
+ * Use
+ *  Loads a template file into memory, translating the file into Glass's
+ *  internal format.  It does not create any windows, although it does
+ *  allocate font handles.
+ *
+ * Parameters
+ *  char *file == the name of the file to load
+ *  char *name == the name to insert in the title bar
+ *
+ * Returns
+ *  A pointer to the structure definition, or 0 for failure.  Note that this
+ *  will only occur if no windows could be loaded.
+ */
+
+glass_tfile *tfile_loadFromFile(char *file,char *name);
+
+/*
+ * void tfile_dragSelected(viewer_icon i,wimp_bbits b,char *package)
+ *
+ * Use
+ *  As for viewer_dragSelected, but uses the specified sprite as the
+ *  'package' sprite is solid sprite drags are enabled.
+ *
+ * Parameters
+ *  viewer_icon i == the icon to drag
+ *  wimp_bbits b == the button status that started it off
+ *  char *package == the sprite to use for a package drag
+ */
+
+void tfile_dragSelected(viewer_icon i,wimp_bbits b,char *package);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/toolbox b/StraySrc/Glass/!Glass/h/toolbox
new file mode 100644 (file)
index 0000000..d61f734
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * toolbox.h
+ *
+ * Toolbox handling
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __toolbox_h
+#define __toolbox_h
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * BOOL toolbox_toolSelected(void)
+ *
+ * Returns
+ *  TRUE if there is a tool selected.  This is useful for handlers thinking
+ *  of starting drag events.
+ */
+
+BOOL toolbox_toolSelected(void);
+
+/*
+ * void toolbox(void)
+ *
+ * Use
+ *  Opens the toolbox window.
+ */
+
+void toolbox(void);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/h/window b/StraySrc/Glass/!Glass/h/window
new file mode 100644 (file)
index 0000000..408c799
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * window.h
+ *
+ * Manipulation of window templates
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Glass.
+ *
+ * Glass is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Glass is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Glass.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __window_h
+#define __window_h
+
+/*----- Required header files ---------------------------------------------*/
+
+#ifndef __gStruct_h
+  #include "gStruct.h"
+#endif
+
+/*----- External routines -------------------------------------------------*/
+
+/*
+ * void window_updateToolbar(void)
+ *
+ * Use
+ *  Updates the display of toolbars as necessary in line with new
+ *  Preferences settings.  It is assumed that Preferences is intelligent
+ *  enough to only call this if something actually needs to be done!
+ */
+
+void window_updateToolbar(void);
+
+/*
+ * void window_boundingBox(glass_windPointer *w,int icon,wimp_box *box)
+ *
+ * Use
+ *  Gets the bounding box of the icon given and returns it in the block
+ *  pointed to by box
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon to 'boxise'
+ *  wimp_box *box == where to put the result
+ */
+
+void window_boundingBox(glass_windPointer *w,int icon,wimp_box *box);
+
+/*
+ * void window_setBox(glass_windPointer *w,int icon,wimp_box *box)
+ *
+ * Use
+ *  Sets the icon bounding box to the box given, taking into account
+ *  Interface borders and so on.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon number
+ *  wimp_box *box == the new box for the icon
+ */
+
+void window_setBox(glass_windPointer *w,int icon,wimp_box *box);
+
+/*
+ * glass_windPointer *window_selectionOwner(void)
+ *
+ * Use
+ *  Returns the window currently owning the selection.
+ */
+
+glass_windPointer *window_selectionOwner(void);
+
+/*
+ * void window_deleteIcon(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Deletes the icon specified, good an' proper.
+ *
+ * Parameters
+ *  glass_windPointer *w == the scene of the crime
+ *  int icon == the victim...
+ */
+
+void window_deleteIcon(glass_windPointer *w,int icon);
+
+/*
+ * void window_redrawIcon(glass_windPointer *w,int icon)
+ *
+ * Use
+ *  Sets the WIMP up to call for a redraw of the spcified icon (i.e. it
+ *  uses Wimp_ForceRedraw).
+ *
+ * Parameters
+ *  glass_windPointer *w == pointer to the window owning the icon
+ *  int icon == the icon to redraw
+ */
+
+void window_redrawIcon(glass_windPointer *w,int icon);
+
+/*
+ * void window_renumber(glass_windPointer *w,int icon,int new)
+ *
+ * Use
+ *  Renumbers an icon, by removing it from the array, shuffling others out
+ *  the way, and the putting it in its new position (i.e. its an insert
+ *  renumber, not a swap renumber like the old version - which wasn't
+ *  terribly useful...)
+ *
+ * Parameters
+ *  glass_windPointer *w == the window containing the icon
+ *  int icon == the icon to renumber
+ *  int new == the new number to give it
+ */
+
+BOOL window_renumber(glass_windPointer *w,int icon,int new);
+
+/*
+ * void window_hasBeenDeleted(glass_windPointer *w)
+ *
+ * Use
+ *  Informs the window system that a window is about to be deleted.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window that bites the dust
+ */
+
+void window_hasBeenDeleted(glass_windPointer *w);
+
+/*
+ * void window_grab(void (*proc)(wimp_mousestr *m,void *handle),void *handle)
+ *
+ * Use
+ *  Turns on 'grab mode' and calls the specified routine when a mouse button
+ *  is clicked.
+ *
+ * Parameters
+ *  void (*proc)(wimp_mousestr *m,void *handle) == the routine to call
+ *  void *handle == the handle to call the routine with
+ */
+
+void window_grab(void (*proc)(wimp_mousestr *m,void *handle),void *handle);
+
+/*
+ * BOOL window_grabbing(void)
+ *
+ * Use
+ *  Returns whether grab mode is set or not
+ *
+ * Returns
+ *  TRUE if grab mode set
+ */
+
+BOOL window_grabbing(void);
+
+/*
+ * void window_recreate(glass_windPointer *w)
+ *
+ * Use
+ *  Recreates a window after editing.  Nothing happens if the window is not
+ *  open already.  If an error occurs, the open window is removed and left
+ *  that way.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window to recreate
+ */
+
+void window_recreate(glass_windPointer *w);
+
+/*
+ * void window_close(glass_windPointer *w)
+ *
+ * Use
+ *  Closes the specified window.
+ *
+ * Parameters
+ *  glass_windPointer *w == the window wot we 'ave to close
+ */
+
+void window_close(glass_windPointer *w);
+
+/*
+ * void window_open(glass_windPointer *w,BOOL test)
+ *
+ * Use
+ *  Opens the specified window.  If the window is off-screen, it is moved
+ *  back.  This routine also registers all handlers required for editing the
+ *  window etc.  If the window is already open, it is brought to the front.
+ *
+ * Parameters
+ *  glass_windPointer *w == pointer to basic window information.
+ *  BOOL test == open in test mode or not
+ */
+
+void window_open(glass_windPointer *w,BOOL test);
+
+/*
+ * void window_init(void)
+ *
+ * Use
+ *  Reads the default template file and ceates the menu etc.
+ */
+
+void window_init(void);
+
+#endif
diff --git a/StraySrc/Glass/!Glass/s/toolSupprt b/StraySrc/Glass/!Glass/s/toolSupprt
new file mode 100644 (file)
index 0000000..7c97998
--- /dev/null
@@ -0,0 +1,110 @@
+;
+; toolSupprt.s
+;
+; Support for Toolbox operations
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Glass.
+;
+; Glass is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Glass is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Glass.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+                   GET     libs:Header
+                   GET     libs:SWIs
+
+;
+; This module attempts to call Wimp_DragBox without it generating exceptions
+; within the program.  Because most of it is operating system interface,
+; I've used standard register names, rather than APCS ones.  It does all
+; sorts of 'orrible things, and queasy maintenence programmers would be well
+; advised to look elsewhere for bits to tweak.
+;
+
+;----- External dependencies ------------------------------------------------
+
+                   AREA    |Asm$Code|,CODE,READONLY
+
+;----- External routines ----------------------------------------------------
+
+;
+; toolSupprt_doDrag
+;
+; Use
+;  Calls Wimp_DragBox, with suitable binding to prevent nasty errors from
+;  bringing the system down (with any luck).  It usurps a bunch of handlers,
+;  does the call, and puts the handlers back.  Pretty simple, really.
+;
+;  Because it does all sorts of 'orrible things, it doesn't use standard
+;  APCS headers.  Instead, it just stacks everything and gets on with it.
+;
+; C prototype
+;  void toolSupprt_doDrag(wimp_dragstr *d);
+;
+; On entry: a1 points to a Wimp_DragBox structure
+; On exit:  -
+;
+
+                   EXPORT  toolSupprt_doDrag
+toolSupprt_doDrag  ROUT
+                   STMFD   R13!,{R4-R12,R14}  ;Save the registers to save
+                   MOV     R11,R0             ;Look after pointer
+                   LDR     R8,=toolSupprt__ohand ;Point to old handler buff
+                   MOV     R0,#2              ;Prefetch abort handler
+                   ADR     R1,toolSupprt__handler ;Point to handler
+                   SWI     XOS_ChangeEnvironment ;Register handler
+                   STMIA   R8!,{R1-R3}        ;Store old handler info
+                   MOV     R0,#3              ;Data abort handler
+                   ADR     R1,toolSupprt__handler ;Point to handler
+                   SWI     XOS_ChangeEnvironment ;Register handler
+                   STMIA   R8!,{R1-R3}        ;Store old handler info
+                   MOV     R0,#4              ;Address exception handler
+                   ADR     R1,toolSupprt__handler ;Point to handler
+                   SWI     XOS_ChangeEnvironment ;Register handler
+                   STMIA   R8!,{R1-R3}        ;Store old handler info
+                   LDR     R0,=toolSupprt__stack ;Ready to store stack ptr
+                   STR     R13,[R0]           ;Stored
+
+                   MOV     R1,R11             ;Get block pointer again
+                   SWI     XWimp_DragBox      ;Do the dodgy SWI
+
+toolSupprt__handler
+                   MOV     R0,PC              ;Get PSR
+                   BIC     R0,R0,#3           ;Clear mode flags
+                   TEQP    R0,#0              ;Back to ol' user mode
+                   LDR     R0,=toolSupprt__stack ;Where we stored the stack
+                   LDR     R13,[R0]           ;Get stack pointer
+                   LDR     R8,=toolSupprt__ohand ;Point to old handler buff
+                   MOV     R0,#2              ;Prefetch abort handler
+                   LDMIA   R8!,{R1-R3}        ;Get old status
+                   SWI     XOS_ChangeEnvironment ;Put back old handler
+                   MOV     R0,#3              ;Data abort handler
+                   LDMIA   R8!,{R1-R3}        ;Get old status
+                   SWI     XOS_ChangeEnvironment ;Put back old handler
+                   MOV     R0,#4              ;Address exception handler
+                   LDMIA   R8!,{R1-R3}        ;Get old status
+                   SWI     XOS_ChangeEnvironment ;Put back old handler
+                   LDMFD   R13!,{R4-R12,PC}^  ;Return to caller
+
+;----- Static data ----------------------------------------------------------
+
+                   AREA    |Asm$Data|,DATA
+
+toolSupprt__ohand  %       4*3*3              ;Old handler information
+toolSupprt__stack  DCD     0                  ;Stack pointer
+
+                   END
diff --git a/StraySrc/Hammer/Makefile,fe1 b/StraySrc/Hammer/Makefile,fe1
new file mode 100644 (file)
index 0000000..d6ed677
--- /dev/null
@@ -0,0 +1,167 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+OBJS = \
+       o.hammer o.driver \
+       o.armEmul o.asm o.brkpt o.diss
+
+VERSION = 1.00
+
+#----- Compiling things -----------------------------------------------------
+
+all: Hammer
+
+LIBS = libs:o.quartz
+
+Hammer: $(OBJS) $(LIBS)
+       $(SETDATE) \
+               o.version \
+               quartz_help="Sledgehammer\t$(VERSION) ($(MODDATE)) $(CRIGHT)"
+       $(LD_MOD) $(OBJS) $(LIBS) o.version
+       $(SET_MOD)
+
+install: Hammer
+       $(INSTALL) Hammer <SSR$ModDir>
+
+clean:
+       -$(RM) o.* Hammer
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.hammer: s.hammer
+o.hammer: libs:header
+o.hammer: libs:swis
+o.hammer: quartz:quartz
+o.hammer: sh.armEmul
+o.hammer: sh.asm
+o.hammer: sh.diss
+o.hammer: sh.brkpt
+o.hammer: s.hammer
+o.hammer: libs:header
+o.hammer: libs:swis
+o.hammer: quartz:quartz
+o.hammer: sh.armEmul
+o.hammer: sh.asm
+o.hammer: sh.diss
+o.hammer: sh.brkpt
+o.driver: s.driver
+o.driver: libs:header
+o.driver: libs:swis
+o.driver: libs:stream
+o.driver: quartz:string
+o.driver: sh.brkpt
+o.driver: sh.armEmul
+o.driver: sh.asm
+o.driver: sh.diss
+o.driver: sh.hammer
+o.armEmul: s.armEmul
+o.armEmul: libs:header
+o.armEmul: libs:swis
+o.armEmul: libs:stream
+o.armEmul: sh.brkpt
+o.armEmul: sh.diss
+o.asm: s.asm
+o.asm: libs:header
+o.asm: libs:swis
+o.asm: libs:stream
+o.asm: quartz:string
+o.asm: sh.diss
+o.brkpt: s.brkpt
+o.brkpt: libs:header
+o.brkpt: libs:swis
+o.brkpt: libs:stream
+o.brkpt: sh.armEmul
+o.brkpt: sh.driver
+o.brkpt: sh.hammer
+o.diss: s.diss
+o.diss: libs:header
+o.diss: libs:swis
+o.diss: libs:stream
+o.diss: quartz:quartz
+o.diss: quartz:string
diff --git a/StraySrc/Hammer/s/armEmul b/StraySrc/Hammer/s/armEmul
new file mode 100644 (file)
index 0000000..1e7f68e
--- /dev/null
@@ -0,0 +1,1170 @@
+;
+; armEmul.s
+;
+; ARM emulation (MDW/TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Don't forget these things --------------------------------------------
+;
+; SWP
+; Trans pin on LDR/STR
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.brkpt
+               GET     sh.diss
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Hammer$$Code|,CODE,READONLY
+
+; --- ae_addr ---
+;
+; On entry:    --
+;
+; On exit:     R0 == address of armEmul routine
+;
+; Use:         Returns the address of the arm emulation code, for speedy
+;              calling.
+
+               EXPORT  ae_addr
+ae_addr                ADR     R0,armEmul
+               MOVS    PC,R14
+
+; --- armEmul ---
+;
+; On entry:    R0 == pointer to register block
+;
+; On exit:     Flags corrupted
+;              May return error
+;
+; Use:         Emulates a given ARM instruction.
+
+               EXPORT  armEmul
+armEmul                ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save some registers
+               MOV     R1,R0                   ;Keep the register block ptr
+               LDR     R2,[R1,#15*4]           ;Load current PC value
+               BIC     R0,R2,#&FC000003        ;Clear the PSR bits
+               BL      ae__translateAddr       ;Translate the address
+               LDR     R0,[R0,#0]              ;Load the instruction
+
+ ; --- Debugging stuff ---
+
+ [ {FALSE}
+ IMPORT stream_regDump
+ STMFD R13!,{R0-R2}
+ SWI   Stream_WriteS
+ =     "armEmul entered with instruction:",13,10,0
+ BIC   R0,R2,#&FC000003
+ BL    diss_address
+ LDR   R0,[R13,#0]
+ BL    diss_disassemble
+ SWI   Stream_Write0
+ SWI   Stream_NewLine
+
+ MOV   R0,R1
+ BL    stream_regDump
+ LDMIA R13!,{R0-R2}
+ RDUMP
+ ]
+
+               ; --- Make sure we need to execute the instruction ---
+
+               MOV     R3,R0,LSR #28           ;Get the condition bits
+               ADR     R14,ae__condTbl         ;Point to the cunning table
+               AND     R4,R3,#&E               ;Get rid of the bottom bit
+               LDR     R4,[R14,R4,LSL #1]      ;Load the entry we want
+               MOV     R6,#&FF                 ;A vaguely useful value
+               TST     R3,#1                   ;Is this a complement
+               BEQ     %10armEmul              ;No -- handle it then
+
+               ; --- We can work directly from the table ---
+
+               ANDS    R14,R6,R4               ;Get the bottom byte
+               AND     R5,R14,R2,LSR #28       ;Get the bits we want
+               CMP     R5,R14,LSR #4           ;Does it match?
+               BEQ     %20armEmul              ;Yes -- we actually execute
+
+               ANDS    R14,R6,R4,LSR #8        ;Get the next byte
+               BEQ     ae__next                ;Nothing there -- advance PC
+               AND     R5,R14,R2,LSR #28       ;Get the bits we want
+               CMP     R5,R14,LSR #4           ;Does it match?
+               BEQ     %20armEmul              ;Yes -- we actually execute
+
+               ANDS    R14,R6,R4,LSR #16       ;Get the next byte
+               BEQ     ae__next                ;Nothing there -- advance PC
+               AND     R5,R14,R2,LSR #28       ;Get the bits we want
+               CMP     R5,R14,LSR #4           ;Does it match?
+               BEQ     %20armEmul              ;Yes -- we actually execute
+
+               B       ae__next                ;Nothing there -- advance PC
+
+               ; --- Handle complementary conditions :-) ---
+
+10armEmul      ANDS    R14,R6,R4               ;Get the bottom byte
+               AND     R5,R14,R2,LSR #28       ;Get the bits we want
+               CMP     R5,R14,LSR #4           ;Does it match?
+               BEQ     ae__next                ;Yes -- don't do it then
+
+               ANDS    R14,R6,R4,LSR #8        ;Get the next byte
+               BEQ     %20armEmul              ;Yes -- then execute it
+               AND     R5,R14,R2,LSR #28       ;Get the bits we want
+               CMP     R5,R14,LSR #4           ;Does it match?
+               BEQ     ae__next                ;Yes -- don't do it then
+
+               ANDS    R14,R6,R4,LSR #16       ;Get the next byte
+               BEQ     %20armEmul              ;Yes -- then execute it
+               AND     R5,R14,R2,LSR #28       ;Get the bits we want
+               CMP     R5,R14,LSR #4           ;Does it match?
+               BEQ     ae__next                ;Yes -- don't do it then
+
+               B       %20armEmul              ;Got all the way -- do it
+
+               ; --- The condition table ---
+               ;
+               ; Format of each byte:
+               ;
+               ; Bits  Meaning
+               ; 0-3   AND mask for processor flags
+               ; 4-7   Value to match for condition true
+
+ae__condTbl    DCD     &00000004               ;NE (!Z)
+               DCD     &00000002               ;CC (!C)
+               DCD     &00000008               ;PL (!N)
+               DCD     &00000001               ;VC (!V)
+               DCD     &00000244               ;LS (!C | Z)
+               DCD     &00001989               ;LT (N & !V) | (!N & V)
+               DCD     &00441989               ;LE (N&!V) | (!N&V) | Z
+               DCD     &00000010               ;NV --
+
+               ; --- Dispatch an instruction ---
+
+20armEmul      AND     R14,R0,#&0C000000       ;Get the opcode field
+               ADD     PC,PC,R14,LSR #24       ;Just dispatch on that then
+               DCB     "TMA!"
+
+               B       ae__type00
+               B       ae__type01
+               B       ae__type10
+               B       ae__type11
+
+               ; --- Normal return point ---
+
+ae__next       AND     R3,R2,#&FC000003        ;Look after PSR bits
+               ADD     R2,R2,#4                ;Bump PC on a bit
+               BIC     R2,R2,#&FC000003        ;Kill off PSR bits
+               ORR     R2,R2,R3                ;Bolt on the old PSR
+
+ae__return     LDR     R3,[R1,#15*4]           ;Get the old PC
+               AND     R3,R3,#&3               ;Get just the mode flags
+               AND     R4,R2,#&3               ;Get the new mode flags
+               CMP     R4,R3                   ;Has the mode changed?
+               BEQ     %90armEmul              ;No -- jump ahead
+
+               ; --- The processor mode has changed ---
+
+               CMP     R4,#2                   ;Are we now in IRQ?
+               CMPNE   R4,#1                   ;Or FIQ?
+               ADREQ   R0,ae__invMode          ;Yes -- point to error
+               LDMEQFD R13!,{R0-R12,R14}       ;...load registers back
+               ORREQS  PC,R14,#V_flag          ;...and return with error
+               MOV     R6,R13                  ;Remember current R13 value
+               ADD     R5,R1,#13*4             ;Point to saved R13
+               LDMIA   R5,{R13,R14}            ;Load correct registers
+               CMP     R4,#0                   ;Are we entering user mode?
+               SWINE   XOS_EnterOS             ;No -- must be entering SVC
+               TEQEQP  PC,#0                   ;Yes -- enter it then
+               MOV     R0,R0                   ;A no-op -- keep ARM happy
+               STMIA   R5,{R13,R14}            ;Store new register values
+               MOV     R13,R6                  ;Restore my stack pointer
+               LDR     R14,[R13,#13*4]         ;Load the link register
+               BIC     R14,R14,#3              ;Clear the current mode
+               ORR     R14,R14,R4              ;Enter the new mode
+               STR     R14,[R13,#13*4]         ;Store back modified R14
+
+               ; --- Return as normal ---
+
+90             STR     R2,[R1,#15*4]           ;Save the new PC back
+               LDMFD   R13!,{R0-R12,R14}       ;Get registers back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+               LTORG
+
+ae__invMode    DCD     1
+               DCB     "Sledgehammer can only operate in "
+               DCB     "User or Supervisor mode",0
+
+; --- ae__type00 ---
+;
+; On entry:    R0 == instruction to execute
+;              R1 == pointer to register block
+;
+; On exit:     R3-R12 mangled beyond redemption
+;
+; Use:         Emulates a type 0 ARM instruction.
+
+ae__type00     ROUT
+
+               AND     R3,R0,#&0FC00000        ;Get the op code
+               AND     R4,R0,#&000000F0        ;We need these bits too
+
+               ; --- See if it is a multiply instruction ---
+
+               CMP     R3,#0                   ;Multiply instruction?
+               CMPEQ   R4,#&90                 ;Double check
+               BEQ     ae__multiply            ;Yes -- deal with it then
+
+               ; --- Is it a SWP instruction ---
+
+               CMP     R3,#&01000000           ;Is this bit set?
+               CMPNE   R3,#&01400000           ;Or maybe this bit too?
+               CMPEQ   R4,#&90                 ;Double check
+               BEQ     ae__swp                 ;Yes -- deal with it
+
+               ; --- Is it an undefined operation? ---
+
+               AND     R3,R3,#&03000000        ;Get the correct bits
+               AND     R4,R4,#&00000090        ;Are these bits set too?
+               CMP     R3,#&01000000           ;Is opcode 0001?
+               CMPEQ   R4,#&00000090           ;And are these bits set?
+               BNE     ae__aluOp               ;No -- deal with alu Op then
+
+               DCD     &E6000090               ;It's undefined, you know
+
+               LTORG
+
+; --- ae__type01 ---
+;
+; On entry:    R0 == instruction to execute
+;              R1 == pointer to register block
+;
+; On exit:     R3-R12 mangled beyond redemption
+;
+; Use:         Emulates a type 1 ARM instruction.
+
+ae__type01     ROUT
+
+               ; --- See if it's undefined ---
+
+               TST     R0,#(1<<25)             ;Is bit 25 set?
+               TSTNE   R0,#(1<<4)              ;And bit 4?
+               BEQ     ae__sDataTrans          ;No -- data transfer then
+
+               DCD     &E6000090               ;It's undefined, you know
+
+               LTORG
+
+; --- ae__type10 ---
+;
+; On entry:    R0 == instruction to execute
+;              R1 == pointer to register block
+;
+; On exit:     R3-R12 mangled beyond redemption
+;
+; Use:         Emulates a type 2 ARM instruction.
+
+ae__type10     ROUT
+
+               TST     R0,#(1<<25)             ;Is this bit set?
+               BNE     ae__branch              ;Yes -- it's a branch
+               B       ae__mTransfer           ;Must be LDM/STM then
+
+               LTORG
+
+; --- ae__type11 ---
+;
+; On entry:    R0 == instruction to execute
+;              R1 == pointer to register block
+;
+; On exit:     R3-R12 mangled beyond redemption
+;
+; Use:         Emulates a type 3 ARM instruction.
+
+ae__type11     ROUT
+
+               TST     R0,#(1<<25)             ;Is this bit clear?
+               BEQ     ae__coDataTran          ;Yes -- do co proc data trans
+
+               AND     R8,R0,#&0F000000        ;Get top nibble of opcode
+               CMP     R8,#&0F000000           ;Is it a SWI instruction?
+               BEQ     ae__swi                 ;Yes -- deal with it
+
+               TST     R0,#(1<<4)              ;Is it a coregister transfer?
+               BNE     ae__coRegTran           ;Yes -- deal with it
+
+               B       ae__coDataOp            ;Do a co-proc data op
+
+               LTORG
+
+; --- ae__multiply ---
+;
+; On entry:    R0 == instruction to do
+;              R1 == pointer to register block
+;              R2 == current PC value
+;
+; On exit:     R2 updated
+;              R3-R12 trashed totally
+;
+; Use:         Emulates a MUL/MLA instruction
+
+ae__multiply   ROUT
+
+               MOV     R3,#&F                  ;A useful value
+               AND     R8,R0,R3                ;Get Rm
+               AND     R5,R3,R0,LSR #8         ;Get Rs
+               AND     R6,R3,R0,LSR #12        ;Get Rn too
+               AND     R7,R3,R0,LSR #16        ;Finally, get Rd
+
+               CMP     R8,#15                  ;Is Rm really the PC?
+               LDR     R4,[R1,R8,LSL #2]       ;Load my values
+               ADDEQ   R4,R4,#12               ;Yes -- bump it along
+
+               CMP     R5,#15                  ;Is Rs really the PC?
+               LDR     R5,[R1,R5,LSL #2]
+               ADDEQ   R5,R5,#8                ;Yes -- bump it up
+               BICEQ   R5,R5,#&FC000003        ;And clear the PSR flags (!)
+
+               CMP     R6,#15                  ;Is Rn really the PC?
+               LDR     R6,[R1,R6,LSL #2]       ;Yes -- load accumulate
+               ADDEQ   R6,R6,#8                ;Yes -- bump it up
+
+               CMP     R7,R8                   ;Is Rd == Rm?
+               BEQ     %10ae__multiply         ;Yes -- then handle weirdly
+
+               TST     R0,#(1<<21)             ;Is it an MLA?
+               MLANE   R8,R4,R5,R6             ;...and do the MLA
+               MULEQ   R8,R4,R5                ;No -- Do the multiply
+               B       %20ae__multiply         ;And set up the results
+
+               ; --- Berk put Rd == Rm -- emulate faithfully ---
+
+10ae__multiply TST     R0,#(1<<21)             ;Is it an MLA?
+               DCD     &10246594               ;MLANE  R4,R4,R5,R6
+               DCD     &00040594               ;MULEQ  R4,R4,R5
+               MOV     R8,R4                   ;And put result in nice reg
+
+               ; --- Now write the results back ---
+
+20ae__multiply CMP     R7,#15                  ;Is destination the PC?
+               STRNE   R8,[R1,R7,LSL #2]       ;No -- then store the result
+               BIC     R2,R2,#Z_flag + N_flag  ;Clear the flags we modify
+               CMP     R8,#0                   ;Is the result zero?
+               ORREQ   R2,R2,#Z_flag           ;Yes -- set the Z bit
+               ORRMI   R2,R2,#N_flag           ;Yes -- set the N bit
+               B       ae__next                ;And get the next instruction
+
+               LTORG
+
+; --- ae__branch ---
+;
+; On entry:    R0 == instruction to do
+;              R1 == pointer to register block
+;              R2 == current PC value
+;
+; On exit:     R3-R12 trashed totally
+;
+; Use:         Emulates a branch instruction
+
+ae__branch     ROUT
+
+               ; --- First try to do the link business ---
+
+               TST     R0,#(1<<24)             ;Is the L bit set?
+               ADDNE   R3,R2,#4                ;Bump on PC thing (overflow!)
+               STRNE   R3,[R1,#14*4]           ;Save it in the reg block
+
+               ; --- Now branch ---
+
+               BIC     R3,R0,#&FF000000        ;Clear unwanted bits
+               AND     R4,R2,#&FC000003        ;Look after PSR bits
+               ADD     R2,R2,R3,LSL #2         ;Bump PC on a bit
+               ADD     R2,R2,#8                ;And allow for `pipeline'
+               BIC     R2,R2,#&FC000003        ;Kill off PSR bits
+               ORR     R2,R2,R4                ;Bolt on the old PSR
+               B       ae__return              ;And that's it for branch
+
+               LTORG
+
+; --- ae__aluOp ---
+;
+; On entry:    R0 == instruction to do
+;              R1 == pointer to register block
+;              R2 == current PC value
+;
+; On exit:     R2 updated
+;              R3-R12 trashed totally
+;
+; Use:         Emulates a general ALU op instruction
+
+ae__aluOp      ROUT
+
+               ; --- Start building the instruction ---
+
+               AND     R3,R0,#&03F00000        ;Get out:
+                                               ;Immediate flag
+                                               ;Opcode number
+                                               ;S bit (FWIW)
+               ORR     R3,R3,#&E0000000        ;Always execute this instr
+               MOV     R11,#0                  ;Some interesting flags
+
+               ; --- Work out the correct PC bump amount ---
+
+               MOV     R12,#8                  ;By default it's 8
+               TST     R0,#(1<<4)              ;Is the reg-shift bit on?
+               MOVNE   R12,#12                 ;Yes -- then actually it's 12
+               TST     R0,#(1<<25)             ;Unless the op's immediate
+               MOVNE   R12,#8                  ;When it's actually 8 anyway
+
+               ; --- Load the register values out ---
+
+               MOV     R14,#&F                 ;Get a register mask
+
+               AND     R4,R14,R0,LSR #12       ;Get Rd's number
+               AND     R10,R0,#&01800000       ;Get the top two opcode bis
+               CMP     R10,#&01000000          ;Is it a comparison instr?
+               ORRNE   R3,R3,#8<<12            ;No -- put in fake Rd value
+               BNE     %05ae__aluOp            ;And branch Ahead
+               ORR     R11,R11,#1              ;Yes -- then remember this
+               CMP     R4,#15                  ;Is a TEQP or the like?
+               BNE     %05ae__aluOp            ;No -- branch ahead
+               ORR     R3,R3,#8<<12            ;Put in fake Rd value
+               BIC     R3,R3,#&01800000        ;Yes -- make a real ALU op
+               ORR     R11,R11,#2              ;Remember we did this
+               AND     R10,R0,#&00600000       ;Get the bottom two bits
+               CMP     R10,#&00600000          ;Is it now an RSB?
+               EOREQ   R3,R3,#&00E00000        ;Yes -- make it an ADD
+
+05ae__aluOp    AND     R5,R14,R0,LSR #16       ;Get Rn's number too
+               CMP     R5,#15                  ;Is Rn the PC?
+               LDR     R5,[R1,R5,LSL #2]       ;Load the register value
+               ADDEQ   R5,R5,R12               ;Yes -- then bump the value
+               BICEQ   R5,R5,#&FC000003        ;And clear the PSR bits
+               ORR     R3,R3,#5<<16            ;Put in our fake Rd value
+
+               ; --- Now deal with Op2 ---
+
+               TST     R0,#(1<<25)             ;Is the operand immediate?
+               ORRNE   R8,R14,#&FF0            ;Build the number &FFF
+               ANDNE   R8,R0,R8                ;Get bottom three nibbles
+               ORRNE   R3,R3,R8                ;And bung 'em in my fake
+               BNE     %10ae__aluOp            ;Yes -- deal with that then
+
+               ; --- Handle Op2 registers ---
+
+               AND     R6,R14,R0               ;Get Rm's number out
+               CMP     R6,#15                  ;Is Rm the PC?
+               LDR     R6,[R1,R6,LSL #2]       ;Load the register value
+               ADDEQ   R6,R6,R12               ;Yes -- then bump the value
+               ORR     R3,R3,#6<<0             ;Put our fake Rm value in
+
+               ; --- Is the shift immediate or reg-done? ---
+
+               TST     R0,#(1<<4)              ;Check the reg-shift bit
+               ANDEQ   R7,R0,#&FF0             ;No -- get the gubbins out
+               ORREQ   R3,R3,R7                ;And put it in our fake instr
+               BEQ     %10ae__aluOp            ;And skip register mangling
+
+               AND     R7,R14,R0,LSR #8        ;Get Rs's number out
+               CMP     R7,#15                  ;Is Rs the PC?
+               LDR     R7,[R1,R7,LSL #2]       ;Load the register value
+               ADDEQ   R7,R7,#8                ;Rs always bumped by 8
+               BICEQ   R7,R7,#&FC000003        ;And PSR bits are stripped
+               ORR     R3,R3,#7<<8             ;Put that in there nicely
+               AND     R8,R0,#&0F0             ;Get the shift type out
+               ORR     R3,R3,R8                ;And put it in our fake instr
+
+               ; --- Do the instruction ---
+
+10ae__aluOp    LDR     R14,ae__retInstr        ;Get the return instruction
+               STMFD   R13!,{R3,R14}           ;Save them on the stack
+
+               MOV     R14,PC                  ;Get my current status
+               AND     R14,R14,#&0C000003      ;Get the special flags
+               AND     R10,R2,#&F0000000       ;Get all of his flags
+               ORR     R10,R10,R14             ;Mix them with my status
+
+               MOV     R14,PC                  ;Set up the return address
+               ORRS    PC,R13,R10              ;And call the instruction
+               ADD     R13,R13,#8              ;Restore the stack
+               MOV     R12,PC                  ;Look after processor status
+
+               ; --- Now stash the result away ---
+
+               TST     R11,#1                  ;Was it a compare instr?
+               TSTNE   R11,#2                  ;Is Rd the program counter?
+               BNE     %50ae__aluOp            ;Yes -- P type comparison
+
+               CMP     R4,#15                  ;Was destination the PC?
+               BEQ     %40ae__aluOp            ;Yes -- this is special then
+
+               TST     R11,#1                  ;Was it a compare instr?
+               STREQ   R8,[R1,R4,LSL#2]        ;Store the result away
+               TST     R0,#(1<<20)             ;Is the `S' bit set?
+               ANDNE   R12,R12,#&F0000000      ;Get the status flags
+               BICNE   R2,R2,#&F0000000        ;Clear the current ones
+               ORRNE   R2,R2,R12               ;Set the flag appropriately
+               B       ae__next                ;And branch to next instr
+
+               ; --- The destination was PC ---
+
+40ae__aluOp    EOR     R14,R2,R8               ;Get bits that WILL change
+               TST     R0,#(1<<20)             ;Is the `S' bit set?
+               BICEQ   R14,R14,#&FC000003      ;No -- don't update PSR
+               TST     R2,#3                   ;Are we in user mode?
+               BICEQ   R14,R14,#&0C000003      ;Yes -- update top 4 bits
+               EOR     R2,R2,R14               ;Munge bits we really want
+               B       ae__return              ;Return happily!@?
+
+               ; --- There was a `P' suffix thingy ---
+
+50ae__aluOp    EOR     R14,R2,R8               ;Get bits that WILL change
+               AND     R14,R14,#&FC000003      ;Clear the PC bits
+               TST     R2,#3                   ;Are we in user mode?
+               BICEQ   R14,R14,#&0C000003      ;Yes -- update top 4 bits
+               EOR     R2,R2,R14               ;Munge bits we really want
+               B       ae__next                ;Return happily!@?
+
+ae__retInstr   MOV     PC,R14                  ;Return, leave status alone
+
+               LTORG
+
+; --- ae__swp ---
+;
+; On entry:    R0 == instruction to do
+;              R1 == pointer to register block
+;              R2 == current PC value
+;
+; On exit:     R2 updated
+;              R3-R12 trashed totally
+;
+; Use:         Emulates a SWP instruction
+
+ae__swp                ROUT
+
+               B       ae__next                ;Ignore it
+
+               LTORG
+
+; --- ae__sDataTrans ---
+;
+; On entry:    R0 == instruction to do
+;              R1 == pointer to register block
+;              R2 == current PC value
+;
+; On exit:     R2 updated
+;              R3-R12 trashed totally
+;
+; Use:         Emulates LDR/STR instructions
+
+ae__sDataTrans ROUT
+
+               ; --- Load the register values out ---
+
+               MOV     R14,#&F                 ;Get a register mask
+               MOV     R11,#0                  ;Some flags and things
+
+               AND     R4,R14,R0,LSR #12       ;Get Rd's number
+               AND     R5,R14,R0,LSR #16       ;Get Rn's number too
+               CMP     R5,#15                  ;Is Rn the PC?
+               LDR     R6,[R1,R5,LSL #2]       ;Load the register value
+               ADDEQ   R6,R6,#8                ;Yes -- then bump the value
+               BICEQ   R6,R6,#&FC000003        ;And clear the PSR bits
+               CMP     R4,R5                   ;Is Rd==Rn?
+               ORREQ   R11,R11,#4              ;Yes -- remember this
+
+               ; --- Now deal with Op2 ---
+
+               TST     R0,#(1<<25)             ;Is the operand immediate?
+               ORREQ   R8,R14,#&FF0            ;Build the number &FFF
+               ANDEQ   R8,R0,R8                ;Get bottom three nibbles
+               BEQ     %10ae__sDataTrans       ;And skip register mangling
+
+               AND     R7,R14,R0               ;Get the offset register
+               CMP     R7,#15                  ;Is it the PC?
+               LDR     R7,[R1,R7,LSL #2]       ;Load the register value
+               ADDEQ   R7,R7,#8                ;Yes -- then bump the value
+
+               AND     R8,R0,#&FF0             ;Get the constant shift bit
+               ORR     R8,R8,#&E1000000        ;Do the shift by...
+               ORR     R8,R8,#&00A00000        ;building MOV R8,R7,shift
+               ORR     R8,R8,#&00008000
+               ORR     R8,R8,#&00000007
+               LDR     R14,ae__retInstr        ;Get the return instruction
+               STMFD   R13!,{R8,R14}           ;Save them on the stack
+
+               AND     R14,PC,#&0C000003       ;Get the special flags
+               AND     R10,R2,#&F0000000       ;Get all of his flags
+               ORR     R10,R10,R14             ;Mix them with my status
+
+               MOV     R14,PC                  ;Set up the return address
+               ORRS    PC,R13,R10              ;Execute the code nicely
+               ADD     R13,R13,#8              ;Recover the stack I used
+
+               ; --- R8 contains the offset -- get the address ---
+
+10             MOV     R3,R0                   ;Preserve R0 for a bit
+               TST     R3,#(1<<23)             ;Is the op an addition?
+               RSBEQ   R8,R8,#0                ;No -- then make it negative
+               TST     R3,#(1<<24)             ;Is the op pre-indexed?
+               ADDNE   R7,R6,R8                ;Yes -- form the address
+               MOVEQ   R7,R6                   ;Otherwise just use base
+
+               BIC     R0,R7,#3                ;Word align the address
+               AND     R7,R7,#3                ;Get the non-word-alignedness
+               BL      ae__translateAddr       ;Translate the address
+               ORR     R7,R7,R0                ;Get the translated address
+               MOV     R0,R3                   ;Put instruction back in R0
+
+               ; --- Now work out whether it's a load or store ---
+
+               TST     R0,#(1<<20)             ;Is it a load then?
+               BEQ     %20ae__sDataTrans       ;No -- then do a store
+
+               TST     R0,#(1<<22)             ;Does he only want a byte?
+               LDREQ   R7,[R7,#0]              ;No -- load a word value
+               LDRNEB  R7,[R7,#0]              ;Yes -- load a byte value
+
+               ; --- Stuff the loaded value into a `register' ---
+
+               CMP     R4,#15                  ;Is destination the PC?
+               ORREQ   R11,R11,#1              ;Yes -- say we've updated it
+               BICEQ   R7,R7,#&FC000003        ;Clear the PSR bits
+               ANDEQ   R2,R2,#&FC000003        ;Keep his PSR bits
+               ORREQ   R2,R2,R7                ;And mix 'em together
+               STRNE   R7,[R1,R4,LSL #2]       ;Otherwise store the value
+               B       %50ae__sDataTrans       ;Tidy everything up nicely
+
+               ; --- Handle a store operation ---
+
+20             CMP     R4,#15                  ;Is the register the PC?
+               LDR     R4,[R1,R4,LSL #2]       ;Load the correct value out
+               ADDEQ   R4,R4,#12               ;Bump the value along a bit
+
+               TST     R0,#(1<<22)             ;Does he only want a byte?
+               STREQ   R4,[R7,#0]              ;No -- store the whole word
+               STRNEB  R4,[R7,#0]              ;Yes -- just store the byte
+
+               ; --- Finish off -- do writeback maybe ---
+
+50             MVN     R14,R0                  ;Toggle all the bits
+               TST     R14,#(1<<24)            ;Is the postindexed bit on?
+               TSTEQ   R0,#(1<<21)             ;Or is the writeback bit on?
+               BEQ     %60ae__sDataTrans       ;No writeback -- skip on
+               TST     R11,#4                  ;Is Rd==Rn?
+               BNE     %60ae__sDataTrans       ;Yes -- don't corrupt Rd
+
+               ; --- Perform the writeback ---
+
+               ADD     R7,R6,R8                ;Get the resulting address
+               CMP     R5,#15                  ;Is Rn the program counter
+               ORREQ   R11,R11,#1              ;Yes -- say we've updated it
+               BICEQ   R7,R7,#&FC000003        ;Clear the PSR bits
+               ANDEQ   R2,R2,#&FC000003        ;Keep his PSR bits
+               ORREQ   R2,R2,R7                ;And mix 'em together
+               STRNE   R7,[R1,R5,LSL #2]       ;Otherwise store the value
+
+               ; --- Finally return to the main thing ---
+
+60             TST     R11,#1                  ;Did we modify the PC?
+               BNE     ae__return              ;Yes -- don't advance PC
+               BEQ     ae__next                ;Otherwise get next instr
+
+               LTORG
+
+               GBLA    count
+
+; --- ae__mTransfer ---
+;
+; On entry:    R0 == instruction to do
+;              R1 == pointer to register block
+;              R2 == current PC value
+;
+; On exit:     R3-R12 trashed totally
+;
+; Use:         Emulates an LDM/STM instruction
+
+ae__mTransfer  ROUT
+
+               ; --- Load the register values out ---
+
+               MOV     R14,#&F                 ;Get a register mask
+               MOV     R11,#0                  ;Some flags and things
+
+               AND     R4,R14,R0,LSR #16       ;Get Rn's number
+               CMP     R4,#15                  ;Is Rn the PC?
+               LDR     R5,[R1,R4,LSL #2]       ;Load the register value
+               ADDEQ   R5,R5,#8                ;Yes -- then bump the value
+
+               ; --- We need to know how may to transfer ---
+
+               MOV     R7,#0                   ;The count so far
+count          SETA    0
+               WHILE   count<=15
+               TST     R0,#1<<count
+               ADDNE   R7,R7,#1
+count          SETA    count+1
+               WEND
+
+               ; --- We need to know where we start writing from ---
+
+               MOV     R14,R0                  ;Take a copy of the instr
+               MOV     R6,R5                   ;The write-backed value
+               TST     R0,#(1<<23)             ;Is this +ve increment?
+               SUBEQ   R5,R5,R7,LSL #2         ;No -- subtract nicely
+               SUBEQ   R6,R6,R7,LSL #2         ;...and apply writeback too
+               MVNEQ   R14,R14                 ;...invert the copy
+               ADDNE   R6,R6,R7,LSL #2         ;Otherwise add writeback
+               TST     R14,#(1<<24)            ;Is it pre-indexed?
+               ADDNE   R5,R5,#4                ;Yes -- then bump on one
+
+               ; --- Pause for breath ---
+               ;
+               ; While we pant in our weary manner, we may as well examine
+               ; the register allocation:
+               ;
+               ;  R1 == pointer to register block.  This is our only source
+               ;        of register values to actually load or store.
+               ;  R2 == the exception: this is the program counter
+               ;  R3 == a bit which shifts along from pos 0 to 15
+               ;  R4 == base register number
+               ;  R5 == address to load/store next register
+               ;  R6 == value to write back to base
+               ;  R7 == pointer into register block
+               ;  R8 == instruction  We will modify this by clearing `W'
+               ;        once writeback is performed, to save time.
+               ;  R11 == flags word
+               ;
+               ;  Just to confuse, R0 and R5 are about to be swapped.
+
+               ; --- Initialise other register values ---
+
+               MOV     R3,#1                   ;Start with R0
+               MOV     R7,R1                   ;Point to R0's value
+               MOV     R8,R0                   ;Put instruction in R8
+               MOV     R11,#0                  ;No flags yet
+               MVN     R14,R8                  ;Get inverted instruction
+               TST     R2,#3                   ;Are we in !(user mode)?
+               TSTNE   R8,#(1<<22)             ;...with 'S' set?
+               TSTNE   R14,#(1<<15)            ;...and without PC in list?
+               ORRNE   R11,R11,#2              ;Yes -- user mode transfer
+
+               ; --- Now we wish to load/store each value ---
+
+00ae__mTransfer        TST     R8,R3                   ;Is the register required?
+               BEQ     %40ae__mTransfer        ;No -- jump ahead
+
+               MOV     R0,R5                   ;Put the address in R0
+               BL      ae__translateAddr       ;Translate the address
+               TST     R8,#(1<<20)             ;Are we loading?
+               BEQ     %10ae__mTransfer        ;No -- do a store then
+
+               TST     R3,#(1<<13)             ;Are we transferring R13?
+               TSTEQ   R3,#(1<<14)             ;...or R14?
+               TSTNE   R11,#2                  ;...with user mode transfer?
+               BNE     %05ae__mTransfer        ;Yes -- special case
+
+               LDR     R9,[R0],#4              ;Load a word
+               CMP     R3,R10,LSL R4           ;Are we loading the base?
+               BICEQ   R8,R8,#(1<<21)          ;Yes -- clear the 'W' flag
+               TST     R3,#(1<<15)             ;Are we loading the PC?
+               STREQ   R9,[R7,#0]              ;No -- store correctly away
+               BEQ     %30ae__mTransfer        ;...and jump ahead
+
+               ; --- We are loading into the PC ---
+
+               EOR     R14,R2,R9               ;Get bits that WILL change
+               TST     R8,#(1<<22)             ;Is the `S' bit set?
+               BICEQ   R14,R14,#&FC000003      ;No -- don't update PSR
+               TST     R2,#3                   ;Are we in user mode?
+               BICEQ   R14,R14,#&0C000003      ;Yes -- update top 4 bits
+               EOR     R2,R2,R14               ;Munge bits we really want
+               ORR     R11,R11,#1              ;Say we changed PC
+               B       %30ae__mTransfer        ;Tidy everything up nicely
+
+               ; --- We are doing a user register transfer ---
+
+05ae__mTransfer        TST     R3,#(1<<13)             ;Transfering R13?
+               LDMNEIA R5,{R13}^               ;Yes -- do that then
+               LDMEQIA R5,{R14}^               ;No -- do R14 instead
+               B       %30ae__mTransfer        ;Jump ahead
+
+               ; --- Do a register store ---
+
+10ae__mTransfer        TST     R3,#(1<<14)+(1<<13)     ;Are we transferring R13/14?
+               TSTNE   R2,#3                   ;...in a non-user mode?
+               TSTNE   R8,#(1<<22)             ;...with 'S' set?
+               BNE     %15ae__mTransfer        ;Yes -- special case
+
+               TST     R3,#(1<<15)             ;Are we storing PC?
+               LDREQ   R9,[R7,#0]              ;No -- load reg in question
+               ADDNE   R9,R2,#12               ;Yes -- work out value
+               STR     R9,[R0,#0]              ;Store it in memory
+               B       %30ae__mTransfer        ;Jump ahead
+
+               ; --- We are doing a user register transfer ---
+
+15ae__mTransfer TST    R3,#(1<<13)             ;Transfering R13?
+               STMNEIA R5,{R13}^               ;Yes -- do that then
+               STMEQIA R5,{R14}^               ;No -- do R14 instead
+
+               ; --- OK, get ready for the next one ---
+
+30ae__mTransfer        TST     R8,#(1<<21)             ;Is 'W' bit set?
+               CMPNE   R4,#15                  ;Yes -- make sure it's not PC
+               STRNE   R6,[R1,R4,LSL #2]       ;Yes -- do the writeback
+               BICNE   R8,R8,#(1<<21)          ;...and clear the 'W' flag
+               ADD     R5,R5,#4                ;Increment location addr
+
+40ae__mTransfer        ADD     R7,R7,#4                ;Point to the next register
+               MOV     R3,R3,LSL #1            ;Move onto next register
+
+               CMP     R3,#(1<<15)             ;Have we finished?
+               BLE     %00ae__mTransfer        ;No -- keep on going then
+               TST     R11,#1                  ;Did we modify PC?
+               BEQ     ae__next                ;No -- go onto next
+               BNE     ae__return              ;Yes -- just return
+
+               LTORG
+
+; --- ae__coDataTran ---
+;
+; On entry:    R0 == instruction to do
+;              R1 == pointer to register block
+;              R2 == current PC value
+;
+; On exit:     R3-R12 trashed totally
+;
+; Use:         Emulates an LDC/STC instruction
+
+ae__coDataTran ROUT
+
+               ; --- Load the register values out ---
+
+               MOV     R14,#&F                 ;Get a register mask
+               MOV     R11,#0                  ;Some flags and things
+
+               AND     R5,R14,R0,LSR #16       ;Get Rn's number
+               CMP     R5,#15                  ;Is Rn the PC?
+               LDR     R6,[R1,R5,LSL #2]       ;Load the register value
+               ADDEQ   R6,R6,#8                ;Yes -- then bump the value
+               BICEQ   R6,R6,#&FC000003        ;And clear the PSR bits
+
+               ; --- Now deal with Op2 ---
+
+               AND     R8,R0,#&FF              ;Get bottom three nibbles
+               MOV     R8,R8,LSL #2            ;Scale up properley
+               MOV     R3,R0                   ;Preserve R0 for a bit
+               TST     R3,#(1<<23)             ;Is the op an addition?
+               RSBEQ   R8,R8,#0                ;No -- then make it negative
+               TST     R3,#(1<<24)             ;Is the op pre-indexed?
+               ADDNE   R7,R6,R8                ;Yes -- form the address
+               MOVEQ   R7,R6                   ;Otherwise just use base
+               ADD     R9,R6,R8                ;Remember this value
+
+               BIC     R0,R7,#3                ;Word align the address
+               AND     R7,R7,#3                ;Get the non-word-alignedness
+               BL      ae__translateAddr       ;Translate the address
+               ORR     R7,R7,R0                ;Get the translated address
+               MOV     R0,R3                   ;Put instruction back in R0
+
+               ; --- Now do the operation ---
+
+               BIC     R8,R0,#&FF              ;Get the basic instruction
+               BIC     R8,R8,#&01200000        ;Say its post indexed, no !
+               BIC     R8,R8,#&000F0000        ;Clear the base register
+               ORR     R8,R8,#(7<<16)          ;Use R7 instead
+
+               LDR     R14,ae__retInstr        ;Get the return instruction
+               STMFD   R13!,{R8,R14}           ;Save them on the stack
+
+               AND     R14,PC,#&0C000003       ;Get the special flags
+               AND     R10,R2,#&F0000000       ;Get all of his flags
+               ORR     R10,R10,R14             ;Mix them with my status
+
+               MOV     R14,PC                  ;Set up the return address
+               ORRS    PC,R13,R10              ;Execute the code nicely
+               ADD     R13,R13,#8              ;Recover the stack I used
+
+               MVN     R14,R0                  ;Get inverted instruction
+               TST     R14,#(1<<24)            ;Is the postindexed bit on?
+               TSTEQ   R0,#(1<<21)             ;Or is the writeback bit on?
+               BEQ     %60ae__coDataTran       ;No writeback -- skip on
+               CMP     R5,#15                  ;Are we using R15 as base?
+               STRNE   R9,[R1,R5,LSL #2]       ;No -- store updated
+
+               ; --- Finally return to the main thing ---
+
+60             B       ae__next                ;Get next instruction
+
+               LTORG
+
+; --- ae__coRegTran ---
+;
+; On entry:    R0 == instruction to do
+;              R1 == pointer to register block
+;              R2 == current PC value
+;
+; On exit:     R3-R12 trashed totally
+;
+; Use:         Emulates an MCR/MRC instruction
+
+ae__coRegTran  ROUT
+
+               ; --- Load the register value out ---
+
+               MOV     R14,#&F                 ;Get a register mask
+               MOV     R11,#0                  ;Some flags and things
+
+               AND     R5,R14,R0,LSR #12       ;Get Rn's number
+               CMP     R5,#15                  ;Is Rn the PC?
+               LDR     R6,[R1,R5,LSL #2]       ;Load the register value
+               ADDEQ   R6,R6,#8                ;Yes -- then bump the value
+
+               BIC     R8,R0,#&0000F000        ;Get the opcode without reg
+               ORR     R8,R8,#(6<<12)          ;Use R6
+
+               LDR     R14,ae__retInstr        ;Get the return instruction
+               STMFD   R13!,{R8,R14}           ;Save them on the stack
+
+               AND     R14,PC,#&0C000003       ;Get the special flags
+               AND     R10,R2,#&F0000000       ;Get all of his flags
+               ORR     R10,R10,R14             ;Mix them with my status
+
+               MOV     R14,PC                  ;Set up the return address
+               ORRS    PC,R13,R10              ;Execute the code nicely
+               ADD     R13,R13,#8              ;Recover the stack I used
+
+               TST     R0,#(1<<20)             ;Was it a load?
+               BEQ     ae__next                ;No -- return then
+               CMP     R5,#15                  ;Are we loading into the PC?
+               STRNE   R6,[R1,R5,LSL #2]       ;No -- store value
+               BNE     ae__next                ;...and return
+               BIC     R2,R2,#&F               ;Clear status flags
+               AND     R6,R6,#&F               ;Get the new ones
+               ORR     R2,R2,R6                ;Put in the new ones
+               BNE     ae__next                ;Return
+
+; --- ae__coDataOp ---
+;
+; On entry:    R0 == instruction to do
+;              R1 == pointer to register block
+;              R2 == current PC value
+;
+; On exit:     R3-R12 trashed totally
+;
+; Use:         Emulates a CDP instruction
+
+ae__coDataOp   ROUT
+
+               LDR     R14,ae__retInstr        ;Get the return instruction
+               STMFD   R13!,{R0,R14}           ;Save them on the stack
+
+               MOV     R14,PC                  ;Set up the return address
+               MOV     PC,R13                  ;Execute the code nicely
+               ADD     R13,R13,#8              ;Recover the stack I used
+
+               B       ae__next                ;Go onto next instruction
+
+               LTORG
+
+; --- ae__swi ---
+;
+; On entry:    R0 == instruction to execute
+;              R1 == pointer to register block
+;              R2 == program counter when it happened
+;
+; On exit:     R0-R2 preserved
+;              R3-R12 mangled beyond recognition
+;
+; Use:         Emulates a SWI instruction.
+
+ae__swi                ROUT
+
+               ; --- Words of Wisdom ---
+               ;
+               ; There are problems with executing SWIs:
+               ;
+               ; User registers R0-R9 and R13 must be set up correctly.
+               ; User flags must be set up correctly too.
+               ;
+               ; This gives me exactly 4 registers to mess with.
+
+               BIC     R3,R0,#&FF000000        ;Get the the SWI bits
+               BIC     R3,R3,#&00F20000        ;Clear off some other bits
+
+               ; --- Check for some location-specific or odd SWIs ---
+
+               CMP     R3,#OS_WriteS           ;Check for OS_WriteS
+               BEQ     %80ae__swi              ;Do this specially
+               CMP     R3,#OS_EnterOS          ;Check for OS_EnterOS
+               BEQ     %70ae__swi              ;Make it do a mode switch
+               LDR     R14,=Stream_WriteS      ;Also check for this
+               CMP     R3,R14                  ;Do they match nicely?
+               BEQ     %90ae__swi              ;And do this specially too
+               LDR     R14,=&CC180+9           ;Is it Sledge_Breakpoint?
+               CMP     R3,R14                  ;Quick check then
+               BEQ     ae__next                ;Yes -- ignore it totally
+
+               ; --- Handle general SWIs ---
+
+               STMFD   R13!,{R0-R2}            ;Save what I must preserve
+
+               MOV     R4,PC                   ;Get my current status
+               AND     R3,R2,#&F0000000        ;Get the user's flags
+               AND     R4,R4,#&0C000003        ;And my special status
+               ORR     R3,R3,R4                ;Mix 'em together nicely
+               TEQP    R3,#0                   ;And set this as my status
+
+               LDR     R14,ae__swiRet          ;Get the special return instr
+               STMFD   R13!,{R0,R14}           ;Save this on the stack
+               MOV     R12,R13                 ;Preserve stack ptr in R12
+               LDR     R13,[R1,#13*4]          ;Load user's stack pointer
+               LDMIA   R1,{R0-R9}              ;Load other SWI arguments
+               MOV     R11,PC                  ;Set up return address oddly
+               MOV     PC,R12                  ;Call the SWI instruction
+
+               MOV     R10,PC                  ;Get the processor flags
+               ADD     R13,R12,#8              ;Restore the stack pointer
+               LDR     R12,[R13,#4]            ;Load the register block ptr
+               STMIA   R12,{R0-R9}             ;Stuff the SWI registers back
+
+               LDMFD   R13!,{R0-R2}            ;Reload our important regs
+               AND     R14,R2,#3               ;Get the processor mode
+               CMP     R14,#SVC_mode           ;Are we in SVC mode?
+               ADDEQ   R14,R2,#4               ;Yes -- make a bogus value
+               STREQ   R14,[R1,#14*4]          ;And save over his R14 value
+               BIC     R2,R2,#&FC000003        ;Just get the PC bits
+               AND     R10,R10,#&FC000003      ;Get the returned PSR bits
+               ORR     R2,R2,R10               ;Mix 'em into the PC
+               B       ae__next                ;And carry on the good work
+
+               ; --- Some special SWIs ---
+
+80ae__swi      STMFD   R13!,{R0-R2}            ;Save what I must preserve
+
+               MOV     R5,#&EF000000           ;Get the basic SWI opcode
+               ORR     R5,R5,#OS_Write0        ;Make it a particular SWI
+               TST     R0,#&00020000           ;Is the X bit set?
+               ORRNE   R5,R5,#&00020000        ;Yes -- set out one too
+
+               MOV     R4,PC                   ;Get my current status
+               AND     R3,R2,#&F0000000        ;Get the user's flags
+               AND     R4,R4,#&0C000003        ;And my special status
+               ORR     R3,R3,R4                ;Mix 'em together nicely
+               TEQP    R3,#0                   ;And set this as my status
+
+               LDR     R14,ae__swiRet          ;Get the special return instr
+               STMFD   R13!,{R5,R14}           ;Save this on the stack
+               MOV     R12,R13                 ;Preserve stack ptr in R12
+               LDR     R13,[R1,#13*4]          ;Load user's stack pointer
+               BIC     R0,R2,#&FC000003        ;Get the string address...
+               ADD     R0,R0,#4                ;... it's just after the SWI
+               MOV     R11,PC                  ;Set up return address oddly
+               MOV     PC,R12                  ;Call the SWI instruction
+
+               MOV     R10,PC                  ;Get the processor flags
+               ADD     R13,R12,#8              ;Restore the stack pointer
+               MOV     R3,R0                   ;Get the string end pointer
+
+               LDMFD   R13!,{R0-R2}            ;Reload our important regs
+               AND     R14,R2,#3               ;Get the processor mode
+               CMP     R14,#SVC_mode           ;Are we in SVC mode?
+               ADDEQ   R14,R2,#4               ;Yes -- make a bogus value
+               STREQ   R14,[R1,#14*4]          ;And save over his R14 value
+
+               ADD     R3,R3,#3                ;Word align the string end
+               BIC     R3,R3,#3                ;To find the next instruction
+               AND     R10,R10,#&FC000003      ;Get the returned PSR bits
+               ORR     R2,R3,R10               ;Mix 'em into the PC
+               B       ae__return              ;And carry on the good work
+
+90ae__swi      STMFD   R13!,{R0-R2}            ;Save what I must preserve
+
+               LDR     R5,=Stream_Write0 :OR: &EF000000
+               TST     R0,#&00020000           ;Is the X bit set?
+               ORRNE   R5,R5,#&00020000        ;Yes -- set out one too
+
+               LDR     R14,ae__swiRet          ;Get the special return instr
+               STMFD   R13!,{R5,R14}           ;Save this on the stack
+               MOV     R12,R13                 ;Preserve stack ptr in R12
+               LDR     R13,[R1,#13*4]          ;Load user's stack pointer
+               BIC     R0,R2,#&FC000003        ;Get the string address...
+               ADD     R0,R0,#4                ;... it's just after the SWI
+               MOV     R11,PC                  ;Set up return address oddly
+               MOV     PC,R12                  ;Call the SWI instruction
+
+               MOV     R10,PC                  ;Get the processor flags
+               ADD     R13,R12,#8              ;Restore the stack pointer
+               MOV     R3,R0                   ;Get the string start ptr
+
+95ae__swi      LDRB    R14,[R3],#1             ;Get a byte from the string
+               CMP     R14,#0                  ;Is it a null?
+               BNE     %95ae__swi              ;No -- jump round again
+               ADD     R3,R3,#3                ;Word align the result
+               BIC     R3,R3,#3
+
+               LDMFD   R13!,{R0-R2}            ;Reload our important regs
+               AND     R14,R2,#3               ;Get the processor mode
+               CMP     R14,#SVC_mode           ;Are we in SVC mode?
+               ADDEQ   R14,R2,#4               ;Yes -- make a bogus value
+               STREQ   R14,[R1,#14*4]          ;And save over his R14 value
+
+               ADD     R3,R3,#3                ;Word align the string end
+               BIC     R3,R3,#3                ;To find the next instruction
+               AND     R10,R2,#&FC000003       ;Get the (preserved) PSR bits
+               ORR     R2,R3,R10               ;Mix 'em into the PC
+               B       ae__return              ;And carry on the good work
+
+70ae__swi      ORR     R2,R2,#3                ;Set the mode to SVC
+               BIC     R2,R2,#V_flag           ;Clear the V flag
+               B       ae__next                ;And move on to next instr
+
+ae__swiRet     MOV     PC,R11                  ;My really odd return instr
+
+               LTORG
+
+; --- ae__translateAddr ---
+;
+; On entry:    R0 == address to load from
+;
+; On exit:     R0 == translates the address
+;
+; Use:         Translates an address, allowing for horrible
+;              things such as breakpoints
+
+ae__translateAddr ROUT
+
+               B       brkpt_translate         ;Get breakpoints to xlate
+
+;----- That's *all*, folks --------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/s/asm b/StraySrc/Hammer/s/asm
new file mode 100644 (file)
index 0000000..c037bcc
--- /dev/null
@@ -0,0 +1,1923 @@
+;
+; asm.s
+;
+; Assembly of instructions (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     quartz:string
+
+               GET     sh.diss
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Hammer$$Code|,CODE,READONLY
+
+; --- asm_assemble ---
+;
+; On entry:    R0 == pointer to the instruction to assemble
+;              R1 == address at which to assemble instruction
+;
+; On exit:     VC and R0 == the assembled instruction
+;              VS and R0 == pointer to an error
+;
+; Use:         Assembles the given insruction, returning the result in
+;              R0. The instruction is NOT placed into the memory location
+;              passed in R1.
+
+               EXPORT  asm_assemble
+asm_assemble   ROUT
+
+
+               STMFD   R13!,{R1-R9,R14}        ;Stack some registers
+
+               ; --- Set up 'global' registers ---
+
+               MOV     R9,#0                   ;Instruction so far
+               MOV     R8,R0                   ;Put string pointer in R8
+               MOV     R7,R1                   ;And address in R7
+
+               ; --- Read the opcode ---
+
+               BL      asm__readOpcode         ;Read opcode
+
+               MOVVC   R0,R9                   ;Place instruction in R0
+               LDMFD   R13!,{R1-R9,R14}        ;Load registers
+               ORRVSS  PC,R14,#V_flag          ;Return with error
+               BICVCS  PC,R14,#V_flag          ;Or hopefully without
+
+               LTORG
+
+; --- asm__readOpcode ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Reads in the current opcode, and deals with it
+
+asm__readOpcode        ROUT
+
+               ; --- First, try to find the opcode number ---
+
+               STMFD   R13!,{R14}              ;Save link for a bit
+               LDRB    R0,[R8,#0]              ;Get a byte from input
+               CMP     R0,#'B'                 ;Is it a 'B'?
+               CMPNE   R0,#'b'
+               BNE     %00asm__readOpcode      ;No -- skip ahead
+               LDRB    R0,[R8,#1]              ;Get the next byte
+               CMP     R0,#'I'                 ;Is it an 'I'
+               CMPNE   R0,#'i'
+               LDMNEFD R13!,{R14}              ;No -- get the link back
+               BNE     asm__branch             ;...it must be a branch
+
+00             ADR     R6,asm__opTable         ;Point to opcode table
+               BL      asm__lookup             ;Try to find it in there
+               LDMFD   R13!,{R14}              ;Restore link again
+               ADDCC   R8,R8,#3                ;Skip past the opcode
+               ADDCC   PC,PC,R5,LSL#2          ;Jump to handling routine
+               B       %80asm__readOpcode      ;If not there, moan
+
+               B       asm__aluOp3             ;AND
+               B       asm__aluOp3             ;EOR
+               B       asm__aluOp3             ;SUB
+               B       asm__aluOp3             ;RSB
+               B       asm__aluOp3             ;ADD
+               B       asm__aluOp3             ;ADC
+               B       asm__aluOp3             ;SBC
+               B       asm__aluOp3             ;RSC
+               B       asm__aluOp3             ;ORR
+               B       asm__aluOp3             ;BIC
+               B       asm__aluOp2             ;MOV
+               B       asm__aluOp2             ;MVN
+               B       asm__aluOpTest          ;TST
+               B       asm__aluOpTest          ;TEQ
+               B       asm__aluOpTest          ;CMP
+               B       asm__aluOpTest          ;CMN
+               B       asm__multiply           ;MUL
+               B       asm__multiply           ;MLA
+               B       asm__sDataTrans         ;LDR
+               B       asm__sDataTrans         ;STR
+               B       asm__mDataTrans         ;LDM
+               B       asm__mDataTrans         ;STM
+               B       asm__swi                ;SWI
+               B       asm__adr                ;ADR
+               B       asm__swp                ;SWP
+               B       asm__cdp                ;CDP
+               B       asm__coDataTrans        ;STC
+               B       asm__coDataTrans        ;LDC
+               B       asm__coRegTrans         ;MRC
+               B       asm__coRegTrans         ;MCR
+
+80             ADR     R0,asm__noOpcode        ;Point to the error message
+               ORRS    PC,R14,#V_flag          ;Return to caller
+
+asm__opTable   DCB     "AND",0,"EOR",0,"SUB",0,"RSB",0,"ADD",0,"ADC",0
+               DCB     "SBC",0,"RSC",0,"ORR",0,"BIC",0,"MOV",0,"MVN",0
+               DCB     "TST",0,"TEQ",0,"CMP",0,"CMN",0,"MUL",0,"MLA",0
+               DCB     "LDR",0,"STR",0,"LDM",0,"STM",0,"SWI",0,"ADR",0
+               DCB     "SWP",0,"CDP",0,"STC",0,"LDC",0,"MRC",0,"MCR",0
+               DCD     0
+
+asm__noOpcode  DCD     1
+               DCB     "Unknown opcode",0
+
+               LTORG
+
+; --- asm__lookup ---
+;
+; On entry:    R6 == pointer to lookup table, with values in words
+;              R8 == pointer to three character thing to read
+;
+; On exit:     CC if found, and R5 == index into table of match
+;              CS if not found
+;              R0-R2, R6 corrupted horridly
+
+asm__lookup    ROUT
+
+               MOV     R5,#0                   ;Zero the initial index
+
+               BIC     R0,R8,#3                ;Get base of thingy
+               AND     R2,R8,#3                ;Get non-wordalignedness
+               LDMIA   R0,{R0,R1}              ;Load the possible bytes
+               MOVS    R2,R2,LSL #3            ;Shift offset up to bytes
+               MOVNE   R0,R0,LSR R2            ;Shift that bit down
+               RSBNE   R2,R2,#32               ;Work out the other shift
+               ORRNE   R0,R0,R1,LSL R2         ;Mix in the top bits
+               BIC     R0,R0,#&FF000000        ;Clear the top byte
+               BIC     R0,R0,#&00200000        ;Force to upper case
+               BIC     R0,R0,#&00002000        ;Force to upper case
+               BIC     R0,R0,#&00000020        ;Force to upper case
+
+00asm__lookup  LDR     R1,[R6],#4              ;Get an entry from table
+               CMP     R1,#0                   ;Are we at end of the table
+               ORREQS  PC,R14,#C_flag          ;Yes -- return failure
+               CMP     R1,R0                   ;Are the strings the same?
+               ADDNE   R5,R5,#1                ;No -- inc instruction no.
+               BNE     %00asm__lookup          ;And keep looking
+
+               BICS    PC,R14,#C_flag          ;Found it -- return C clear
+
+               LTORG
+
+; --- asm__condition ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;                     R0,R1,R5,R6 corrupted
+;
+; Use:         Reads in the current opcode, and deals with it
+
+asm__condition ROUT
+
+               ADR     R6,asm__condTable       ;Point to the table
+               LDRB    R0,[R8,#0]              ;Get a character
+               CMP     R0,#32                  ;Is it a control character?
+               ORRLE   R9,R9,#&E0000000        ;Yes -- make it 'AL'
+               MOVLES  PC,R14                  ;Return to caller
+               MOV     R5,#0                   ;Set up the count again
+00             LDRB    R0,[R8,#0]              ;Get a character
+               BIC     R0,R0,#&00000020        ;Force to upper case
+               LDRB    R1,[R6],#2              ;Get a byte from the table
+               BIC     R1,R1,#&00000020        ;Force to upper case
+               CMP     R0,R1                   ;Are they the same
+               LDREQB  R0,[R8,#1]              ;Yes -- get another character
+               BICEQ   R0,R0,#&00000020        ;...force to upper case
+               LDREQB  R1,[R6,#-1]             ;...and one from the table
+               BICEQ   R1,R1,#&00000020        ;...force to upper case
+               CMPEQ   R0,R1                   ;...and compare them
+               ORREQ   R9,R9,R5,LSL #28        ;If we've found it, yippee
+               ADDEQ   R8,R8,#2                ;...skip past condition code
+               MOVEQS  PC,R14                  ;...and return to caller
+               ADD     R5,R5,#1                ;Increment the counter
+               CMP     R5,#21                  ;Have we tried them all?
+               BLE     %00asm__condition       ;And keep trying if not
+               ORR     R9,R9,#&E0000000        ;Make it 'AL'
+               MOVS    PC,R14                  ;Return to caller
+
+asm__condTable DCB     "EQ","NE","CS","CC","MI","PL","VS","VC"
+               DCB     "HI","LS","GE","LT","GT","LE","AL","NV"
+               DCB     "ZS","ZC","HS","LO","NS","NC"
+
+               LTORG
+
+; --- asm__doSBit ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Reads in an optional 'S', setting the bit, and then skips
+;              the following spaces (ensuring that there is at least one).
+
+asm__doSBit    ROUT
+               STMFD   R13!,{R14}              ;Stack the link register
+
+               LDRB    R14,[R8,#0]             ;Read another byte
+               CMP     R14,#'S'                ;Is it an 'S'?
+               CMPNE   R14,#'s'
+               ORREQ   R9,R9,#(1<<20)          ;Yes -- set the bit
+               ADDEQ   R8,R8,#1                ;...skip past the 'S'
+               LDREQB  R14,[R8,#0]             ;...and read another byte
+               CMP     R14,#' '                ;Is it a space?
+               CMPNE   R14,#9                  ;Allow a tab here too
+               ADRNE   R0,asm__opcJunk         ;No -- something odd's there
+               BNE     %95asm__doSBit          ;So moan about it then
+
+10asm__doSBit  LDRB    R14,[R8],#1             ;Load the next byte
+               CMP     R14,#' '                ;Is it a space?
+               CMPNE   R14,#9                  ;Allow a tab here too
+               BEQ     %10asm__doSBit          ;Yes -- ignore it then
+               SUB     R8,R8,#1                ;We overstepped the mark
+
+               LDMFD   R13!,{R14}              ;Get the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+95asm__doSBit  LDMFD   R13!,{R14}              ;Get the link back
+               ORRS    PC,R14,#V_flag          ;Return without error
+
+               LTORG
+
+asm__opcJunk   DCD     1
+               DCB     "Rubbish on end of opcode",0
+
+; --- asm__doSpaces ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Skips the following spaces, ensureing that there is
+;              at least one.
+
+asm__doSpaces  ROUT
+               STMFD   R13!,{R14}              ;Stack the link register
+
+               LDRB    R14,[R8,#0]             ;...and read another byte
+               CMP     R14,#' '                ;Is it a space?
+               CMPNE   R14,#9                  ;Allow a tab here too
+               ADRNE   R0,asm__opcJunk         ;No -- something odd's there
+               BNE     %95asm__doSpaces        ;So moan about it then
+
+10asm__doSpaces        LDRB    R14,[R8],#1             ;Load the next byte
+               CMP     R14,#' '                ;Is it a space?
+               CMPNE   R14,#9                  ;Allow a tab here too
+               BEQ     %10asm__doSpaces        ;Yes -- ignore it then
+               SUB     R8,R8,#1                ;We overstepped the mark
+
+               LDMFD   R13!,{R14}              ;Get the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+95asm__doSpaces        LDMFD   R13!,{R14}              ;Get the link back
+               ORRS    PC,R14,#V_flag          ;Return without error
+
+               LTORG
+
+; --- asm__aluOp3 ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with 3 operand ALU operations
+
+asm__aluOp3    ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               CMP     R5,#7                   ;Does R5 hold correct code?
+               MOVLE   R9,R5,LSL #21           ;Yes -- put it in the inst.
+               CMP     R5,#8                   ;Is it ORR?
+               MOVEQ   R9,#&01800000           ;Yes -- make it so
+               CMP     R5,#9                   ;Is it a BIC?
+               MOVEQ   R9,#&01C00000           ;Yes -- make it so
+               MOV     R4,R5                   ;Remember the opcode
+               BL      asm__condition          ;Read the condition
+               BL      asm__doSBit             ;Skip onto next register
+
+               ; --- First off is a register name ---
+
+               BL      asm_register            ;Read a register name
+               ORRVC   R9,R9,R0,LSL #12        ;Insert Rd in nicely
+               BLVC    asm__comma              ;Read and ignore a comma
+
+               ; --- So's the next one ---
+
+               BLVC    asm_register            ;Read a register name
+               ORRVC   R9,R9,R0,LSL #16        ;Insert Rn in nicely
+               BLVC    asm__comma              ;Read a comma
+
+               BVS     %95asm__aluOp3          ;Barf if there's an error
+
+               ; --- Now for the last op (easy one, this) ---
+
+               LDRB    R14,[R8]                ;Read a character
+               CMP     R14,#'#'                ;Is is a hash?
+               BNE     %50asm__aluOp3          ;No -- Next is a register
+
+               ; --- Operand 2 is an immediate constant ---
+
+               ADD     R8,R8,#1                ;Skip past the '#'
+               BL      asm__constant           ;Read the constant
+               MOV     R1,R0                   ;Remember the number
+               BVS     %95asm__aluOp3          ;If error -- barf
+               ORR     R9,R9,#(1<<25)          ;Operand 2 is immediate
+               BL      asm__doConstShift       ;Make it into a valid shift
+               BVC     %90asm__aluOp3          ;All OK -- return
+
+               ; --- Try an alternative opcode ---
+
+               CMP     R4,#0                   ;Was it an AND
+               CMPNE   R4,#9                   ;Or a BIC
+               CMPNE   R4,#4                   ;Or an ADD
+               CMPNE   R4,#5                   ;Or a ADC
+               CMPNE   R4,#2                   ;Perhaps a SUB
+               CMPNE   R4,#6                   ;Or an SBC
+               ADRNE   R0,asm__invConst        ;No, point to the error
+               BNE     %95asm__aluOp3          ;And return with error
+
+               MOV     R0,R1                   ;Put the number back in R0
+               CMP     R4,#0                   ;Was it an AND
+               MVNEQ   R0,R0                   ;Yes -- invert the number
+               MOVEQ   R4,#9                   ;And make it a BIC
+               BEQ     %20asm__aluOp3          ;Try the new opcode then
+
+               CMP     R4,#9                   ;Was it a BIC
+               MVNEQ   R0,R0                   ;Yes -- invert the number
+               MOVEQ   R4,#0                   ;And make it an AND
+               BEQ     %20asm__aluOp3          ;Try the new opcode then
+
+               CMP     R4,#4                   ;Was it an ADD
+               RSBEQ   R0,R0,#0                ;Yes -- negate the number
+               MOVEQ   R4,#2                   ;And make it a SUB
+               BEQ     %20asm__aluOp3          ;Try the new opcode then
+
+               CMP     R4,#2                   ;Was it a SUB
+               RSBEQ   R0,R0,#0                ;Yes -- negate the number
+               MOVEQ   R4,#4                   ;And make it an ADD
+               BEQ     %20asm__aluOp3          ;Try the new opcode then
+
+               CMP     R4,#5                   ;Was it an ADC
+               MVNEQ   R0,R0                   ;Yes -- negate the number
+               MOVEQ   R4,#6                   ;And make it a SBC
+               BEQ     %20asm__aluOp3          ;Try the new opcode then
+
+               CMP     R4,#6                   ;Was it an SBC
+               MVNEQ   R0,R0                   ;Yes -- negate the number
+               MOVEQ   R4,#5                   ;And make it a ADC
+               BEQ     %20asm__aluOp3          ;Try the new opcode then
+
+20asm__aluOp3  BIC     R9,R9,#&01E00000        ;Clear the current opcode
+               CMP     R4,#9                   ;Is it a BIC?
+               MOVEQ   R4,#14                  ;Yes -- make it so
+               ORR     R9,R9,R4,LSL#21         ;And put in the new one
+               BL      asm__doConstShift       ;Make it into a valid shift
+               BVC     %90asm__aluOp3          ;Return without error
+               BVS     %95asm__aluOp3          ;Return with error
+
+               ; --- Operand 2 is a register ---
+
+50asm__aluOp3  MOV     R0,#0                   ;No -- set up some flags
+               BL      asm__op2reg             ;..read in operand 2
+
+90asm__aluOp3  BLVC    asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95asm__aluOp3  LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- asm__aluOp2 ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with 2 operand ALU operations
+
+asm__aluOp2    ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R9,#&01A00000           ;Make it a MOV
+               CMP     R5,#11                  ;Was it a MVN?
+               ORREQ   R9,R9,#&00400000        ;Yes -- make it so
+               MOV     R4,R5                   ;Remember the opcode
+               BL      asm__condition          ;Read the condition
+               BL      asm__doSBit             ;Skip to first register
+
+               ; --- First off is a register name ---
+
+               BL      asm_register            ;Read a register name
+               BVS     %95asm__aluOp2          ;On error -- report it
+               ORR     R9,R9,R0,LSL #12        ;Insert Rd in nicely
+               BL      asm__comma              ;Read a comma
+               BVS     %95asm__aluOp2          ;On error -- report it
+
+               ; --- Now for the last op (easy one, this) ---
+
+               LDRB    R14,[R8]                ;Read a character
+               CMP     R14,#'#'                ;Is is a hash?
+               BNE     %50asm__aluOp2          ;No -- Next is a register
+
+               ; --- Operand 2 is an immediate constant ---
+
+               ADD     R8,R8,#1                ;Skip past the '#'
+               BL      asm__constant           ;Read the constant
+               MOV     R1,R0                   ;Remember the number
+               BVS     %95asm__aluOp2          ;If error -- barf
+               ORR     R9,R9,#(1<<25)          ;Operand 2 is immediate
+               BL      asm__doConstShift       ;Make it into a valid shift
+               BVC     %90asm__aluOp2          ;All OK -- return
+
+               ; --- Try an alternative opcode ---
+
+               MVN     R0,R1                   ;Put the number back in R0
+               CMP     R4,#10                  ;Was it a MOV
+               MOVEQ   R4,#11                  ;Yes -- make it an MVN
+               MOVNE   R4,#10                  ;No -- it's a MOV then
+
+20asm__aluOp2  BIC     R9,R9,#&01E00000        ;Clear the current opcode
+               ORR     R9,R9,#&01A00000        ;Make it a MOV
+               CMP     R4,#11                  ;Was it a MVN?
+               ORREQ   R9,R9,#&00400000        ;Yes -- make it so
+               BL      asm__doConstShift       ;Make it into a valid shift
+               BVC     %90asm__aluOp2          ;Return without error
+               BVS     %95asm__aluOp2          ;Return with error
+
+               ; --- Operand 2 is a register ---
+
+50asm__aluOp2  MOV     R0,#0                   ;No -- set up some flags
+               BL      asm__op2reg             ;..read in operand 2
+
+90asm__aluOp2  BLVC    asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95asm__aluOp2  LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- asm__aluOpTest ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with comparison ALU operations
+
+asm__aluOpTest ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R9,#&01100000           ;Set top opcode bit, and 'S'
+               MOV     R4,R5                   ;Remember the opcode
+               SUB     R5,R5,#12               ;Index opcode from 0
+               ADD     R9,R9,R5,LSL#21         ;Correct the instruction
+               BL      asm__condition          ;Read the condition
+               BL      asm__doSBit             ;Skip to next register
+
+               ; --- First off is a register name ---
+
+               BL      asm_register            ;Read a register name
+               BVS     %95asm__aluOpTest       ;On an error -- moan
+               ORR     R9,R9,R0,LSL #12        ;Insert Rd in nicely
+               BL      asm__comma              ;Read a comma
+               BVS     %95asm__aluOpTest       ;On an error -- moan
+
+               ; --- Now for the last op (easy one, this) ---
+
+               LDRB    R14,[R8]                ;Read a character
+               CMP     R14,#'#'                ;Is is a hash?
+               BNE     %50asm__aluOpTest       ;No -- Next is a register
+
+               ; --- Operand 2 is an immediate constant ---
+
+               ADD     R8,R8,#1                ;Skip past the hash sign
+               BL      asm__constant           ;Read the constant
+               MOV     R1,R0                   ;Remember the number
+               BVS     %95asm__aluOpTest       ;If error -- barf
+               ORR     R9,R9,#(1<<25)          ;Operand 2 is immediate
+               BL      asm__doConstShift       ;Make it into a valid shift
+               BVC     %90asm__aluOpTest       ;All OK -- return
+
+               ; --- Try an alternative opcode ---
+
+               CMP     R4,#14                  ;Was it a CMP
+               CMPNE   R4,#15                  ;Or a CMN
+               ADRNE   R0,asm__invConst        ;No, point to the error
+               BNE     %95asm__aluOpTest       ;And return with error
+
+               RSB     R0,R1,#0                ;Negate the number
+               CMP     R4,#14                  ;Was it a CMP
+               MOVEQ   R4,#15                  ;Yes -- make it a CMN
+               MOVNE   R4,#14                  ;No -- make it a CMP then
+               BIC     R9,R9,#&00E00000        ;Clear the current opcode
+               SUB     R4,R4,#12               ;Index opcode from 0
+               ADD     R9,R9,R4,LSL#21         ;Correct the instruction
+               BL      asm__doConstShift       ;Make it into a valid shift
+               BVC     %90asm__aluOpTest       ;Return without error
+               BVS     %95asm__aluOpTest       ;Return with error
+
+               ; --- Operand 2 is a register ---
+
+50             MOV     R0,#0                   ;No -- set up some flags
+               BL      asm__op2reg             ;..read in operand 2
+
+90             BLVC    asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95             LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- asm__doConstShift ---
+;
+; On entry:    R0 == The immediate
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Tries to find a way of fitting the given constant into
+;              8 bits, with an even rotation.
+
+asm__doConstShift ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+               MOV     R1,#0                   ;The current shift count
+10             MOV     R2,R0,ROR R1            ;Perform the shift
+               AND     R3,R2,#&FF              ;Just get the bottom byte
+               CMP     R2,R3                   ;Were any other bits set?
+               BEQ     %50asm__doConstShift    ;No -- we've found one
+               ADD     R1,R1,#2                ;Increment the shift count
+               CMP     R1,#30                  ;Have we finished
+               BLE     %10asm__doConstShift    ;No -- keep trying
+
+               ; --- The constant is invalid ---
+
+               ADR     R0,asm__invConst        ;Point to the error message
+               LDMFD   R13!,{R0-R3,R14}        ;Load the link back
+               ADR     R0,asm__invConst        ;Point to the error
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               ; --- We have found an valid rotation ---
+
+50             CMP     R1,#0                   ;Is rotation greater than 0?
+               RSBGT   R1,R1,#32               ;Yes -- get 'reverse' value
+               ORR     R9,R9,R1,LSL #7         ;Put the rotation in inst
+               ORR     R9,R9,R2                ;And put the constant in too
+               LDMFD   R13!,{R0-R3,R14}        ;Load the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+asm__invConst  DCD     1
+               DCB     "Invalid immediate constant",0
+
+               LTORG
+
+; --- asm__op2reg ---
+;
+; On entry:    R0 == A nice flags word
+;              R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with the dreaded operand 2
+;              (Rx [[,]<shift type> [(#<num> | Ry)]]
+
+asm__op2reg    ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+
+               ; --- Read a (shifed) register ---
+
+               MOV     R4,R0                   ;Remember the flags word
+               BL      asm_register            ;Read a register name
+               BVS     %95asm__op2reg          ;Barf if there's an error
+               ORR     R9,R9,R0                ;ORR in register
+               BL      asm__comma              ;Skip the optional comma
+               ORRVS   R4,R4,#(1<<31)          ;If error -- remember this
+
+               ; --- Read in the shift ---
+
+               MOV     R0,R4                   ;Put flags in R0
+               BL      asm__readShift          ;Read in the shift type
+               BVC     %90asm__op2reg          ;All OK -- return
+
+               TST     R4,#(1<<31)             ;Was there an error before?
+               ADREQ   R0,asm__badShift        ;No -- we expected a shift
+               BEQ     %95asm__op2reg          ;Right -- report the error
+
+90asm__op2reg  LDMFD   R13!,{R14}              ;Load the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+95asm__op2reg  LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+asm__badShift  DCD     1
+               DCB     "Bad or missing shift",0
+
+; --- asm__comma ---
+;
+; On entry:    R8 == pointer into the instruction
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8 updated appropriately
+;
+; Use:         Reads in a comma, skipping spaces
+
+asm__comma     ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+
+               ; --- First we skip spaces ---
+
+00             LDRB    R14,[R8],#1             ;Load a new byte
+               CMP     R14,#' '                ;Skip over spaces
+               CMPNE   R14,#9                  ;And tabs too
+               BEQ     %00asm__comma           ;And stop when it isn't one
+
+               ; --- No we read a comma ---
+
+               CMP     R14,#','                ;Is it a comma
+               BNE     %95asm__comma           ;No -- complain
+
+               ; --- Skip more spaces ---
+
+10             LDRB    R14,[R8],#1             ;Load a new byte
+               CMP     R14,#' '                ;Skip over spaces
+               CMPNE   R14,#9                  ;And tabs too
+               BEQ     %00asm__comma           ;And stop when it isn't one
+
+               SUB     R8,R8,#1                ;We overstepped the mark
+               LDMFD   R13!,{R14}              ;Load the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+               ; --- Return an error ---
+
+95asm__comma   SUB     R8,R8,#1                ;We overstepped the mark
+               LDMFD   R13!,{R14}              ;Load the link back
+               ADR     R0,asm__commaExp        ;Point to the message
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+asm__commaExp  DCD     1
+               DCB     "Comma expected",0
+
+               LTORG
+
+; --- asm__endOfLine ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8 updated appropriately
+;
+; Use:         Ensures that the end of the line has been reached
+
+asm__endOfLine ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+
+               ; --- First we skip spaces ---
+
+00             LDRB    R14,[R8],#1             ;Load a new byte
+               CMP     R14,#' '                ;Skip over spaces
+               CMPNE   R14,#9                  ;And tabs too
+               BEQ     %00asm__endOfLine       ;And stop when it isn't one
+
+               CMP     R14,#';'                ;Is it a semicolon
+               CMPNE   R14,#31                 ;Or a control character
+
+               LDMFD   R13!,{R14}              ;Get the link back
+               BICLES  PC,R14,#V_flag          ;All OK -- return nicely
+               ADR     R0,asm__eofError        ;Point to error message
+               ORRS    PC,R14,#V_flag          ;And return an error
+
+asm__eofError  DCD     1
+               DCB     "Rubbish at end of instruction",0
+
+               LTORG
+
+; --- asm__constant ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R0 == number, R8 updated appropriately
+;
+; Use:         Reads in a constant from the expression
+
+asm__constant  ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Stack some registers
+
+               LDRB    R3,[R8]                 ;Read in a character
+               CMP     R3,#'-'                 ;Is it a minus character
+               ADDEQ   R8,R8,#1                ;Yes -- jump over it
+               MOV     R0,#10                  ;Read decimal by default
+               MOV     R1,R8                   ;Point to the string
+               SWI     XOS_ReadUnsigned        ;Read in the number
+               BVS     %95asm__constant        ;If error -- report it
+               MOV     R8,R1                   ;Make R8 correct again
+               MOV     R0,R2                   ;Put the number in R0
+               CMP     R3,#'-'                 ;Should we negate number?
+               RSBEQ   R0,R0,#0                ;Yes -- make it negative
+
+90asm__constant        LDMFD   R13!,{R1-R3,R14}        ;Load the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+95asm__constant        LDMFD   R13!,{R1-R3,R14}        ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- asm_register ---
+;
+; On entry:    R8 == pointer into the instruction
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R0 == number, R8 updated appropriately
+;
+; Use:         Reads in a register name
+
+               EXPORT  asm_register
+asm_register   ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+
+00asm_register LDRB    R14,[R8],#1             ;Read a character
+               CMP     R14,#32                 ;Is it a space?
+               CMPNE   R14,#9                  ;Or a tab
+               BEQ     %00asm_register         ;Yes -- skip spaces
+               SUB     R8,R8,#1                ;We overshot the mark
+
+               BL      diss_regTable           ;Find the register name table
+               MOV     R3,R0                   ;Look after this pointer
+
+               ; --- Start the main loop thing ---
+
+               MOV     R0,#15                  ;Start testing R15
+05asm_register MOV     R1,R8                   ;Point to the name start
+               LDR     R2,[R3,R0,LSL #2]       ;Load the correct name ptr
+
+10asm_register LDRB    R4,[R2],#1              ;Get a byte from reg name
+               LDRB    R5,[R1],#1              ;Get a byte from the string
+
+               ; --- Mangle R5 to be upper case, digit, or 0 ---
+
+               CMP     R5,#'Z'                 ;Is it bigger than a 'Z'?
+               BICHI   R5,R5,#&20              ;Yes -- make it upper case
+               SUB     R14,R5,#'A'             ;Subtract upper case 'A'
+               CMP     R14,#26                 ;Is it a letter of some kind?
+               SUBHS   R14,R5,#'0'             ;No -- try a digit then
+               CMPHS   R14,#10                 ;Is it one of them instead
+               MOVHS   R5,#0                   ;No -- it's not alnum then
+
+               ; --- Now make R4 upper case if it isn't already ---
+
+               SUB     R14,R4,#'a'             ;Subtract lower case 'a'
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R4,R4,#&20              ;Yes -- make it upper case
+
+               ; --- Do the actual comparison then ---
+
+               CMP     R4,R5                   ;Do they match nicely?
+               BNE     %20asm_register         ;No -- try the next register
+               CMP     R4,#0                   ;Is it the end of the string?
+               BNE     %10asm_register         ;No -- then try more bytes
+
+               ; --- We found a match -- yippee ---
+
+               SUB     R8,R1,#1                ;Update the string pointer
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack some registers
+               BICS    PC,R14,#V_flag          ;And there wuz no error
+
+               ; --- Try the next register ---
+
+20asm_register SUBS    R0,R0,#1                ;Move down a register
+               BGE     %05asm_register         ;If more to try, do 'em
+
+               ADR     R0,asm__badReg          ;Point to the error message
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack some registers
+               ORRS    PC,R14,#V_flag          ;And return with my error
+
+asm__badReg    DCD     1
+               DCB     "Bad register name",0
+
+               LTORG
+
+; --- asm__readShift ---
+;
+; On entry:    R0 == A nice flags word
+;              R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with the dreaded operand 2
+;              (#<num> or Rx [[,]<shift type> [(#<num> | Ry)]]
+
+asm__readShift ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R4,R0                   ;Look after the flags
+
+               ADR     R6,asm__shifts          ;Point to the possibilities
+               BL      asm__lookup             ;Find the one that matches
+               BCS     %94asm__readShift       ;And return the error
+
+               ADD     R8,R8,#3                ;Skip past shift op
+               CMP     R5,#4                   ;Is it an RRX?
+               MOVEQ   R0,#0                   ;Yes -- shift size is 0 then
+               MOVEQ   R5,#3                   ;And it's realy an ROR
+               BEQ     %20asm__readShift       ;And skip onwards
+               CMP     R5,#5                   ;Is it ASL?
+               MOVEQ   R5,#0                   ;Yes -- ASL doesn't exist!
+
+00             LDRB    R14,[R8],#1             ;Load a new byte
+               CMP     R14,#' '                ;Skip over spaces
+               CMPNE   R14,#9                  ;And tabs too
+               BEQ     %00asm__readShift       ;And stop when it isn't one
+
+               ; --- We now reach the Shift Operand ---
+
+               CMP     R14,#'#'                ;Is it immediate?
+               BEQ     %10asm__readShift       ;Yes -- read the operand
+
+               TST     R4,#1                   ;Is this a single reg trans?
+               BNE     %94asm__readShift       ;And return the error
+
+               SUB     R8,R8,#1                ;We overstepped as usual
+               BL      asm_register            ;Get the register value
+               BVS     %95asm__readShift       ;Failed -- report the error
+               ORR     R9,R9,R5,LSL #5         ;Bang in the shift type
+               ORR     R9,R9,R0,LSL #8         ;Put that in there too
+               ORR     R9,R9,#(1<<4)           ;And set reg-shifty bit
+               B       %90asm__readShift       ;Finished... 'RAY!!!
+
+               ; --- Immediate shifts ---
+
+10             BL      asm__constant           ;Read a constant value
+               BVS     %95asm__readShift       ;Failed -- report the error
+               CMP     R0,#0                   ;Is this vaguely sensible?
+               BLT     %94asm__readShift       ;-ve shifts are daft
+
+               CMPEQ   R5,#0                   ;Check for LSL by 0
+               BEQ     %20asm__readShift       ;This is OK
+               CMP     R0,#0                   ;Otherwise, is it 0?
+               BEQ     %94asm__readShift       ;0 has special meanings
+
+               CMP     R0,#32                  ;Is it too big?
+               BGT     %94asm__readShift       ;Yes -- that's really bad
+               BLT     %20asm__readShift       ;Less is OK though
+               CMP     R5,#1                   ;32 is allowed for LSR
+               CMPNE   R5,#2                   ;And for ASR
+               BNE     %94asm__readShift       ;But not for anything else
+               MOV     R0,#0                   ;Fix it to be 0 cunningly
+
+20             ORR     R9,R9,R5,LSL #5         ;Bang in the shift type
+               ORR     R9,R9,R0,LSL #7         ;Put the constant in too
+
+90             LDMFD   R13!,{R14}              ;Load the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+94             ADR     R0,asm__badShift        ;Point to bad shift message
+95             LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+asm__shifts    DCB     "LSL",0,"LSR",0,"ASR",0,"ROR",0,"RRX",0,"ASL",0
+               DCD     0
+
+               LTORG
+
+; --- asm__branch ---
+;
+; On entry:    R0 == The second character
+;              R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with branch instructions
+
+asm__branch    ROUT
+
+               STMFD   R13!,{R14}              ;Stack what we need
+               ADD     R8,R8,#1                ;Skip past the 'B'
+               CMP     R0,#'L'                 ;Is it a 'BL'?
+               CMPNE   R0,#'l'
+               MOVNE   R9,#&0A000000           ;No -- make instr a branch
+               BNE     %00asm__branch          ;And skip ahead
+               LDRB    R0,[R8,#2]              ;Is there a 3rd letter here?
+               CMP     R0,#32                  ;What is it?
+               MOVLE   R9,#&0A000000           ;Nothing -- must be a branch
+               MOVGT   R9,#&0B000000           ;A character -- BL then
+               ADDGT   R8,R8,#1                ;...skip past the 'L'
+
+00asm__branch  BL      asm__condition          ;Read in the condition
+               BL      asm__doSpaces           ;Skip following spaces
+
+               ; --- Read in the value ---
+
+               BLVC    asm__readAddress        ;Read in the address
+               BVS     %95asm__branch          ;If there's an error, barf
+               BIC     R0,R0,#3                ;Clear the lower 2 bits
+               SUB     R0,R0,R7                ;Branch is PC relative
+               MOV     R0,R0,LSR#2             ;Shift it down a bit
+               SUB     R0,R0,#2                ;Allow for pipelining
+               BIC     R0,R0,#&FF000000        ;Clear the top bits
+               ORR     R9,R9,R0                ;Put value into instruction
+
+90asm__branch  BL      asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95asm__branch  LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- asm__readAddress ---
+;
+; On entry:    R8 == pointer into the instruction
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8 updated appropriately
+;
+; Use:         Reads in an address
+
+asm__readAddress ROUT
+               STMFD   R13!,{R1-R3,R14}        ;Stack some registers
+
+               MOV     R0,#10                  ;Read decimal by default
+               MOV     R1,R8                   ;Point to the string
+               SWI     XOS_ReadUnsigned        ;Read in the number
+               BVS     %95asm__readAddress     ;If error -- report it
+               MOV     R8,R1                   ;Make R8 correct again
+               MOV     R0,R2                   ;Put the number in R0
+
+90             LDMFD   R13!,{R1-R3,R14}        ;Load the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+95             LDMFD   R13!,{R1-R3,R14}        ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- asm__multiply ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with multiply operation
+
+asm__multiply  ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R9,#&90                 ;Make it identifiable
+               CMP     R5,#17                  ;Is it an MLA?
+               ORREQ   R9,R9,#&00200000        ;Yes -- make it so
+               MOV     R4,R5                   ;Remember the opcode
+               BL      asm__condition          ;Read in the condition code
+               BL      asm__doSBit             ;Skip to first register
+
+               ; --- First off is a register name ---
+
+               BL      asm_register            ;Read a register name
+               ORRVC   R9,R9,R0,LSL #16        ;Insert Rd in nicely
+               BLVC    asm__comma              ;Read and ignore a comma
+
+               ; --- So's the next one ---
+
+               BLVC    asm_register            ;Read a register name
+               ORRVC   R9,R9,R0                ;Insert Rm in nicely
+               BLVC    asm__comma              ;Read and ignore a comma
+
+               ; --- So's the next one ---
+
+               BLVC    asm_register            ;Read a register name
+               ORRVC   R9,R9,R0,LSL#8          ;Insert Rs in nicely
+               BVS     %95asm__multiply        ;Barf if there's an error
+
+               CMP     R4,#17                  ;Is this an MLA
+               BNE     %90asm__multiply        ;No -- we're finished then
+
+               BL      asm__comma              ;Read and ignore a comma
+               BLVC    asm_register            ;Read a register name
+               ORRVC   R9,R9,R0,LSL#12         ;Insert Rn in nicely
+               BVS     %95asm__multiply        ;Barf if there's an error
+
+90asm__multiply        BL      asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95asm__multiply        LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- asm__sDataTrans ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with LDR/STR type instructions
+
+asm__sDataTrans        ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R9,#&04000000           ;Make it identifiable
+               CMP     R5,#18                  ;Is it an LDR?
+               ORREQ   R9,R9,#(1<<20)          ;Yes -- make it so
+               BL      asm__condition          ;Read in the condition
+               LDRB    R14,[R8,#0]             ;Read the next character
+               CMP     R14,#'B'                ;Is it a 'B'?
+               CMPNE   R14,#'b'
+               ORREQ   R9,R9,#(1<<22)          ;Yes -- make it byte transfer
+               ADDEQ   R8,R8,#1                ;...skip over it
+               LDREQB  R14,[R8,#0]             ;...and read another char
+               CMP     R14,#'T'                ;Is it a 'T'?
+               CMPNE   R14,#'t'
+               ORREQ   R9,R9,#(1<<21)          ;Yes -- set 'W' bit
+               ADDEQ   R8,R8,#1                ;...skip over it
+               BL      asm__doSpaces           ;Skip over spaces
+
+               ; --- First off is a register name ---
+
+               BL      asm_register            ;Read a register name
+               ORRVC   R9,R9,R0,LSL #12        ;Insert Rd in nicely
+               BLVC    asm__comma              ;Read and ignore a comma
+               BVS     %95asm__sDataTrans      ;Report a possible error
+
+               LDRB    R14,[R8,#0]             ;Read a character
+               CMP     R14,#'['                ;Is it an open bracket?
+               BNE     %70asm__sDataTrans      ;No -- jump ahead
+               ADD     R8,R8,#1                ;Skip over the bracket
+
+               BL      asm_register            ;Read a register name
+               BVS     %95asm__sDataTrans      ;Report a possible error
+               ORR     R9,R9,R0,LSL #16        ;Insert Rd in nicely
+               LDRB    R14,[R8,#0]             ;Read a character
+               CMP     R14,#']'                ;Is it an close bracket?
+               ORRNE   R9,R9,#(1<<24)          ;No -- set 'P' bit
+               ADDEQ   R8,R8,#1                ;Yes -- skip over it
+               BEQ     %10asm__sDataTrans      ;...and jump ahead a little
+               TST     R9,#(1<<21)             ;Is the 'W' bit set?
+               ADRNE   R0,asm__preAndT         ;Yes -- point to an error
+               BNE     %95asm__sDataTrans      ;And report the error
+
+10             BL      asm__comma              ;Read in the comma
+               BVS     %60asm__sDataTrans      ;No comma -- tidy up
+
+               ; --- Now for the last op (easy one, this) ---
+
+               LDRB    R14,[R8]                ;Read a character
+               CMP     R14,#'#'                ;Is is a hash?
+               BNE     %50asm__sDataTrans      ;No -- Next is a register
+
+               ; --- Operand 2 is an immediate constant ---
+
+               ADD     R8,R8,#1                ;Skip past the '#'
+               BL      asm__constant           ;Read the constant
+               BVS     %95asm__sDataTrans      ;If error -- barf
+               CMP     R0,#0                   ;Is it negative
+               RSBLT   R0,R0,#0                ;Yes -- make it positive
+               ORRGE   R9,R9,#(1<<23)          ;No -- offset is +ve
+               TST     R0,#&FF000000           ;Are any of these bits set?
+               TSTEQ   R0,#&00FF0000           ;Or these bits?
+               TSTEQ   R0,#&0000F000           ;Or even these?
+               ADRNE   R0,asm__invOffset       ;Yes -- point to error
+               BNE     %95asm__sDataTrans      ;And report error
+               ORR     R9,R9,R0                ;ORR in the value
+               B       %60asm__sDataTrans      ;And finsh off nicely
+
+               ; --- Operand 2 is a register ---
+
+50             LDRB    R14,[R8,#0]             ;Read in the next character
+               CMP     R14,#'-'                ;Is it a minus sign?
+               ADDEQ   R8,R8,#1                ;Yes -- skip past it then
+               ORRNE   R9,R9,#(1<<23)          ;No -- offset is +ve
+               ORR     R9,R9,#(1<<25)          ;Offset is register based
+               MOV     R0,#1                   ;Set up some flags
+               BL      asm__op2reg             ;..read in operand 2
+               BVS     %95asm__sDataTrans      ;If error -- barf
+
+               ; --- Finish off now ---
+
+60             TST     R9,#(1<<24)             ;Is this pre-indexed?
+               BEQ     %90asm__sDataTrans      ;No -- return OK
+               LDRB    R14,[R8],#1             ;Read a character
+               CMP     R14,#']'                ;Is it the close character
+               ADRNE   R0,asm__noClose         ;No -- point to an error
+               BNE     %95asm__sDataTrans      ;And report an error
+               LDRB    R14,[R8,#0]             ;Read a character
+               CMP     R14,#'!'                ;Is it a '!'?
+               ORREQ   R9,R9,#(1<<21)          ;Yes -- set write back bit
+               ADDEQ   R8,R8,#1                ;And skip past the pling
+               B       %90asm__sDataTrans      ;All OK then
+
+               ; --- The instruction is PC relative ---
+
+70             BL      asm__readAddress        ;Read the address
+               BVS     %95asm__sDataTrans      ;Report the error
+               ORR     R9,R9,#(1<<24)          ;Make instruction pre-indexed
+               ORR     R9,R9,#(15<<16)         ;Rn = PC
+               BIC     R0,R0,#3                ;Clear the lower 2 bits
+               SUB     R0,R0,R7                ;Branch is PC relative
+               SUBS    R0,R0,#8                ;Allow for pipelining
+               RSBLT   R0,R0,#0                ;If -ve -- make it positive
+               ORRGE   R9,R9,#(1<<23)          ;Otherwise say offset is +ve
+               BIC     R0,R0,#&FF000000        ;Clear the top bits
+               TST     R0,#&FF000000           ;Are any of these bits set?
+               TSTEQ   R0,#&00FF0000           ;Or these bits?
+               TSTEQ   R0,#&0000F000           ;Or even these?
+               ADRNE   R0,asm__invOffset       ;Yes -- point to error
+               BNE     %95asm__sDataTrans      ;And report error
+               ORR     R9,R9,R0                ;Put value into instruction
+
+90             BL      asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95             LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+asm__invOffset DCD     1
+               DCB     "Invalid offset",0
+
+asm__noClose   DCD     1
+               DCB     "] Expected",0
+
+asm__preAndT   DCD     1
+               DCB     "Can't set Trans pin with pre-indexed "
+               DCB     "data transfer",0
+
+               LTORG
+
+; --- asm__mDataTrans ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with LDM/STM type instructions
+
+asm__mDataTrans        ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R9,#&08000000           ;Make it identifiable
+               CMP     R5,#20                  ;Is it a load instruction
+               ORREQ   R9,R9,#(1<<20)          ;Yes -- make it so
+               MOV     R4,R5                   ;Remember the opcode
+               BL      asm__condition          ;Read the condition
+               LDRB    R14,[R8],#1             ;Read a character
+               CMP     R14,#'D'                ;Is it a 'D'?
+               CMPNE   R14,#'d'
+               BEQ     %10asm__mDataTrans      ;Yes -- jump ahead a bit
+               CMP     R14,#'I'                ;Is it an 'I'?
+               CMPNE   R14,#'i'
+               ORREQ   R9,R9,#(1<<23)          ;Yes -- make increase +ve
+               BEQ     %10asm__mDataTrans      ;...and jump ahead a bit
+               CMP     R14,#'F'                ;Is it an 'F'?
+               CMPNE   R14,#'f'
+               BEQ     %20asm__mDataTrans      ;Yes -- deal with it
+               CMP     R14,#'E'                ;Is it an 'E'?
+               CMPNE   R14,#'e'
+               BEQ     %30asm__mDataTrans      ;Yes -- deal with it
+               ADR     R0,asm__invStk          ;Point to the error message
+               B       %95asm__mDataTrans      ;And report it
+
+               ; --- It's an I/D stack ---
+
+10             LDRB    R14,[R8],#1             ;Load another character
+               CMP     R14,#'B'                ;Is it a 'B'?
+               CMPNE   R14,#'b'
+               ORREQ   R9,R9,#(1<<24)          ;Yes -- make it pre-indexed
+               CMPNE   R14,#'A'                ;Is it a 'A'?
+               CMPNE   R14,#'a'
+               ADRNE   R0,asm__invStk          ;Neither -- Point to error
+               BNE     %95asm__mDataTrans      ;And report it
+               B       %40asm__mDataTrans      ;Deal with the rest of it
+
+               ; --- It's a F stack ---
+
+20             LDRB    R14,[R8],#1             ;Load another character
+               CMP     R14,#'D'                ;Is it a 'D'?
+               CMPNE   R14,#'d'
+               CMPEQ   R4,#21                  ;...and is it a store?
+               ORREQ   R9,R9,#(1<<24)          ;Yes -- make it pre-indexed
+               BEQ     %40asm__mDataTrans      ;Deal with the rest of it
+               CMP     R14,#'D'                ;Is it a 'D'?
+               CMPNE   R14,#'d'
+               CMPEQ   R4,#20                  ;...and is it a load?
+               ORREQ   R9,R9,#(1<<23)          ;Yes -- make it increasing
+               BEQ     %40asm__mDataTrans      ;Deal with the rest of it
+               CMP     R14,#'A'                ;Is it a 'A'?
+               CMPNE   R14,#'a'
+               CMPEQ   R4,#21                  ;...and is it a store?
+               ORREQ   R9,R9,#&01800000        ;Yes -- make it pre & +ve
+               BEQ     %40asm__mDataTrans      ;Deal with the rest of it
+               CMP     R14,#'A'                ;Is it a 'A'?
+               CMPNE   R14,#'a'
+               CMPEQ   R4,#20                  ;...and is it a load?
+               BEQ     %40asm__mDataTrans      ;Yes -- deal with rest of it
+               ADR     R0,asm__invStk          ;Point to error
+               B       %95asm__mDataTrans      ;And report it
+
+               ; --- It's a E stack ---
+
+30             LDRB    R14,[R8],#1             ;Load another character
+               CMP     R14,#'D'                ;Is it a 'D'?
+               CMPNE   R14,#'d'
+               CMPEQ   R4,#21                  ;...and is it a store?
+               BEQ     %40asm__mDataTrans      ;Yes -- deal with rest of it
+               CMP     R14,#'D'                ;Is it a 'D'?
+               CMPNE   R14,#'d'
+               CMPEQ   R4,#20                  ;...and is it a load?
+               ORREQ   R9,R9,#&01800000        ;Yes -- make it increasing
+               BEQ     %40asm__mDataTrans      ;Deal with the rest of it
+               CMP     R14,#'A'                ;Is it a 'A'?
+               CMPNE   R14,#'a'
+               CMPEQ   R4,#21                  ;...and is it a store?
+               ORREQ   R9,R9,#(1<<23)          ;Yes -- make it +ve
+               BEQ     %40asm__mDataTrans      ;Deal with the rest of it
+               CMP     R14,#'A'                ;Is it a 'A'?
+               CMPNE   R14,#'a'
+               CMPEQ   R4,#20                  ;...and is it a load?
+               ORREQ   R9,R9,#(1<<24)          ;Yes -- make it pre-indexed
+               BEQ     %40asm__mDataTrans      ;Yes -- deal with rest of it
+               ADR     R0,asm__invStk          ;Point to error
+               B       %95asm__mDataTrans      ;And report it
+
+               ; --- Now parse the rest of the instruction ---
+
+40             BL      asm__doSpaces           ;Skip the following spaces
+               BVS     %95asm__mDataTrans      ;Report the error
+               BL      asm_register            ;Read in the next register
+               BVS     %95asm__mDataTrans      ;Report the error
+               ORR     R9,R9,R0,LSL #16        ;Store it in the instruction
+               LDRB    R14,[R8,#0]             ;Read the next character
+               CMP     R14,#'!'                ;Is it a pling?
+               ORREQ   R9,R9,#(1<<21)          ;Yes -- we want write back
+               ADDEQ   R8,R8,#1                ;...skip past the pling
+               BL      asm__comma              ;Skip the comma
+               BVS     %95asm__mDataTrans      ;Report the error
+               LDRB    R14,[R8],#1             ;Read the next character
+               CMP     R14,#'{'                ;Is it the '{'
+               ADRNE   R0,asm__expLOpen        ;No -- Point to error
+               BNE     %95asm__mDataTrans      ;...and report it
+
+               ; --- Now we read in the register list ---
+
+50             BL      asm_register            ;Read in the register
+               BVS     %95asm__mDataTrans      ;Report the error
+               MOV     R3,R0                   ;Remember this register
+               LDRB    R14,[R8,#0]             ;Load the next character
+               CMP     R14,#'-'                ;Is it a register range?
+               MOVNE   R4,R3                   ;No -- this is the final one
+               BNE     %60asm__mDataTrans      ;...and jump ahead a little
+               ADD     R8,R8,#1                ;Skip over the minus sign
+               BL      asm_register            ;Read in the register
+               BVS     %95asm__mDataTrans      ;Report the error
+               MOV     R4,R0                   ;Remember this register too
+               CMP     R3,R4                   ;Is first higher than second?
+               ADRGT   R0,asm__invListSyn      ;No -- Point to error
+               BGT     %95asm__mDataTrans      ;...and report it
+60             MOV     R5,#1                   ;Get a nice 1 value
+               ORR     R9,R9,R5,LSL R3         ;Set a register bit
+               ADD     R3,R3,#1                ;Increment the count
+               CMP     R3,R4                   ;Have we finished?
+               BLE     %60asm__mDataTrans      ;No -- keep on going
+               LDRB    R14,[R8,#0]             ;Get the next character
+               CMP     R14,#'}'                ;Is it a close bracket?
+               BEQ     %70asm__mDataTrans      ;Yes -- we're nearly finished
+               BL      asm__comma              ;Read in a comma
+               BVS     %95asm__mDataTrans      ;Report the error
+               B       %50asm__mDataTrans      ;Keep looping round
+
+70             ADD     R8,R8,#1                ;Skip the bracket
+               LDRB    R14,[R8,#0]             ;Read in the next character
+               CMP     R14,#'^'                ;Is it the caret?
+               ORREQ   R9,R9,#(1<<22)          ;Yes -- set the 'S' bit
+               ADDEQ   R8,R8,#1                ;And skip over it
+
+90             BL      asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95             LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+asm__invStk    DCD     1
+               DCB     "Unrecognised stack type",0
+
+asm__expLOpen  DCD     1
+               DCB     "Missing {",0
+
+asm__invListSyn        DCD     1
+               DCB     "Invalid list syntax",0
+
+               LTORG
+
+; --- asm__swi ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with SWI instructions
+
+asm__swi       ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R9,#&0F000000           ;Make it a SWI then
+               BL      asm__condition          ;Read the condition code
+               BL      asm__doSpaces           ;Skip over spaces
+               BVS     %95asm__swi             ;Report possible error
+
+               ; --- Try to read a number ---
+
+               MOV     R0,#10                  ;Default base
+               MOV     R1,R8                   ;Point to the number
+               SWI     XOS_ReadUnsigned        ;Read it in
+               MOVVC   R8,R1                   ;All OK -- point to end
+               MOVVC   R0,R2                   ;Put number in R0
+               BVC     %80asm__swi             ;...and return
+
+               ; --- It must be a string then ---
+
+               MOV     R1,R8                   ;Point to it again
+               SWI     XOS_SWINumberFromString ;Translate to a number
+               BVS     %04asm__swi             ;On error -- look ahead
+
+00asm__swi     LDRB    R14,[R8],#1             ;Read a character
+               CMP     R14,#32                 ;Is it a terminator?
+               BGT     %00asm__swi             ;No -- keep looking
+               SUB     R8,R8,#1                ;We overshot
+               B       %80asm__swi             ;...and return
+
+               ; --- As a last resort, see if it's an OS_WriteI ---
+
+04asm__swi     MOV     R4,R8                   ;Point to the first character
+               BL      str_buffer              ;Get a buffer use
+               MOV     R0,R1                   ;Remember this buffer
+05asm__swi     LDRB    R14,[R4],#1             ;Read a character
+               CMP     R14,#'+'                ;Is it a plus?
+               BEQ     %10asm__swi             ;Yes -- jump ahead
+               CMP     R14,#31                 ;Or a terminatore?
+               BLE     %95asm__swi             ;Yes -- return
+               STRB    R14,[R0],#1             ;Store the character
+               B       %05asm__swi             ;Keep on searching
+
+               ; --- We have found a plus sign ---
+
+10asm__swi     MOV     R14,#0                  ;Get a NULL byte
+               STRB    R14,[R0,#0]             ;Store at end of sting
+               SWI     XOS_SWINumberFromString ;Translate to a number
+               BVS     %95asm__swi             ;Return possible error
+               CMP     R0,#&100                ;Is it OS_WriteC?
+               ADRNE   R0,asm__unknownSWI      ;No -- point to error message
+               BNE     %95asm__swi             ;..and return error
+               MOV     R0,#10                  ;Default base to read
+               MOV     R1,R4                   ;Point to after '+'
+               SWI     XOS_ReadUnsigned        ;Read in a number
+               BVC     %70asm__swi             ;All OK -- jump ahead
+               LDRB    R14,[R4,#0]             ;Read the next character
+               CMP     R14,#'"'                ;Is it a quote?
+               CMPNE   R14,#'''                ;Allow single ones too
+               ADRNE   R0,asm__unknownSWI      ;No -- point to error
+               BNE     %95asm__swi             ;And return error
+               LDRB    R1,[R4,#2]              ;Read the next character
+               CMP     R1,R14                  ;Is it a quote?
+               ADRNE   R0,asm__unknownSWI      ;No -- point to error
+               BNE     %95asm__swi             ;And return error
+               LDRB    R2,[R4,#1]              ;Read the character
+               ADD     R1,R4,#3                ;Skip over string
+
+70asm__swi     MOV     R0,R2                   ;Put number in R0
+               ADD     R0,R0,#&100             ;Form correct number
+               MOV     R8,R1                   ;Point to end of string
+
+80asm__swi     TST     R0,#&FF000000           ;Are these bits set?
+               ADRNE   R0,asm__invSWINum       ;Yes -- point to error
+               BNE     %95asm__swi             ;...and return
+               ORR     R9,R9,R0                ;ORR in the number
+
+90asm__swi     BL      asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95asm__swi     LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+asm__unknownSWI        DCD     1
+               DCB     "SWI name not known",0
+
+asm__invSWINum DCD     1
+               DCB     "SWI number too high",0
+
+               LTORG
+
+; --- asm__adr ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Copes with the ADR directive
+
+asm__adr       ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R9,#&02000000           ;ALU with immediate operand 2
+               ORR     R9,R9,#(15<<16)         ;Make Rn = PC
+               BL      asm__condition          ;Read a condition
+               BL      asm__doSpaces           ;Skips past spaces
+               BVS     %95asm__adr             ;Complain bitterley
+               BL      asm_register            ;Read in a register
+               BVS     %95asm__adr             ;Complain if we need to
+               ORR     R9,R9,R0,LSL#12         ;Set up Rd
+               BL      asm__comma              ;Skip over the comma
+               BVS     %95asm__adr             ;Complain if we need to
+               BL      asm__readAddress        ;Read the following address
+               BVS     %95asm__adr             ;Complain if we need to
+               SUB     R0,R0,#8                ;Allow for pipelining
+               CMP     R0,R7                   ;What sort of offset is it?
+               SUBLT   R0,R7,R0                ;Maybe its positive
+               SUBGE   R0,R0,R7                ;Or even positive
+               ORRLT   R9,R9,#&00400000        ;Make it a SUB
+               ORRGE   R9,R9,#&00800000        ;Or an ADD as appropriate
+               BL      asm__doConstShift       ;Make it into a valid shift
+               BVS     %95asm__adr             ;Complain n an error
+
+90asm__adr     BL      asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95asm__adr     LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- asm__swp ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with SWP instructions
+
+asm__swp       ROUT
+
+               STMFD   R13!,{R14}              ;Save the link
+               MOV     R9,#&01000000           ;Make it identifiable
+               ORR     R9,R9,#&90              ;Set these bits right too
+               BL      asm__condition          ;Read the condition
+               LDRB    R14,[R8,#0]             ;Load the next character
+               CMP     R14,#'B'                ;Is it a 'B'
+               CMPNE   R14,#'b'
+               ADDEQ   R8,R8,#1                ;Yes -- skip over it
+               ORREQ   R9,R9,#(1<<22)          ;...and make it a byte trans.
+               BL      asm__doSpaces           ;Skip spaces
+               BVS     %95asm__swp             ;And complain if we can
+               BL      asm_register            ;Read a register
+               ORRVC   R9,R9,R0,LSL #12        ;Put Rd in instruction
+               BLVC    asm__comma              ;And read a comma
+               BLVC    asm_register            ;Read a register
+               ORRVC   R9,R9,R0                ;Put Rm in instruction
+               BLVC    asm__comma              ;And read a comma
+               BVS     %95asm__swp             ;And complain if we can
+               LDRB    R14,[R8],#1             ;Load the next character
+               CMP     R14,#'['                ;Is it a '['
+               ADRNE   R0,asm__invSWPSyn       ;No -- point to the error
+               BNE     %95asm__swp             ;...and report it
+               BL      asm_register            ;Read a register
+               BVS     %95asm__swp             ;And complain if we can
+               ORR     R9,R9,R0,LSL #16        ;Put Rn in instruction
+               LDRB    R14,[R8],#1             ;Load the next character
+               CMP     R14,#']'                ;Is it a ']'
+               ADRNE   R0,asm__invSWPSyn       ;No -- point to the error
+               BNE     %95asm__swp             ;...and report it
+
+90asm__swp     BL      asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95asm__swp     LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+asm__invSWPSyn DCD     1
+               DCB     "Invalid synatax for SWP",0
+
+               LTORG
+
+; --- asm__coproc ---
+;
+; On entry:    R8 == pointer into the instruction
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8 updated appropriately
+;                     R0 == co-processor number
+;
+; Use:         Reads a co-processor number of the form CPxx
+
+asm__coproc    ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               LDRB    R14,[R8],#1             ;Read a character
+               CMP     R14,#'C'                ;Is it a 'C'?
+               CMPNE   R14,#'c'
+               ADRNE   R0,asm__invCoproc       ;No -- point to error
+               BNE     %95asm__coproc          ;...and return
+               LDRB    R14,[R8],#1             ;Read a character
+               CMP     R14,#'P'                ;Is it a 'P'?
+               CMPNE   R14,#'p'
+               ADRNE   R0,asm__invCoproc       ;No -- point to error
+               BNE     %95asm__coproc          ;...and return
+               BL      asm__constant           ;Read in a constant
+               CMP     R0,#16                  ;Is it in range?
+               ADRHS   R0,asm__invCoproc       ;No -- point to error
+               BHS     %95asm__coproc          ;...and return
+
+90asm__coproc  LDMFD   R13!,{R14}              ;Load the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+95asm__coproc  LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+asm__invCoproc DCD     1
+               DCB     "Invalid co-processor number",0
+
+               LTORG
+
+; --- asm__coprocReg ---
+;
+; On entry:    R8 == pointer into the instruction
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8 updated appropriately
+;                     R0 == co-processor number
+;
+; Use:         Reads a co-processor register number of the form Cxx
+
+asm__coprocReg ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               LDRB    R14,[R8],#1             ;Read a character
+               CMP     R14,#'C'                ;Is it a 'C'?
+               CMPNE   R14,#'c'
+               ADRNE   R0,asm__invCoReg        ;No -- point to error
+               BNE     %95asm__coprocReg       ;...and return
+               BL      asm__constant           ;Read in a constant
+               CMP     R0,#16                  ;Is it in range?
+               ADRHS   R0,asm__invCoReg        ;No -- point to error
+               BHS     %95asm__coprocReg       ;...and return
+
+90             LDMFD   R13!,{R14}              ;Load the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+95             LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+asm__invCoReg  DCD     1
+               DCB     "Invalid co-processor register",0
+
+               LTORG
+
+; --- asm__cpOpc ---
+;
+; On entry:    R0 == maximum number allowed
+;              R8 == pointer into the instruction
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8 updated appropriately
+;                     R0 == co-processor number
+;
+; Use:         Reads a co-processor register number of the form xx.
+;              It ensures that the number is between 0 and R0
+
+asm__cpOpc     ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R1,R0                   ;Remember this value
+               BL      asm__constant           ;Read in a constant
+               CMP     R0,R1                   ;Is it in range?
+               ADRHI   R0,asm__invCoOp         ;No -- point to error
+               BHI     %95asm__cpOpc           ;...and return
+
+90asm__cpOpc   LDMFD   R13!,{R14}              ;Load the link back
+               BICS    PC,R14,#V_flag          ;Return without error
+
+95asm__cpOpc   LDMFD   R13!,{R14}              ;Lad the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+asm__invCoOp   DCD     1
+               DCB     "Operation code is out of range",0
+
+               LTORG
+
+; --- asm__cdp ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with CDP instructions
+
+asm__cdp       ROUT
+               STMFD   R13!,{R14}
+
+               MOV     R9,#&0E000000           ;Set up the instruction
+               BL      asm__condition          ;Read the condition type
+               BL      asm__doSpaces           ;Skip spaces
+               BLVC    asm__coproc             ;Read the co-processor number
+               ORRVC   R9,R9,R0,LSL #8         ;Put it in the instruction
+               BLVC    asm__comma              ;Read a comma
+               MOVVC   R0,#15                  ;Maximum allowed operation
+               BLVC    asm__cpOpc              ;Read the operation type
+               ORRVC   R9,R9,R0,LSL#20         ;Put it in the instruction
+               BLVC    asm__comma              ;Read a comma
+               BLVC    asm__coprocReg          ;Read CRd
+               ORRVC   R9,R9,R0,LSL#12         ;Put it in the instruction
+               BLVC    asm__comma              ;Read a comma
+               BLVC    asm__coprocReg          ;Read CRn
+               ORRVC   R9,R9,R0,LSL#16         ;Put it in the instruction
+               BLVC    asm__comma              ;Read a comma
+               BLVC    asm__coprocReg          ;Read CRm
+               ORRVC   R9,R9,R0                ;Put it in the instruction
+               BVS     %95asm__cdp             ;Return possible error
+               BL      asm__comma              ;Read a comma
+               BVS     %90asm__cdp             ;If no comma, return OK
+               BL      asm__constant           ;Read a constant
+               BVS     %95asm__cdp             ;Return possible error
+               CMP     R0,#8                   ;Is number out of range?
+               ADRHS   R0,asm__invAux          ;Yes -- point to error
+               BHS     %95asm__cdp             ;Return possible error
+               ORR     R9,R9,R0,LSL #5         ;Store the number
+
+90asm__cdp     BL      asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95asm__cdp     LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+asm__invAux    DCD     1
+               DCB     "Auxilary expression must be 0-7",0
+
+; --- asm__coRegTrans ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with MCR/MRC instructions
+
+asm__coRegTrans        ROUT
+               STMFD   R13!,{R14}
+
+               MOV     R9,#&0E000000           ;Set up the instruction
+               ORR     R9,R9,#(1<<4)           ;This bit should be set
+               CMP     R5,#29                  ;Is it MCR?
+               ORREQ   R9,R9,#(1<<20)          ;Yes -- make it so
+               BL      asm__condition          ;Read the condition type
+               BL      asm__doSpaces           ;Skip spaces
+               BLVC    asm__coproc             ;Read the co-processor number
+               ORRVC   R9,R9,R0,LSL #8         ;Put it in the instruction
+               BLVC    asm__comma              ;Read a comma
+               MOVVC   R0,#7                   ;Maximum allowed operation
+               BLVC    asm__cpOpc              ;Read the operation type
+               ORRVC   R9,R9,R0,LSL#21         ;Put it in the instruction
+               BLVC    asm__comma              ;Read a comma
+               BLVC    asm_register            ;Read Rd
+               ORRVC   R9,R9,R0,LSL#12         ;Put it in the instruction
+               BLVC    asm__comma              ;Read a comma
+               BLVC    asm__coprocReg          ;Read CRn
+               ORRVC   R9,R9,R0,LSL#16         ;Put it in the instruction
+               BLVC    asm__comma              ;Read a comma
+               BLVC    asm__coprocReg          ;Read CRm
+               ORRVC   R9,R9,R0                ;Put it in the instruction
+               BVS     %95asm__coRegTrans      ;Return possible error
+               BL      asm__comma              ;Read a comma
+               BVS     %90asm__coRegTrans      ;If no comma, return OK
+               BL      asm__constant           ;Read a constant
+               BVS     %95asm__coRegTrans      ;Return possible error
+               CMP     R0,#8                   ;Is number out of range?
+               ADRHS   R0,asm__invAux          ;Yes -- point to error
+               BHS     %95asm__coRegTrans      ;Return possible error
+               ORR     R9,R9,R0,LSL #5         ;Store the number
+
+90             BL      asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95             LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- asm__coDataTrans ---
+;
+; On entry:    R8 == pointer into the instruction
+;              R9 == instruction so far
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R8,R9 updated appropriately
+;
+; Use:         Deals with LDC/STC instructions
+
+asm__coDataTrans ROUT
+
+               STMFD   R13!,{R14}
+
+               MOV     R9,#&0C000000           ;Set up the instruction
+               CMP     R5,#26                  ;Is it STC?
+               ORRNE   R9,R9,#(1<<20)          ;No -- make it load then
+               BL      asm__condition          ;Read the condition type
+               LDRB    R14,[R8,#0]             ;Read the next character
+               CMP     R14,#'L'                ;Is it an 'L'?
+               CMPNE   R14,#'l'
+               ORREQ   R9,R9,#(1<<22)          ;Yes -- make it long transfer
+               ADDEQ   R8,R8,#1                ;...skip over it
+               LDREQB  R14,[R8,#0]             ;...and read another char
+               CMP     R14,#'T'                ;Is it a 'T'?
+               CMPNE   R14,#'t'
+               ORREQ   R9,R9,#(1<<21)          ;Yes -- set 'W' bit
+               ADDEQ   R8,R8,#1                ;...skip over it
+               BL      asm__doSpaces           ;Skip spaces
+
+               BLVC    asm__coproc             ;Read the co-processor number
+               ORRVC   R9,R9,R0,LSL #8         ;Put it in the instruction
+               BLVC    asm__comma              ;Read a comma
+               BLVC    asm__coprocReg          ;Read CRd
+               ORRVC   R9,R9,R0,LSL#12         ;Put it in the instruction
+               BLVC    asm__comma              ;Read a comma
+               BVS     %95asm__coDataTrans     ;Return possible error
+
+               LDRB    R14,[R8,#0]             ;Read a character
+               CMP     R14,#'['                ;Is it an open bracket?
+               BNE     %70asm__coDataTrans     ;No -- jump ahead
+               ADD     R8,R8,#1                ;Skip over the bracket
+
+               BL      asm_register            ;Read a register name
+               BVS     %95asm__coDataTrans     ;Report a possible error
+               ORR     R9,R9,R0,LSL #16        ;Insert Rn in nicely
+               LDRB    R14,[R8,#0]             ;Read a character
+               CMP     R14,#']'                ;Is it an close bracket?
+               ORRNE   R9,R9,#(1<<24)          ;No -- set 'P' bit
+               ADDEQ   R8,R8,#1                ;Yes -- skip over it
+               BEQ     %10asm__coDataTrans     ;...and jump ahead a little
+               TST     R9,#(1<<21)             ;Is the 'W' bit set?
+               ADRNEL  R0,asm__preAndT         ;Yes -- point to an error
+               BNE     %95asm__coDataTrans     ;And report the error
+
+10             BL      asm__comma              ;Read in the comma
+               ORRVS   R9,R9,#(1<<23)          ;No comma -- offset is +ve
+               BVS     %60asm__coDataTrans     ;...tidy up
+
+               ; --- Now for the last op (easy one, this) ---
+
+               LDRB    R14,[R8]                ;Read a character
+               CMP     R14,#'#'                ;Is is a hash?
+               ADRNE   R0,asm__invCoOffset     ;No -- point to error
+               BNE     %95asm__coDataTrans     ;And return an error
+
+               ; --- Operand 2 is an immediate constant ---
+
+               ADD     R8,R8,#1                ;Skip past the '#'
+               BL      asm__constant           ;Read the constant
+               BVS     %95asm__coDataTrans     ;If error -- barf
+               CMP     R0,#0                   ;Is it negative
+               RSBLT   R0,R0,#0                ;Yes -- make it positive
+               ORRGE   R9,R9,#(1<<23)          ;No -- offset is +ve
+               MOV     R0,R0,LSR#2             ;Scale it a little
+               AND     R1,R0,#&FF              ;Just get lower bits
+               CMP     R1,R0                   ;Were just these set?
+               ADRNEL  R0,asm__invOffset       ;No -- point to error
+               BNE     %95asm__coDataTrans     ;And report error
+               ORR     R9,R9,R0                ;ORR in the value
+
+               ; --- Finish off now ---
+
+60             TST     R9,#(1<<24)             ;Is this pre-indexed?
+               BEQ     %90asm__coDataTrans     ;No -- return OK
+               LDRB    R14,[R8],#1             ;Read a character
+               CMP     R14,#']'                ;Is it the close character
+               ADRNEL  R0,asm__noClose         ;No -- point to an error
+               BNE     %95asm__coDataTrans     ;And report an error
+               LDRB    R14,[R8,#0]             ;Read a character
+               CMP     R14,#'!'                ;Is it a '!'?
+               ORREQ   R9,R9,#(1<<21)          ;Yes -- set write back bit
+               ADDEQ   R8,R8,#1                ;And skip past the pling
+               B       %90asm__coDataTrans     ;All OK then
+
+               ; --- The instruction is PC relative ---
+
+70             BL      asm__readAddress        ;Read the address
+               BVS     %95asm__coDataTrans     ;Report the error
+               TST     R0,#3                   ;Is the address word-aligned
+               ADRNE   R0,asm__ldcWord         ;No -- point to error
+               BNE     %95asm__coDataTrans     ;Report the error
+               ORR     R9,R9,#(1<<24)          ;Make instruction pre-indexed
+               ORR     R9,R9,#(15<<16)         ;Rn = PC
+               SUB     R0,R0,R7                ;Branch is PC relative
+               SUBS    R0,R0,#8                ;Allow for pipelining
+               RSBLT   R0,R0,#0                ;If -ve -- make it positive
+               ORRGE   R9,R9,#(1<<23)          ;Otherwise say offset is +ve
+               MOV     R0,R0,LSR #2            ;Shift the offset down
+               AND     R1,R0,#&FF              ;Just get lower bits
+               CMP     R1,R0                   ;Were just these set?
+               ADRNEL  R0,asm__invOffset       ;No -- point to error
+               BNE     %95asm__coDataTrans     ;And report error
+               ORR     R9,R9,R0                ;Put value into instruction
+
+90             BL      asm__endOfLine          ;Make sure it ends here
+               LDMVCFD R13!,{R14}              ;Load the link back
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+95             LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+asm__ldcWord   DCD     1
+               DCB     "Target is not word aligned",0
+
+asm__invCoOffset DCD   1
+               DCB     "Offset must be immediate constant",0
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/s/brkpt b/StraySrc/Hammer/s/brkpt
new file mode 100644 (file)
index 0000000..db2111b
--- /dev/null
@@ -0,0 +1,522 @@
+;
+; brkpt.s
+;
+; Breakpoint handling (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Things not to forget -------------------------------------------------
+;
+; When removing a break point, ensure instruction is still our branch
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.armEmul
+               GET     sh.driver
+               GET     sh.hammer
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Hammer$$Code|,CODE,READONLY
+
+; --- brkpt_set ---
+;
+; On entry:    R0 == address to set breakpoint
+;
+; On exit:     May return error
+;
+; Use:         Sets a breakpoint at the given location, giving it the
+;              current handle.  The address is assumed to be word-aligned,
+;              and writable.
+
+               EXPORT  brkpt_set
+brkpt_set      ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R5,R0                   ;Look after the address
+               LDR     R12,brkpt__wSpace       ;Find my workspace address
+
+               ; --- Check for an exisiting break point ---
+
+               BL      brkpt__findBlock        ;Try to find it
+               ADRCS   R0,brkpt__exists        ;Already one there?
+               BCS     %90brkpt_set            ;Yes -- return with error
+
+               ; --- Allocate the breakpoint block ---
+
+               MOV     R0,#6                   ;Allocate from the RMA
+               MOV     R3,#brkpt__size         ;Get the size of the block
+               SWI     XOS_Module              ;Allocate the block nicely
+               BVS     %90brkpt_set            ;If it failed, return error
+
+               ; --- Fill in the breakpoint block ---
+
+               LDR     R0,brkpt__current       ;Load the current handle
+               ADR     R14,brkpt__table        ;Point to the main table
+               LDR     R1,[R14,R0,LSL #2]      ;Load the correct list head
+               STR     R1,[R2,#brkpt__next]    ;Store in the breakpoint blk
+               STR     R2,[R14,R0,LSL #2]      ;And fill in the head again
+               STR     R5,[R2,#brkpt__address] ;Save the address there too
+               LDR     R1,[R5,#0]              ;Load the old contents
+               STR     R1,[R2,#brkpt__old]     ;Store this away for later
+
+               ; --- Build the breakpoint entry code ---
+
+               ADR     R14,brkpt__entry        ;Point to the basic entry
+               LDMIA   R14,{R0,R1}             ;Load them into registers
+               ADR     R3,brkpt__handler       ;Point to the main handler
+               ADD     R14,R2,#brkpt__code+16  ;Find the branch instruction
+               SUB     R3,R3,R14               ;Subtract the offset
+               MOV     R3,R3,LSR #2            ;Shift right two places
+               BIC     R3,R3,#&FF000000        ;Clear the opcode byte
+               ORR     R3,R3,#&EA000000        ;Make it a branch instruction
+               ADD     R14,R2,#brkpt__code     ;Point to the actual code
+               STMIA   R14,{R0,R1,R3}          ;Build the code nicely
+
+               ; --- Now insert the breakpoint ---
+
+               SUB     R0,R2,R5                ;Find offset from code to blk
+               ADD     R0,R0,#brkpt__code-8    ;Find the code, handle pipe
+               MOV     R0,R0,LSR #2            ;Shift right two places
+               BIC     R0,R0,#&FF000000        ;Clear the opcode byte
+               ORR     R0,R0,#&EA000000        ;Make it a branch instruction
+               STR     R0,[R5,#0]              ;Store it away nicely
+               LDMFD   R13!,{R0-R5,R14}        ;Unstack registers
+               BICS    PC,R14,#V_flag          ;And return no errors
+
+brkpt__entry   STR     R14,{PC}-brkpt__code+brkpt__R14
+               ADR     R14,{PC}-brkpt__code-4
+
+               ; --- It went amiss ---
+
+90brkpt_set    ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+brkpt__exists  DCD     1
+               DCB     "There is already a breakpoint at this address",0
+
+               LTORG
+
+; --- brkpt__setViaStar ---
+;
+; On entry:    R0 == Pointer to command tail
+;              R1 == number of parameters
+;
+; On exit:     --
+;
+; Use:         Sets a break point at the desired address. This call
+;              is made via a * command
+
+brkpt__setViaStar ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R1,R0                   ;Point to the string
+               MOV     R0,#16                  ;Default base to read
+               SWI     XOS_ReadUnsigned        ;Read the address
+               BVS     %90brkpt__setViaStar    ;Barf on error
+               MOV     R0,R2                   ;Put address in R0
+               BL      brkpt_set               ;Set the breakpoint
+               LDMVCFD R13!,{R0-R2,PC}^        ;Return if no error
+
+90             ADD     R13,R13,#4              ;Skip over R0
+               LDMFD   R13!,{R1-R2,R14}        ;Get the registers back
+               ORRS    PC,R14,#V_flag          ;And return with error
+
+               LTORG
+
+brkpt__setHelp DCB     "*SB sets up a Sledgehammer "
+               DCB     "breakpoint at the given address.",13
+brkpt__setSyn  DCB     "Syntax: *SB <address>",0
+
+; --- brkpt__handler ---
+;
+; On entry:    R14 == pointer to the breakpint block
+;
+; On exit:     --
+;
+; Use:         Called by a breakpoint block, to stop execution
+
+brkpt__handler STR     R12,brkpt__tmp          ;Save R12 -- we need it
+               LDR     R12,brkpt__wSpace       ;Load my workspace address
+               ADR     R12,brkpt__regs         ;Find the register save block
+               STMIA   R12,{R0-R11}            ;Save most of his registers
+               STR     R13,[R12,#13*4]         ;Also save his R13
+               LDR     R0,[R14,#brkpt__R14]    ;Find the R14 the bp saved
+               STR     R0,[R12,#14*4]          ;Write it to the reg block
+               LDR     R0,brkpt__tmp           ;Get the R12 I saved earlier
+               STR     R0,[R12,#12*4]          ;Write that to the reg block
+               MOV     R0,PC                   ;Get the PC value
+               AND     R0,R0,#&FC000003        ;Extract the flags
+               LDR     R1,[R14,#brkpt__address] ;Find the bp's address
+               ORR     R0,R0,R1                ;Mix 'em to find his PC
+               STR     R0,[R12,#15*4]          ;Store as his R15
+
+               MOV     R0,R12
+               B       driver
+
+brkpt__tmp     DCD     4
+
+; --- brkpt__hbHandler ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Stops execution after a SWI Sledgehammer_BreakPoint.
+
+brkpt__hbHandler ROUT
+
+               STR     R12,brkpt__tmp          ;Save R12 -- we need it
+               LDR     R12,brkpt__wSpace       ;Load my workspace address
+               ADR     R12,brkpt__regs         ;Find the register save block
+               STMIA   R12,{R0-R11}            ;Save most of his registers
+               STR     R13,[R12,#13*4]         ;Also save his R13
+               STR     R14,[R12,#14*4]         ;And his R14
+               LDR     R0,brkpt__tmp           ;Get the R12 I saved earlier
+               STR     R0,[R12,#12*4]          ;Write that to the reg block
+
+               MOV     R0,R12
+               B       driver
+
+               ROUT
+
+; --- brkpt_hardBreak ---
+;
+; On entry:    [R13+4] == return address to stomp on
+;
+; On exit:     --
+;
+; Use:         Sets an immediate break specified by a SWI call.
+
+               EXPORT  brkpt_hardBreak
+brkpt_hardBreak        ROUT
+
+               MOV     R11,R13                 ;Keep stack pointer save
+               LDR     R12,brkpt__wSpace       ;Find my workspace address
+               LDR     R10,[R11,#4]            ;Load the return address
+               ADR     R12,brkpt__regs         ;Point to the regs buffer
+               STR     R10,[R12,#15*4]         ;And as the PC value
+               AND     R10,R10,#&FC000003      ;Get his processor flags
+               ADR     R12,brkpt__hbHandler    ;Point to handler routine
+               ORR     R10,R10,R12             ;Mix them up nicely
+               STR     R10,[R11,#4]            ;Save over return address
+               MOVS    PC,R14                  ;And return normally
+
+               LTORG
+
+; --- brkpt__findBlock ---
+;
+; On entry:    R0 == address of breakpoint
+;
+; On exit:     CS and R0 == address of breakpoint block
+;                     R1 == address of previous next pointer
+;              CC and R1 corrupted otherwise
+;
+; Use:         A little obvious, I feel!
+
+brkpt__findBlock ROUT
+
+               STMFD   R13!,{R2-R5,R12}        ;Stack some registers
+               LDR     R12,brkpt__wSpace       ;Locate my workspace
+               MOV     R5,#brkpt__handles      ;A counter thing
+               ADR     R4,brkpt__table         ;Point to the table
+               MOV     R3,R0                   ;Remember this value
+
+               ; --- The main loop ---
+
+00             LDR     R0,[R4],#4              ;Load the list head
+               SUB     R1,R4,#4                ;Get address of previous next
+               CMP     R0,#0                   ;Is this the end?
+               BEQ     %20brkpt__findBlock     ;Yes -- skip onwards then
+
+10             LDR     R2,[R0,#brkpt__address] ;And find its address
+               CMP     R2,R3                   ;Are these values the same
+               LDMEQFD R13!,{R2-R5,R12}        ;Load back my registers
+               ORREQS  PC,R14,#C_flag          ;Return with C set
+
+               ADD     R1,R0,#brkpt__next      ;This is now prev next addr
+               LDR     R0,[R0,#brkpt__next]    ;Load the next pointer
+               CMP     R0,#0                   ;Have we finished yet?
+               BNE     %10brkpt__findBlock     ;No -- keep looking
+
+20             SUBS    R5,R5,#1                ;Decrement the counter
+               BGT     %00brkpt__findBlock     ;If more to do, loop
+
+               MOV     R0,R3                   ;Put R0 back again
+               LDMFD   R13!,{R2-R5,R12}        ;Load back my registers
+               BICS    PC,R14,#C_flag          ;Return with C clear
+
+               LTORG
+
+; --- brkpt_translate ---
+;
+; On entry:    R0 == address to translate
+;
+; On exit:     R0 == the address we are really interested in
+;
+; Use:         Returns the address given, as if there was no breakpoint
+;              there.
+
+               EXPORT  brkpt_translate
+brkpt_translate        ROUT
+
+               STMFD   R13!,{R1,R14}           ;Stack registers
+               BL      brkpt__findBlock        ;Find the block
+               ADDCS   R0,R0,#brkpt__old       ;Found it -- add happily
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- brkpt_remove ---
+;
+; On entry:    R0 == address of breakpoint
+;
+; On exit:     --
+;
+; Use:         Removes the break point (if any) at the given address
+
+               EXPORT  brkpt_remove
+brkpt_remove   ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack registers
+               BL      brkpt__findBlock        ;Find the block
+               BCC     %99brkpt_remove         ;Found it -- add happily
+
+               LDR     R14,[R0,#brkpt__next]   ;Load the next pointer
+               STR     R14,[R1,#0]             ;Store over previous addr
+               LDR     R14,[R0,#brkpt__old]    ;Get the old value out
+               LDR     R2,[R0,#brkpt__address] ;And find its address
+               STR     R14,[R2,#0]             ;Store the value back
+               MOV     R2,R0                   ;Point to block in R2
+               MOV     R0,#7                   ;Free the block
+               SWI     XOS_Module              ;Yes siree bob matey
+
+99brkpt_remove LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- brkpt_remAll ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Removes all the breakpoints currently installed.
+
+               EXPORT  brkpt_remAll
+brkpt_remAll   ROUT
+
+               STMFD   R13!,{R0-R5,R12,R14}    ;Save some registers
+               LDR     R12,brkpt__wSpace       ;Find my workspace address
+               MOV     R5,#brkpt__handles      ;A counter thing
+               ADR     R4,brkpt__table         ;Point to the table
+
+               ; --- The main loop ---
+
+00brkpt_remAll LDR     R2,[R4],#4              ;Load the list head
+               CMP     R2,#0                   ;Is this the end?
+               BEQ     %20brkpt_remAll         ;Yes -- skip onwards then
+05brkpt_remAll LDR     R14,[R2,#brkpt__old]    ;Get the old value out
+               LDR     R0,[R2,#brkpt__address] ;And find its address
+               STR     R14,[R0,#0]             ;Store the value back
+               LDR     R3,[R2,#brkpt__next]    ;Load the next pointer
+               MOV     R0,#7                   ;Free the RMA block
+               SWI     XOS_Module              ;Yes, really do it
+               MOVS    R2,R3                   ;Move on to the next one
+               BNE     %05brkpt_remAll         ;If more to do, loop
+
+20brkpt_remAll MOV     R14,#0                  ;Zero the breakpoint list hdr
+               STR     R14,[R4,#-4]            ;Store over the list head
+               SUBS    R5,R5,#1                ;Decrement the counter
+               BGT     %00brkpt_remAll         ;If more to do, loop
+
+               LDMFD   R13!,{R0-R5,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- brkpt__remViaStar ---
+;
+; On entry:    R0 == Pointer to command tail
+;              R1 == number of parameters
+;
+; On exit:     --
+;
+; Use:         Removes the break point at the given address. This call
+;              is made via a * command
+
+brkpt__remViaStar ROUT
+
+               CMP     R1,#0                   ;Has he ommitted the args?
+               BEQ     %50brkpt__remViaStar    ;Yes -- maybe we get 'em all
+               LDRB    R2,[R0,#0]              ;Get the first character
+               CMP     R2,#'Y'                 ;Is it a 'Y'?
+               CMPNE   R2,#'y'                 ;Check both cases
+               BEQ     brkpt_remAll            ;Yes -- remove all then
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R1,R0                   ;Point to the string
+               MOV     R0,#16                  ;Default base to read
+               SWI     XOS_ReadUnsigned        ;Read the address
+               BVS     %90brkpt__remViaStar    ;Barf on error
+               MOV     R0,R2                   ;Put address in R0
+               BL      brkpt_remove            ;Set the breakpoint
+               LDMVCFD R13!,{R0-R2,PC}^        ;Return if no error
+
+90             ADD     R13,R13,#4              ;Skip over R0
+               LDMFD   R13!,{R1-R2,R14}        ;Get the registers back
+               ORRS    PC,R14,#V_flag          ;And return with error
+
+               ; --- Maybe remove all breakpoints ---
+
+50             STMFD   R13!,{R0,R14}           ;Save some registers
+               ADR     R0,brkpt__rmConf        ;Point to confirm message
+               BL      hammer_confirm          ;Are we sure about this?
+               BLCS    brkpt_remAll            ;Yes -- do it then
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+brkpt__rmConf  DCB     "Remove all breakpoints?",0
+
+               LTORG
+
+brkpt__remHelp DCB     "*RB removes any Sledgehammer "
+               DCB     "breakpoint set at that address. If the address "
+               DCB     "is omitted, all breakpoints are removed.",13
+brkpt__remSyn  DCB     "Syntax: *RB [<address>]",0
+
+; --- brkpt_exist ---
+;
+; On entry:    R0 == address to test for
+;
+; On exit:     CC if there is no breakpoint here
+;              CS otherwise
+;
+; Use:         Informs the user if there is a breakpint at the address
+;              passed.
+
+               EXPORT  brkpt_exist
+brkpt_exist    ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Stack some registers
+               BL      brkpt__findBlock        ;Find the block thingy
+               LDMFD   R13!,{R0,R1,PC}         ;Return all happy
+
+; --- brkpt__init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the breakpoint manager.
+
+brkpt__init    ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Save a load of registers
+               MOV     R0,#bpFlag__inited
+               MOV     R1,#0
+               MOV     R2,#0
+               MOV     R3,#0
+               MOV     R4,#0
+               MOV     R5,#0
+               MOV     R6,#0
+               MOV     R7,#0
+               MOV     R8,#0
+               MOV     R9,#0
+               STMIA   R12,{R0-R9}             ;Fill the workspace
+               LDMFD   R13!,{R0-R9,PC}^        ;Return to caller
+
+               LTORG
+
+; --- brkpt__die ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Tidies away all installed breakpoints.
+
+brkpt__die     ROUT
+
+               B       brkpt_remAll            ;Remove all the breakpoints
+
+               LTORG
+
+brkpt__wSpace  DCD     0
+
+;----- Constants ------------------------------------------------------------
+
+brkpt__handles EQU     8
+
+;----- Data structures ------------------------------------------------------
+
+               ^       0
+brkpt__next    #       4                       ;Link to next breakpoint
+brkpt__address #       4                       ;Where the breakpoint `is'
+brkpt__old     #       4                       ;The previous value
+brkpt__R14     #       4                       ;User's R14 value on entry
+brkpt__code    #       12                      ;The breakpoint entry code
+brkpt__size    #       0                       ;Size of a breakpoint block
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+brkpt__wStart  #       0
+
+brkpt__flags   #       4                       ;Various flags
+brkpt__current #       4                       ;Current breakpoint handle
+brkpt__table   #       brkpt__handles*4        ;The links for the bp lists
+
+brkpt__regs    #       16*4                    ;Register block for brkpt
+
+brkpt__wSize   EQU     {VAR}-brkpt__wStart
+
+bpFlag__inited EQU     (1<<0)
+
+               AREA    |Quartz$$Table|,CODE,READONLY
+
+               DCD     brkpt__wSize
+               DCD     brkpt__wSpace
+               DCD     brkpt__init
+               DCD     brkpt__die
+
+               AREA    |Quartz$$Commands|,CODE,READONLY
+
+               DCB     "SB",0
+               DCD     brkpt__setViaStar
+               DCD     &00010001
+               DCD     brkpt__setSyn
+               DCD     brkpt__setHelp
+
+               DCB     "RB",0
+               DCD     brkpt__remViaStar
+               DCD     &00010000
+               DCD     brkpt__remSyn
+               DCD     brkpt__remHelp
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/s/diss b/StraySrc/Hammer/s/diss
new file mode 100644 (file)
index 0000000..9b81ec5
--- /dev/null
@@ -0,0 +1,1780 @@
+;
+; diss.s
+;
+; Superior Disassembly of ARM instructions (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Things to do ---------------------------------------------------------
+;
+; Disassemble Floating point instructions
+; Deal with labels
+; Recognise XRel's
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     quartz:quartz
+               GET     quartz:string
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Hammer$$Code|,CODE,READONLY
+
+; --- diss_setOptions ---
+;
+; On entry:    R0 == new options field
+;
+; On exit:     --
+;
+; Use:         Sets up the new display options for the disassembly
+
+               EXPORT  diss_setOptions
+diss_setOptions        ROUT
+
+               STMFD   R13!,{R12}              ;Stack registers
+               LDR     R12,diss__wSpace        ;Locate my workspace
+               STR     R0,ws__options          ;Save the new options
+               LDMFD   R13!,{R12}              ;Reclaim stack
+               MOVS    PC,R14
+
+; --- diss_address ---
+;
+; On entry:    R0 == address to start disassembly
+;
+; On exit:     --
+;
+; Use:         Initialises the disassembly to start at the given address
+
+               EXPORT  diss_address
+diss_address   ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               LDR     R12,diss__wSpace        ;Find my workspace address
+               LDR     R14,ws__flags           ;Load the flags word
+               AND     R14,R14,#wFlag__inited  ;Clear most of the flags
+               STR     R14,ws__flags           ;Save the flags back again
+               STR     R0,ws__nextAddr         ;Store as next address
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+; --- diss_disassemble ---
+;
+; On entry:    R0 == the instruction itself
+;
+; On exit:     R0 == pointer to buffer containing disassembly of
+;                    instruction
+;
+; Use:         Disassembles the instruction given, and places
+;              the resulting string in the returned buffer.
+
+               EXPORT  diss_disassemble
+diss_disassemble ROUT
+
+               STMFD   R13!,{R1-R12,R14}       ;Stack lots of registers
+               LDR     R12,diss__wSpace        ;Locate my workspace
+               LDR     R9,ws__nextAddr         ;Get the address to use
+               MOV     R8,R0                   ;And the contents in R8
+
+               ; --- We don't have any comments yet ---
+
+               MOV     R2,#0                   ;A nice NULL byte
+               STR     R2,ws__comment          ;Zero the comment
+               ADR     R2,ws__comment          ;Point to the comment
+               STR     R2,ws__commentEnd       ;Start comment from here
+
+               ; --- Sort out the flags ---
+
+               LDR     R14,ws__flags           ;Load the flags
+               TST     R14,#wFlag__newAdr      ;Was it a new ADR?
+               BICNE   R14,R14,#wFlag__newAdr  ;Yes -- clear the flag
+               BICEQ   R14,R14,#wFlag__wasAdr  ;Otherwise clear was ADR flag
+               STR     R14,ws__flags           ;Save the flags back again
+
+                ; --- First do the address ---
+
+               MOV     R0,R9                   ;Put the address in R0
+               ADR     R7,ws__buffer           ;Point to string buffer
+               ADR     R1,ws__buffer           ;Point to string buffer
+               MOV     R2,#16                  ;The buffer size
+               SWI     OS_ConvertHex8          ;Convert the address
+
+               MOV     R3,#' '                 ;A nice space
+               STRB    R3,[R1],#1              ;Put it in the buffer
+
+               ; --- Display the label ---
+
+               MOV     R4,#20                  ;Enter 20 spaces
+00             STRB    R3,[R1],#1              ;Store the space
+               SUBS    R4,R4,#1                ;Decrement the counter
+               BNE     %00diss_disassemble     ;Keep on looping
+
+               MOV     R3,#' '                 ;A nice space
+               STRB    R3,[R1],#1              ;Put it in the buffer
+
+               ; --- Display the word ---
+
+               MOV     R0,R8                   ;Load the word into R0
+               MOV     R2,#16                  ;The buffer size
+               SWI     OS_ConvertHex8          ;Convert the address
+
+               MOV     R3,#' '                 ;A nice space
+               STRB    R3,[R1],#1              ;Put it in the buffer
+
+               ; --- Display the ASCII field ---
+
+               MOV     R0,R8                   ;Get the instruction
+               BL      diss__showChar          ;Show a character
+               MOV     R0,R0,LSR#8             ;Get nextww byte
+               BL      diss__showChar          ;Show a character
+               MOV     R0,R0,LSR#8             ;Get next byte
+               BL      diss__showChar          ;Show a character
+               MOV     R0,R0,LSR#8             ;Get next byte
+               BL      diss__showChar          ;Show a character
+
+               MOV     R3,#' '                 ;A nice space
+               STRB    R3,[R1],#1              ;Put it in the buffer
+
+               ; --- Disassemble the instruction ---
+
+               AND     R0,R8,#&0F000000        ;Get just the opcode
+               MOV     R0,R0,LSR#26            ;Get top two bits of opcode
+
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,PC,R0,LSL#2          ;Branch to correct routine
+               B       %90diss_disassemble     ;Branch ahead
+
+               B       diss__type00
+               B       diss__type01
+               B       diss__type10
+               B       diss__type11
+
+               ; --- Return to caller ---
+
+90             LDRB    R14,ws__comment         ;Is there a comment?
+               CMP     R14,#0                  ;Look and see
+               BEQ     %95diss_disassemble     ;No -- jump ahead
+
+               MOV     R3,#68                  ;Set up the tab
+               BL      diss__tab               ;And do it
+               MOV     R0,R1                   ;Point to the buffer end
+               ADR     R1,ws__comment          ;Point at the comment
+               BL      str_cpy                 ;Copy it over
+
+95             ADD     R9,R9,#4                ;Set up the next address
+               STR     R9,ws__nextAddr         ;And store it away
+               ADR     R0,ws__buffer           ;Point to the buffer
+               MOV     R2,#0                   ;A nice NULL value
+               STRB    R2,[R1]                 ;Terminate the string
+               LDMFD   R13!,{R1-R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- diss__showChar ---
+;
+; On entry:    R0 == character to display
+;              R1 == address to insert character
+;
+; On exit:     --
+;
+; Use:         Inserts the character in the bottom 8 bits of R0 into
+;              the buffer pointed to by R1
+
+diss__showChar ROUT
+
+               STMFD   R13!,{R2-R3}            ;Stack some registers
+               AND     R2,R0,#&FF              ;Get LSB
+               CMP     R2,#127                 ;Is it the delete char?
+               CMPNE   R2,#31                  ;..or a control character
+               MOVLE   R2,#'.'                 ;Yes -- make it a dot
+               STRB    R2,[R1],#1              ;Store char in the buffer
+               LDMFD   R13!,{R2-R3}            ;Get registers back
+               MOVS    PC,R14                  ;Return to caller
+
+; --- diss__addComment ---
+;
+; On entry:    R0 == pointer to comment to add
+;
+; On exit:     R0 corrupted
+;
+; Use:         Adds the given comment to the current one
+
+diss__addComment ROUT
+
+               STMFD   R13!,{R1,R14}           ;Stack some registers
+               MOV     R1,R0                   ;Copying from here
+               LDR     R0,ws__commentEnd       ;Point to the comment end
+               ADR     R14,ws__comment         ;Get the beginning
+               CMP     R14,R0                  ;Are they the same?
+               MOVEQ   R14,#';'                ;Yes -- get a semicolon
+               STREQB  R14,[R0],#1             ;And put it at beginning
+               BL      str_cpy                 ;Copy the string over
+               STR     R0,ws__commentEnd       ;This is now comment end
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+; --- diss__typeXX ---
+;
+; On entry:    R1 == buffer position to write to
+;              R8 == the instruction
+;              R9 == address from which instruction came
+;
+; On exit:     R0,R2-R6,R10-R12 possibly corrupted
+;
+; Use:         Disassemble instructions with an opcode prefix of XX.
+
+diss__type00   ROUT
+
+               AND     R5,R8,#&0FC00000        ;Get the op code
+               AND     R6,R8,#&000000F0        ;We need these bits too
+
+               ; --- See if it is a multiply instruction ---
+
+               CMP     R5,#0                   ;Multiply instruction?
+               CMPEQ   R6,#&90                 ;Double check
+               BEQ     diss__multiply          ;Yes -- deal with it then
+
+               ; --- Is it a SWP instruction ---
+
+               CMP     R5,#&01000000           ;Is this bit set?
+               CMPNE   R5,#&01400000           ;Or maybe this bit too?
+               CMPEQ   R6,#&90                 ;Double check
+               BEQ     diss__swp               ;Yes -- deal with it
+
+               ; --- Is it an undefined operation? ---
+
+               AND     R0,R5,#&03000000        ;Get the correct bits
+               AND     R3,R6,#&00000090        ;Are these bits set too?
+               CMP     R0,#&01000000           ;Is opcode 0001?
+               CMPEQ   R3,#&00000090           ;And are these bits set?
+               BEQ     diss__undefined         ;Yes -- deal with it then
+
+               ; --- It must be a data processing operation then ---
+
+               B       diss__aluOp             ;Dissassemble an ALU op
+
+               LTORG
+
+diss__type01   ROUT
+
+               ; --- See if it's undefined ---
+
+               TST     R8,#(1<<25)             ;Is bit 25 set?
+               TSTNE   R8,#(1<<4)              ;And bit 4?
+               BNE     diss__undefined         ;Yes -- it's undefined then
+
+               ; --- So it must be a data transfer ---
+
+               B       diss__sTransfer         ;Deal with it
+
+               LTORG
+
+diss__type10   ROUT
+
+               ; --- Test to see if it's a branch ---
+
+               TST     R8,#(1<<25)             ;Is this bit set?
+               BNE     diss__branch            ;Yes -- it's a branch
+
+               ; --- It must be a multiple load then ---
+
+               B       diss__mTransfer         ;Disassemble it
+
+               LTORG
+
+diss__type11   ROUT
+
+               TST     R8,#(1<<25)             ;Is this bit clear?
+               BEQ     diss__coDataTran        ;Yes -- do co proc data trans
+
+               AND     R0,R8,#&0F000000        ;Get top nibble of opcode
+               CMP     R0,#&0F000000           ;Is it a SWI instruction?
+               BEQ     diss__swi               ;Yes -- deal with it
+
+               TST     R8,#(1<<4)              ;Is it a coregister transfer?
+               BNE     diss__coRegTran         ;Yes -- deal with it
+
+               B       diss__coDataOp          ;Do a co-proc data op
+
+               LTORG
+
+diss__undefined        ROUT
+
+               MOVS    R3,R14                  ;Remember return address
+               MOVS    R0,R1                   ;Copy to here
+               ADR     R1,diss__undef          ;Point to the message
+               BL      str_cpy                 ;Copy the string across
+               MOVS    R1,R0                   ;Make R1 point to buffer end
+               MOVS    PC,R3                   ;Return to caller
+
+diss__undef    DCB     "Undefined instruction",0
+
+               LTORG
+
+; --- diss__multiply ---
+;
+; On entry     R1 == position in buffer to write dissassembly
+;              R7 == address of buffer for dissassembled line
+;              R8 == instruction to dissassemble
+;              R9 == location in memory of instruction
+;
+; On exit:     R0,R2,R3,R4 corrupted
+;
+; Use:         Dissassembles a multiply instruction
+
+
+diss__multiply ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+
+               ; --- Set up the opcode in the buffer ---
+
+               TST     R8,#(1<<21)             ;Is it an MLA?
+               LDRNE   R14,diss__mla           ;Yes -- load that name
+               LDREQ   R14,diss__mul           ;No -- load MUL word then
+               STR     R14,[R1],#3             ;Store the opcode in buffer
+               BL      diss__cond              ;Put the condition code in
+
+               TST     R8,#(1<<20)             ;Write back condition code?
+               MOVNE   R14,#'S'                ;Yes -- stick an `S' on it
+               STRNEB  R14,[R1],#1             ;And write it on the end
+
+               MOV     R3,#52                  ;Tab to here please
+               BL      diss__tab               ;Do a 'tab' character
+
+               ; --- Write out the registers ---
+
+               MOV     R2,#','                 ;A comma, for niceness
+               MOV     R3,R8,LSR #16           ;Get Rd
+               AND     R3,R3,#&F               ;Get the register
+               CMP     R3,#&F                  ;Is it PC?
+               ADREQ   R0,diss__mulErr1        ;Yes -- point to comment
+               BLEQ    diss__addComment        ;And add the comment
+               BL      diss__reg               ;Write out the register name
+               STRB    R2,[R1],#1              ;Separate Rd from the rest
+               MOV     R4,R8                   ;Get Rm next
+               AND     R4,R4,#&F               ;Get the register
+               CMP     R4,R3                   ;Is Rd == Rm?
+               ADREQ   R0,diss__mulErr2        ;Yes -- point to comment
+               BLEQ    diss__addComment        ;And add the comment
+               MOV     R3,R4                   ;Display this register
+
+               BL      diss__reg               ;Write out the register name
+               STRB    R2,[R1],#1              ;Separate Rm from next one
+               MOV     R3,R8,LSR #8            ;Get Rs
+               BL      diss__reg               ;Write out the register name
+               TST     R8,#(1<<21)             ;Is this an MLA instruction
+               STRNEB  R2,[R1],#1              ;Separate Rs from next one
+               MOVNE   R3,R8,LSR #12           ;Get Rn
+               BLNE    diss__reg               ;And write that on the end
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+diss__mla      DCB     "MLA",0
+diss__mul      DCB     "MUL",0
+
+diss__mulErr1  DCB     "! Rd=PC ",0
+diss__mulErr2  DCB     "! Rd=Rm ",0
+
+               LTORG
+
+; --- diss__swp ---
+;
+; On entry     R1 == position in buffer to write dissassembly
+;              R7 == address of buffer for dissassembled line
+;              R8 == instruction to dissassemble
+;              R9 == location in memory of instruction
+;
+; On exit:     R0,R2,R3,R4 corrupted
+;
+; Use:         Dissassembles an SWP operation instruction
+
+
+diss__swp      ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+
+               ; --- Set up the opcode in the buffer ---
+
+               LDR     R14,diss__swpName               ;Get the SWP word
+               STR     R14,[R1],#3             ;Store the opcode in buffer
+               BL      diss__cond              ;Put the condition code in
+
+               TST     R8,#(1<<22)             ;Single byte transfer?
+               MOVNE   R14,#'B'                ;Yes -- stick an `B' on it
+               STRNEB  R14,[R1],#1             ;And write it on the end
+
+               MOV     R3,#52                  ;Tab to here please
+               BL      diss__tab               ;Do a 'tab' character
+
+               ; --- Write out the registers ---
+
+               MOV     R2,#','                 ;A comma, for niceness
+               MOV     R3,R8,LSR #12           ;Get Rd
+               BL      diss__reg               ;Write out the register name
+               STRB    R2,[R1],#1              ;Separate Rd from the rest
+               MOV     R4,R8                   ;Get Rm next
+               MOV     R3,R4                   ;Display this register
+               BL      diss__reg               ;Write out the register name
+               STRB    R2,[R1],#1              ;Separate Rm from next one
+               MOV     R2,#'['                 ;Get a '['
+               STRB    R2,[R1],#1              ;Put it in the string
+               MOV     R3,R8,LSR #16           ;Get Rn
+               BL      diss__reg               ;Write out the register name
+               MOV     R2,#']'                 ;Get a ']'
+               STRB    R2,[R1],#1              ;Put it in the string
+               ADR     R0,diss__swpComment     ;Point to the comment
+               BL      diss__addComment        ;And add it nicley
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+diss__swpName  DCB     "SWP",0
+diss__swpComment DCB   "Not available on ARM 2",0
+
+; --- diss__aluOp ---
+;
+; On entry:    R1 == position in buffer to write dissassembly
+;              R7 == address of buffer for dissassembled line
+;              R8 == instruction to dissassemble
+;              R9 == location in memory of instruction
+;
+; On exit:     R0,R2-R6,R10 corrupted
+;
+; Use:         Dissassembles an ALU operation instruction
+
+diss__aluOp    ROUT
+
+               STMFD   R13!,{R14}              ;Save some register(s)
+
+               ; --- Display the opcode nicely ---
+
+               MOV     R2,R8,LSR #21           ;Get the opcode
+               AND     R2,R2,#15               ;Mask of unwanted bits
+               ADR     R3,diss__aluTable       ;Point to my table
+               ADD     R3,R3,R2,LSL #3         ;Point to the entry I want
+               LDMIA   R3,{R3,R5}              ;Load text opcode and flags
+
+               ; --- Check for ADR instructions ---
+
+               TST     R5,#dFlag__adrable      ;Is it at all possible?
+               TSTNE   R8,#(1<<25)             ;Is it also an immediate op?
+               BEQ     %05diss__aluOp          ;No -- skip onwards then
+               TSTNE   R8,#(1<<20)             ;Is he writing back flags?
+               BNE     %05diss__aluOp          ;Yes -- it's not an ADR then
+               MOV     R14,R8,LSR #16          ;Get the middle register
+               AND     R14,R14,#15             ;Mask off unwanted bits
+               CMP     R14,#15                 ;Is it the PC?
+               BEQ     %70diss__aluOp          ;Yes -- then handle it
+
+               ; --- Just do it the old fashioned way (oo-er) ---
+
+05diss__aluOp  STR     R3,[R1],#3              ;Store the opcode
+               BL      diss__cond              ;Add on the condition code
+
+               TST     R8,#(1<<20)             ;Do we need to write an S?
+               TSTNE   R5,#dFlag__nonCmp       ;Would it be superfluous?
+               MOVNE   R14,#'S'                ;All OK, get an `S' char
+               STRNEB  R14,[R1],#1             ;And store it away
+               BNE     %10diss__aluOp          ;And don't mess with CMPs
+
+               ; --- Handle the `P' suffix on CMP instructions ---
+
+               TST     R5,#dFlag__nonCmp       ;Is this a CMP-type instr?
+               BNE     %10diss__aluOp          ;No -- don't bother with P
+               MOV     R3,R8,LSR #12           ;Otherwise get dest reg
+               AND     R3,R3,#15               ;Mask off other bits
+               CMP     R3,#15                  ;Is it a `P' instruction?
+               MOVEQ   R14,#'P'                ;Yes -- get a `P' char
+               STREQB  R14,[R1],#1             ;And store it away
+
+10diss__aluOp  MOV     R3,#52                  ;Get the tab position
+               BL      diss__tab               ;And move the position on
+
+               ; --- Output the operands ---
+
+               MOV     R2,#','                 ;Get our trusty comma
+               TST     R5,#dFlag__nonCmp       ;Is there a destination reg?
+               MOVNE   R3,R8,LSR #12           ;Yes -- get the register sym
+               BLNE    diss__reg               ;And display it nicely
+               STRNEB  R2,[R1],#1              ;And separate it off nicely
+
+               TST     R5,#dFlag__noMiddle     ;Is there a middle operand?
+               MOVEQ   R3,R8,LSR #16           ;Yes -- get the register
+               BLEQ    diss__reg               ;And display it nicely
+               STREQB  R2,[R1],#1              ;And separate it off nicely
+
+               ; --- Oh no -- it's the last operand ---
+
+               TST     R8,#(1<<25)             ;Is it an immediate op?
+               BNE     %50diss__aluOp          ;Yes -- AAARRRGHHHH
+
+               MOV     R3,R8                   ;Get the Op2 register
+               BL      diss__reg               ;Display it nicely
+
+               ; --- It's fun with shifts time, boys and girls ---
+
+               TST     R8,#(1<<4)              ;Is it a register shift
+               BLEQ    diss__shift             ;No -- do a constant shift
+               BEQ     %90diss__aluOp          ;...and return
+
+               MOV     R3,#','                 ;Get a comma
+               STRB    R3,[R1],#1              ;Store it away then
+               MOV     R3,R8,LSR #5            ;Get the shift type
+               AND     R3,R3,#3                ;Kill off excess bits
+               ADRL    R4,diss__shifts         ;Point to the shifts table
+               LDR     R4,[R4,R3,LSL #2]       ;Load the shift name
+
+               STRB    R4,[R1],#1              ;Store the first byte
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+               STRB    R4,[R1],#1              ;Store the second byte
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+               STRB    R4,[R1],#1              ;Store the third byte
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+               STRB    R4,[R1],#1              ;Store the last byte (space)
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+
+               MOV     R3,R8,LSR #8            ;Get the shift register
+               BL      diss__reg               ;Display the register name
+               B       %90diss__aluOp          ;And return to caller
+
+               ; --- Now deal with immediate constants ---
+
+50diss__aluOp  AND     R2,R8,#&F00             ;Get the shift size
+               MOV     R2,R2,LSR #7            ;Make it an even rotation
+               AND     R0,R8,#&FF              ;Get the actual immediate
+               MOV     R0,R0,ROR R2            ;And work out the real value
+
+               ; --- Add a comment if we need to ---
+
+               SUB     R14,R0,#32              ;Greater or equal to this?
+               CMP     R14,#255                ;Or lower than this?
+               BHS     %53diss__aluOp          ;No -- jump ahead
+               CMP     R0,#127                 ;Is it ASCII 127?
+               BEQ     %53diss__aluOp          ;Yes -- jump ahead
+               MOV     R2,R0                   ;Put the character in R2
+               MOV     R3,R1                   ;Preserve buffer pointer
+               MOV     R4,R0                   ;Preserve the number too
+               SUB     R13,R13,#12             ;Get a small block
+               MOV     R1,R13                  ;Point to it nicely
+               ADR     R0,diss__chMess         ;Point to the skeleton
+               BL      str_subst               ;Substitute the string
+               BL      diss__addComment        ;Add the comment
+               ADD     R13,R13,#12             ;Get my stack back again
+               MOV     R0,R4                   ;Restore the constant
+               MOV     R1,R3                   ;And restore buffer pointer
+
+               ; --- Handle possible ADRLs ---
+
+53diss__aluOp  TST     R5,#dFlag__adrable      ;Is it a possible
+               LDRNE   R14,ws__flags           ;Load the jolly old flags
+               TSTNE   R14,#wFlag__wasAdr      ;Was the last one an ADR?
+               BEQ     %55diss__aluOp          ;No -- skip ahead then
+               MOV     R2,R8,LSR #16           ;Get Rn out
+               AND     R2,R2,#15               ;Clear off excess bits
+               LDRB    R3,ws__lastReg          ;Get the last register
+               CMP     R2,R3                   ;Do they match nicely?
+               LDREQB  R2,ws__lastCond         ;Get the previous condition
+               MOVEQ   R3,R8,LSR #28           ;Get the current condition
+               CMPEQ   R2,R3                   ;Do they match too?
+               BNE     %55diss__aluOp          ;No -- skip ahead then
+
+               ; --- It's an ADRL -- it's official ---
+
+               STMFD   R13!,{R1}               ;Save the old buffer pointer
+               MOV     R10,R0                  ;Keep the offset value safe
+               BL      str_buffer              ;Get a buffer thingy
+               MOV     R6,R1                   ;Keep this buffer ptr
+               LDR     R14,diss__adr           ;Load the opcode text
+               STR     R14,[R1],#3             ;Save it in the buffer
+               BL      diss__cond              ;Attach the condition code
+               MOV     R14,#'L'                ;Say this is a long ADR
+               STRB    R14,[R1],#1             ;Tack the L on the end
+               MOV     R14,#' '                ;Put a space in there too
+               STRB    R14,[R1],#1             ;Put that in nicely
+               MOV     R3,R8,LSR #12           ;Get Rd
+               BL      diss__reg               ;Insert the register name
+               STRB    R3,ws__lastReg          ;Save the new register val
+               MOV     R14,#','                ;The magic comma again
+               STRB    R14,[R1],#1             ;Put that in nicely
+               LDR     R0,ws__lastAddr         ;Load the previous address
+               TST     R8,#(1<<23)             ;Is it an ADD instruction?
+               ADDNE   R0,R0,R10               ;Yes -- add offset to old
+               SUBEQ   R0,R0,R10               ;Otherwise subtract it
+               STR     R0,ws__lastAddr         ;Store this new address
+               BL      diss__address           ;Insert the address
+               MOV     R0,R6                   ;Point to the buffer
+               LDMFD   R13!,{R1}               ;Restore my old buffer
+               BL      diss__addComment        ;Insert the comment string
+               MOV     R0,R10                  ;Get the immediate value back
+
+               LDR     R14,ws__flags           ;Load the old flags word
+               ORR     R14,R14,#wFlag__newAdr  ;This is another ADR thing
+               STR     R14,ws__flags           ;Save the flags back again
+
+               ; --- Display the mystic hash sign ---
+
+55diss__aluOp  MOV     R14,#'#'                ;Get a hash sign
+               STRB    R14,[R1],#1             ;Add it to the string
+
+               ; --- Now work out how we want to display it ---
+
+               LDR     R14,ws__options         ;Load the options word
+               TST     R5,#dFlag__bitwise      ;Is this a bitwise operation?
+               MOVEQ   R14,R14,LSR #1          ;No -- then shift options
+               TST     R14,#dOpt__bitHex       ;Now, do we display in hex?
+               BNE     %60diss__aluOp          ;Yes -- do that then
+
+               ; --- Display the constant in decimal ---
+
+               MOV     R2,#50                  ;Say my buffer is big
+               SWI     XOS_ConvertInteger4     ;Display the number
+               B       %90diss__aluOp          ;Now we can go home
+
+               ; --- Display it in hexadecimal ---
+
+60diss__aluOp  BL      diss__displayHex        ;Print the hex value
+               B       %90diss__aluOp          ;Return to caller
+
+               ; --- Display an ADR pseudo instruction ---
+
+70diss__aluOp  LDR     R0,diss__adr            ;Load the characters `ADR'
+               STR     R0,[R1],#3              ;Save them in the buffer
+               BL      diss__cond              ;Add on a condition code
+               MOV     R3,#52                  ;Get the tab position
+               BL      diss__tab               ;Tab up to the right pos
+
+               ; --- Set up the flags to say this was an ADR ---
+
+               LDR     R14,ws__flags           ;Load the flags word
+               ORR     R14,R14,#wFlag__wasAdr+wFlag__newAdr
+               STR     R14,ws__flags           ;Save the flags back again
+               MOV     R14,R8,LSR #28          ;Get the condition code
+               STRB    R14,ws__lastCond        ;Save that for later nicely
+
+               ; --- Display the destination register ---
+
+               MOV     R3,R8,LSR #12           ;Get the register number
+               AND     R3,R3,#15               ;Kill off the excess bits
+               STRB    R3,ws__lastReg          ;Store this register away
+               BL      diss__reg               ;And display it nicely
+               MOV     R2,#','                 ;Get our trusty comma
+               STRB    R2,[R1],#1              ;And separate it off nicely
+
+               AND     R2,R8,#&F00             ;Get the shift size
+               MOV     R2,R2,LSR #7            ;Make it an even rotation
+               AND     R0,R8,#&FF              ;Get the actual immediate
+               MOV     R0,R0,ROR R2            ;And work out the real value
+               ADD     R14,R9,#8               ;Move PC on a little bit
+               TST     R8,#(1<<23)             ;Is it an ADD instruction?
+               ADDNE   R0,R14,R0               ;Yes -- add offset to PC
+               SUBEQ   R0,R14,R0               ;Otherwise subtract it
+               STR     R0,ws__lastAddr         ;Save this address away
+               BL      diss__address           ;Display the address
+
+90diss__aluOp  LDMFD   R13!,{PC}^              ;Return to caller
+
+dFlag__bitwise EQU     (1<<0)
+dFlag__adrable EQU     (1<<1)
+dFlag__multiply        EQU     (1<<2)
+dFlag__noMiddle        EQU     (1<<3)
+dFlag__nonCmp  EQU     (1<<4)
+
+diss__adr      DCB     "ADR",0
+
+diss__aluTable DCB     "AND",0
+               DCD     dFlag__bitwise+dFlag__nonCmp
+               DCB     "EOR",0
+               DCD     dFlag__bitwise+dFlag__nonCmp
+               DCB     "SUB",0
+               DCD     dFlag__adrable+dFlag__nonCmp
+               DCB     "RSB",0
+               DCD     dFlag__multiply+dFlag__nonCmp
+
+               DCB     "ADD",0
+               DCD     dFlag__multiply+dFlag__adrable+dFlag__nonCmp
+               DCB     "ADC",0
+               DCD     dFlag__nonCmp
+               DCB     "SBC",0
+               DCD     dFlag__nonCmp
+               DCB     "RSC",0
+               DCD     dFlag__nonCmp
+
+               DCB     "TST",0
+               DCD     dFlag__bitwise
+               DCB     "TEQ",0
+               DCD     dFlag__bitwise
+               DCB     "CMP",0
+               DCD     0
+               DCB     "CMN",0
+               DCD     0
+
+               DCB     "ORR",0
+               DCD     dFlag__bitwise+dFlag__nonCmp
+               DCB     "MOV",0
+               DCD     dFlag__noMiddle+dFlag__multiply+dFlag__nonCmp
+               DCB     "BIC",0
+               DCD     dFlag__bitwise+dFlag__nonCmp
+               DCB     "MVN",0
+               DCD     dFlag__noMiddle+dFlag__nonCmp
+
+diss__chMess   DCB     "='%c0'",0
+               ALIGN
+
+               LTORG
+
+diss__shifts   DCB     "LSL "
+               DCB     "LSR "
+               DCB     "ASR "
+               DCB     "ROR "
+diss__rrx      DCB     " RRX"
+
+; --- diss__shift ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R5 == Flags word of the instruction
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;
+; On exit:     R3,R4 corrupted
+;
+; Use:         Disassemble a constant controlled shift
+
+
+diss__shift    ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+
+               AND     R3,R8,#&FF0             ;Get the shift type and size
+               CMP     R3,#&000                ;Is it an LSL #0?
+               LDMEQFD R13!,{PC}^              ;Yes -- nothing to do then
+
+               CMP     R3,#&060                ;Is it an RRX?
+               BNE     %10diss__shift          ;No -- do other things then
+
+               LDR     R4,diss__rrx            ;Get the RRX string
+               STRB    R4,[R1],#1              ;Store the first byte (comma)
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+               STRB    R4,[R1],#1              ;Store the second byte
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+               STRB    R4,[R1],#1              ;Store the third byte
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+               STRB    R4,[R1],#1              ;Store the last byte
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+               LDMEQFD R13!,{PC}^              ;And return to caller
+
+               ; --- Do ordinary things now ---
+
+10diss__shift  MOV     R14,#' '                ;Put a comma in
+               STRB    R14,[R1],#1             ;Store that in the buffer
+               MOV     R14,R8,LSR #5           ;Get the shift type
+               AND     R14,R14,#3              ;Kill off excess bits
+               ADR     R4,diss__shifts         ;Point to the shifts table
+               LDR     R4,[R4,R14,LSL #2]      ;Load the shift name
+
+               MOV     R0,R3,LSR #7            ;Get the shift amount value
+               CMP     R0,#0                   ;Is it zero?
+               MOVEQ   R0,#32                  ;Then pretend it's 32
+
+               ; --- Add in the multipy comment ---
+
+               TST     R5,#dFlag__multiply     ;Does it apply to the inst?
+               BEQ     %50diss__shift          ;No -- jump ahead
+               CMP     R14,#0                  ;Is it an LSL?
+               BNE     %50diss__shift          ;No -- jump ahead
+
+               MOV     R6,R8                   ;Get Rm
+               AND     R6,R6,#&F               ;Clear unwanted bits
+               MOV     R3,R8,LSR#16            ;Get Rn
+               AND     R3,R3,#&F               ;Clear unwanted bits
+               TST     R5,#dFlag__noMiddle     ;Does it have a middle reg?
+               BNE     %12diss__shift          ;No -- jump folowing test
+               CMP     R3,R6                   ;And is Rm <> Rn?
+               BNE     %50diss__shift          ;If so -- jump ahead
+               TST     R5,#dFlag__noMiddle     ;Does it have a middle reg?
+
+12             MOV     R5,#1                   ;We start with 1
+               MOV     R5,R5,LSL R0            ;Work out the multiply
+
+               BNE     %15diss__shift          ;No -- jump ahead a bit
+               TST     R8,#(1<<23)             ;Is it a RSB?
+               ADDNE   R5,R5,#1                ;No -- increment multiply
+               SUBEQ   R5,R5,#1                ;Yes -- decrement multiply
+
+15             MOV     R11,R0                  ;Preserve R0
+               MOV     R3,R8,LSR#12            ;Get Rd
+               MOV     R10,R1                  ;Preserve the buffer pointer
+               BL      str_buffer              ;Get a buffer
+               STMFD   R13!,{R1}               ;Remember this position
+               BL      diss__reg               ;Display the destination
+               MOV     R3,#'='                 ;Get the equal sign
+               STRB    R3,[R1],#1              ;Store it in the buffer
+               MOV     R3,R6                   ;Get the operand register
+               BL      diss__reg               ;Display that
+               MOV     R3,#'*'                 ;Get the '*' sign
+               STRB    R3,[R1],#1              ;Store it in the buffer
+               MOV     R0,R5                   ;Put 'multiply by' in R0
+               SWI     OS_ConvertInteger4      ;Convert to a string
+               LDMFD   R13!,{R0}               ;Get comment pointer
+               BL      diss__addComment        ;Add the comment
+               MOV     R0,R11                  ;Restore R0 value
+               MOV     R1,R10                  ;Get buffer pos back
+
+               ; --- Display the shift ---
+
+50             STRB    R4,[R1],#1              ;Store the first byte
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+               STRB    R4,[R1],#1              ;Store the second byte
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+               STRB    R4,[R1],#1              ;Store the third byte
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+               STRB    R4,[R1],#1              ;Store the last byte (space)
+               MOV     R4,R4,LSR #8            ;Shift it down one byte
+
+               MOV     R14,#'#'                ;Put a hash sign in
+               STRB    R14,[R1],#1             ;Store it away
+               MOV     R2,#50                  ;Say my buffer's massive
+               SWI     XOS_ConvertInteger1     ;Write it out in decimal
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- diss__displayHex ---
+;
+; On entry:    R0 == hex number to display
+;              R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;
+; On exit:     R0,R2,R3 corrupted
+;
+; Use:         Displays a hex number without leading NULL bytes
+
+diss__displayHex ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R2,#'&'                 ;Tell user it's in hex
+               STRB    R2,[R1],#1              ;Save it in the buffer
+               MOV     R2,#8                   ;No nastiness done yet
+               TST     R0,#&FF000000           ;Is the top byte set?
+               MOVEQ   R0,R0,LSL #8            ;No -- shift it up then
+               SUBEQ   R2,R2,#2                ;Two digits lost here
+               TST     R0,#&FF000000           ;Is the top byte set?
+               MOVEQ   R0,R0,LSL #8            ;No -- shift it up then
+               SUBEQ   R2,R2,#2                ;Two digits lost here
+               TST     R0,#&FF000000           ;Is the top byte set?
+               MOVEQ   R0,R0,LSL #8            ;No -- shift it up then
+               SUBEQ   R2,R2,#2                ;Two digits lost here
+               ADR     R3,diss__hexDigits      ;Point to my hex table
+
+10             MOV     R14,R0,LSR #28          ;Get the top nibble
+               LDRB    R14,[R3,R14]            ;Get the correct hex digit
+               STRB    R14,[R1],#1             ;Store it in the buffer
+               MOV     R0,R0,LSL #4            ;Shift up by a nibble
+               SUBS    R2,R2,#1                ;One less digit to go
+               BGT     %10diss__displayHex     ;If I've done it, stop
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+diss__hexDigits        DCB     "0123456789ABCDEF"
+
+               LTORG
+
+; --- diss__sTransfer ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;
+; On exit:     Lots corrupted
+;
+; Use:         Disassemble LDR/STR instructions, putting the result into
+;              the buffer.
+
+diss__sTransfer        ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+
+               ; --- Display the instruction ---
+
+               TST     R8,#(1<<20)             ;Is it an LDR?
+               LDRNE   R14,diss__ldr           ;Yes -- load that name
+               LDREQ   R14,diss__str           ;No -- load STR word then
+               STR     R14,[R1],#3             ;Store the opcode in buffer
+               BL      diss__cond              ;Put the condition code in
+               TST     R8,#(1<<22)             ;Is this  byte load?
+               MOVNE   R3,#'B'                 ;Yes -- get a 'B' character
+               STRNEB  R3,[R1],#1              ;...and store it in buffer
+
+               ; --- Display the 'T' suffix ---
+
+               TST     R8,#(1<<21)             ;Is the W bit set?
+               BEQ     %00diss__sTransfer      ;No -- jump ahead a bit
+               TST     R8,#(1<<24)             ;How about the P bit?
+               MOVEQ   R3,#'T'                 ;No -- get a 'B' character
+               STREQB  R3,[R1],#1              ;...and store it in buffer
+
+               ; --- Now the destination register ---
+
+00             MOV     R3,#52                  ;Tab to this position
+               BL      diss__tab               ;Do the tabbing
+               MOV     R3,R8,LSR#12            ;Get Rd in bottom nibble
+               BL      diss__reg               ;Display the register
+               MOV     R3,#','                 ;Get a comma
+               STRB    R3,[R1],#1              ;...and store it in buffer
+               TST     R8,#(1<<24)             ;Are we pre-indexed?
+               BNE     diss__preIndexed        ;Yes -- deal with it then
+               BEQ     diss__postIndexed       ;No -- must be post-indexed
+
+diss__ldr      DCB     "LDR",0
+diss__str      DCB     "STR",0
+
+               LTORG
+
+; --- diss__preIndexed ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;              Return address is on the stack
+;
+; On exit:     Lots corrupted
+;
+; Use:         Disassembles the pre-indexed part of a data transfer op.
+
+diss__preIndexed ROUT
+
+               ; --- Deal with the base register ---
+
+               MOV     R3,R8,LSR#16            ;Get the base register
+               AND     R3,R3,#&F               ;Mask off unwanted bits
+               CMP     R3,#&F                  ;Is it the PC?
+               TSTEQ   R8,#(1<<25)             ;And is data immediate?
+               TSTEQ   R8,#(1<<21)             ;And are we not using !
+               BEQ     diss__pcRel             ;Yes -- it's PC relative
+
+               MOV     R2,#'['                 ;Get an open bracket
+               STRB    R2,[R1],#1              ;Store it nicely
+               BL      diss__reg               ;Display the base register
+               MOV     R5,#&FF                 ;Prepare the bit mask
+               ORR     R5,R5,#&F00             ;Finish it off
+               AND     R0,R8,R5                ;Get the offset
+
+               MOV     R2,#','                 ;Get an comma
+               STRB    R2,[R1],#1              ;Store it in the buffer
+               TST     R8,#(1<<25)             ;Is data immediate?
+               MOVEQ   R2,#'#'                 ;Yes -- get an hash
+               STREQB  R2,[R1],#1              ;...and store it
+               TST     R8,#(1<<23)             ;Is data negative?
+               MOVEQ   R2,#'-'                 ;Yes -- get a minus sugn
+               STREQB  R2,[R1],#1              ;...and store that
+
+               TST     R8,#(1<<25)             ;Is data immediate?
+               MOV     R5,#0                   ;The flags word
+               BEQ     %10diss__preIndexed     ;Yes -- deal with it
+
+               MOV     R3,R8                   ;Get the register
+               BL      diss__reg               ;Display the register
+               BL      diss__shift             ;Display the shift
+               B       %20diss__preIndexed     ;and jump ahead
+
+               ; --- Now work out how we want to display constant ---
+
+10             LDR     R14,ws__options         ;Load the options word
+               TST     R14,#dOpt__tranHex      ;Now, do we display in hex?
+               BLNE    diss__displayHex        ;Yes -- do it then
+               MOVEQ   R2,#50                  ;No -- say my buffer is big
+               SWIEQ   XOS_ConvertInteger4     ;...display the number
+
+               ; --- Finish off the instruction ---
+
+20             MOV     R2,#']'                 ;Yes -- get an close bracket
+               STRB    R2,[R1],#1              ;...and store it
+               TST     R8,#(1<<21)             ;Are we writing back?
+               MOVNE   R2,#'!'                 ;Yes -- get the pling
+               STRNEB  R2,[R1],#1              ;...and store it
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- diss__postIndexed ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;              Return address is on the stack
+;
+; On exit:     Lots corrupted
+;
+; Use:         Disassembles the post-indexed part of a data transfer op.
+
+diss__postIndexed ROUT
+
+               ; --- Deal with the base register ---
+
+               MOV     R3,R8,LSR#16            ;Get the base register
+               MOV     R2,#'['                 ;Get an open bracket
+               STRB    R2,[R1],#1              ;Store it nicely
+               BL      diss__reg               ;Display the base register
+               MOV     R2,#']'                 ;Get an close bracket
+               STRB    R2,[R1],#1              ;Store it nicely
+
+               ; --- Is there any post index to display ---
+
+               MOV     R5,#&FF                 ;Prepare the bit mask
+               ORR     R5,R5,#&F00             ;Finish it off
+               AND     R0,R8,R5                ;Get the offset
+
+               MOV     R2,#','                 ;Get an comma
+               STRB    R2,[R1],#1              ;Store it in the buffer
+               TST     R8,#(1<<25)             ;Is data immediate?
+               MOVEQ   R2,#'#'                 ;Yes -- get an hash
+               STREQB  R2,[R1],#1              ;...and store it
+               TST     R8,#(1<<23)             ;Is data negative?
+               MOVEQ   R2,#'-'                 ;Yes -- get a minus sugn
+               STREQB  R2,[R1],#1              ;...and store that
+
+               TST     R8,#(1<<25)             ;Is data immediate?
+               BEQ     %10diss__postIndexed    ;Yes -- deal with it
+
+               MOV     R3,R8                   ;Get the register
+               BL      diss__reg               ;Display the register
+               MOV     R5,#0                   ;The flags word
+               BL      diss__shift             ;Display the shift
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               ; --- Now work out how we want to display constant ---
+
+10             LDR     R14,ws__options         ;Load the options word
+               TST     R14,#dOpt__tranHex      ;Now, do we display in hex?
+               BLNE    diss__displayHex        ;Yes -- do it then
+               MOVEQ   R2,#50                  ;No -- say my buffer is big
+               SWIEQ   XOS_ConvertInteger4     ;...display the number
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- diss__pcRel ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;              Return address is on the stack
+;
+; On exit:     Lots corrupted
+;
+; Use:         Disassembles PC relative data transfer instructions
+
+diss__pcRel    ROUT
+
+               ADD     R2,R9,#8                ;Allow for the pipeline
+               MOV     R0,#&FF                 ;Prepare the bit mask
+               ORR     R0,R0,#&F00             ;Finish it off
+               AND     R0,R8,R0                ;Get the offset
+               TST     R8,#(1<<23)             ;Is offset negative?
+               SUBEQ   R0,R2,R0                ;Yes -- do a subtraction
+               ADDNE   R0,R2,R0                ;No -- do an addition
+               BIC     R0,R0,#&FC000000        ;Clear silly bits
+               BL      diss__address           ;Display the address
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- diss__mTransfer ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;
+; On exit:     Lots corrupted
+;
+; Use:         Disassembles LDM/STM instruction
+
+diss__mTransfer        ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link
+
+               TST     R8,#(1<<20)             ;Is it a load?
+               LDRNE   R14,diss__ldm           ;Yes -- load that name
+               LDREQ   R14,diss__stm           ;No -- load STM word then
+               STR     R14,[R1],#3             ;Store the opcode in buffer
+               BL      diss__cond              ;Put the condition code in
+
+               MOV     R5,R8,LSR#16            ;Get the base register
+               AND     R5,R5,#&F               ;Clear unwanted bits
+               LDR     R0,ws__options          ;Get the options
+               TST     R0,#dOpt__r13Stack      ;Do we use alternative type
+               BEQ     %10diss__mTransfer      ;No -- jump ahead
+               CMP     R5,#13                  ;Are we using R13?
+               BNE     %10diss__mTransfer      ;No -- jump ahead
+               TST     R8,#(1<<21)             ;Is there write back?
+               BEQ     %10diss__mTransfer      ;No -- jump ahead
+
+               ; --- Work out stack type (FD etc.) ---
+
+               TST     R8,#(1<<20)             ;Yes -- Are we storing?
+               BNE     %05diss__mTransfer      ;No -- do load seperatley
+
+               TST     R8,#(1<<24)             ;Are we full?
+               MOVNE   R0,#'F'                 ;Yes -- use 'F'
+               MOVEQ   R0,#'E'                 ;No -- use 'E'
+               STRB    R0,[R1],#1              ;Store the character
+               TST     R8,#(1<<23)             ;Are we incrementing?
+               MOVNE   R0,#'A'                 ;Yes -- use 'A'
+               MOVEQ   R0,#'D'                 ;No -- use 'D'
+               STRB    R0,[R1],#1              ;Store the character
+               B       %20diss__mTransfer      ;Jump ahead
+
+05             TST     R8,#(1<<24)             ;Are we full?
+               MOVNE   R0,#'E'                 ;Yes -- use 'E'
+               MOVEQ   R0,#'F'                 ;No -- use 'F'
+               STRB    R0,[R1],#1              ;Store the character
+               TST     R8,#(1<<23)             ;Are we incrementing?
+               MOVNE   R0,#'D'                 ;Yes -- use 'D'
+               MOVEQ   R0,#'A'                 ;No -- use 'A'
+               STRB    R0,[R1],#1              ;Store the character
+               B       %20diss__mTransfer      ;Jump ahead
+
+               ; --- Word out stack type normally ---
+
+10             TST     R8,#(1<<23)             ;Are we incrementing?
+               MOVNE   R0,#'I'                 ;Yes -- use 'I'
+               MOVEQ   R0,#'D'                 ;No -- use 'D'
+               STRB    R0,[R1],#1              ;Store the character
+               TST     R8,#(1<<24)             ;Are we full?
+               MOVNE   R0,#'B'                 ;Yes -- use 'B'
+               MOVEQ   R0,#'A'                 ;No -- use 'A'
+               STRB    R0,[R1],#1              ;Store the character
+               B       %20diss__mTransfer      ;Jump ahead
+
+               ; --- Continue the disassembly ---
+
+20             MOV     R3,#52                  ;Tab to here
+               BL      diss__tab               ;Do the tab
+               MOV     R3,R5                   ;Put the base regster in R3
+               BL      diss__reg               ;And display it
+               TST     R8,#(1<<21)             ;Do we want write back?
+               MOVNE   R0,#'!'                 ;Yes -- get the '!'
+               STRNEB  R0,[R1],#1              ;...store the character
+               MOV     R0,#','                 ;Get a comma
+               STRB    R0,[R1],#1              ;Store it
+               MOV     R0,#'{'                 ;Get the '{'
+               STRB    R0,[R1],#1              ;And store that too
+
+               ; --- Now do the register list ---
+
+               MOV     R6,#1                   ;The flags so far
+               MOV     R4,#0                   ;The current register
+               MOV     R5,#0                   ;Number in a row so far
+
+30             MOV     R2,#1                   ;A nice 1 value
+               MOV     R2,R2,LSL R4            ;Set up the bit mask
+               ANDS    R14,R8,R2               ;Is the register in the list?
+               BNE     %50diss__mTransfer      ;Yes -- jump ahead
+35             TST     R6,#4                   ;Are we in a sequence?
+               BEQ     %40diss__mTransfer      ;No -- jump a bit
+               CMP     R5,#2                   ;Have there been >2 regs?
+               MOVGT   R14,#'-'                ;Yes -- get the dash
+               MOVLE   R14,#','                ;No -- get a comma then
+               STRB    R14,[R1],#1             ;Store it in the buffer
+               SUB     R3,R4,#1                ;Put previous register in R3
+               BL      diss__reg               ;And display it
+
+40             BIC     R6,R6,#&6               ;Clear some flags
+               MOV     R5,#0                   ;None in a row now
+               B       %70diss__mTransfer      ;And jump to end of loop
+
+               ; --- The register is in the list ---
+
+50             ADD     R5,R5,#1                ;Increment reg count
+               TST     R6,#2                   ;Is this the second?
+               BNE     %55diss__mTransfer      ;Yes -- jump ahead a bit
+               TST     R6,#4                   ;Are we in a sequence?
+               BNE     %70diss__mTransfer      ;Yes -- jump to loop end
+               TST     R6,#1                   ;Is this the *very* first?
+               MOVEQ   R14,#','                ;No -- get a comma then
+               STREQB  R14,[R1],#1             ;...store it in the buffer
+               MOVEQ   R6,#2                   ;...just set 'first' bit now
+               BEQ     %60diss__mTransfer      ;...and jump ahead
+55             TST     R6,#2                   ;Was last one first one?
+               MOVNE   R6,#4                   ;Yes -- now in sequence
+               BNE     %70diss__mTransfer      ;...and  jump to loop end
+
+60             MOV     R3,R4                   ;Put register in R3
+               BL      diss__reg               ;Display the register
+               MOV     R6,#2                   ;That was the first
+
+70             ADD     R4,R4,#1                ;Increment current register
+               CMP     R4,#15                  ;Have we finished?
+               BLE     %30diss__mTransfer      ;No -- keep on looping
+               TST     R6,#4                   ;Are we still in a sequence?
+               MOVNE   R4,#16                  ;Yes -- say were on R16
+               BNE     %35diss__mTransfer      ;And finish off nicely
+
+               ; --- Finish off the instruction ---
+
+               MOV     R0,#'}'                 ;Get the closing bracket
+               STRB    R0,[R1],#1              ;Store it
+               TST     R8,#(1<<22)             ;Is there a '^'?
+               MOVNE   R0,#'^'                 ;Yes -- get the character
+               STRNEB  R0,[R1],#1              ;And store that too
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+diss__ldm      DCB     "LDM",0
+diss__stm      DCB     "STM",0
+
+               LTORG
+
+; --- diss__branch ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;
+; On exit:     Lots corrupted
+;
+; Use:         Disassembles branch instructions
+
+diss__branch   STMFD   R13!,{R14}              ;Stack the link
+               MOV     R3,#'B'                 ;It's a B instruction
+               STRB    R3,[R1],#1              ;So store it away
+               TST     R8,#(1<<24)             ;Is it BL?
+               MOVNE   R3,#'L'                 ;Yes -- get the 'L'
+               STRNEB  R3,[R1],#1              ;...and store it in buffer
+               BL      diss__cond              ;Put in the condition
+               MOV     R3,#52                  ;Tab to here
+               BL      diss__tab               ;Do the tab
+               BIC     R0,R8,#&FF000000        ;Get the offset
+               ADD     R0,R9,R0,LSL#2          ;Offset correctld
+               ADD     R0,R0,#8                ;Take pipeline into account
+               BIC     R0,R0,#&FC000000        ;Make sure its not silly
+               BL      diss__address           ;Print the address
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+; --- diss__coDataOp ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;
+; On exit:     Lots corrupted
+;
+; Use:         Disassembles co-processor data operations
+
+
+diss__coDataOp ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link
+               LDR     R14,diss__cdp           ;Load the mnemonic
+               STR     R14,[R1],#3             ;Store the opcode in buffer
+               BL      diss__cond              ;Put the condition code in
+
+10             MOV     R3,#52                  ;Set up the tab position
+               BL      diss__tab               ;And do the tab
+               MOV     R3,#'C'                 ;Get the 'C'
+               STRB    R3,[R1],#1              ;And store it in buffer
+               MOV     R3,#'P'                 ;Get the 'P'
+               STRB    R3,[R1],#1              ;And store it in buffer
+               MOV     R0,R8,LSR#8             ;Get cp#
+               AND     R0,R0,#&F               ;Clear unwanted bits
+               MOV     R2,#50                  ;Say that buffer is big
+               SWI     OS_ConvertInteger1      ;Translate the number
+               MOV     R4,#','                 ;Get the ','
+               STRB    R4,[R1],#1              ;And store it in buffer
+               MOV     R0,R8,LSR#20            ;Get cp instruction
+               AND     R0,R0,#&F               ;Clear unwanted bits
+               MOV     R2,#50                  ;Say that buffer is big
+               SWI     OS_ConvertInteger1      ;Translate the number
+               STRB    R4,[R1],#1              ;Store comma in buffer
+               MOV     R3,R8,LSR#12            ;Get destination register
+               BL      diss__coReg             ;Display the register
+               STRB    R4,[R1],#1              ;Store comma in buffer
+               MOV     R3,R8,LSR#16            ;Get CRn
+               BL      diss__coReg             ;Display it
+               STRB    R4,[R1],#1              ;Store comma in buffer
+               MOV     R3,R8                   ;Get CRm
+               BL      diss__coReg             ;Display it
+               MOV     R0,R8,LSR#5             ;Get optional constant
+               ANDS    R0,R0,#&7               ;Clear unwanted bits
+               STRNEB  R4,[R1],#1              ;Store comma in buffer
+               MOVNE   R2,#50                  ;...say that buffer is big
+               SWINE   OS_ConvertInteger1      ;...translate the number
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+diss__cdp      DCB     "CDP",0
+
+               LTORG
+
+; --- diss__coDataTran ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;
+; On exit:     Lots corrupted
+;
+; Use:         Disassembles co-processor data transfers
+
+
+diss__coDataTran ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link
+               TST     R8,#(1<<20)             ;Is it a load?
+               LDRNE   R14,diss__ldc           ;Yes -- load that name
+               LDREQ   R14,diss__stc           ;No -- load STC word then
+               STR     R14,[R1],#3             ;Store the opcode in buffer
+               BL      diss__cond              ;Put the condition code in
+               TST     R8,#(1<<22)             ;Is it long transfer?
+               MOVNE   R3,#'L'                 ;Yes -- get the 'L'
+               STRNEB  R3,[R1],#1              ;...and store it in buffer
+
+       [ 1<>1                  ;T on co-processor trandfers
+               TST     R8,#(1<<21)             ;Is the W bit set?
+               BEQ     %10diss__coDataTran     ;No -- jump ahead a bit
+               TST     R8,#(1<<24)             ;How about the P bit?
+               MOVEQ   R3,#'T'                 ;No -- get a 'T' character
+               STREQB  R3,[R1],#1              ;...and store it in buffer
+       ]
+
+10             MOV     R3,#52                  ;Set up the tab position
+               BL      diss__tab               ;And do the tab
+               MOV     R3,#'C'                 ;Get the 'C'
+               STRB    R3,[R1],#1              ;And store it in buffer
+               MOV     R3,#'P'                 ;Get the 'P'
+               STRB    R3,[R1],#1              ;And store it in buffer
+               MOV     R0,R8,LSR#8             ;Get cp#
+               AND     R0,R0,#&F               ;Clear unwanted bits
+               MOV     R2,#50                  ;Say that buffer is big
+               SWI     OS_ConvertInteger1      ;Translate the number
+               MOV     R3,#','                 ;Get the ','
+               STRB    R3,[R1],#1              ;And store it in buffer
+               MOV     R3,#'C'                 ;Get the 'C'
+               STRB    R3,[R1],#1              ;And store that in the buffer
+               MOV     R0,R8,LSR#12            ;Get cp#
+               AND     R0,R0,#&F               ;Clear unwanted bits
+               MOV     R2,#50                  ;Say that buffer is big
+               SWI     OS_ConvertInteger1      ;Translate the number
+               MOV     R3,#','                 ;Get the ','
+               STRB    R3,[R1],#1              ;And store it in buffer
+
+               ; --- Sabotage into and LDR/STR form ---
+
+               BIC     R0,R8,#&000000FF        ;Clear bottom bits
+               BIC     R0,R0,#&00000F00        ;Those ones too
+               AND     R2,R8,#&FF              ;Get the offset
+               MOV     R2,R2,LSL#2             ;Shift it up properley
+               ORR     R0,R0,R2                ;Merge the two words
+               MOV     R8,R0                   ;Put new instruction in R8
+               TST     R8,#(1<<24)             ;Are we pre-indexing?
+               BNE     diss__preIndexed        ;Yes -- deal with it
+               BEQ     diss__postIndexed       ;No -- do a post index
+
+diss__ldc      DCB     "LDC",0
+diss__stc      DCB     "STC",0
+
+               LTORG
+
+; --- diss__coRegTran ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;
+; On exit:     Lots corrupted
+;
+; Use:         Disassembles co-processor register transfers
+
+
+diss__coRegTran ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link
+               TST     R8,#(1<<20)             ;Is it a co->arc
+               LDRNE   R14,diss__mcr           ;Yes -- load that name
+               LDREQ   R14,diss__mrc           ;No -- load MRC word then
+               STR     R14,[R1],#3             ;Store the opcode in buffer
+               BL      diss__cond              ;Put the condition code in
+
+10             MOV     R3,#52                  ;Set up the tab position
+               BL      diss__tab               ;And do the tab
+               MOV     R3,#'C'                 ;Get the 'C'
+               STRB    R3,[R1],#1              ;And store it in buffer
+               MOV     R3,#'P'                 ;Get the 'P'
+               STRB    R3,[R1],#1              ;And store it in buffer
+               MOV     R0,R8,LSR#8             ;Get cp#
+               AND     R0,R0,#&F               ;Clear unwanted bits
+               MOV     R2,#50                  ;Say that buffer is big
+               SWI     OS_ConvertInteger1      ;Translate the number
+               MOV     R4,#','                 ;Get the ','
+               STRB    R4,[R1],#1              ;And store it in buffer
+               MOV     R0,R8,LSR#21            ;Get cp instruction
+               AND     R0,R0,#&7               ;Clear unwanted bits
+               MOV     R2,#50                  ;Say that buffer is big
+               SWI     OS_ConvertInteger1      ;Translate the number
+               STRB    R4,[R1],#1              ;Store comma in buffer
+               MOV     R3,R8,LSR#12            ;Get arc register
+               BL      diss__reg               ;Display the register
+               STRB    R4,[R1],#1              ;Store comma in buffer
+               MOV     R3,R8,LSR#16            ;Get CRn
+               BL      diss__coReg             ;Display it
+               STRB    R4,[R1],#1              ;Store comma in buffer
+               MOV     R3,R8                   ;Get CRm
+               BL      diss__coReg             ;Display it
+               MOV     R0,R8,LSR#5             ;Get optional constant
+               ANDS    R0,R0,#&7               ;Clear unwanted bits
+               STRNEB  R4,[R1],#1              ;Store comma in buffer
+               MOVNE   R2,#50                  ;...say that buffer is big
+               SWINE   OS_ConvertInteger1      ;...translate the number
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+diss__mcr      DCB     "MCR",0
+diss__mrc      DCB     "MRC",0
+
+               LTORG
+
+; --- diss__swi ---
+;
+; On entry:    R1 == pointer to buffer to disassemble into
+;              R7 == pointer to the start of the buffer
+;              R8 == the instruction
+;              R9 == location in memory from which instruction came
+;
+; On exit:     Lots corrupted
+;
+; Use:         Disassembles swi instructions
+
+
+diss__swi      ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link
+               LDR     R0,diss__swiCode        ;Load the opcode
+               STR     R0,[R1],#3              ;Store it in the buffer
+               BL      diss__cond              ;Put in the condition
+               MOV     R3,#52                  ;Set up the tab position
+               BL      diss__tab               ;Do the tabbing
+               MOV     R4,R1                   ;Look after the buffer pos
+               BL      str_buffer              ;Get a buffer to use
+               MOV     R6,R1                   ;Don't lose this either!
+               BIC     R0,R8,#&FF000000        ;Get the swi number
+               MOV     R5,R0                   ;Look after this too
+               MOV     R2,#256                 ;The buffer size
+               SWI     XOS_SWINumberToString   ;Get the SWI name
+
+               ; --- Now try to convert back again ---
+
+               BIC     R2,R5,#(1<<17)          ;Clear the X bit
+               SUB     R2,R2,#&100             ;Do a range check between
+               SUBS    R2,R2,#&200             ;...if its OS_WriteI
+               BLO     %10diss__swi            ;It is -- return
+
+               SWI     XOS_SWINumberFromString ;Convert back again
+               BVC     %10diss__swi            ;All OK, jump ahead
+               MOV     R1,R6                   ;...point to the number
+               MOV     R2,#'&'                 ;Get the '&' character
+               STRB    R2,[R1],#1              ;Store it in the buffer
+               MOV     R0,R5                   ;Put number in R0
+               MOV     R2,#50                  ;Say buffer is big
+               SWI     XOS_ConvertHex8         ;And convert the number
+               MOV     R1,R6                   ;Point to the number
+
+               ; --- Now put the string in the buffer ---
+
+10diss__swi    MOV     R0,R4                   ;Write to here
+               BL      str_cpy                 ;Copy the string over
+               MOV     R1,R0                   ;Make R1 point to buffer end
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+diss__swiCode  DCB     "SWI",0
+
+               LTORG
+
+; --- diss__cond ---
+;
+; On entry:    R1 == position in buffer to put string
+;              R8 == the instruction
+;
+; On exit:     --
+;
+; Use:         Inserts the condition code into the buffer
+
+diss__cond     ROUT
+
+               MOV     R3,R8,LSR#28            ;Get the condition code
+               ADR     R4,diss__condTable      ;Point to the table
+               ADD     R4,R4,R3,LSL#2          ;Point to the string
+               LDRB    R2,[R4],#1              ;Get a byte
+               CMP     R2,#0                   ;Am I there yet
+               STRNEB  R2,[R1],#1              ;Store the byte
+               LDRNEB  R2,[R4],#1              ;Get a byte
+               CMPNE   R2,#0                   ;Am I there yet
+               STRNEB  R2,[R1],#1              ;Store the byte
+               MOVS    PC,R14                  ;Return to caller
+
+diss__condTable        DCB     "EQ",0,0
+               DCB     "NE",0,0
+               DCB     "CS",0,0
+               DCB     "CC",0,0
+               DCB     "MI",0,0
+               DCB     "PL",0,0
+               DCB     "VS",0,0
+               DCB     "VC",0,0
+               DCB     "HI",0,0
+               DCB     "LS",0,0
+               DCB     "GE",0,0
+               DCB     "LT",0,0
+               DCB     "GT",0,0
+               DCB     "LE",0,0
+               DCB     0,0,0,0
+               DCB     "NV",0,0
+
+; --- diss__tab ---
+;
+; On entry:    R1 == Current position within buffer
+;              R3 == tab position required
+;              R7 == start of the buffer
+;
+; On exit:     R1 updated appropriately
+;
+; Use:         Inserts as many spaces as in nessesary to get to the
+;              right position in the buffer.
+
+diss__tab      ROUT
+
+               ADD     R4,R7,R3                ;Word out the offset
+               MOV     R2,#' '                 ;Get a space character
+00diss__tab    STRB    R2,[R1],#1              ;Store the sapce character
+               CMP     R1,R4                   ;Have we finished yet?
+               BLT     %00diss__tab            ;No -- keep looping
+               MOVS    PC,R14                  ;Return
+
+               LTORG
+
+; --- diss__reg ---
+;
+; On entry:    R1 == position in buffer to write register name
+;              R3 == register number to write (in bottom 4 bits)
+;
+; On exit:     R1 updated
+;
+; Use:         Writes a register name to the output buffer
+
+diss__reg      ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+               ADR     R14,ws__names           ;Find the register names
+               AND     R3,R3,#15               ;Hack off unwanted bits
+               MOV     R0,R1                   ;Point to the output buffer
+               LDR     R1,[R14,R3,LSL #2]      ;Find the name I want
+               BL      str_cpy                 ;Copy the string out
+               MOV     R1,R0                   ;Point to string terminator
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- diss__coReg ---
+;
+; On entry:    R1 == position in buffer to write register name
+;              R3 == register number to write (in bottom 4 bits)
+;
+; On exit:     R1 updated
+;
+; Use:         Writes a co-processor register name to the output buffer
+
+diss__coReg    ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+               AND     R0,R3,#15               ;Hack off unwanted bits
+               MOV     R14,#'C'                ;Get the prefix
+               STRB    R14,[R1],#1             ;Store it
+               MOV     R2,#50                  ;Say buffer is big
+               SWI     OS_ConvertInteger1      ;Write number into buffer
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- diss__address ---
+;
+; On entry:    R0 == an address to display
+;              R1 == pointer to where to store it
+;
+; On exit:     R1 updated
+;
+; Use:         Displays an address, looking it up in the symbol table
+;              and trying to turn it into a label if possible.
+;
+;              (26-Aug-1994 Symbol table not implemented)
+
+diss__address  ROUT
+
+               STMFD   R13!,{R14}              ;Stash the link away
+               MOV     R14,#'&'                ;The address is in hex
+               STRB    R14,[R1],#1             ;Store it in the buffer
+               MOV     R2,#50                  ;Please fondle my buffer (?)
+               SWI     XOS_ConvertHex8         ;Convert to nice address
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- diss_regTable ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to register table
+;
+; Use:         Returns a pointer to the register name table, so that the
+;              assembler can get its grubby paws on it.
+
+               EXPORT  diss_regTable
+diss_regTable  ROUT
+
+               LDR     R0,diss__wSpace         ;Find the workspace address
+               ADD     R0,R0,#:INDEX: ws__names
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- diss_init ---
+;
+; On entry:    R12 == pointer to workspace
+;
+; On exit:     --
+;
+; Use:         Initialises the disassembler segment nicely.
+
+               EXPORT  diss_init
+diss_init      ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack what we need
+
+               ; --- If we are already initialised, return ---
+
+               LDR     R0,ws__flags            ;Load my flags word
+               TST     R0,#wFlag__inited       ;Are we initialised?
+               BNE     %99diss_init            ;Yes -- return
+
+               ORR     R0,R0,#wFlag__inited    ;We are initialised now
+               STR     R0,ws__flags            ;Store this fact
+
+               ; --- Set up the default options ---
+
+               MOV     R0,#0                   ;The default options
+               STR     R0,ws__options          ;Store them here
+
+               ; --- Set up the default register names ---
+
+               BL      quartz_base             ;Find the module base
+               ADR     R1,ws__names            ;Point to the name table
+               ADR     R2,diss__defNames       ;Point to default name table
+               MOV     R3,#16                  ;Copy over this many
+
+10diss_init    LDR     R14,[R2],#4             ;Get a name pointer
+               ADD     R14,R14,R0              ;Relocate the name pointer
+               STR     R14,[R1],#4             ;Copy it over
+               SUBS    R3,R3,#1                ;Decrement the counter
+               BNE     %10diss_init            ;More to go -- do them
+
+99diss_init    LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+diss__wSpace   DCD     0
+
+diss__defNames DCD     dName__R0,dName__R1,dName__R2,dName__R3
+               DCD     dName__R4,dName__R5,dName__R6,dName__R7
+               DCD     dName__R8,dName__R9,dName__R10,dName__R11
+               DCD     dName__R12,dName__R13,dName__R14,dName__R15
+
+dName__R0      DCB     "R0",0
+dName__R1      DCB     "R1",0
+dName__R2      DCB     "R2",0
+dName__R3      DCB     "R3",0
+dName__R4      DCB     "R4",0
+dName__R5      DCB     "R5",0
+dName__R6      DCB     "R6",0
+dName__R7      DCB     "R7",0
+dName__R8      DCB     "R8",0
+dName__R9      DCB     "R9",0
+dName__R10     DCB     "R10",0
+dName__R11     DCB     "R11",0
+dName__R12     DCB     "R12",0
+dName__R13     DCB     "R13",0
+dName__R14     DCB     "R14",0
+dName__R15     DCB     "PC",0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+
+ws__start      #       0
+
+ws__flags      #       4                       ;The main flags word
+ws__options    #       4                       ;Disassembler options
+ws__commentEnd #       4                       ;End of the current comment
+ws__lastReg    #       1                       ;Register in ADR / LDR
+ws__lastCond   #       3                       ;Last condition code thing
+ws__lastAddr   #       4                       ;Address from ADR / LDR
+ws__nextAddr   #       4                       ;Address of next instruction
+ws__names      #       16*4                    ;Table of register names
+ws__buffer     #       256                     ;Somewhere to put the string
+ws__comment    #       80                      ;Somewhere to put comments
+
+ws__size       EQU     {VAR}-ws__start         ;The workspace size
+
+wFlag__inited  EQU     (1<<0)                  ;We are initialised
+wFlag__wasAdr  EQU     (1<<1)                  ;Last instruction was ADR
+wFlag__newAdr  EQU     (1<<2)                  ;This instruction is ADR
+
+dOpt__bitHex   EQU     (1<<0)                  ;Display bitwise in hex
+dOpt__arthHex  EQU     (1<<1)                  ;Display arithmetic in hex
+dOpt__tranHex  EQU     (1<<2)                  ;Display data transfer in hex
+dOpt__r13Stack EQU     (1<<3)                  ;Use FD etc. if R13 is base
+
+               AREA    |Quartz$$Table|,CODE,READONLY
+
+               DCD     ws__size
+               DCD     diss__wSpace
+               DCD     diss_init
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/s/driver b/StraySrc/Hammer/s/driver
new file mode 100644 (file)
index 0000000..66badf4
--- /dev/null
@@ -0,0 +1,582 @@
+;
+; driver.s
+;
+; The text-only interface to Sledgehammer (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     quartz:string
+
+               GET     sh.brkpt
+               GET     sh.armEmul
+               GET     sh.asm
+               GET     sh.diss
+               GET     sh.hammer
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Hammer$$Code|,CODE,READONLY
+
+; --- driver ---
+;
+; On entry:    R0 == pointer to a register block
+;
+; On exit:     Doesn't
+;
+; Use:         Text only interactive debugger interface
+
+               EXPORT driver
+driver         ROUT
+
+               BL      hammer_getStack         ;Get our own pretty stack
+               MOV     R3,R0                   ;Preserve block pointer
+               MOV     R10,R13                 ;Remember stack base address
+               MOV     R14,PC                  ;Get PC with flags
+               TST     R14,#3                  ;Are we in user mode?
+               LDRNE   R13,[R3,#13*4]          ;No -- use his stack pointer
+
+driver__next   LDR     R0,[R3,#15*4]           ;Get the 'PC'
+               BIC     R0,R0,#&FC000003        ;Clear flags
+               BL      diss_address            ;Set this as the diss address
+               BL      brkpt_translate         ;Translate the address
+               LDR     R0,[R0,#0]              ;Load the instruction
+               BL      diss_disassemble        ;Disassemble the instruction
+               SWI     XOS_NewLine             ;Print a newline
+               SWI     XOS_Write0              ;Print it out nicely
+               SWI     XOS_NewLine             ;Print a newline
+
+10driver       SWI     XOS_WriteS              ;Print out the following
+               DCB     10,"Sledgehammer [stwx rad bke nzcv *oh]",0
+
+               MOV     R0,#229                 ;Set escape action
+               MOV     R1,#1                   ;Just generate key code
+               MOV     R2,#0                   ;Set the state
+               SWI     XOS_Byte                ;Do it
+
+15driver       SWI     XOS_ReadC               ;Read a character
+               CMP     R0,#27                  ;Was it escape?
+               MOVEQ   R0,#'t'                 ;Yes -- make it continue
+               CMP     R0,#32                  ;How about space
+               MOVEQ   R0,#'s'                 ;Yeap -- make it step
+               ORR     R0,R0,#&20              ;Make it lower case
+               ADR     R2,driver__table        ;Point to the table
+20driver       LDR     R4,[R2],#8              ;Load the byte
+               CMP     R4,#0                   ;Was there one?
+               BEQ     %15driver               ;Nope -- keep trying
+               CMP     R4,R0                   ;Was this what he typed?
+               BNE     %20driver               ;No -- keep on trying
+               SWI     XOS_WriteI+32           ;Print a space
+               SWI     XOS_WriteC              ;Print out the character
+               SWI     XOS_NewLine             ;Let's be pretty about this
+               SWI     XOS_NewLine
+               SUB     PC,R2,#4                ;Do the instruction
+
+driver__table  DCD     's'
+               B       driver__step
+               DCD     't'
+               B       driver__cont
+               DCD     'w'
+               B       driver__soft
+               DCD     'x'
+               SWI     OS_BreakPt
+               DCD     'r'
+               B       driver__regDump
+               DCD     'a'
+               B       driver__next;driver__alter
+               DCD     'd'
+               B       driver__diss
+               DCD     'b'
+               B       driver__break
+               DCD     'k'
+               B       driver__killBrk
+               DCD     'e'
+               B       driver__killAll
+               DCD     'n'
+               B       driver__toggleN
+               DCD     'z'
+               B       driver__toggleZ
+               DCD     'c'
+               B       driver__toggleC
+               DCD     'v'
+               B       driver__toggleV
+               DCD     '*'
+               B       driver__oscli
+               DCD     'o'
+               B       driver__next;driver__options
+               DCD     'h'
+               B       driver__help
+               DCD     0
+
+               ; --- Single Step ---
+
+driver__step   MOV     R0,#229                 ;Set escape action
+               MOV     R2,#0                   ;Set the state to what it was
+               SWI     XOS_Byte                ;Do it
+
+               MOV     R13,R10                 ;Use our private stack
+               MOV     R0,R3                   ;Point to register block
+               BL      armEmul                 ;Emulate an instruction
+               MOV     R14,PC                  ;Get PC with flags
+               TST     R14,#3                  ;Are we in user mode?
+               LDRNE   R13,[R3,#13*4]          ;No -- use his stack pointer
+               B       driver__next            ;Do the next one
+
+               ; --- Continue ---
+
+driver__cont   MOV     R0,#229                 ;Set escape action
+               MOV     R2,#0                   ;Set the state to what it was
+               SWI     XOS_Byte                ;Do it
+
+               LDR     R0,[R3,#15*4]           ;Get the current PC
+               BIC     R0,R0,#&FC000003        ;Get rid of flags
+               BL      brkpt_exist             ;Is there a breakpoint here?
+               LDMCCIA R3,{R0-PC}^             ;No -- continue his execution
+
+               MOV     R13,R10                 ;Use our private stack
+               MOV     R0,R3                   ;Point to register block
+               BL      armEmul                 ;Emulate an instruction
+               LDMIA   R3,{R0-PC}^             ;Continue pleasently
+
+               ; --- Soft emulation ---
+
+driver__soft   ROUT
+
+               MOV     R0,#229                 ;Set escape action
+               MOV     R2,#0                   ;Set the state to what it was
+               SWI     XOS_Byte                ;Do it
+
+               MOV     R13,R10                 ;Yes -- Use our private stack
+00driver__soft MOV     R0,R3                   ;...point to register block
+               BL      armEmul                 ;...emulate an instruction
+               LDR     R0,[R3,#15*4]           ;Get the current PC
+               BIC     R0,R0,#&FC000003        ;Get rid of flags
+               BL      brkpt_exist             ;Is there a breakpoint here?
+               BCC     %00driver__soft         ;No -- keep looping
+               MOV     R14,PC                  ;Get PC with flags
+               TST     R14,#3                  ;Are we in user mode?
+               LDRNE   R13,[R3,#13*4]          ;No -- use his stack pointer
+               B       driver__next            ;And tell user about it
+
+               LTORG
+
+               ; --- Help display ---
+
+driver__help   ADR     R0,driver__helpText     ;Point to my help text
+               SWI     XOS_PrettyPrint         ;Display it on the screen
+               B       driver__next            ;Rejoin the main loop
+
+driver__helpText
+               DCB     "Commands available:",13
+               DCB     13
+               DCB     "[S]ingle step (also SPACE)",13
+               DCB     "con[T]inue (also ESCAPE)",13
+               DCB     "[W]hisper mode",13
+               DCB     "e[X]it application",13
+               DCB     "[R]egister list",13
+               DCB     "[A]lter register value",13
+               DCB     "[D]isassemble around current PC",13
+               DCB     "[B]reakpoint set",13
+               DCB     "[K]ill breakpoint",13
+               DCB     "toggle [N,Z,C,V] flag",13
+               DCB     "[E]xterminate all breakpoints",13
+               DCB     "[*] commands",13
+               DCB     "[O]ptions",13
+               DCB     "[H]elp",13
+               DCB     0
+
+               ; --- Set a breakpoint ---
+
+driver__break  BL      driver__readAddr        ;Read the address he typed
+               BVS     driver__error           ;If he spasmed, return
+               BLCS    brkpt_set               ;Try to set the breakpoint
+               BVS     driver__error           ;If he spasmed, return
+               B       driver__next            ;And rejoin the main loop
+
+               ; --- Remove a breakpoint ---
+
+driver__killBrk        BL      driver__readAddr        ;Read the address he typed
+               BVS     driver__error           ;If he spasmed, return
+               BLCS    brkpt_remove            ;Try to set the breakpoint
+               BVS     driver__error           ;If he spasmed, return
+               B       driver__next            ;And rejoin the main loop
+
+               ; --- Remove all breakpoints ---
+
+driver__killAll        ADR     R0,driver__kaMsg        ;Point to message string
+               BL      hammer_confirm          ;Get confirmation on this
+               BLCS    brkpt_remAll            ;If OK, remove all of them
+               B       driver__next            ;And rejoin the main loop
+
+driver__kaMsg  DCB     "Remove all breakpoints?",0
+
+driver__error  ADD     R0,R0,#4                ;Point to the error
+               SWI     XOS_Write0              ;Display the message
+               SWI     XOS_NewLine             ;Move to new line
+               B       driver__next            ;And rejoin the main loop
+
+               ; --- * commands ---
+
+driver__oscli  ROUT
+
+               STMFD   R13!,{R0-R5}            ;Save some registers
+               BL      str_buffer              ;Get me a nice buffer
+               MOV     R5,R1                   ;Look after the buffer
+
+00driver__oscli        SWI     XOS_WriteS              ;Write a prompt string
+               DCB     "Sledgehammer *",0
+               MOV     R0,R5                   ;Point to it nicely
+               MOV     R1,#256                 ;Give the buffer size
+               MOV     R2,#32                  ;Allow all printable chars
+               MOV     R3,#255
+               SWI     XOS_ReadLine            ;Read a command line
+               BVS     %10driver__oscli        ;Failed -- report error
+               LDRB    R1,[R5,#0]              ;Load the first character
+               CMP     R1,#13                  ;Is the string empty?
+               BEQ     %20driver__oscli        ;Yes -- return then
+               MOV     R0,R5                   ;Point to the buffer
+               SWI     XOS_CLI                 ;Do the command nicely
+               BVS     %10driver__oscli        ;Failed -- report error
+               B       %00driver__oscli        ;Go round for some more
+
+10driver__oscli        ADD     R0,R0,#4                ;Point to error message
+               SWI     XOS_Write0              ;Display it
+               B       %00driver__oscli        ;Go round for some more
+
+20driver__oscli        LDMFD   R13!,{R0-R5}            ;Unstack registers
+               B       driver__next            ;And rejoin the main loop
+
+               ; --- Toggle flags ---
+
+driver__toggleN        MOV     R4,#N_flag              ;Get the flag bit
+               MOV     R5,#'N'                 ;And the name
+               B       driver__toggle          ;Do the toggle op
+
+driver__toggleZ        MOV     R4,#Z_flag              ;Get the flag bit
+               MOV     R5,#'Z'                 ;And the name
+               B       driver__toggle          ;Do the toggle op
+
+driver__toggleC        MOV     R4,#C_flag              ;Get the flag bit
+               MOV     R5,#'C'                 ;And the name
+               B       driver__toggle          ;Do the toggle op
+
+driver__toggleV        MOV     R4,#V_flag              ;Get the flag bit
+               MOV     R5,#'V'                 ;And the name
+               B       driver__toggle          ;Do the toggle op
+
+driver__toggle LDR     R14,[R3,#15*4]          ;Load current flags
+               EOR     R14,R14,R4              ;Toggle the flag
+               STR     R14,[R3,#15*4]          ;Save them back again
+               TST     R14,R4                  ;Is it on or off now?
+               MOV     R0,R5                   ;Get the flag's name
+               SWI     XOS_WriteC              ;Display it
+               SWI     XOS_WriteS              ;Display some text
+               DCB     " flag now ",0
+               ADREQ   R0,driver__flagOff      ;Point to the right string
+               ADRNE   R0,driver__flagOn       ;Whichever one that is
+               SWI     XOS_Write0              ;And display it
+               SWI     XOS_NewLine             ;Follow with a newline
+               B       driver__next            ;And rejoin main loop
+
+driver__flagOff        DCB     "off.",0
+driver__flagOn DCB     "on.",0
+
+               ; --- Disassemble context ---
+
+driver__diss   ROUT
+
+               LDR     R4,[R3,#15*4]           ;Load current program count
+               BIC     R4,R4,#&FC000003        ;Clear PSR flags
+
+               BL      driver__readAddr        ;Get an address to display
+               BVS     driver__error           ;If he goofed, report error
+               MOVCC   R0,R4                   ;If none, use the PC
+
+               SUB     R5,R0,#40               ;Do 10 instrs each side
+               MOV     R6,#21                  ;That's 21 instructions total
+
+               MOV     R0,R5                   ;Get the disassembly base
+               BL      diss_address            ;Set disassembly up nicely
+
+00driver__diss MOV     R0,R5                   ;Get the disassembly address
+               BL      brkpt_exist             ;Is there a breakpoint there?
+               SWICS   XOS_WriteI+"*"          ;Yes -- put a splodge there
+               SWICC   XOS_WriteI+" "          ;Otherwise leave a gap
+               CMP     R0,R4                   ;Is this the current one?
+               SWIEQ   XOS_WriteI+">"          ;Yes -- mark it somehow
+               SWINE   XOS_WriteI+" "          ;Otherwise leave a space
+               SWI     XOS_WriteI+" "          ;Gap before disassembly
+
+               BL      brkpt_translate         ;Translate the address
+               LDR     R0,[R0,#0]              ;Load the instruction
+               BL      diss_disassemble        ;Disassemble it
+               SWI     XOS_Write0              ;Display the result
+               SWI     XOS_NewLine             ;And move down a line
+
+               SUBS    R6,R6,#1                ;Decrement the counter
+               ADDGE   R5,R5,#4                ;If more to go, bump address
+               BGE     %00driver__diss         ;And go round again
+
+               B       driver__next            ;Rejoin the main loop
+
+               LTORG
+
+               ; --- Register dump ---
+
+driver__regDump        ROUT
+
+               STMFD   R13!,{R0-R12}           ;Save some registers
+               MOV     R0,#229                 ;Set escape action
+               MOV     R2,#0                   ;Set the state to what it was
+               SWI     XOS_Byte                ;Do it
+
+               ; --- Start the main display loop ---
+
+               MOV     R12,R3                  ;Keep pointer to dump block
+               ADR     R11,driver__regNames    ;Point to register name tbl
+               MOV     R10,#0                  ;Which register we're on
+
+               ; --- Display a register ---
+
+00             ADD     R0,R11,R10,LSL #2       ;Point to the string
+               SWI     OS_Write0               ;Display register name
+               SWI     OS_WriteS               ;Display immediate string
+               DCB     " == &",0               ;A separater string
+               LDR     R0,[R12,R10,LSL #2]     ;Load the register value
+               BL      driver__writeHex        ;Display register value
+               SWI     OS_WriteS               ;Display more immediate
+               DCB     "   ",0                 ;Just some spaces
+               ADD     R10,R10,#1              ;Increment register count
+               TST     R10,#3                  ;Now a multiple of 4?
+               SWIEQ   OS_NewLine              ;Yes -- new line then
+               CMP     R10,#16                 ;Finished all registers?
+               BLT     %00driver__regDump      ;No -- do some more then
+
+               ; --- Now display R14 and R15 with PSR bits testually ---
+
+               SWI     OS_NewLine              ;Another newline
+               SWI     OS_WriteS               ;Display immediate stuff
+               DCB     "R14 == &",0
+               LDR     R9,[R12,#14*4]          ;Load the R14 value
+               BL      driver__psr             ;Display all the PSR bits
+               SWI     OS_NewLine              ;Another newline
+               SWI     OS_WriteS               ;Display immediate stuff
+               DCB     " PC == &",0
+               LDR     R9,[R12,#15*4]          ;Load the PC value
+               BL      driver__psr             ;Display all the PSR bits
+               SWI     OS_NewLine              ;Another newline
+               SWI     OS_NewLine              ;And one more for luck
+               LDMFD   R13!,{R0-R12}           ;Get register back
+               B       driver__next            ;Get the next command
+
+               LTORG
+
+driver__regNames
+               DCB     " R0",0
+               DCB     " R1",0
+               DCB     " R2",0
+               DCB     " R3",0
+               DCB     " R4",0
+               DCB     " R5",0
+               DCB     " R6",0
+               DCB     " R7",0
+               DCB     " R8",0
+               DCB     " R9",0
+               DCB     "R10",0
+               DCB     "R11",0
+               DCB     "R12",0
+               DCB     "R13",0
+               DCB     "R14",0
+               DCB     " PC",0
+
+; --- driver__psr ---
+;
+; On entry:    R9 == value to display
+;
+; On exit:     R0-R12 corrupted, maybe
+;
+; Use:         Displays R9 with PSR bits stripped away, and then with
+;              all the PSR bits described too.
+
+driver__psr    ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+               BIC     R0,R9,#&FC000003        ;Get the PC bits only
+               BL      driver__writeHex        ;Display them in hex
+
+               SWI     OS_WriteS               ;Some more spaces
+               DCB     ", flags == ",0
+               MOV     R0,#'N'                 ;First do the `N' flag
+               TST     R9,#N_flag              ;Is it set
+               ORREQ   R0,R0,#&20              ;No -- force to lower case
+               SWI     OS_WriteC               ;Display the character
+               MOV     R0,#'Z'                 ;First do the `N' flag
+               TST     R9,#Z_flag              ;Is it set
+               ORREQ   R0,R0,#&20              ;No -- force to lower case
+               SWI     OS_WriteC               ;Display the character
+               MOV     R0,#'C'                 ;First do the `N' flag
+               TST     R9,#C_flag              ;Is it set
+               ORREQ   R0,R0,#&20              ;No -- force to lower case
+               SWI     OS_WriteC               ;Display the character
+               MOV     R0,#'V'                 ;First do the `N' flag
+               TST     R9,#V_flag              ;Is it set
+               ORREQ   R0,R0,#&20              ;No -- force to lower case
+               SWI     OS_WriteC               ;Display the character
+
+               SWI     OS_WriteS               ;Yet more stuff
+               DCB     ", mode == ",0
+               ADR     R0,driver__modes        ;Point to the mode strings
+               AND     R14,R9,#3               ;Get the mode bits
+               ADD     R0,R0,R14,LSL #2        ;Point to the correct string
+               SWI     OS_Write0               ;Display the mode setting
+
+               TST     R9,#IRQ_disable         ;Is the IRQ bit on or off?
+               ADREQ   R0,driver__irqOn        ;If off, point to message
+               SWIEQ   OS_Write0               ;And display the string
+               TST     R9,#FIQ_disable         ;Is the FIQ bit on or off?
+               ADREQ   R0,driver__fiqOn        ;If off, point to message
+               SWIEQ   OS_Write0               ;And display the string
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+driver__modes  DCB     "USR",0
+               DCB     "FIQ",0
+               DCB     "IRQ",0
+               DCB     "SVC",0
+
+driver__irqOn  DCB     ", IRQ",0
+driver__fiqOn  DCB     ", FIQ",0
+
+driver__writeHex ROUT
+
+               STMFD   R13!,{R0-R2,R14}
+               SUB     R13,R13,#16
+               MOV     R1,R13
+               MOV     R2,#16
+               SWI     OS_ConvertHex8
+               SWI     OS_Write0
+               ADD     R13,R13,#16
+               LDMFD   R13!,{R0-R2,PC}^
+
+               LTORG
+
+; --- driver__readAddr ---
+;
+; On entry:    --
+;
+; On exit:     Error, or CC for no entry, or R0 == address
+;
+; Use:         Interprets an address as typed by the user.
+
+driver__readAddr ROUT
+
+               BIC     R14,R14,#V_flag         ;Assume all is well
+               STMFD   R13!,{R1-R5,R8,R14}     ;Save some registers
+               SWI     XOS_WriteS              ;Display the prompt
+               DCB     "([<reg>] [+|- <offset>]) | <address> :",0
+               SUB     R13,R13,#20             ;Make a small buffer
+               MOV     R5,R3                   ;Look after register block
+               MOV     R0,R13                  ;Point to my buffer
+               MOV     R1,#20                  ;Give it the buffer size
+               MOV     R2,#32                  ;Minimum value to allow
+               MOV     R3,#255                 ;Allow all printable chars
+               SWI     XOS_ReadLine            ;Read the line then
+               BVS     %90driver__readAddr     ;If he messed up, report err
+               MOV     R3,R5                   ;Restore register block ptr
+
+               MOV     R8,R13                  ;Point to the string
+               MOV     R5,#0                   ;Initial address offset
+               MOV     R4,#0                   ;Clear some flags
+               BL      asm_register            ;Try to read a register name
+               LDRVC   R5,[R3,R0,LSL #2]       ;If OK get register value
+               BICVC   R5,R5,#&FC000003        ;And clear possible PSR flags
+               ORRVC   R4,R4,#3                ;We have reg/We read sthing
+
+00             LDRB    R14,[R8],#1             ;Load a byte from the string
+               CMP     R14,#' '                ;Is it a space
+               BEQ     %00driver__readAddr     ;Yes -- go for another
+
+               CMP     R14,#32                 ;Is this the string end?
+               BLO     %10driver__readAddr     ;Yes -- weird things happened
+               CMP     R14,#'-'                ;Is it a '-'?
+               ORREQ   R4,R4,#4                ;Yes -- subtract offset then
+               CMPNE   R14,#'+'                ;Or a '+'?
+               ORREQ   R4,R4,#1                ;This is something typed
+               BNE     %05driver__readAddr     ;No -- skip
+
+               TST     R4,#2                   ;Do we have a base reg?
+               LDREQ   R5,[R3,#15*4]           ;No -- use the PC then
+               BICEQ   R5,R5,#&FC000003        ;And clear possible PSR flags
+
+               MOV     R1,R8                   ;Point to the string
+               MOV     R0,#10                  ;Expect a decimal number
+               SWI     XOS_ReadUnsigned        ;Try to understand the value
+               BVS     %90driver__readAddr     ;If failed, report error
+               TST     R4,#4                   ;Was it a subtract?
+               SUBNE   R5,R5,R2                ;Yes -- subtract offset
+               ADDEQ   R5,R5,R2                ;Otherwise add it
+               B       %10driver__readAddr     ;And branch ahead
+
+05             TST     R4,#2                   ;Was there a register?
+               BNE     %10driver__readAddr     ;Yes -- almost done then
+
+               SUB     R1,R8,#1                ;Point to the string
+               MOV     R0,#16                  ;Expect a hex number
+               SWI     XOS_ReadUnsigned        ;Try to understand the value
+               BVS     %90driver__readAddr     ;If failed, report error
+               MOV     R5,R2                   ;Get the address he typed
+               ORR     R4,R4,#1                ;He typed something
+
+10             TST     R4,#1                   ;Was there anything at all?
+               BEQ     %80driver__readAddr     ;No -- return C clear then
+
+               BIC     R0,R5,#3                ;Truncate to word boundary
+               ADD     R13,R13,#20             ;Restore the stack
+               LDMFD   R13!,{R1-R5,R8,R14}     ;Unstack registers
+               ORRS    PC,R14,#C_flag          ;And return with C proudly on
+
+               ; --- Lazy user typed nothing ---
+
+80             ADD     R13,R13,#20             ;Restore the stack
+               LDMFD   R13!,{R1-R5,R8,R14}     ;Unstack registers
+               BICS    PC,R14,#C_flag          ;And return with C sadly off
+
+               ; --- Stupid user caused an error ---
+
+90             ADD     R13,R13,#20             ;Restore the stack
+               LDMFD   R13!,{R1-R5,R8,R14}     ;Unstack registers
+               ORRS    PC,R14,#V_flag          ;So set V on exit
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/s/hammer b/StraySrc/Hammer/s/hammer
new file mode 100644 (file)
index 0000000..4ec3c1f
--- /dev/null
@@ -0,0 +1,188 @@
+;
+; hammer.s
+;
+; Main definitions for Sledgehammer (TMA & MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     quartz:quartz
+
+               GET     sh.armEmul
+               GET     sh.asm
+               GET     sh.diss
+               GET     sh.brkpt
+               IMPORT  ae_addr
+
+;----- Module information ---------------------------------------------------
+
+               AREA    |Hammer$$Code|,CODE,READONLY
+
+               EXPORT  quartz_name
+quartz_name    DCB     "Sledgehammer",0
+
+;----- SWI information ------------------------------------------------------
+
+               EXPORT  quartz_swiChunk
+quartz_swiChunk        EQU     &4A380
+
+               EXPORT  quartz_swiNames
+quartz_swiNames        DCB     "Sledgehammer",0
+
+               DCB     "SetDissOptions",0      ;Sledgehammer_0
+               DCB     "DissAddress",0         ;Sledgehammer_1
+               DCB     "Disassemble",0         ;Sledgehammer_2
+               DCB     "Assemble",0            ;Sledgehammer_3
+               DCB     "Step",0                ;Sledgehammer_4
+               DCB     "StepAddr",0            ;Sledgehammer_5
+               DCB     "SetBP",0               ;Sledgehammer_6
+               DCB     "RemoveBP",0            ;Sledgehammer_7
+               DCB     "Translate",0           ;Sledgehammer_8
+               DCB     "BreakPoint",0          ;Sledgehammer_9
+               DCB     0
+
+               EXPORT  quartz_swiCode
+quartz_swiCode ROUT
+
+               CMP     R11,#(%10-%00)/4        ;Is the SWI in range?
+               ADDCC   PC,PC,R11,LSL #2        ;Yes -- dispatch it then
+               B       %10quartz_swiCode       ;Return an error if not
+
+               ; --- SWI dispatch table ---
+
+00             B       diss_setOptions         ;Sledgehammer_SetDissOptions
+               B       diss_address            ;Sledgehammer_DissAddress
+               B       diss_disassemble        ;Sledgehammer_Disassemble
+               B       asm_assemble            ;Sledgehammer_Assemble
+               B       armEmul                 ;Sledgehammer_Step
+               B       ae_addr                 ;Sledgehammer_StepAddr
+               B       brkpt_set               ;Sledgehammer_BreakSet
+               B       brkpt_remove            ;Sledgehammer_Remove
+               B       brkpt_translate         ;Sledgehammer_Translate
+               B       brkpt_hardBreak         ;Sledgehammer_BreakPoint
+
+               ; --- Unknown SWI found ---
+
+10             ADR     R0,hammer__badSwi       ;Point at the error block
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+hammer__badSwi DCD     &1E6
+               DCB     "Unknown Sledgehammer operation",0
+
+               LTORG
+
+;---- Some standard routines ------------------------------------------------
+
+; --- hammer_confirm ---
+;
+; On entry:    R0 == pointer to confirmation message
+;
+; On exit:     C set to proceed with whatever it was you wanted to confirm
+;
+; Use:         Displays a message with a confirmation prompt and waits
+;              for a response from the user.
+
+               EXPORT  hammer_confirm
+hammer_confirm ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               SWI     XOS_Write0              ;Display caller's message
+               SWI     XOS_WriteS              ;And now display the prompt
+               DCB     " [yn]",0
+
+               MOV     R0,#229                 ;Set escape action
+               MOV     R1,#1                   ;Just generate key code
+               MOV     R2,#0                   ;Set the state
+               SWI     XOS_Byte                ;Do it
+
+00             SWI     XOS_ReadC               ;Read a byte from the user
+               CMP     R0,#13                  ;Is it return?
+               CMPNE   R0,#32                  ;Or a space
+               MOVEQ   R0,#'y'                 ;Yes -- take that as a yes
+               CMP     R0,#27                  ;Was it escape?
+               MOVEQ   R0,#'n'                 ;Yes -- guess that's a no
+               ORR     R0,R0,#&20              ;Make it lower case
+               CMP     R0,#'y'                 ;Is it a yes?
+               CMPNE   R0,#'n'                 ;Or a no, that'll do too
+               BNE     %00hammer_confirm       ;Neither -- try again then
+
+               SWI     XOS_WriteI+' '          ;Put a space in nicely
+               SWI     XOS_WriteC              ;Display the response
+               SWI     OS_NewLine              ;And move to the next line
+               CMP     R0,#'y'                 ;Was it a yes again?
+
+               MOV     R0,#229                 ;Set escape action
+               MOV     R2,#0                   ;Set the state
+               SWI     XOS_Byte                ;Restore the old action
+
+               LDMFD   R13!,{R0-R2,R14}        ;Restore the registers
+               ORREQS  PC,R14,#C_flag          ;If so, set C on exit
+               BICNES  PC,R14,#C_flag          ;Otherwise clear it
+
+               LTORG
+
+; --- hammer_getStack ---
+;
+; On entry:    --
+;
+; On exit      R13 == pointer to the sledghammer stack
+;
+; Use:         Returns a pointer to the sledgehammer stack!
+
+               EXPORT  hammer_getStack
+hammer_getStack        ROUT
+
+               LDR     R13,hammer__wSpace      ;Get workspace pointer
+               ADD     R13,R13,#:INDEX: ws__stackBase
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+hammer__wSpace DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+
+ws__start      #       0
+
+ws__stackTop   #       1024                    ;Just a 1K stack
+ws__stackBase  #       0                       ;The top of the stack!
+
+ws__size       EQU     {VAR}-ws__start         ;The workspace size
+
+               AREA    |Quartz$$Table|,CODE,READONLY
+
+               DCD     ws__size
+               DCD     hammer__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/sh/armEmul b/StraySrc/Hammer/sh/armEmul
new file mode 100644 (file)
index 0000000..fadb0ec
--- /dev/null
@@ -0,0 +1,46 @@
+;
+; armEmul.sh
+;
+; ARM emulation
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   armEmul
+
+; --- armEmul ---
+;
+; On entry:    R0 == instruction to execute
+;              R1 == pointer to register block
+;
+; On exit:     --
+;
+; Use:         Emulates a given ARM instruction.
+
+               IMPORT  armEmul
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/sh/asm b/StraySrc/Hammer/sh/asm
new file mode 100644 (file)
index 0000000..7461645
--- /dev/null
@@ -0,0 +1,61 @@
+;
+; asm.s
+;
+; Assembly of instructions -- Blurg
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   asm_assemble
+;   asm_register
+
+; --- asm_assemble ---
+;
+; On entry:    R0 == pointer to the instruction to assemble
+;              R1 == address at which to assemble instruction
+;
+; On exit:     VC and R0 == the assembled instruction
+;              VS and R0 == pointer to an error
+;
+; Use:         Assembles the given insruction, returning the result in
+;              R0. The instruction is NOT placed into the memory location
+;              passed in R1.
+
+               IMPORT  asm_assemble
+
+; --- asm_register ---
+;
+; On entry:    R8 == pointer into the instruction
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R0 == number, R8 updated appropriately
+;
+; Use:         Reads in a register name
+
+               IMPORT  asm_register
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/sh/brkpt b/StraySrc/Hammer/sh/brkpt
new file mode 100644 (file)
index 0000000..d87318e
--- /dev/null
@@ -0,0 +1,105 @@
+;
+; brkpt.sh
+;
+; Breakpoint handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   brkpt_set
+;   brkpt_hardBreak
+;   brkpt_translate
+;   brkpt_remove
+;   brkpt_remAll
+;   brkpt_exist
+
+; --- brkpt_set ---
+;
+; On entry:    R0 == address to set breakpoint
+;
+; On exit:     May return error
+;
+; Use:         Sets a breakpoint at the given location, giving it the
+;              current handle.  The address is assumed to be word-aligned,
+;              and writable.
+
+               IMPORT  brkpt_set
+
+; --- brkpt_hardBreak ---
+;
+; On entry:    [R13+4] == return address to stomp on
+;
+; On exit:     --
+;
+; Use:         Sets an immediate break specified by a SWI call.
+
+               IMPORT  brkpt_hardBreak
+
+; --- brkpt_translate ---
+;
+; On entry:    R0 == address to translate
+;
+; On exit:     R0 == the address we are really interested in
+;
+; Use:         Returns the address given, as if there was no breakpoint
+;              there.
+
+               IMPORT  brkpt_translate
+
+; --- brkpt_remove ---
+;
+; On entry:    R0 == address of breakpoint
+;
+; On exit:     --
+;
+; Use:         Removes the break point (if any) at the given address
+
+               IMPORT  brkpt_remove
+
+; --- brkpt_remAll ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Removes all the breakpoints currently installed.
+
+               IMPORT  brkpt_remAll
+
+; --- brkpt_exist ---
+;
+; On entry:    R0 == address to test for
+;
+; On exit:     CC if there is no breakpoint here
+;              CS otherwise
+;
+; Use:         Informs the user if there is a breakpint at the address
+;              passed.
+
+               IMPORT  brkpt_exist
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/sh/diss b/StraySrc/Hammer/sh/diss
new file mode 100644 (file)
index 0000000..28bfe7f
--- /dev/null
@@ -0,0 +1,92 @@
+;
+; diss.s
+;
+; Superior Disassembly of ARM instructions
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   diss_setOptions
+;   diss_address
+;   diss_disassemble
+;   diss_regTable
+;   diss_init
+
+; --- diss_setOptions ---
+;
+; On entry:    R0 == new options field
+;
+; On exit:     --
+;
+; Use:         Sets up the new display options for the disassembly
+
+               IMPORT  diss_setOptions
+
+; --- diss_address ---
+;
+; On entry:    R0 == address to start disassembly
+;
+; On exit:     --
+;
+; Use:         Initialises the disassembly to start at the given address
+
+               IMPORT  diss_address
+
+; --- diss_disassemble ---
+;
+; On entry:    R0 == address of the instruction
+;
+; On exit:     R0 == pointer to buffer containing disassembly of
+;              next instruction
+;
+; Use:         Disassembles the instruction pointered to, and places
+;              the resulting string in the returned buffer.
+
+               IMPORT  diss_disassemble
+
+; --- diss_regTable ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to register table
+;
+; Use:         Returns a pointer to the register name table, so that the
+;              assembler can get its grubby paws on it.
+
+               IMPORT  diss_regTable
+
+; --- diss_init ---
+;
+; On entry:    R12 == pointer to workspace
+;
+; On exit:     --
+;
+; Use:         Initialises the disassembler segment nicely.
+
+               IMPORT  diss_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/sh/driver b/StraySrc/Hammer/sh/driver
new file mode 100644 (file)
index 0000000..64a7697
--- /dev/null
@@ -0,0 +1,45 @@
+;
+; driver.sh
+;
+; The text-only interface to Sledgehammer
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   driver
+
+; --- driver ---
+;
+; On entry:    R0 == pointer to a register block
+;
+; On exit:     Doesn't
+;
+; Use:         Text only interactive debugger interface
+
+               IMPORT driver
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Hammer/sh/hammer b/StraySrc/Hammer/sh/hammer
new file mode 100644 (file)
index 0000000..166d62d
--- /dev/null
@@ -0,0 +1,57 @@
+;
+; hammer.sh
+;
+; Main definitions for Sledgehammer
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sledgehammer debugger.
+;
+; Sledgehammer is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sledgehammer is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sledgehammer.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   hammer_confirm
+;   hammer_getStack
+
+; --- hammer_confirm ---
+;
+; On entry:    R0 == pointer to confirmation message
+;
+; On exit:     C set to proceed with whatever it was you wanted to confirm
+;
+; Use:         Displays a message with a confirmation prompt and waits
+;              for a response from the user.
+
+               IMPORT  hammer_confirm
+
+; --- hammer_getStack ---
+;
+; On entry:    --
+;
+; On exit      R13 == pointer to the sledghammer stack
+;
+; Use:         Returns a pointer to the sledgehammer stack!
+
+               IMPORT  hammer_getStack
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/Makefile,fe1 b/StraySrc/Libraries/BAS/Makefile,fe1
new file mode 100644 (file)
index 0000000..e362d22
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all:
+       submake *.Makefile
+
+install:
+       submake *.Makefile -- install
+
+clean:
+       submake *.Makefile -- clean
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/Libraries/BAS/exports b/StraySrc/Libraries/BAS/exports
new file mode 100644 (file)
index 0000000..9ae3f86
--- /dev/null
@@ -0,0 +1,56 @@
+bas_init
+bas_aofInit
+bas_aofSaveAs
+bas_aofSave
+pass
+import
+importAs
+importWeak
+importWeakAs
+export
+exportAs
+exportStrong
+exportStrongAs
+get
+bas_lib
+area
+reloc
+noReloc
+entry
+litStart
+litw
+lits
+litmagic
+litsz
+literr
+literal
+litAlign
+ltorg
+align
+reserve
+bin
+fSize
+ws_start
+ws_base
+ws
+ws_align
+ws_word
+ws_byte
+adrl
+adrccl
+addl
+addccl
+ldrl
+ldrccl
+ldrrl
+ldrrccl
+bas_a
+bas_b
+bas_c
+bas_d
+bas_e
+bas_f
+bas_g
+bas_h
+bas_i
+bas_j
diff --git a/StraySrc/Libraries/BAS/src/Makefile,fe1 b/StraySrc/Libraries/BAS/src/Makefile,fe1
new file mode 100644 (file)
index 0000000..5c835a1
--- /dev/null
@@ -0,0 +1,247 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+# --- Object files for the code section ---
+
+OBJS = \
+       o.bas \
+       o.aofGen o.basTalk o.get o.insert o.lit o.vars \
+       o.fastMove o.flex o.string \
+       o.messages
+
+SCRIPTS = \
+       scripts.crunchit \
+       scripts.execit \
+       scripts.nonsqueeze \
+       scripts.preproc
+
+#----- Compiling things -----------------------------------------------------
+
+all: bas
+
+bas: bc.bas bascode
+       copy bc.bas bas ~c~v~nf~r
+       print bascode { >> bas }
+
+bascode: $(OBJS)
+       $(LD_BIN) $(OBJS)
+
+o.messages: rsc.messages
+       msgaof rsc.messages o.messages sh.messages
+
+bc.bas: b.bas scripts.crunchit
+       @echo *** Crunching Basic library ***
+       obey scripts.crunchit
+       @$(RM) work.*
+
+install: bas scripts.exports
+       $(INSTALL) bas scripts.exports <SSR$LibDir>.BAS
+
+clean:
+       -$(RM) o.* bc.* work.* bas bascode
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.insert: s.insert
+o.insert: libs:header
+o.insert: libs:swis
+o.insert: libs:stream
+o.insert: sh.bas
+o.insert: sh.workspace
+o.insert: libs:sh.flexws
+o.vars: s.vars
+o.vars: libs:header
+o.vars: libs:swis
+o.vars: libs:stream
+o.vars: sh.bas
+o.vars: sh.basTalk
+o.fastMove: s.fastMove
+o.fastMove: libs:s.fastMove
+o.fastMove: libs:header
+o.fastMove: libs:swis
+o.string: s.string
+o.string: libs:swis
+o.string: libs:header
+o.string: sh.workspace
+o.string: libs:sh.flexws
+o.basTalk: s.basTalk
+o.basTalk: libs:header
+o.basTalk: libs:swis
+o.basTalk: libs:stream
+o.basTalk: sh.basicEnv
+o.basTalk: sh.messages
+o.basTalk: sh.string
+o.basTalk: sh.workspace
+o.basTalk: libs:sh.flexws
+o.bas: s.bas
+o.bas: libs:header
+o.bas: libs:swis
+o.bas: libs:stream
+o.bas: sh.aofGen
+o.bas: sh.basicEnv
+o.bas: sh.basTalk
+o.bas: sh.fastMove
+o.bas: libs:sh.fastMove
+o.bas: sh.flex
+o.bas: libs:sh.flex
+o.bas: sh.get
+o.bas: sh.insert
+o.bas: sh.lit
+o.bas: sh.messages
+o.bas: sh.string
+o.bas: sh.vars
+o.bas: sh.workspace
+o.bas: libs:sh.flexws
+o.aofGen: s.aofGen
+o.aofGen: libs:header
+o.aofGen: libs:swis
+o.aofGen: libs:stream
+o.aofGen: sh.bas
+o.aofGen: sh.basTalk
+o.aofGen: sh.flex
+o.aofGen: libs:sh.flex
+o.aofGen: sh.insert
+o.aofGen: sh.lit
+o.aofGen: sh.messages
+o.aofGen: sh.string
+o.aofGen: sh.workspace
+o.aofGen: libs:sh.flexws
+o.get: s.get
+o.get: libs:header
+o.get: libs:swis
+o.get: libs:stream
+o.get: sh.aofGen
+o.get: sh.bas
+o.get: sh.basTalk
+o.get: sh.flex
+o.get: libs:sh.flex
+o.get: sh.string
+o.get: sh.workspace
+o.get: libs:sh.flexws
+o.lit: s.lit
+o.lit: libs:header
+o.lit: libs:swis
+o.lit: libs:stream
+o.lit: sh.aofGen
+o.lit: sh.bas
+o.lit: sh.fastMove
+o.lit: libs:sh.fastMove
+o.lit: sh.flex
+o.lit: libs:sh.flex
+o.lit: sh.insert
+o.lit: sh.workspace
+o.lit: libs:sh.flexws
+o.flex: s.flex
+o.flex: libs:header
+o.flex: sh.workspace
+o.flex: libs:sh.flexws
+o.flex: libs:s.flex
+o.flex: libs:header
+o.flex: libs:swis
+o.flex: s.flex
+o.flex: libs:header
+o.flex: sh.workspace
+o.flex: libs:sh.flexws
+o.flex: libs:s.flex
+o.flex: libs:header
+o.flex: libs:swis
+o.flex: s.flex
+o.flex: libs:header
+o.flex: sh.workspace
+o.flex: libs:sh.flexws
+o.flex: libs:s.flex
+o.flex: libs:header
+o.flex: libs:swis
+o.flex: s.flex
+o.flex: libs:header
+o.flex: sh.workspace
+o.flex: libs:sh.flexws
+o.flex: libs:s.flex
+o.flex: libs:header
+o.flex: libs:swis
diff --git a/StraySrc/Libraries/BAS/src/README b/StraySrc/Libraries/BAS/src/README
new file mode 100644 (file)
index 0000000..08a5a8b
--- /dev/null
@@ -0,0 +1,330 @@
+BAS -- the Basic Assembler Supplement
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+       Once upon a time, this was meant to be a commercial Straylight
+       product.  I never got around to writing the documentation.
+
+       BAS is Yet Another tool for people who use the BASIC assembler.  The
+       odd thing is that Straylight use Acorn's `objasm' assembler for all
+       our `real' work.  The idea was to produce a procedure library for
+       generating linkable AOF code from BASIC, and the functionality grew
+       from there.  Features are:
+
+         * Generates AOF version 2 object code.
+         * Handles literal pools.  (I'll come to them.)
+         * Translates (a simple subset of) objasm header files.
+         * A small collection of other tools.
+
+       BAS is almost entirely written in assembler, with a BASIC procedure
+       library thrown in.  You don't need to worry about that -- the code
+       is tacked on the end of the BASIC file, so it all comes as one
+       package.
+
+_____________________________________________________________________________
+
+LICENCE
+
+       BAS is Free Software; you can redistribute it and/or modify
+       it under the terms of the GNU General Public License as published by
+       the Free Software Foundation; either version 2, or (at your option)
+       any later version.
+
+       BAS is distributed in the hope that it will be useful, but WITHOUT
+       ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+       or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+       License for more details.
+
+       You should have received a copy of the GNU General Public License
+       along with BAS; if not, write to the Free Software Foundation, Inc.,
+       675 Mass Ave, Cambridge, MA 02139, USA.
+
+       Of course, you can do what you like with the output of BAS.
+
+_____________________________________________________________________________
+
+AOF CODE GENERATION
+
+       I'll assume you understand how linkable objects work.  We'll be
+       here all day if you don't.
+
+       All code must be in an `area'.  You start an area by saying
+
+               FNarea("NAME", "ATTRIBUTES")
+
+       The name can be anything you like; common names are `C$$Code' for
+       C code, and similar.  Dollars are popular for some reason.
+
+       The attributes define properties of areas, which in turn affect
+       positioning and access permissions.  We've tried to use the same
+       names as Objasm here:
+
+               CODE            -- area contains code (implies `READONLY')
+               COMDEF          -- definitons for a common area
+               COMMON          -- overlay areas with this name
+                                       (implies `NOINIT')
+               NOINIT          -- initialise this area with zeros
+               READONLY        -- I don't need to write to this area
+               DEBUG           -- contains debugging information
+
+       By default, areas with the same name are concatenated.  You get
+       given symbols `NAME$$Base' and `NAME$$Limit' to tell you the
+       boundaries of the complete area called `NAME', which is useful for
+       building tables.
+
+       Attribute names can be separated by anything you like -- they're
+       parsed by the BASIC library using INSTR.  Objasm uses commas, so
+       I tend to too.
+
+       A program generating AOF code will usually look something like this:
+
+               LIBRARY "libs:BAS"
+               PROCbas_init
+
+               PROCbas_aofInit(SIZE)
+               FOR o%=4 TO 6 STEP 2
+               [       opt o%
+                       FNpass
+
+                       FNarea("Foo$$Code", "CODE, READONLY")
+                       ...
+
+               ]
+               NEXT
+               PROCbas_aofSave / PROCbas_aofSaveAs(FILENAME)
+
+       Here, `SIZE' is the amount of space to reserve for the code, and
+       `FILENAME' is the name to save it as.  The PROCbas_aofSave function
+       uses the value of <BAS$Output> as a default filename: this allows
+       you to declare an alias
+
+               Set Alias$BasAsm Set BAS$Output %1|mBASIC -quit %0
+
+       which you can use in Makefiles.
+
+       You're not limited to one assembly per source file -- you can create
+       any number of object files, although each one must start with a
+       call to PROCbas_aofInit and end with PROCbas_aofSave[As].
+
+       Note that you must begin each assembly by calling FNpass -- this
+       will set the P% and O% variables appropriately for the assembly, and
+       make sure that the BAS code understands where you are in the
+       assembly.
+
+       You can export a synbol (so that other object files can see it) by
+       calling FNexport; for example:
+
+               FNexport("hello")
+       .hello  stmfd r13!,{r0,r14}
+               ldr r0,FNlitsz("Hello, world")
+               swi "OS_Write0"
+               ldmfd r13!,{r0,pc}^
+               FNltorg
+
+       Because AOF allows a wider range of identifiers than BASIC, you can
+       `alias' names as you export them; for example:
+
+               FNexport("foo", "My$$FooishThing")
+
+       takes the value represented in the BASIC variable `foo' and exports
+       it as `My$$FooishThing' in an object file.
+
+       You import values in the same way:
+
+               FNimport("malloc")
+               FNexport("xmalloc")
+
+       .xmalloc
+               stmfd r13!,{r1-r3,r12,r14}
+               bl malloc
+               cmp r0,#0
+               ldmnefd r13!,{r1-r3,r12,r14}
+               ldr r0,FNliterr(1,"Not enough memory")
+               swi "OS_GenerateError"
+
+               FNltorg
+
+       (I'll explain the FNlit... and FNltorg macros later.  Bear with me.)
+
+       You can also FNimportAs a symbol with a funny name:
+
+               FNimportAs("Image$$RW$$Limit","program_end")
+
+       fetches the limit of the read-write area of the image, telling you
+       where the program ends.  This is quite handy.
+
+
+       How this all works is possibly interesting.  It (ab)uses offset
+       assembly, directing output (O%) to a buffer BAS allocates for you,
+       and starting P% at &FC000000, which is an illegal instruction, and
+       hopefully unlikely to appear in `real' code.  Once the assembly's
+       finished, BAS runs through and picks out references to things in
+       with addresses &FCxxxxxx and creates relocation directives for them
+       in the AOF file.  Imported things get given addresses &FDxxxxxx.
+       Assuming these values don't appear in genuine code, we're OK.  Just
+       in case you want to make arbitrary data appear in the object, BAS
+       has directives for disabling and reenabling relocation:
+
+               FNnoreloc
+               ...
+               FNreloc
+
+       won't munge anything between them.
+
+       Finally, the call
+
+               FNentry
+
+       marks the entry point in an AIF program -- execution will start
+       here.  That's all there is to it.
+
+_____________________________________________________________________________
+
+LITERALS AND LITERAL POOLS
+
+       Data like strings and absolute addresses are a pain in the BASIC
+       assembler -- you have to make up labels for them, and then reference
+       them.  BAS tries to handle this sort of thing for you, which is
+       rather more pleasant of it.
+
+       At any point in an assembly, BAS is building a `literal pool'.  You
+       create a literal using one of the supplied directives, and BAS is
+       responsible for putting it in a literal pool; it gives you the
+       address at which the literal will be placed in the finished output.
+       The current literal pool will be written to the assembly when you
+       call FNltorg.  A literal pool is also written at the very end of
+       the assembly.
+
+       Essentially, then
+
+               adr r0,FNlitsz("Hello, world")
+               ...
+               FNltorg
+
+       is equivalent to
+
+               adr r0,hello_string
+               ...
+       .hello_string
+               equs "Hello, world" + CHR$(0)
+
+       The literal creation macros provided are:
+
+         * FNlitw(WORD) stores a 32-bit value WORD at a word-aligned
+           address, e.g.,
+
+               FNimportAs("Image$$RW$$Limit", "prog_end")
+               ldr r0,FNlitw(prog_end)
+
+           puts the address of the end of the program in R0.
+
+         * FNlits(STRING) stores a string, unterminated, and non-word-
+           aligned.  This isn't very useful.
+
+         * FNlitmagic(STRING) stores an unterminated string at a word-
+           aligned address.  This is for things like
+
+               ldr r1,FNlitmagic("TASK")
+
+           so you don't have to remember that this is &4B534154.  I
+           remember it anyway.
+
+         * FNlitsz(STRING) stores a null-terminated string at a non-word-
+           aligned address.  This is useful for all kinds of messages.
+
+         * FNliterr(NUM, STRING) stores a RISC OS error block at a word-
+           aligned address.
+
+       If you need some kind of structure which isn't provided, you can
+       build it yourself.  PROClitStart informs BAS that it's meant to
+       assemble a literal; FNliteral completes the literal, returning
+       the address where BAS will eventually put it.  FNlitAlign does
+       the same job, only it word-aligns the literal.
+
+_____________________________________________________________________________
+
+READING OBJASM HEADERS
+
+       FNget(FILENAME) reads an Objasm-format header file.  It's not perfect
+       but it tries hard.
+
+       Objasm directives supported are: `^', `#'. `EQU', and `IMPORT'.
+       This is hopefully enough for most purposes.  The `*' synonym for
+       `EQU' is also supported.
+
+       BAS can't understand Objasm macros.  Instead, it understands `active
+       comments'.  The only one implemented is `LIB':
+
+               ;+      LIB     FILENAME
+
+       which loads the BASIC procedure library FILENAME.  A BAS macro
+       library `foo' must contain a function FNfoo_test, which is used by
+       BAS to see whether the library is loaded.
+
+_____________________________________________________________________________
+
+OTHER USEFUL TOYS
+
+       BAS defines a whole slew of constants:
+
+         * r0-r15, R0-R15, a1-a4, v1-v6, sb, sl, fp, sp, SP, lr, LR,
+           lk, LK, pc and PC are all set to the appropriate register
+           numbers.
+
+         * EQ, NE etc. are set to the appropriate condition code values.
+
+       FNalign aligns the output position to a word boundary, padding with
+       zero bytes. FNreserve(SIZE) writes SIZE zero bytes to the output.
+
+       FNbin(FILENAME) inserts the contents of the file FILENAME into the
+       output, protecting it from relocation.  FNfSize(FILENAME) returns
+       the size of the file FILENAME.  This can be handy for setting up
+       sprite areas.
+
+       FNws_start clears a storage-area counter to zero.  FNws_base(VALUE)
+       sets the counter to VALUE.  FNws_align word-aligns the counter.
+       FNws(SIZE) returns the counter, and increases it by SIZE.  FNws_word,
+       and FNws_byte are equivalent to FNws(4) and FNws(1) respectively.
+       These are useful for laying out workspace areas and data structures.
+
+       FNadrl(REG, ADDR) assembles a long ADR; FNadrccl(COND, REG, ADDR)
+       assembles a conditional long ADR.  FNaddl(REG, BASE, OFFSET)
+       assembles a long ADD; FNaddccl(COND, REG, BASE, OFFSET) does the
+       same conditionally.
+
+       FNldrl(REG, ADDR) assembles a long LDR; FNldrccl(COND, REG, ADDR)
+       assembles a conditional long LDR.  FNldrrl(REG, BASE, OFFSET)
+       assembles a long non-PC-relative LDR;
+       FNldrrccl(COND, REG, BASE, OFFSET) does that conditionally.
+
+_____________________________________________________________________________
+
+BUILDING BAS FROM SOURCES
+
+       This is quite involved.  You need to have:
+
+         * Acorn Desktop Assembler or later
+
+         * An implementation of `sed' -- I recommend the port of GNU sed.
+
+         * Straylight's basic library set (`header', `swis' and `stream')
+           available from the same place you got this from.
+
+         * A copy of Cy Booker's `ccrunch' BASIC compressor.  If you don't
+           have this, edit `remnames' and remove the `ccrunch' line -- the
+           BAS output file will be a little larger, but that's OK.
+
+       Build the ARM code part by running the Makefile.  Now run `Setup'
+       to mangle the nice BASIC library part, and to tack the code on
+       the end.  That should be it.
+
+_____________________________________________________________________________
+
+WHAT USE IS BAS?
+
+       Dunno.  Straylight were hoping to sell it for maybe fifteen quid a
+       go.  We use it in-house for building simple AOF-outputting tools;
+       our message-file and template-file compilers are BAS-based, for
+       example.  (These are available as part of the SDLS and Sapphire
+       packages, if they're out yet.)
+
+_____________________________________________________________________________
diff --git a/StraySrc/Libraries/BAS/src/b/bas,ffb b/StraySrc/Libraries/BAS/src/b/bas,ffb
new file mode 100644 (file)
index 0000000..5340de1
Binary files /dev/null and b/StraySrc/Libraries/BAS/src/b/bas,ffb differ
diff --git a/StraySrc/Libraries/BAS/src/rsc/messages b/StraySrc/Libraries/BAS/src/rsc/messages
new file mode 100644 (file)
index 0000000..72fa4d7
--- /dev/null
@@ -0,0 +1,26 @@
+;
+; BAS messages
+;
+; © 1996 Straylight
+;
+
+; --- General error messages ---
+
+errBadArg:[1]Bad arguments passed to BAS
+errNoMoreMem:[1]No more memory for BAS
+
+; --- Errors passed on from BASIC ---
+
+errBadLValue:[1]Syntax error: '%0' is not a valid lvalue
+errVarNotFound:[1]Variable '%0' not found
+errOddString:[1]Type mismatch: number needed
+
+; --- Error messages for AOF generation ---
+
+errInitTwice:[1]BAS is already generating AOF code
+errNoAreas:[1]No AREAs defined in assembly
+errNotInArea:[1]Junk found before first AREA start
+errNoArea:[1]Can't set entry point: not in an AREA
+errMultiEntry:[1]Already set entry point
+errExpImported:[1]Exporting IMPORTed symbols is not permitted
+errNotDone:[1]Can't save AOF file: still on first pass or FNpass not called
\ No newline at end of file
diff --git a/StraySrc/Libraries/BAS/src/s/aofGen b/StraySrc/Libraries/BAS/src/s/aofGen
new file mode 100644 (file)
index 0000000..af61839
--- /dev/null
@@ -0,0 +1,1170 @@
+;
+; aofGen.s
+;
+; Generate AOF files from BASIC
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.bas
+               GET     sh.basTalk
+               GET     sh.flex
+               GET     sh.insert
+               GET     sh.lit
+               GET     sh.messages
+               GET     sh.string
+               GET     sh.workspace
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |BAS$$Code|,CODE,READONLY
+
+; --- aof_init ---
+;
+; On entry:    R7 == address of workspace
+;              R8-R12 set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: asmCode%
+;
+; Use:         Initialises workspace for generation of AOF code.  Remembers
+;              that code generation will start at asmCode%.
+
+               EXPORT  aof_init
+aof_init       ROUT
+
+               STMFD   R13!,{R0-R6,R9,R10,R12,R14}
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Get my workspace address
+
+               LDR     R14,aof__objHead        ;Load the header area address
+               CMP     R14,#0                  ;Is it created already?
+               ADRNEL  R0,msg_errInitTwice     ;Yes -- point to error
+               SWINE   OS_GenerateError        ;And inform the user
+
+               ; --- First, save the start address ---
+
+               SUBS    R10,R10,#1              ;Decrement argument counter
+               BCC     bas_badCall             ;If none there, complain
+               LDMIA   R9!,{R0,R1}             ;Load the argument types
+               BL      bTalk_load              ;Load value into R2
+               STR     R2,aof__base            ;Save this base address
+
+               ; --- Set up initial indices ---
+
+               MOV     R0,#0                   ;Zero some locations
+               STR     R0,aof__area            ;No current area either
+               STR     R0,aof__pass            ;Not done any passes yet
+               STR     R0,aof__relocCount      ;Clear the flags word
+
+               ; --- Now initialise our memory structures ---
+
+               MOV     R2,#0                   ;Initial space used
+               MOV     R3,#256                 ;Initial space allocated
+               MOV     R1,#256                 ;Allocate this space
+
+               ADR     R0,aof__objHead         ;Point to header area block
+               BL      flex_alloc              ;Allocate the block
+               STMCCIB R0,{R2,R3}              ;Save values after it
+               ADRCC   R0,aof__objReloc        ;Point to relocation block
+               BLCC    flex_alloc              ;Allocate the block
+               STMCCIB R0,{R2,R3}              ;Save values after it
+               ADRCC   R0,aof__objSymT         ;Point to symbol table block
+               BLCC    flex_alloc              ;Allocate the block
+               STMCCIB R0,{R2,R3}              ;Save values after it
+               ADRCC   R0,aof__objStrT         ;Point to string table block
+               BLCC    flex_alloc              ;Allocate the block
+               STMCCIB R0,{R2,R3}              ;Save values after it
+               ADRCC   R0,aof__imports         ;Point to import table block
+               BLCC    flex_alloc              ;Allocate the block
+               STMCCIB R0,{R2,R3}              ;Save values after it
+               ADRCC   R0,aof__noReloc         ;Point to non-reloc anchor
+               BLCC    flex_alloc              ;Allocate the block
+               STMCCIB R0,{R2,R3}              ;Save values after it
+               BCS     bas_noMem               ;If no memory, complain
+
+               ; --- Build the header chunk ---
+
+               LDR     R0,aof__objHead         ;Find the header area
+               LDR     R1,=&C5E2D080           ;The really odd magic number
+               MOV     R2,#150                 ;Version of AOF we like
+               MOV     R3,#0                   ;No areas yet
+               MOV     R4,#0                   ;No symbols either
+               MOV     R5,#0                   ;No entry area yet
+               MOV     R6,#0                   ;No entry offset, then
+               STMIA   R0,{R1-R6}              ;Build most of the header
+               MOV     R14,#24                 ;Now used 24 bytes
+               STR     R14,aof__objHead+4      ;Save this in the info
+
+               MOV     R14,#4                  ;Length of string table
+               LDR     R0,aof__objStrT         ;Find the string table
+               STR     R14,[R0,#0]             ;Save that in the string tbl
+               STR     R14,aof__objStrT+4      ;And as the size used
+
+               BL      lit_init                ;Initialise Literal Manager
+
+               LDMFD   R13!,{R0-R6,R9,R10,R12,PC}^
+
+               LTORG
+
+; --- aof_pass ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Signals the start of a new assembly pass.
+
+               EXPORT  aof_pass
+
+aof_pass       ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Find my workspace
+
+               ; --- Bump the pass counter ---
+
+               LDR     R1,aof__pass            ;Load the pass counter
+               ADD     R1,R1,#1                ;Increment it
+               CMP     R1,#2                   ;Is this the second pass?
+               BLEQ    lit_ltorg               ;Yes -- insert lit pool
+               STR     R1,aof__pass            ;And store it back again
+               BNE     %10aof_pass             ;No -- skip ahead then
+
+               ; --- Make sure the AREA addresses are OK ---
+
+               LDR     R0,aof__area            ;Load the number of AREAs
+               CMP     R0,#0                   ;Are there any defined?
+               ADREQL  R0,msg_errNoAreas       ;No -- point to an error
+               SWIEQ   OS_GenerateError        ;And raise an error
+               LDR     R14,aof__objHead        ;Find the header chunk
+               LDR     R14,[R14,#24+16]        ;Load base of first AREA
+               CMP     R14,#&FC000000          ;Is this an OK value
+               ADRNEL  R0,msg_errNotInArea     ;No -- point to error
+               SWINE   OS_GenerateError        ;And raise it
+
+               ; --- Work out end address ---
+
+               BL      aof__findArea           ;Look up its header info
+               LDR     R14,be__percents        ;Load % variable base address
+               LDR     R1,[R14,#('P'-'A')*4]   ;Load current location count
+               ADD     R1,R1,#3                ;Word align this nicely
+               BIC     R1,R1,#3                ;To keep link happy
+               STR     R1,aof__limit           ;Save as the code limit
+               LDR     R14,[R0,#16]            ;Load AREA base address
+               SUB     R1,R1,R14               ;Work out the AREA's size
+               STR     R1,[R0,#8]              ;Store it in the block
+
+               ; --- Now set up O% and P% correctly ---
+
+10aof_pass     LDR     R0,aof__base            ;Load assembly base address
+               LDR     R14,be__percents        ;Load % variable base address
+               STR     R0,[R14,#('O'-'A')*4]   ;Save in correct variable
+               MOV     R0,#&FC000000           ;Start assembly here (!)
+               STR     R0,[R14,#('P'-'A')*4]   ;Save that in P%
+
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- aof_firstPass ---
+;
+; On entry:    --
+;
+; On exit:     CS if on first pass, CC otherwise
+;
+; Use:         Informs the caller whether we're on the first or second pass.
+
+               EXPORT  aof_firstPass
+aof_firstPass  ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,aof__pass           ;Which pass are we on?
+               CMP     R14,#1                  ;Is this the first one?
+               LDMFD   R13!,{R14}              ;Restore link register
+               ORRLES  PC,R14,#C_flag          ;Yes -- return CS then
+               BICGTS  PC,R14,#C_flag          ;No -- return CC then
+
+               LTORG
+
+; --- aof_ensure ---
+;
+; On entry:    R0 == address of anchor and size info
+;              R1 == free space required
+;
+; On exit:     R0 == address of first free byte in area
+;
+; Use:         Ensures that there is the requested quantity of memory free
+;              in the given block.  If not, bas_noMem is called.
+
+               EXPORT  aof_ensure
+aof_ensure     ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               LDMIB   R0,{R2,R14}             ;Load used and size words
+               ADD     R1,R1,R2                ;Find new total size
+               STR     R1,[R0,#4]              ;Save this back
+               ADD     R1,R1,#255              ;Align up to next 256
+               BIC     R1,R1,#255              ;For niceness's sake
+               CMP     R1,R14                  ;Do we already have enough?
+               BHI     %50aof_ensure           ;No -- allocate some more
+10aof_ensure   STR     R1,[R0,#8]              ;Save new total size
+               LDR     R0,[R0,#0]              ;Load address of block
+               ADD     R0,R0,R2                ;Point to first free byte
+               LDMFD   R13!,{R1,R2,PC}^        ;And return to caller
+
+50aof_ensure   BL      flex_extend             ;No -- then extend the block
+               BCS     bas_noMem               ;If we couldn't, we die
+               B       %10aof_ensure           ;Rejoin the main program
+
+               LTORG
+
+; --- aof__addString ---
+;
+; On entry:    R0 == pointer to string to add
+;
+; On exit:     R0 == offset of string in string table
+;
+; Use:         Adds a string to the string table chunk and returns its
+;              offset.
+
+aof__addString ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               LDR     R2,aof__objStrT+4       ;Load free offset
+               FSAVE   R0                      ;Save the string address
+               BL      str_len                 ;Find the string length
+               ADD     R1,R0,#1                ;Remember the terminator
+               ADR     R0,aof__objStrT         ;Point to string table anchor
+               BL      aof_ensure              ;Make sure there's enough
+               FLOAD   R1                      ;Load the source string
+               BL      str_cpy                 ;Copy string into area
+               MOV     R0,R2                   ;Return offset in R0
+               LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- aof_area ---
+;
+; On entry:    R0 == AREA attributes word
+;              R7 == address of workspace
+;              R8-R12 set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: name$
+;
+; Use:         Makes a new AREA start at the current location.
+
+               EXPORT  aof_area
+aof_area       ROUT
+
+               STMFD   R13!,{R0-R6,R9,R10,R12,R14}
+               BL      insert_align            ;Word align current position
+               BL      lit_ltorg               ;Insert a literal pool
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Find workspace address
+               BL      aof_firstPass           ;Which pass am I on?
+               BCC     %90aof_area             ;If not the first, quit now
+
+               ; --- Insert new AREA block in header ---
+
+               MOV     R3,R0                   ;Keep the AREA attributes
+               BL      str_buffer              ;Find a string buffer
+               BL      bas_argString           ;Read the AREA's name
+               MOV     R0,R1                   ;Point to the string
+               BL      aof__addString          ;Put it in the string table
+               MOV     R2,R0                   ;Keep the string offset
+
+               ADR     R0,aof__objHead         ;Find the header chunk
+               MOV     R1,#20                  ;Want 20 bytes of data
+               BL      aof_ensure              ;Make sure it's there
+
+               MOV     R4,#0                   ;Don't know the size yet
+               MOV     R5,#0                   ;Don't know about relocations
+               LDR     R14,be__percents        ;Find the % variables
+               LDR     R6,[R14,#('P'-'A')*4]   ;Load current loc counter
+               STMIA   R0,{R2-R6}              ;Save this in the header
+
+               ; --- Now try to fix up old AREA ---
+
+               LDR     R14,aof__area           ;Which area are we on?
+               CMP     R14,#0                  ;Is this the dummy area?
+               LDRNE   R5,[R0,#-4]             ;No -- load old start pos
+               SUBNE   R5,R6,R5                ;Get the AREA's size
+               STRNE   R5,[R0,#-12]            ;Save the AREA's size
+
+               ADD     R14,R14,#1              ;Increment AREA count
+               STR     R14,aof__area           ;And save that back
+
+               LDR     R14,aof__relocCount     ;Load current flags
+               CMP     R14,#0                  ;Is relocation enabled?
+               BEQ     %90aof_area             ;Relocation enabled -- skip
+               MOV     R14,#0                  ;Clear the counter nicely
+               STR     R14,aof__relocCount     ;Save counter back again
+
+               ; --- If noReloc is at current address, remove it ---
+
+               LDR     R2,be__percents         ;Find the % variables
+               LDR     R2,[R2,#('O'-'A')*4]    ;Load current address
+               ADR     R0,aof__noReloc         ;Find noreloc table
+               LDMIA   R0,{R0,R1}              ;Load the size and base
+               SUB     R1,R1,#4                ;Find the end value
+               LDR     R14,[R0,R1]             ;Load the value out
+               CMP     R14,R2                  ;Is this a match?
+               STREQ   R1,aof__noReloc+4       ;Yes -- chop one off size
+
+90aof_area     LDMFD   R13!,{R0-R6,R9,R10,R12,PC}^
+
+               LTORG
+
+; --- aof_entry ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets the image entry point to be the current location.
+
+               EXPORT  aof_entry
+aof_entry      ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Find my workspace address
+               BL      insert_align            ;Word align current pos
+               BL      aof_firstPass           ;Is this the first pass?
+               BCC     %90aof_entry            ;No -- then do nothing
+
+               ; --- Make sure we have an AREA ---
+
+               LDR     R14,aof__area           ;Find the current AREA
+               CMP     R14,#0                  ;Is this sensible?
+               ADREQL  R0,msg_errNoArea        ;No -- then point to error
+               SWIEQ   OS_GenerateError        ;And report an error
+
+               ; --- Set up the entry AREA number ---
+
+               LDR     R0,aof__objHead         ;Find the header chunk
+               LDR     R1,[R0,#16]             ;Load current entry area
+               CMP     R1,#0                   ;Is this defined yet?
+               ADRNEL  R0,msg_errMultiEntry    ;Yes -- point to error
+               SWINE   OS_GenerateError        ;And report an error
+               STR     R14,[R0,#16]            ;Save our AREA number
+
+               ; --- Work out the entry offset ---
+
+               ADD     R14,R14,R14,LSL #2      ;Multiply index by 5
+               MOV     R14,R14,LSL #2          ;Multiply index by 4 (x20)
+               ADD     R14,R14,#20             ;Get offset of AREA start
+               LDR     R1,[R0,R14]             ;Load AREA start address
+               LDR     R2,be__percents         ;Find the % variables
+               LDR     R2,[R2,#('P'-'A')*4]    ;Get current location ptr
+               SUB     R1,R1,R2                ;Get offset into AREA
+               STR     R1,[R0,#20]             ;Save the entry offset
+
+90aof_entry    LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- aof_import ---
+;
+; On entry:    R0 == pointer to variable name
+;              R1 == pointer to symbol name
+;              R3 == attribute bits (not including bits 0,1)
+;
+; On exit:     --
+;
+; Use:         Imports a symbol, and sets the given variable to point to
+;              it.  If the symbol is already imported, another alias is
+;              set up, but no actual symbol is created.
+
+               EXPORT  aof_import
+aof_import     ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Save some registers
+               FSAVE   R0                      ;Save pointer to alias
+
+               ; --- See if it's already been IMPORTed ---
+
+               ADR     R2,aof__imports         ;Find the symbol table
+               LDMIA   R2,{R2,R5}              ;Load address and size
+               ADD     R5,R2,R5                ;Find limit address
+               LDR     R4,aof__objStrT         ;And find the string table
+               LDR     R6,aof__objSymT         ;And the symbol table
+
+00aof_import   CMP     R2,R5                   ;Reached the end yet?
+               BCS     %10aof_import           ;Yes -- carry on then
+               LDR     R0,[R2],#4              ;Load the symbol index
+               LDR     R0,[R6,R0]              ;Load the name offset
+               ADD     R0,R4,R0                ;Find the string address
+               BL      str_cmp                 ;Does the string match?
+               BNE     %00aof_import           ;No -- ignore it then
+
+               ; --- Found a match -- use this symbol then ---
+
+               LDR     R14,aof__imports        ;Find the base of the table
+               SUB     R2,R2,R14               ;Turn address into offset
+               B       %20aof_import           ;Rejoin the main routine
+
+               ; --- Couldn't find the symbol -- create it then ---
+
+10aof_import   MOV     R0,R1                   ;Point to the symbol name
+               BL      aof__addString          ;Put it in the string table
+               MOV     R2,R0                   ;Remember string's offset
+               ADR     R0,aof__objSymT         ;Point to symbol table
+               MOV     R1,#16                  ;Size of a symbol
+               BL      aof_ensure              ;Make that amount of space
+
+               ORR     R3,R3,#2                ;Get the symbol attributes
+               MOV     R4,#0                   ;Symbol has no sensible value
+               MOV     R5,#0                   ;Symbol has no area name
+               STMIA   R0,{R2-R5}              ;Save symbol definition
+
+               ; --- Now set up the imports table ---
+
+               SUB     R2,R0,R6                ;Get the symbol table offset
+               ADR     R0,aof__imports         ;Point to imports table
+               MOV     R1,#4                   ;Entries are 4 bytes each
+               BL      aof_ensure              ;Get the memory I want
+               STR     R2,[R0],#4              ;Save the symbol index
+
+               ; --- Work out the import entry offset ---
+
+               LDR     R2,aof__imports         ;Find the imports table base
+               SUB     R2,R0,R2                ;Find the table offset
+
+               ; --- Write this into the variable ---
+
+20aof_import   RSB     R2,R2,#&FD000000        ;Work out the dummy value
+               FLOAD   R0                      ;Get variable name back
+               BL      bTalk_create            ;Create the variable
+               BL      bTalk_store             ;Save the value in it
+
+               LDMFD   R13!,{R0-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- aof_iImport ---
+;
+; On entry:    R0 == WEAK flag
+;              R7 == address of workspace
+;              R8-R12 set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: name$,alias$
+;
+; Use:         Imports a symbol name$, and makes the variable whose name
+;              is in alias$ refer to it.
+
+               EXPORT  aof_iImport
+aof_iImport    ROUT
+
+               STMFD   R13!,{R0,R1,R9,R10,R12,R14}
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Get my workspace address
+               BL      aof_firstPass           ;Is this the first pass?
+               BCC     %90aof_iImport          ;No -- ignore it then
+
+               MOV     R3,R0,LSL #4            ;Set up WEAK bit
+               BL      str_buffer              ;Find a string buffer
+               BL      bas_argString           ;Read variable name string
+               MOV     R0,R1                   ;Pass this in R0
+               BL      str_buffer              ;Find another string buffer
+               BL      bas_argString           ;Read symbol name string
+               BL      aof_import              ;Import this symbol
+
+90aof_iImport  LDMFD   R13!,{R0,R1,R9,R10,R12,PC}^
+
+               LTORG
+
+; --- aof__findArea ---
+;
+; On entry:    R0 == index of AREA
+;
+; On exit:     R0 == pointer to AREA description in header chunk
+;
+; Use:         Locates a given AREA's data.
+
+aof__findArea  ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,aof__objHead        ;Find the header chunk
+               ADD     R0,R0,R0,LSL #2         ;Multiply index by 5
+               ADD     R0,R14,R0,LSL #2        ;And again by 4 (x20)
+               ADD     R0,R0,#4                ;Add on a bit to find block
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- aof__findSym ---
+;
+; On entry:    R0 == symbol value
+;
+; On exit:     CS if symbol recognised, and
+;                VS if symbol is external reference, and
+;                  R0 == index of symbol in symbol table
+;                  R1 corrupted
+;                else VC if symbol is internal reference, and
+;                  R0 == offset of symbol within AREA
+;                  R1 == AREA index
+;              else CC if symbol is absolute (i.e. not recognised) and
+;                R0 preserved
+;                R1 corrupted
+;
+; Use:         Looks up a 32-bit value and tries to interpret it as a
+;              symbol, returning information about it as required.  This
+;              routine attempts to be as quick as it can, but it can't
+;              promise anything.
+
+aof__findSym   ROUT
+
+               ; --- Make sure it can be anything other than absolute ---
+
+               MOV     R1,R0,LSR #24           ;Get the top byte
+               CMP     R1,#&FC                 ;Is this our magic range?
+               BICNES  PC,R14,#C_flag          ;No -- clear C and exit
+
+               ; --- See if it's an external symbol ---
+
+               LDR     R1,aof__objSymT+4       ;Get size of symbol table
+               RSB     R1,R1,#&FD000000        ;Work out lowest import addr
+               CMP     R0,R1                   ;Is this an imported symbol?
+               BCS     %50aof__findSym         ;Yes -- find symbol index
+
+               ; --- See if it's an internal reference ---
+
+               LDR     R1,aof__limit           ;Load the limit address
+               CMP     R0,R1                   ;Is this within the code?
+               BICCSS  PC,R14,#C_flag          ;No -- then ignore it
+
+               ; --- Work out which AREA it's in ---
+
+               BIC     R14,R14,#V_flag         ;Clear V for internal ref
+               ORR     R14,R14,#C_flag         ;Set C for symbol match
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               SUB     R0,R0,#&FC000000        ;Get the symbol's offset
+               MOV     R1,#1                   ;Start at index 1
+               LDR     R2,aof__objHead         ;Find the header chunk
+               ADD     R2,R2,#24               ;Find first AREA block
+10aof__findSym LDR     R14,[R2,#8]             ;Load the AREA's size
+               CMP     R0,R14                  ;Is this within the AREA?
+               LDMCCFD R13!,{R2,PC}^           ;Yes -- then return it
+               SUB     R0,R0,R14               ;Move into next AREA
+               ADD     R1,R1,#1                ;Increment AREA index
+               ADD     R2,R2,#20               ;Move to next AREA block
+               B       %10aof__findSym         ;And loop back round again
+
+               ; --- Find the appropriate symbol ---
+
+50aof__findSym RSB     R0,R0,#&FD000000        ;Find the import table index
+               LDR     R1,aof__imports         ;Find the import table
+               SUB     R0,R0,#4                ;Compensate for strangeness
+               LDR     R0,[R1,R0]              ;Load the symbol index
+               MOV     R0,R0,LSR #4            ;And divide by symbol size
+               ORRS    PC,R14,#C_flag + V_flag ;Return, setting C and V
+
+               LTORG
+
+; --- aof_export ---
+;
+; On entry:    R0 == STRONG flag
+;              R7 == pointer to workspace
+;              R8-R12 as set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: alias$,name$
+;
+; Use:         Exports the value held in the given alias as the symbol
+;              name$.
+
+               EXPORT  aof_export
+aof_export     ROUT
+
+               STMFD   R13!,{R0-R6,R9,R10,R12,R14}
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Find my workspace address
+               BL      aof_firstPass           ;Is this the first pass?
+               BCS     %90aof_export           ;Yes -- may not be set up
+               MOV     R3,R0,LSL #5            ;Keep the STRONG flag safe
+
+               ; --- Put the symbol name in the string table ---
+
+               BL      str_buffer              ;Get a string buffer
+               BL      bas_argString           ;Read the symbol name out
+               MOV     R0,R1                   ;Point to the symbol name
+               BL      aof__addString          ;Put it in the string table
+               MOV     R4,R0                   ;Remember this offset
+
+               ; --- Now find the symbol value ---
+
+               BL      str_buffer              ;Get a string buffer
+               BL      bas_argString           ;Read the string's value
+               MOV     R0,R1                   ;Point to the string
+               BL      bTalk_lvblnk            ;Find the lvalue
+               BL      bTalk_load              ;And load its value
+
+               ; --- Create a block for the symbol ---
+
+               ADR     R0,aof__objSymT         ;Point to the symbol table
+               MOV     R1,#16                  ;Make space for a symbol
+               BL      aof_ensure              ;Make sure there's space
+               MOV     R6,R0                   ;Remember this address
+
+               ; --- Now build the symbol ---
+
+               MOV     R0,R2                   ;Get the symbol value
+               BL      aof__findSym            ;Work out its meaning
+               BCC     %20aof_export           ;If it's absolute, skip on
+               ADRVSL  R0,msg_errExpImported   ;If imported, say it's silly
+               SWIVS   OS_GenerateError        ;And complain to the user
+
+               ; --- Create a program-relative symbol ---
+
+               MOV     R2,R4                   ;Get the symbol name offset
+               ORR     R3,R3,#3                ;Get the symbol attributes
+               MOV     R4,R0                   ;Get the symbol offset
+               MOV     R0,R1                   ;Put AREA index in R0
+               BL      aof__findArea           ;Find the AREA data
+               LDR     R5,[R0,#0]              ;Get the AREA's name offset
+               STMIA   R6,{R2-R5}              ;Save the symbol info
+               B       %90aof_export           ;Return to caller
+
+               ; --- Create an absolute symbol ---
+
+20aof_export   MOV     R2,R4                   ;Get the symbol name offset
+               ORR     R3,R3,#&07              ;Get the symbol attributes
+               MOV     R4,R0                   ;Get the symbol value
+               MOV     R5,#0                   ;Say that the AREA is 0
+               STMIA   R6,{R2-R5}              ;Save the symbol info
+
+90aof_export   LDMFD   R13!,{R0-R6,R9,R10,R12,PC}^
+
+               LTORG
+
+; --- aof_reloc ---
+;
+; On entry:    R7 == workspace address
+;
+; On exit:     --
+;
+; Use:         Marks the current address as being the start of a relocation
+;              block.  If a relocation block is current, this is a no-op.
+
+               EXPORT  aof_reloc
+aof_reloc      ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Find my workspace pointer
+               BL      insert_align            ;Word align current pos
+
+               ; --- Only accept reloc/noReloc directives on first pass ---
+
+               BL      aof_firstPass           ;Is this the first pass?
+               LDMCCFD R13!,{R0-R2,R12,PC}^    ;No -- do nothing then
+
+               ; --- Check that we're alternating states ---
+
+               LDR     R14,aof__relocCount     ;Load current counter
+               SUBS    R14,R14,#1              ;Decrement counter
+               STRGE   R14,aof__relocCount     ;If was >0, store it
+               LDMNEFD R13!,{R0-R2,R12,PC}^    ;If state still same, return
+
+               ; --- Check we need to do this ---
+               ;
+               ; If the last entry is at the current address, we remove it
+               ; and return.
+
+               LDR     R2,be__percents         ;Load the percents table
+               LDR     R2,[R2,#('O'-'A')*4]    ;Load current real address
+               ADR     R0,aof__noReloc         ;Point to noReloc table
+               LDMIA   R0,{R1,R14}             ;Load size and address
+               SUBS    R14,R14,#4              ;Find previous entry
+               BLT     %10aof_reloc            ;If none defined, skip on
+               LDR     R1,[R1,R14]             ;Load the value out
+               CMP     R1,R2                   ;Do the entries match?
+               STREQ   R14,aof__noReloc+4      ;Yes -- decrement used size
+               LDMEQFD R13!,{R0-R2,R12,PC}^    ;And return to caller
+
+               ; --- Add in the item ---
+
+10aof_reloc    MOV     R1,#4                   ;Entries are 4 bytes each
+               BL      aof_ensure              ;Extend the table
+               STR     R2,[R0],#4              ;Save this in the table
+
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- aof_noReloc ---
+;
+; On entry:    R7 == workspace address
+;
+; On exit:     --
+;
+; Use:         Marks the current address as being the start of a non-
+;              relocation block.  If a non-relocation block is current,
+;              this is a no-op.
+
+               EXPORT  aof_noReloc
+aof_noReloc    ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Find my workspace pointer
+               BL      insert_align            ;Word align current pos
+
+               ; --- Only accept reloc/noReloc directives on first pass ---
+
+               BL      aof_firstPass           ;Is this the first pass?
+               LDMCCFD R13!,{R0-R2,R12,PC}^    ;No -- do nothing then
+
+               ; --- Check that we're alternating states ---
+
+               LDR     R14,aof__relocCount     ;Load current counter value
+               ADD     R14,R14,#1              ;Increment the value
+               STR     R14,aof__relocCount     ;Save value back again
+               CMP     R14,#1                  ;Was relocation enabled?
+               LDMNEFD R13!,{R0-R2,R12,PC}^    ;No -- return to caller
+
+               ; --- Check we need to do this ---
+               ;
+               ; If the last entry is at the current address, we remove it
+               ; and return.
+
+               LDR     R2,be__percents         ;Load the percents table
+               LDR     R2,[R2,#('O'-'A')*4]    ;Load current real address
+               ADR     R0,aof__noReloc         ;Point to noReloc table
+               LDMIA   R0,{R1,R14}             ;Load size and address
+               SUBS    R14,R14,#4              ;Find previous entry
+               BLT     %10aof_noReloc          ;If none defined, skip on
+               LDR     R1,[R1,R14]             ;Load the value out
+               CMP     R1,R2                   ;Do the entries match?
+               STREQ   R14,aof__noReloc+4      ;Yes -- decrement used size
+               LDMEQFD R13!,{R0-R2,R12,PC}^    ;And return to caller
+
+               ; --- Add in the item ---
+
+10aof_noReloc  MOV     R1,#4                   ;Entries are 4 bytes each
+               BL      aof_ensure              ;Extend the table
+               STR     R2,[R0],#4              ;Save this in the table
+
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- aof_save ---
+;
+; On entry:    R7 == workspace address
+;              R8-R12 set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: file$
+;
+; Use:         Saves the current AOF file.  It also resets all the AOF
+;              state, so that another AOF file can be built subsequently.
+
+               EXPORT  aof_save
+aof_save       ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save loads of registers
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Find my workspace pointer
+
+               BL      aof_firstPass           ;Is this the first pass?
+               ADRCSL  R0,msg_errNotDone       ;Yes -- point to error
+               SWICS   OS_GenerateError        ;And make an error
+
+               BL      lit_end                 ;Turn off the literal system
+
+               ADR     R0,aof__noReloc         ;Point to noReloc table
+               MOV     R1,#4                   ;Entries are 4 bytes each
+               BL      aof_ensure              ;Extend the table
+               MOV     R14,#-1                 ;Add a terminator
+               STR     R14,[R0],#4             ;Save this in the table
+
+               MOV     R0,#0                   ;Zero NOINIT size count
+               STMFD   R13!,{R0,R9,R10}        ;Save argument pointers
+
+               ; --- Build relocation directives ---
+               ;
+               ; Also fix up relocation counts for area defs
+
+               MOV     R11,#1                  ;Current AREA number
+               LDR     R10,aof__objHead        ;Find the header chunk
+               ADD     R10,R10,#24             ;Point to first AREA info
+               LDR     R9,aof__area            ;Load the number of AREAs
+               LDR     R8,aof__base            ;Find the code base address
+               LDR     R4,aof__noReloc         ;Find non-relocation block
+               LDR     R3,[R4],#4              ;Load next value out
+
+05aof_save     SUBS    R9,R9,#1                ;Decrement the AREA counter
+               BCC     %20aof_save             ;If all done, skip onwards
+               STMFD   R13!,{R9}               ;Save AREA counter
+               MOV     R9,R3                   ;Look after next reloc value
+               MOV     R7,#0                   ;No relocations created yet
+               LDR     R6,[R10,#8]             ;Load the AREA size
+               MOV     R5,#-4                  ;Start at offset 0
+
+               LDR     R14,[R10,#4]            ;Load AREA attributes
+               TST     R14,#&1000              ;Is it NOINITed?
+               BEQ     %10aof_save             ;No -- deal with normally
+
+               LDR     R14,[R13,#4]            ;Load current NOINIT size
+               ADD     R14,R14,R6              ;Add on size of this AREA
+               STR     R14,[R13,#4]            ;Save new size back again
+               ADD     R8,R8,R6                ;Move pointer past AREA
+               B       %19aof_save             ;And skip out relocations
+
+               ; --- Scan an AREA for relocations ---
+
+07aof_save     ADD     R6,R6,#4                ;Decremented down below
+               CMP     R8,R9                   ;Is this in reloc block?
+               LDRCS   R9,[R4],#4              ;Yes -- load next value
+               BCS     %10aof_save             ;And relocate data nicely
+
+               ADD     R14,R8,R6               ;Find end of AREA
+               CMP     R14,R9                  ;Any data to relocate?
+               ADDCC   R8,R8,R6                ;No -- skip on to AREA end
+               BCC     %19aof_save             ;And move to next AREA
+
+               SUB     R14,R9,R8               ;Find out how much to skip
+               ADD     R8,R8,R14               ;Move on AREA address
+               ADD     R5,R5,R14               ;And move on the offset
+               SUB     R6,R6,R14               ;And decrement AREA size
+               LDR     R9,[R4],#4              ;Load next reloc value
+
+10aof_save     SUBS    R6,R6,#4                ;Decrement AREA size
+               BCC     %19aof_save             ;If all done, move to next
+
+               CMP     R8,R9                   ;Is this in non-reloc block?
+               LDRCS   R9,[R4],#4              ;Yes -- load next value
+               BCS     %07aof_save             ;And skip on until reloc
+
+               LDR     R0,[R8],#4              ;Load the next word out
+               ADD     R5,R5,#4                ;Bump current offset
+
+               AND     R14,R0,#&0E000000       ;Get opcode field
+               CMP     R14,#&0A000000          ;Is it a branch or BL?
+               BEQ     %15aof_save             ;Yes -- handle this then
+
+               BL      aof__findSym            ;Try and interpret the value
+               BCC     %10aof_save             ;If no match, ignore it
+               BVS     %13aof_save             ;If symbol relocation, skip
+
+               ; --- Build an internal additive relocation ---
+
+               STR     R0,[R8,#-4]             ;Save offset back into code
+               SUB     R3,R1,#1                ;And the AREA index
+               ADR     R0,aof__objReloc        ;Point to relocation chunk
+               MOV     R1,#8                   ;Need 8 bytes for relocation
+               BL      aof_ensure              ;Make sure there's enough
+               ORR     R14,R3,#&82000000       ;Set up relocation info
+               STMIA   R0,{R5,R14}             ;Make the directive
+               ADD     R7,R7,#1                ;Bump the relocation count
+               B       %10aof_save             ;Go back round for more
+
+               ; --- Build a symbol additive relocation ---
+
+13aof_save     MOV     R14,#0                  ;Make word reference symbol
+               STR     R14,[R8,#-4]            ;By zeroing the word
+               MOV     R3,R0                   ;Look after symbol index
+               ADR     R0,aof__objReloc        ;Point to relocation chunk
+               MOV     R1,#8                   ;Need 8 bytes for relocation
+               BL      aof_ensure              ;Make sure there's enough
+               ORR     R14,R3,#&000A0000       ;Set up relocation info
+               STMIA   R0,{R5,R14}             ;Make the directive
+               ADD     R7,R7,#1                ;Bump the relocation count
+               B       %10aof_save             ;Go back round for more
+
+               ; --- Handle a B or BL instruction ---
+
+15aof_save     AND     R2,R0,#&FF000000        ;Get condition and type
+               BIC     R0,R0,#&FF000000        ;Get branch offset value
+               ADD     R0,R0,#2                ;Add on the required offset
+               LDR     R3,[R10,#16]            ;Load the AREA base address
+               ADD     R3,R3,R5                ;Add on current offset
+               ADD     R0,R3,R0,LSL #2         ;Work out branch destination
+               BL      aof__findSym            ;Look up the symbol type
+               BCC     %10aof_save             ;It's absolute -- ignore it
+               BVS     %17aof_save             ;It's symbol relative -- skip
+
+               ; --- Handle an internal PCRelative relocation ---
+
+               CMP     R1,R11                  ;Is it to this AREA?
+               BEQ     %10aof_save             ;Yes -- don't bother then
+
+               SUB     R0,R0,R3                ;Work out the branch offset
+               MOV     R0,R0,LSR #2            ;Shift it right by 2 nicely
+               SUB     R0,R0,#2                ;And account for pipeline
+               BIC     R0,R0,#&FF000000        ;Clear the top bits
+               ORR     R0,R0,R2                ;And put in old opcode bits
+               STR     R0,[R8,#-4]             ;Write this instruction back
+               SUB     R3,R1,#1                ;Look after AREA index
+               ADR     R0,aof__objReloc        ;Point to relocation chunk
+               MOV     R1,#8                   ;Need 8 bytes for relocation
+               BL      aof_ensure              ;Make sure there's enough
+               ORR     R14,R3,#&86000000       ;Set up relocation flags
+               STMIA   R0,{R5,R14}             ;Save relocation directive
+               ADD     R7,R7,#1                ;Bump the relocation count
+               B       %10aof_save             ;And try the next word
+
+               ; --- Handle a symbol PCRelative relocation ---
+
+17aof_save     STR     R2,[R8,#-4]             ;B/BL all bits zero
+               MOV     R3,R0                   ;Keep the symbol index
+               ADR     R0,aof__objReloc        ;Point to relocation chunk
+               MOV     R1,#8                   ;Need 8 bytes for relocation
+               BL      aof_ensure              ;Make sure there's enough
+               ORR     R14,R3,#&000E0000       ;Set up relocation flags
+               STMIA   R0,{R5,R14}             ;Save relocation directive
+               ADD     R7,R7,#1                ;Bump the relocation count
+               B       %10aof_save             ;And try the next word
+
+               ; --- Reached end of the AREA ---
+
+19aof_save     STR     R7,[R10,#12]            ;Save the relocation count
+               MOV     R14,#0                  ;A zero word
+               STR     R14,[R10,#16]           ;Write over reserved word
+               ADD     R10,R10,#20             ;Move to next AREA block
+               ADD     R11,R11,#1              ;Increment the AREA counter
+               MOV     R3,R9                   ;Look after noReloc address
+               LDMFD   R13!,{R9}               ;Load the AREA countdown
+               B       %05aof_save             ;And branch back for the rest
+
+               ; --- Work out chunk file header format ---
+               ;
+               ; Pointless comment for separation, 'cos Tim said so.
+
+20aof_save     LDMFD   R13!,{R4}               ;Load NOINIT size
+               SUB     R13,R13,#5*4*4 + 3*4    ;Allocate space from stack
+               MOV     R14,R13                 ;Point to base of this area
+
+               LDR     R0,=&C3CBC6C5           ;Strange magic guard word
+               MOV     R1,#5                   ;We have 5 chunks
+               MOV     R2,#5                   ;We will always have 5 chunks
+               STMIA   R14!,{R0-R2}            ;Save this away
+
+               LDR     R0,aof__objName         ;Load string `OBJ_'
+               MOV     R2,#5*4*4 + 3*4         ;Where the chunks start
+
+               ; --- Set up the OBJ_IDFN entry ---
+
+               LDR     R1,aof__idfnName        ;Load string `IDFN'
+               MOV     R3,# ? aof__objIdfn     ;Find length of identifier
+               STMIA   R14!,{R0-R3}            ;Save chunk information
+               ADD     R2,R2,R3                ;Work out next offset
+               ADD     R2,R2,#3                ;Size may not be word aligned
+               BIC     R2,R2,#3                ;It is now
+
+               ; --- Set up the OBJ_HEAD entry ---
+
+               LDR     R1,aof__headName        ;Load string `HEAD'
+               LDR     R3,aof__objHead+4       ;Point to header anchor
+               STMIA   R14!,{R0-R3}            ;Save chunk information
+               ADD     R2,R2,R3                ;Work out next offset
+
+               ; --- Set up the OBJ_AREA entry ---
+
+               LDR     R1,aof__areaName        ;Load string `AREA'
+               LDR     R3,aof__objReloc+4      ;Load size of reloc block
+               SUB     R3,R3,R4                ;Subtract NOINIT size
+               LDR     R4,aof__limit           ;Load end of code
+               BIC     R4,R4,#&FF000000        ;Mask off strange marker bits
+               ADD     R3,R3,R4                ;And work out chunk size
+
+               STMIA   R14!,{R0-R3}            ;Save chunk information
+               ADD     R2,R2,R3                ;Work out next offset
+
+               ; --- Set up the OBJ_SYMT entry ---
+
+               LDR     R1,aof__symTName        ;Load string `SYMT'
+               LDR     R3,aof__objSymT+4       ;Point to table anchor
+               STMIA   R14!,{R0-R3}            ;Save chunk information
+               ADD     R2,R2,R3                ;Work out next offset
+
+               ; --- Set up the OBJ_STRT entry ---
+
+               LDR     R1,aof__strTName        ;Load string `STRT'
+               LDR     R3,aof__objStrT+4       ;Point to table anchor
+               STMIA   R14!,{R0-R3}            ;Save chunk information
+               ADD     R2,R2,R3                ;Work out next offset
+               ADD     R2,R2,#3                ;Size may not be word aligned
+               BIC     R2,R2,#3                ;It is now
+
+               ; --- Open the output file ---
+
+               LDMIA   R14,{R9,R10}            ;Load BASIC's arguments
+               BL      str_buffer              ;Find a string buffer
+               BL      bas_argString           ;Copy the name string here
+               MOV     R10,R1                  ;Look after name pointer
+               MOV     R0,#&8C                 ;Make lots of errors
+               SWI     OS_Find                 ;Open the file
+               MOV     R11,R0                  ;Look after the file handle
+
+               ; --- Write individual chunks to output file ---
+
+               MOV     R0,#2                   ;Write bytes to file
+               MOV     R1,R11                  ;Get the file handle
+               MOV     R2,R13                  ;Point to header block
+               MOV     R3,#5*4*4 + 3*4         ;Size of the header block
+               SWI     XOS_GBPB                ;Write that out to the file
+               BVS     %90aof_save             ;If that failed, tidy up
+
+               ADR     R2,aof__objIdfn         ;Point to identification str
+               MOV     R3,# ? aof__objIdfn     ;And read the length of it
+               ADD     R3,R3,#3                ;Word align this size
+               BIC     R3,R3,#3                ;To keep everything nice
+               SWI     XOS_GBPB                ;Write that out to the file
+               BVS     %90aof_save             ;If that failed, tidy up
+
+               ; --- Set up the header and write it ---
+
+               ADR     R2,aof__objHead         ;Point to header chunk data
+               LDMIA   R2,{R2,R3}              ;Load address and size
+               LDR     R14,aof__area           ;Get the number of AREAs
+               STR     R14,[R2,#8]             ;Save this in the header
+               LDR     R14,aof__objSymT+4      ;Load symbol table size
+               MOV     R14,R14,LSR #4          ;Divide by symbol block size
+               STR     R14,[R2,#12]            ;Save this in the header
+               SWI     XOS_GBPB                ;Write that out to the file
+               BVS     %90aof_save             ;If that failed, tidy up
+
+               ; --- Write the AREA chunk (yuk) ---
+
+               LDR     R5,aof__base            ;Find AREA data base address
+               LDR     R6,aof__objHead         ;Find the header chunk
+               ADD     R6,R6,#24               ;Find the first AREA block
+               LDR     R7,aof__objReloc        ;Find the relocation chunk
+               LDR     R8,aof__area            ;Get the AREAs counter
+
+50aof_save     SUBS    R8,R8,#1                ;Decrement AREA counter
+               BCC     %60aof_save             ;If all done, skip onwards
+
+               LDR     R14,[R6,#4]             ;Load AREA attributes
+
+               MOV     R2,R5                   ;Point to AREA base
+               LDR     R3,[R6,#8]              ;Load AREA size
+               ADD     R5,R5,R3                ;Move on the AREA pointer
+               TST     R14,#&1000              ;Should we include the data?
+               SWIEQ   XOS_GBPB                ;Write bytes to file
+               BVS     %90aof_save             ;If that failed, tidy up
+
+               MOV     R2,R7                   ;Point to relocation data
+               LDR     R3,[R6,#12]             ;Load number of relocations
+               MOV     R3,R3,LSL #3            ;Multiply by directive size
+               ADD     R7,R7,R3                ;Move on relocation pointer
+               TST     R14,#&1000              ;Should we include the data?
+               SWIEQ   XOS_GBPB                ;Write bytes to file
+               BVS     %90aof_save             ;If that failed, tidy up
+
+               ADD     R6,R6,#20               ;Move on to next AREA
+               B       %50aof_save             ;And go round for the rest
+
+               ; --- And now for the rest ---
+
+60aof_save     ADR     R2,aof__objSymT         ;Point to symbol table data
+               LDMIA   R2,{R2,R3}              ;Load address and size
+               SWI     XOS_GBPB                ;Write that out to the file
+               BVS     %90aof_save             ;If that failed, tidy up
+
+               ADR     R2,aof__objStrT         ;Point to string table data
+               LDMIA   R2,{R2,R3}              ;Load address and size
+               STR     R3,[R2,#0]              ;Fill in the size word
+               ADD     R3,R3,#3                ;Word align this size
+               BIC     R3,R3,#3                ;To keep everything nice
+               SWI     XOS_GBPB                ;Write that out to the file
+               BVS     %90aof_save             ;If that failed, tidy up
+
+               ; --- Close the file ---
+
+               MOV     R0,#0                   ;Close a file
+               MOV     R1,R11                  ;Get the file handle
+               SWI     OS_Find                 ;Close the file
+               ADD     R13,R13,#5*4*4 + 3*4    ;Reclaim that stack space
+
+               MOV     R0,#9                   ;Stamp the file
+               MOV     R1,R10                  ;Point to the filename
+               SWI     OS_File                 ;Update the datestamp
+
+               ; --- Free all of our flex blocks ---
+
+               ADR     R0,aof__objHead         ;Point to header anchor
+               BL      flex_free               ;Free it
+               ADR     R0,aof__objSymT         ;Point to symbol table anchor
+               BL      flex_free               ;Free it
+               ADR     R0,aof__objStrT         ;Point to string table anchor
+               BL      flex_free               ;Free it
+               ADR     R0,aof__objReloc        ;Point to reloc chunk anchor
+               BL      flex_free               ;Free it
+               ADR     R0,aof__imports         ;Point to import table anchor
+               BL      flex_free               ;Free it
+               ADR     R0,aof__noReloc         ;Point to non-reloc anchor
+               BL      flex_free               ;Free it
+               MOV     R14,#0                  ;Say we're now happy again
+               STR     R14,aof__objHead        ;By zeroing header pointer
+               BL      flex_compact            ;Ensure heap is compacted
+
+               ADD     R13,R13,#8              ;Skip past saved R9, R10
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller finally
+
+               ; --- Something went wrong during the write ---
+
+90aof_save     MOV     R9,R0                   ;Keep the error pointer
+               MOV     R0,#0                   ;Close the file
+               MOV     R1,R11                  ;Get the file handle
+               SWI     OS_Find                 ;Try hard to close the file
+               MOV     R0,#6                   ;Delete named object
+               MOV     R1,R10                  ;Point to the file name
+               SWI     OS_File                 ;Delete it happily
+               MOV     R0,R9                   ;Point to the error again
+               SWI     OS_GenerateError        ;And raise the error
+
+aof__objName   DCB     "OBJ_"
+aof__idfnName  DCB     "IDFN"
+aof__headName  DCB     "HEAD"
+aof__areaName  DCB     "AREA"
+aof__symTName  DCB     "SYMT"
+aof__strTName  DCB     "STRT"
+
+aof__objIdfn   DCB     "Straylight Basic Assembler Supplement v. 1.00",0
+               ALIGN
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/s/bas b/StraySrc/Libraries/BAS/src/s/bas
new file mode 100644 (file)
index 0000000..0b8db94
--- /dev/null
@@ -0,0 +1,260 @@
+;
+; bas.s
+;
+; Base code for BAS
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.aofGen
+               GET     sh.basicEnv
+               GET     sh.basTalk
+               GET     sh.fastMove
+               GET     sh.flex
+               GET     sh.get
+               GET     sh.insert
+               GET     sh.lit
+               GET     sh.messages
+               GET     sh.string
+               GET     sh.vars
+               GET     sh.workspace
+
+;----- Branch table header --------------------------------------------------
+
+               AREA    |!BAS$$Header|,CODE,READONLY
+
+               B       bas__workSize           ;Find workspace requirements
+               B       bas__init               ;Initialise workspace
+               B       aof_init                ;Initialise AOF generation
+               B       aof_pass                ;Signal start of new pass
+               B       aof_iImport             ;Import a symbol
+               B       aof_export              ;Export a symbol
+               B       get                     ;Read in a header file
+               B       aof_area                ;Define start of new area
+               B       aof_reloc               ;Mark start of reloc area
+               B       aof_noReloc             ;Mark start of non-reloc area
+               B       aof_entry               ;Define entry point of image
+               B       aof_save                ;Save AOF file
+               B       insert_align            ;Align and add zeroes
+               B       insert_reserve          ;Reserve lots of zeroes
+               B       lit_add                 ;Add data to literal pool
+               B       lit_ltorg               ;Insert a literal pool
+               B       bas__saveOpt            ;Read the current OPT value
+               B       bas__restoreOpt         ;Restore the OPT value
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |BAS$$Code|,CODE,READONLY
+
+; --- bas__workSize ---
+;
+; On entry:    --
+;
+; On exit:     R0 == size of workspace required (picked up by USR())
+;
+; Use:         Allows the BASIC component to allocate a workspace block of
+;              the right size.  This will then be passed to us in R7 when
+;              we get called later.
+
+bas__workSize  ROUT
+
+               LDR     R0,=bas_wSize           ;Get the workspace size
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- bas__init ---
+;
+; On entry:    R7 == address of workspace
+;              R8-R14 from BASIC's CALL
+;
+; On exit:     --
+;
+; Use:         Initialises the code component of BAS.
+
+bas__init      ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Point to my workspace
+
+               ; --- Fill in the BASIC environment things ---
+
+               STR     R8,be__argp             ;Save BASIC's workspace addr
+               STR     R14,be__interface       ;And save the interface ptr
+
+               ; --- Set up some special bits ---
+
+               MOV     R14,#0                  ;Set up string's buffer
+               STR     R14,str__buffNum        ;Tell it to use the first one
+               STR     R14,aof__objHead        ;We're not generating AOF
+
+               ; --- Work out address of A% ---
+
+               ADR     R0,bas__aPercent        ;Find the variable name
+               BL      bTalk_lvblnk            ;Find the address of it
+               STR     R0,be__percents         ;Save this address
+
+               ; --- Start up our memory manager ---
+
+               BL      flex_init               ;Initialise flex
+               BL      vars_set                ;Set up register names etc.
+
+               LDMFD   R13!,{R12,PC}^          ;And return to caller
+
+bas__aPercent  DCB     "A%",0
+
+               LTORG
+
+; --- bas__saveOpt ---
+;
+; On entry:    R8 == BASIC's ARGP pointer
+;
+; On exit:     R0 == current value of OPT
+;
+; Use:         Returns the current value of BASIC's assembler options.  This
+;              is handy, because BASIC doesn't seem terribly good at
+;              handling this by itself.  The value -38 used here is stolen
+;              from BAX.
+
+bas__saveOpt   ROUT
+
+               LDRB    R0,[R8,#-38]            ;Load the OPT value
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- bas__restoreOpt ---
+;
+; On entry:    R0 == OPT value to restore
+;              R8 == BASIC's ARGP pointer
+;
+; On exit:     --
+;
+; Use:         Sets the value of BASIC's assembler options to the given
+;              value.  This is necessary because BASIC isn't terribly good
+;              at nesting the option values.
+
+bas__restoreOpt        ROUT
+
+               STRB    R0,[R8,#-38]            ;Store the OPT value
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- bas_argString ---
+;
+; On entry:    R1 == address of destination buffer
+;              R9 == pointer to argument entry
+;              R10 == number of arguments left
+;
+; On exit:     R9 increased by 8
+;              R10 decreased by 1
+;
+; Use:         Reads a string argument into a buffer and null terminates
+;              it sensibly so we can use it.
+
+               EXPORT  bas_argString
+bas_argString  ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               SUBS    R10,R10,#1              ;Decrement R10 as promised
+               BCC     bas_badCall             ;If there wasn't one, die
+               LDR     R14,[R9,#4]             ;Load the argument type
+               CMP     R14,#&81                ;Is this a $(addr) string?
+               BEQ     %50bas_argString        ;Yes -- handle that then
+               CMP     R14,#&80                ;Is it a normal string?
+               BNE     bas_badCall             ;No -- the make an error
+
+               ; --- Handle a normal string variable ---
+
+               MOV     R0,R1                   ;Point to caller's buffer
+               LDR     R3,[R9],#8              ;Load the string pointer
+               ANDS    R14,R3,#3               ;Get non-word-alignedness
+               BIC     R1,R3,#3                ;Word align anyway
+               LDMIA   R1,{R1,R2}              ;Load the possible bytes
+               MOV     R14,R14,LSL #3          ;Convert bytes to bits
+               MOVNE   R1,R1,LSR R14           ;Shove the bytes down
+               RSB     R14,R14,#32             ;Get the other shift size
+               ORRNE   R1,R1,R2,LSL R14        ;And work that out
+               LDRB    R2,[R3,#4]              ;Load the string length
+               BL      fastMove                ;(This is overkill)
+               MOV     R14,#0                  ;Terminate the string
+               STRB    R14,[R0,R2]             ;Do this nicely
+               B       %90bas_argString        ;And return to caller
+
+               ; --- Handle a $(addr) type string ---
+
+50bas_argString        MOV     R2,R1                   ;Keep the buffer pointer
+               MOV     R0,R1                   ;And point to it for str_cpy
+               LDR     R1,[R9],#8              ;Point to caller's string
+               BL      str_cpy                 ;Copy it over (and null term)
+
+90bas_argString        LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- bas_badCall ---
+;
+; On entry:    --
+;
+; On exit:     Generates an error
+;
+; Use:         Generates an error about bad arguments.  It saves space to
+;              just have this here.
+
+               EXPORT  bas_badCall
+bas_badCall    ROUT
+
+               ADRL    R0,msg_errBadArg
+               SWI     OS_GenerateError
+
+               LTORG
+
+; --- bas_noMem ---
+;
+; On entry:    --
+;
+; On exit:     Generates an error
+;
+; Use:         Generates an error about not having any memory left.
+
+
+               EXPORT  bas_noMem
+bas_noMem      ROUT
+
+               ADRL    R0,msg_errNoMoreMem
+               SWI     OS_GenerateError
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/s/basTalk b/StraySrc/Libraries/BAS/src/s/basTalk
new file mode 100644 (file)
index 0000000..12d11d8
--- /dev/null
@@ -0,0 +1,285 @@
+;
+; basTalk.s
+;
+; Interface to BASIC's weird routines
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.basicEnv
+               GET     sh.messages
+               GET     sh.string
+               GET     sh.workspace
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |BAS$$Code|,CODE,READONLY
+
+; --- bTalk_lvblnk ---
+;
+; On entry:    R0 == pointer to variable name to find (not tokenised)
+;
+; On exit:     R0 == address of lvalue
+;              R1 == type of lvalue
+;
+; Use:         Tries to locate the given BASIC variable.
+
+               EXPORT  bTalk_lvblnk
+bTalk_lvblnk   ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save some registers
+
+               ; --- Make sure name is tokenised ---
+
+               BL      str_buffer              ;Get a string buffer nicely
+               MOV     R2,R1                   ;This is the destination
+               MOV     R11,R2                  ;Keep a pointer to it
+               MOV     R1,R0                   ;Point to his source string
+               BL      bTalk_match             ;Tokenise the variable name
+
+               ; --- Find the lvalue ---
+
+               LDR     R7,be__interface        ;Point to EIB
+               LDR     R8,be__argp             ;Get argp pointer
+               LDR     R12,be__line            ;Get line pointer
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R7,#bEnv_lvblnk      ;Call BASIC's strange routine
+               MOVNE   R1,R9                   ;Get variable type in R1
+               ADDNE   R13,R13,#8              ;Don't keep R0, R1 saved
+               LDMNEFD R13!,{R2-R12,PC}^       ;Return if found
+
+               ; --- Complain about duff variable names ---
+
+bTalk__badName LDR     R12,[R13,#48]           ;Find workspace (good plan)
+               LDR     R2,[R13,#0]             ;Point to the variable name
+               ADRCSL  R0,msg_errBadLValue     ;If very bad, point to error
+               ADRCCL  R0,msg_errVarNotFound   ;Otherwise say couldn't find
+               BL      str_error               ;Build appropriate error
+               SWI     OS_GenerateError        ;And report it nicely
+
+               LTORG
+
+; --- bTalk_create ---
+;
+; On entry:    R0 == pointer to name of variable
+;
+; On exit:     R0 == address of variable lvalue
+;              R1 == type of variable created
+;
+; Use:         Creates a variable, if it doesn't already exist.  Otherwise
+;              a pointer to the existing variable is returned.
+
+               EXPORT  bTalk_create
+bTalk_create   ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save too many registers
+
+               ; --- Make sure name is tokenised ---
+
+               BL      str_buffer              ;Get a string buffer nicely
+               MOV     R2,R1                   ;This is the destination
+               MOV     R11,R2                  ;Keep a pointer to it
+               MOV     R1,R0                   ;Point to his source string
+               BL      bTalk_match             ;Tokenise the variable name
+
+               ; --- Find the lvalue ---
+
+               LDR     R7,be__interface        ;Point to EIB
+               LDR     R8,be__argp             ;Get argp pointer
+               LDR     R12,be__line            ;Get line pointer
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R7,#bEnv_lvblnk      ;Call BASIC's strange routine
+               MOVNE   R1,R9                   ;Get variable type in R1
+               ADDNE   R13,R13,#8              ;Don't keep R0, R1 saved
+               LDMNEFD R13!,{R2-R12,PC}^       ;Return if found
+               BCS     bTalk__badName          ;Contort rampantly on error
+
+               ; --- Wasn't there -- try to create it ---
+
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R7,#bEnv_create      ;Call CREATE routine
+               MOV     R1,R9                   ;Get the variable type
+               ADD     R13,R13,#8              ;Don't keep R0, R1 saved
+               LDMFD   R13!,{R2-R12,PC}^       ;Return pristine variable
+
+               LTORG
+
+; --- bTalk_store ---
+;
+; On entry:    R0 == lvalue in which to store
+;              R1 == type of lvalue
+;              R2 == (integer) value to store
+;
+; On exit:     --
+;
+; Use:         Stores an integer value in a BASIC variable.  The value is
+;              converted to floating point if required (without loss of
+;              precision).
+
+               EXPORT  bTalk_store
+bTalk_store    ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save too many registers
+               MOV     R4,R0                   ;Point to the lvalue
+               MOV     R5,R1                   ;Get the lvalue's type
+               MOV     R0,R2                   ;Put value in R0
+               MOV     R9,#&40000000           ;It's an integer, Jim
+               LDR     R7,be__interface        ;Find the EIB
+               LDR     R8,be__argp             ;Get BASIC's workspace
+               LDR     R12,be__line            ;Tell it which line we're on
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R7,#bEnv_storea      ;Save the values away
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- bTalk_load ---
+;
+; On entry:    R0 == address of lvalue
+;              R1 == type of lvalue
+;
+; On exit:     R2 == integer value of lvalue
+;
+; Use:         Loads an integer variable from an lvalue.
+
+               EXPORT  bTalk_load
+bTalk_load     ROUT
+
+               STMFD   R13!,{R0,R1,R3-R12,R14} ;Save lots of registers
+
+               ; --- Load value from register ---
+
+               LDR     R8,be__argp             ;Load BASIC's workspace
+               LDR     R7,be__interface        ;Find the EIB
+               LDR     R12,be__line            ;And get the current LINE
+
+               MOV     R9,R1                   ;Get the lvalue's type
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R7,#bEnv_varind      ;Load the variable value
+               TEQ     R9,#0                   ;Was it a string?
+               BEQ     %80bTalk_load           ;Yes -- this is evil
+
+               ; --- Now convert floating point to integer ---
+
+               MOVMI   R14,PC                  ;Set up return address
+               ADDMI   PC,R7,#bEnv_fix         ;And fix it into R0
+
+               ; --- Return the value ---
+
+               MOV     R2,R0                   ;Put value in R2 nicely
+               LDMFD   R13!,{R0,R1,R3-R12,PC}^ ;Return to caller
+
+               ; --- Silly user gave us a string ---
+
+80bTalk_load   ADRL    R0,msg_errOddString     ;Point to error
+               SWI     OS_GenerateError        ;And tell the world
+
+               LTORG
+
+; --- bTalk_eval ---
+;
+; On entry:    R1 == pointer to a control-terminated string
+;
+; On exit:     R0 == value of expression
+;
+; Use:         Evaluates a BASIC expression.
+
+               EXPORT  bTalk_eval
+bTalk_eval     ROUT
+
+               STMFD   R13!,{R1-R12,R14}       ;Save some registers
+               MOV     R0,R1                   ;Look after string address
+               BL      str_buffer              ;Get a string buffer
+               MOV     R2,R1                   ;This is destination buffer
+               MOV     R1,R0                   ;Point to source buffer
+               BL      bTalk_match             ;Tokenise the string nicely
+
+               ; --- Evaluate the expression ---
+
+               LDR     R8,be__argp             ;Load BASIC's workspace
+               LDR     R7,be__interface        ;Find the interface block
+               LDR     R12,be__line            ;Load current LINE value
+               MOV     R11,R2                  ;Point to tokenised expr
+               STMFD   R13!,{R7}               ;Save environment pointer
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R7,#bEnv_expr        ;Get BASIC to evaluate it
+               LDMFD   R13!,{R7}               ;Restore environment pointer
+               BEQ     %80bTalk_eval           ;If string, make an error
+
+               MOVMI   R14,PC                  ;If floating point, fix it
+               ADDMI   PC,R7,#bEnv_fix         ;To get an integer
+
+               LDMFD   R13!,{R1-R12,PC}^       ;And return value to caller
+
+               ; --- Expression gave us a string ---
+
+80bTalk_eval   ADRL    R0,msg_errOddString     ;Point to error message
+               SWI     OS_GenerateError        ;And raise an error nicely
+
+               LTORG
+
+; --- bTalk_match ---
+;
+; On entry:    R1 == ctrl terminated string
+;              R2 == destination pointer
+;
+; On exit:     --
+;
+; Use:         Tokenises the given sting, and puts the result in the
+;              destination buffer given.
+
+               EXPORT  bTalk_match
+bTalk_match    ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Store some registers
+
+               ; --- BASIC wants string CR terminated ---
+
+               MOV     R3,R1                   ;Point to source string
+00bTalk_match  LDRB    R14,[R3],#1             ;Load the next byte
+               CMP     R14,#32                 ;Is this the end of it?
+               BCS     %00bTalk_match          ;No -- go round again then
+               MOV     R14,#13                 ;Want it CR terminated
+               STRB    R14,[R3,#-1]            ;Save over terminator
+
+               ; --- Get BASIC to do tokenising ---
+
+               MOV     R3,#0                   ;Parse an lvalue
+               MOV     R4,#0                   ;Without line numbers
+               LDR     R5,be__interface        ;Get the EIB
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R5,#bEnv_match       ;Call match routine
+               LDMFD   R13!,{R0-R5,PC}^        ;Return with gleefulness
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/s/fastMove b/StraySrc/Libraries/BAS/src/s/fastMove
new file mode 100644 (file)
index 0000000..559d930
--- /dev/null
@@ -0,0 +1 @@
+ LNK libs:s.fastMove
diff --git a/StraySrc/Libraries/BAS/src/s/flex b/StraySrc/Libraries/BAS/src/s/flex
new file mode 100644 (file)
index 0000000..eb81eaa
--- /dev/null
@@ -0,0 +1,21 @@
+;
+; flex.s
+;
+; Flexible memory handling
+;
+; © 1998 Straylight
+;
+
+               GET     libs:header
+               GET     sh.workspace
+
+               GBLL    OPT_STANDALONE
+               GBLL    OPT_STACK
+
+               MACRO
+$label         WSPACE  $addr,$reg
+               ; nothing
+               MEND
+
+               LNK     libs:s.flex
+
diff --git a/StraySrc/Libraries/BAS/src/s/get b/StraySrc/Libraries/BAS/src/s/get
new file mode 100644 (file)
index 0000000..1a42574
--- /dev/null
@@ -0,0 +1,648 @@
+;
+; get.s
+;
+; Parsing of simple objasm header files
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.aofGen
+               GET     sh.bas
+               GET     sh.basTalk
+               GET     sh.flex
+               GET     sh.string
+               GET     sh.workspace
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |BAS$$Code|,CODE,READONLY
+
+; --- get ---
+;
+; On entry:    R7 == pointer to workspace
+;              R8-R12 as set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: filename
+;
+; Use:         Parses a Straylight format objasm header file and sets up
+;              BASIC variables appropriately.
+
+               EXPORT  get
+get            ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save some registers
+               STR     R12,[R7,#:INDEX:be__line] ;Save BASIC's LINE value
+               MOV     R12,R7                  ;Set up my workspace pointer
+
+               ; --- Find out if we need to do anything ---
+
+               BL      aof_firstPass           ;Is this the first pass?
+               LDMCCFD R13!,{R0-R12,PC}^       ;No -- then return to caller
+
+               ; --- Load the file into a flex block ---
+
+               BL      str_buffer              ;Find a string buffer
+               BL      bas_argString           ;Read a string argument
+               MOV     R7,R1                   ;Look after this pointer
+               MOV     R0,#17                  ;Read information about file
+               SWI     OS_File                 ;Find out the file info
+               TST     R0,#1                   ;Is this a file?
+               BEQ     %80get                  ;No -- then report error
+
+               MOV     R0,#0                   ;Clear a flags word
+               STR     R0,[R13,#-4]!           ;Save it on the stack
+               SUB     R13,R13,#8              ;Make a flex anchor
+               MOV     R0,R13                  ;Point at the anchor
+               ADD     R1,R4,#1                ;Bump file size by 1
+               BL      flex_alloc              ;Allocate lots of memory
+               BCS     bas_noMem               ;If it failed, complain
+
+               MOV     R0,#16                  ;Load a file name
+               MOV     R1,R7                   ;Point to the file name
+               LDR     R2,[R13,#0]             ;Load the flex pointer
+               MOV     R3,#0                   ;Load file right here
+               SWI     XOS_File                ;Load the file
+               BVS     %90get                  ;If it failed, tidy up
+
+               ; --- Set up for parsing the file ---
+               ;
+               ; Register allocation:
+               ;
+               ;   R12 == workspace
+               ;   R11 == pointer to end of file
+               ;   R10 == pointer to current position
+               ;   R9 == pointer to next line start
+
+               MOV     R14,#&10                ;Put a newline at the end
+               LDR     R9,[R13,#0]             ;Load flex block base
+               STRB    R14,[R9,R4]             ;Save at end of the file
+               ADD     R11,R9,R4               ;Find the end of the file
+
+               ; --- Loop throught the lines of the file ---
+
+10get          BL      get__nextLine           ;Get the next line
+               BCS     %70get                  ;If now finished, return
+
+               ; --- See if there's a comment here ---
+
+               MOV     R8,R10                  ;Remember current position
+               BL      get__byte               ;Read a character
+               BCS     %10get                  ;If end of line, loop back
+               MOVMI   R8,#0                   ;If whitespace, no label
+               BMI     %12get                  ;And skip on a little
+               CMP     R0,#';'                 ;Is this a line comment?
+               BEQ     %20get                  ;Yes -- may be active comment
+
+11get          BL      get__byte               ;Read a character
+               BPL     %11get                  ;And wait for whitespace
+
+               ; --- Skip whitespace and find opcode ---
+
+12get          MOV     R7,R10                  ;Remember current position
+               BL      get__byte               ;Read a character
+               BCS     %10get                  ;If end of line, loop back
+               BMI     %12get                  ;If whitespace, loop back
+
+               ; --- Find end of opcode ---
+
+13get          MOV     R6,R10                  ;Remember current position
+               BL      get__byte               ;Read a character
+               BPL     %13get                  ;And wait for whitespace
+               MOV     R14,#0                  ;Mark end of opcode
+               STRB    R14,[R6,#0]             ;Terminate opcode string
+
+               ; --- Attempt to match the opcode ---
+
+               MOV     R1,R7                   ;Point to the opcode
+               ADR     R0,get__table           ;Point to opcode table
+               BL      get__match              ;Try to find a match
+               MOV     R14,PC                  ;Set up return address
+               ADDCS   PC,PC,R0,LSL #2         ;Do dispatch table things
+               B       %10get                  ;And get the next line
+
+               ; --- The dispatch table ---
+
+               B       get__hash               ;Hash (#) directive
+               B       get__hat                ;Hat (^) directive
+               B       get__equ                ;EQU directive
+               B       get__equ                ;EQU directive
+               B       get__import             ;IMPORT dirctive
+               B       get__macro              ;MACRO directive
+               B       get__mend               ;MEND directive
+
+               ; --- The directive table ---
+
+get__table     DCB     "#",0
+               DCB     "^",0
+               DCB     "EQU",0
+               DCB     "*",0
+               DCB     "IMPORT",0
+               DCB     "MACRO",0
+               DCB     "MEND",0
+               DCB     0
+
+               ; --- Found an active comment ---
+               ;
+               ; We use active comments to give this specific parser
+               ; instructions, of which objasm should be blissfully
+               ; unaware.  This is used to load BASIC macro libraries
+               ; which we use instead of the objasm ones.
+
+20get          BL      get__byte               ;Read the next byte
+               BCS     %10get                  ;If end-of-line, move on
+               CMP     R0,#'+'                 ;Is it a BAS active comment?
+               BNE     %10get                  ;No -- ignore this line
+
+               ; --- Find start of directive ---
+
+21get          MOV     R7,R10                  ;Remember this position
+               BL      get__byte               ;Get another byte
+               BCS     %10get                  ;If end-of-line, ignore it
+               BMI     %21get                  ;If whitespace, skip on
+
+22get          MOV     R6,R10                  ;Remember end of directive
+               BL      get__byte               ;Get another byte
+               BPL     %22get                  ;If nonwhitespace, skip
+               MOV     R14,#0                  ;Null terminate the directive
+               STRB    R14,[R6,#0]             ;Save the null byte then
+
+               ; --- Call the correct directive ---
+
+               ADR     R0,get__actComm         ;Point to directive table
+               MOV     R1,R7                   ;Point to this directive
+               BL      get__match              ;Try to match the name
+               MOV     R14,PC                  ;Set up a return address
+               ADDCS   PC,PC,R0,LSL #2         ;Dispatch through the table
+               B       %10get                  ;And get the next line
+
+               ; --- The dispatch table ---
+
+               B       get__lib                ;Include BASIC macro lib
+
+               ; --- Active comment directives ---
+
+get__actComm   DCB     "LIB",0
+               DCB     0
+
+               ; --- Close the file and return ---
+
+70get          MOV     R0,R13                  ;Point to flex anchor
+               BL      flex_free               ;Free the block
+               BL      flex_compact            ;And reduce memory usage
+               ADD     R13,R13,#12             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+90get          MOV     R10,R0                  ;Look after error pointer
+               MOV     R0,R13                  ;Point to flex anchor
+               BL      flex_free               ;Free the block
+               BL      flex_compact            ;And reduce memory usage
+               ADD     R13,R13,#12             ;Restore the stack pointer
+               MOV     R0,R10                  ;Get error back again
+               SWI     OS_GenerateError        ;And raise the error
+
+80get          MOV     R2,R0                   ;Get returned object type
+               MOV     R0,#19                  ;Return error message
+               SWI     OS_File                 ;Make the error
+
+               LTORG
+
+; --- get__hat ---
+;
+; On entry:    R9 == pointer to end of line
+;              R10 == pointer to directive operands
+;              R11 == pointer to end of file
+;
+; On exit:     R0-R8, R10 corrupted
+;
+; Use:         Handles a hat (^) directive.
+
+get__hat       ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+
+               ; --- Find start of operands ---
+
+00get__hat     MOV     R8,R10                  ;Remember current position
+               BL      get__byte               ;Read another byte
+               BMI     %00get__hat             ;If whitespace, skip on
+
+               ; --- Now find the end ---
+
+               MOV     R1,#32                  ;Make whitespace into spaces
+10get__hat     MOV     R7,R10                  ;Remember current position
+               BL      get__byte               ;Read another byte
+               BCS     %15get__hat             ;If end-of-line, skip out
+               STRMIB  R1,[R7,#0]              ;If whitespace, space it
+               CMP     R0,#','                 ;Could be a comma, maybe
+               CMPNE   R0,#';'                 ;Also stop at a comment
+               BNE     %10get__hat             ;If not, keep going
+
+15get__hat     MOV     R14,#0                  ;Null terminate expression
+               STRB    R14,[R7,#0]             ;Done that then
+
+               ; --- Evaluate the expression ---
+
+               MOV     R1,R8                   ;Point to the expression
+               BL      bTalk_eval              ;Evaluate the expression
+
+               STR     R0,[R13,#8]             ;Save the new `at' value
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- get__hash ---
+;
+; On entry:    R8 == pointer to label, or 0
+;              R9 == pointer to end of line
+;              R10 == pointer to directive operands
+;              R11 == pointer to end of file
+;
+; On exit:     R0-R8, R10 corrupted
+;
+; Use:         Handles a hash (#) directive.
+
+get__hash      ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+
+               ; --- Find start of operands ---
+
+00get__hash    MOV     R7,R10                  ;Remember current position
+               BL      get__byte               ;Read another byte
+               BMI     %00get__hash            ;If whitespace, skip on
+
+               ; --- Now find the end ---
+
+               MOV     R1,#32                  ;Make whitespace into spaces
+10get__hash    MOV     R6,R10                  ;Remember current position
+               BL      get__byte               ;Read another byte
+               BCS     %15get__hash            ;If end-of-line, skip out
+               STRMIB  R1,[R6,#0]              ;If whitespace, space it
+               CMP     R0,#';'                 ;Also stop at a comment
+               BNE     %10get__hash            ;If not, keep going
+
+15get__hash    MOV     R14,#0                  ;Null terminate expression
+               STRB    R14,[R6,#0]             ;Done that then
+
+               ; --- Save the current `at' value ---
+
+               LDR     R2,[R13,#8]             ;Load current `at' value
+               MOVS    R0,R8                   ;Point to label name
+               BEQ     %20get__hash            ;No label -- don't assign
+
+               BL      bTalk_create            ;Create the variable
+               BL      bTalk_store             ;Store that in lvalue
+
+               ; --- Evaluate the expression ---
+
+20get__hash    MOV     R1,R7                   ;Point to the expression
+               BL      bTalk_eval              ;Evaluate the expression
+               ADD     R0,R0,R2                ;Increment the `at' value
+               STR     R0,[R13,#8]             ;And store it back
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- get__equ ---
+;
+; On entry:    R8 == pointer to label, or 0
+;              R9 == pointer to end of line
+;              R10 == pointer to directive operands
+;              R11 == pointer to end of file
+;
+; On exit:     R0-R8, R10 corrupted
+;
+; Use:         Handles an EQU directive.
+
+get__equ       ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+               LDR     R14,[R13,#12]           ;Load the flags word
+               TST     R14,#1                  ;Are we in macro?
+               LDMNEFD R13!,{PC}^              ;Yes -- return to caller
+
+               ; --- Find start of operands ---
+
+00get__equ     MOV     R7,R10                  ;Remember current position
+               BL      get__byte               ;Read another byte
+               BMI     %00get__equ             ;If whitespace, skip on
+
+               ; --- Now find the end ---
+
+               MOV     R1,#32                  ;Turn whitespace into spaces
+10get__equ     MOV     R6,R10                  ;Remember current position
+               BL      get__byte               ;Read another byte
+               BCS     %15get__equ             ;If end-of-line, skip out
+               STRMIB  R1,[R6,#0]              ;If whitespace, space it
+               CMP     R0,#';'                 ;Also stop at a comment
+               BNE     %10get__equ             ;If not, keep going
+
+15get__equ     MOV     R14,#0                  ;Null terminate expression
+               STRB    R14,[R6,#0]             ;Done that then
+
+               ; --- Evaluate the expression ---
+
+               MOV     R1,R7                   ;Point to the operand
+               BL      bTalk_eval              ;Evaluate it nicely
+               MOV     R2,R0                   ;This is the value to store
+
+               MOV     R0,R8                   ;Point to label
+               BL      bTalk_create            ;Create the variable
+               BL      bTalk_store             ;And store the value away
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- get__import ---
+;
+; On entry:    R9 == pointer to end of line
+;              R10 == pointer to directive operands
+;              R11 == pointer to end of file
+;
+; On exit:     R0-R8, R10 corrupted
+;
+; Use:         Handles an IMPORT directive.
+
+get__import    ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+               LDR     R14,[R13,#12]           ;Load the flags word
+               TST     R14,#1                  ;Are we in macro?
+               LDMNEFD R13!,{PC}^              ;Yes -- return to caller
+
+               ; --- Find start of operands ---
+
+00get__import  MOV     R7,R10                  ;Remember current position
+               BL      get__byte               ;Read another byte
+               BMI     %00get__import          ;If whitespace, skip on
+
+               ; --- Now find the end ---
+
+               MOV     R1,#32                  ;Turn whitespace into spaces
+10get__import  MOV     R6,R10                  ;Remember current position
+               BL      get__byte               ;Read another byte
+               BCS     %15get__import          ;If end-of-line, skip out
+               STRMIB  R1,[R6,#0]              ;If whitespace, space it
+               CMP     R0,#';'                 ;Also stop at a comment
+               BNE     %10get__import          ;If not, keep going
+
+15get__import  MOV     R14,#0                  ;Null terminate expression
+               STRB    R14,[R6,#0]             ;Done that then
+
+               ; --- Now import the symbol ---
+
+               MOV     R0,R7                   ;Point to operand name
+               MOV     R1,R7                   ;Make this the alias too
+               MOV     R3,#0                   ;No special attributes
+               FSAVE   R9-R11                  ;Save the block pointers
+               BL      aof_import              ;Import the symbol
+               FLOAD   R9-R11                  ;Load them back again
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- get__macro ---
+;
+; On entry:    --
+;
+; On exit:     R0-R8 corrupted
+;
+; Use:         Sets the `in a macro' flag, so that strange EQU directives
+;              don't get read.
+
+get__macro     ROUT
+
+               LDR     R0,[R13,#8]             ;Load the flags word
+               ORR     R0,R0,#1                ;Set the flag
+               STR     R0,[R13,#8]             ;Save the flags back
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- get__mend ---
+;
+; On entry:    --
+;
+; On exit:     R0-R8 corrupted
+;
+; Use:         Clears the `in a macro' flag, so that strange EQU directives
+;              don't get read.
+
+get__mend      ROUT
+
+               LDR     R0,[R13,#8]             ;Load the flags word
+               BIC     R0,R0,#1                ;Clear the flag
+               STR     R0,[R13,#8]             ;Save the flags back
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- get__lib ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Loads a macro library.  This is done so that an objasm
+;              header file can load BASIC macros as appropriate, since
+;              objasm macros are obviously not much use.  We do this by
+;              evaluating a call to FNlib(), which the BASIC part will
+;              implement as loading a library.
+
+get__lib       ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+
+               ; --- Find start of operands ---
+
+00get__lib     MOV     R7,R10                  ;Remember current position
+               BL      get__byte               ;Read another byte
+               BMI     %00get__lib             ;If whitespace, skip on
+
+               ; --- Now find the end ---
+
+10get__lib     MOV     R6,R10                  ;Remember current position
+               BL      get__byte               ;Read another byte
+               BCS     %15get__lib             ;If end-of-line, skip out
+               CMP     R0,#';'                 ;Also stop at a comment
+               BNE     %10get__lib             ;If not, keep going
+
+15get__lib     MOV     R14,#0                  ;Null terminate expression
+               STRB    R14,[R6,#0]             ;Done that then
+
+               ; --- Build the string to evaluate ---
+
+               BL      str_buffer              ;Get a buffer
+               ADR     R0,get__libSkel         ;Point to skeleton string
+               BL      str_subst               ;Build the correct invocation
+               MOV     R1,R0                   ;Point to the string built
+               BL      bTalk_eval              ;Evaluate the expression
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+get__libSkel   DCB     "FNbas_lib(""%5"")",0
+
+               LTORG
+
+; --- get__nextLine ---
+;
+; On entry:    R9 == pointer to start of next line
+;              R11 == pointer to end of file
+;
+; On exit:     CC if more to come, and
+;                R9 == pointer to start of next line line
+;                R10 == pointer to next line
+;              else CS if end of file reached and
+;                R9, R10 corrupted
+;              R0 always corrupted
+;
+; Use:         Finds the start address of the next line
+
+get__nextLine  ROUT
+
+               CMP     R9,R11                  ;Are we at end of file?
+               ORRCSS  PC,R14,#C_flag          ;Yes -- return with C set
+
+               MOV     R10,R9                  ;Point to the next line
+00get__nextLine        LDRB    R0,[R9],#1              ;Get next character
+               CMP     R0,#&0A                 ;Is this a newline?
+               BNE     %00get__nextLine        ;No -- go round for more then
+               LDRB    R0,[R9,#0]              ;Load the next byte
+               CMP     R0,#&0D                 ;Is this a carriage return?
+               ADDEQ   R0,R0,#1                ;Yes -- then move along one
+               BICS    PC,R14,#C_flag          ;And return with C clear
+
+               LTORG
+
+; --- get__byte ---
+;
+; On entry:    R10 == pointer to next byte
+;
+; On exit:     CC if read a byte, and
+;                R0 == byte read
+;                R10 moved to byte after
+;                MI if byte is whitespace, else PL
+;              else CS if end of line and
+;                R0, R10 corrupted
+;
+; Use:         Reads a byte from the block
+
+get__byte      ROUT
+
+               LDRB    R0,[R10],#1             ;Load a byte
+               CMP     R10,R9                  ;Reached end of line yet?
+               ORRCSS  PC,R14,#C_flag + N_flag ;Yes -- set C on exit then
+               BIC     R14,R14,#C_flag         ;Clear R14's C flag ready
+               CMP     R0,#&9                  ;Is it a tab?
+               CMPNE   R0,#&0C                 ;Or a form feed? (oddness)
+               CMPNE   R0,#&0D                 ;Or a carriage return?
+               CMPNE   R0,#&20                 ;Or a space, indeed?
+               ORREQS  PC,R14,#N_flag          ;Yes -- set the N flag
+               BICNES  PC,R14,#N_flag          ;Otherwise clear N
+
+               LTORG
+
+; --- get__match ---
+;
+; On entry:    R0 == pointer to command line argument table
+;              R1 == pointer to command line word read (null terminated)
+;
+; On exit:     CS if word found in table and
+;                R0 == index of item matched
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Looks up a given word in the command table given.  The
+;              command table consists of null-terminated strings, and is
+;              itself terminated by a null entry.
+;
+;              Matching is not case sensitive.  Indexing is from 0.
+
+get__match     ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+               MOV     R2,#0                   ;Index of the current item
+               LDRB    R14,[R1,#0]             ;Load the first byte
+               CMP     R14,#0                  ;Is it a null string?
+               BEQ     %90get__match           ;Yes -- no match then
+
+               ; --- The main loop ---
+
+00get__match   MOV     R3,R1                   ;Point to argument start
+               LDRB    R4,[R0],#1              ;Load a byte from the table
+               LDRB    R5,[R3],#1              ;Load a byte from the arg
+               CMP     R4,#0                   ;Is this an empty string?
+               BEQ     %90get__match           ;Yes -- no match then
+
+               ; --- Try to match a word ---
+
+10get__match   CMP     R5,#0                   ;End of argument string?
+               CMPEQ   R4,#0                   ;And end of match string?
+               BEQ     %80get__match           ;Yes -- that's a match then
+               SUB     R14,R4,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R4,R4,#&20              ;Yes -- convert to upper
+               SUB     R14,R5,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R5,R5,#&20              ;Yes -- convert to upper
+               CMP     R4,R5                   ;Do characters match up?
+               LDREQB  R4,[R0],#1              ;Load a byte from the table
+               LDREQB  R5,[R3],#1              ;Load a byte from the arg
+               BEQ     %10get__match           ;Yes -- go round for more
+
+               ; --- Failed -- find end of table entry ---
+
+20get__match   CMP     R4,#0                   ;End of entry string?
+               LDRNEB  R4,[R0],#1              ;No -- load byte from table
+               BNE     %20get__match           ;And go round again
+               ADD     R2,R2,#1                ;Increment item index
+               B       %00get__match           ;Loop round for next entry
+
+               ; --- Found a match ---
+
+80get__match   MOV     R0,R2                   ;Get the item index
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack the registers
+               ORRS    PC,R14,#C_flag          ;And return with C set
+
+               ; --- No match found ---
+
+90get__match   LDMFD   R13!,{R1-R5,R14}        ;Unstack the registers
+               BICS    PC,R14,#C_flag          ;And return with C clear
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
+
diff --git a/StraySrc/Libraries/BAS/src/s/insert b/StraySrc/Libraries/BAS/src/s/insert
new file mode 100644 (file)
index 0000000..1a9d6a2
--- /dev/null
@@ -0,0 +1,152 @@
+;
+; insert.s
+;
+; Insert zero-filled chunks of data
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.bas
+               GET     sh.workspace
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |BAS$$Code|,CODE,READONLY
+
+; --- insert_align ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Inserts `0' bytes to align O% and P% to the next word
+;              boundary.
+
+               EXPORT  insert_align
+insert_align   ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               LDR     R14,[R7,#:INDEX:be__percents]
+               LDR     R0,[R14,#('P'-'A')*4]   ;Load current loc counter
+               ANDS    R0,R0,#3                ;Get non-word-alignedness
+               RSBNE   R0,R0,#4                ;Work out bytes to insert
+               BLNE    insert_reserve          ;Reserve so many bytes
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               LTORG
+
+; --- insert_reserve ---
+;
+; On entry:    R0 == amount of memory to reserve
+;
+; On exit:     --
+;
+; Use:         Reserves R0 bytes of memory at the current position.  The
+;              memory is filled with 0s.
+
+               EXPORT  insert_reserve
+insert_reserve ROUT
+
+               STMFD   R13!,{R0-R9,R12,R14}    ;Save some registers
+               MOV     R12,R7                  ;Get workspace in R12
+
+               LDR     R14,be__percents        ;Load the % variable address
+               ADD     R14,R14,#('O'-'A')*4    ;Find O% and P%
+               LDMIA   R14,{R1,R3}             ;Load them out nicely
+               ADD     R2,R1,R0                ;Bump along O%
+               ADD     R3,R3,R0                ;And bump along P%
+               STMIA   R14,{R2,R3}             ;Save them back again
+
+               CMP     R0,#0                   ;Insert no bytes?
+               BEQ     %90insert_reserve       ;Yup -- do nothing then
+               MOV     R2,#0                   ;A zero word
+
+               TST     R1,#3                   ;Is destination word-aligned?
+               BEQ     %10insert_reserve       ;Yes -- skip onwards then
+00             STRB    R2,[R1],#1              ;Zero a single byte
+               SUBS    R0,R0,#1                ;Decrement counter
+               BEQ     %90insert_reserve       ;Done it all -- return
+               TST     R1,#3                   ;Is destination word-aligned?
+               BNE     %00insert_reserve       ;No -- go round again
+
+               ; --- Now blast 0s out AQAP ---
+
+10             MOV     R3,#0
+               MOV     R4,#0
+               MOV     R5,#0
+               MOV     R6,#0
+               MOV     R7,#0
+               MOV     R8,#0
+               MOV     R9,#0
+
+               SUBS    R0,R0,#16               ;4 or more words to do?
+               BLT     %03insert_reserve
+               SUBS    R0,R0,#16               ;8 or more words to do?
+               BLT     %02insert_reserve
+
+01             STMIA   R1!,{R2-R9}             ;Blank out 8 words
+               SUBS    R0,R0,#32               ;Decrement counter
+               BGE     %01insert_reserve       ;And keep going round
+
+               CMP     R0,#-32                 ;Are we finished?
+               BEQ     %90insert_reserve       ;Yes -- return then
+
+02             ADDS    R0,R0,#16               ;4 whole words to do?
+               BLT     %03insert_reserve
+               STMIA   R1!,{R2-R5}             ;Blank out 4 words
+               BEQ     %90insert_reserve       ;Done -- return then
+               SUB     R0,R0,#16
+
+03             ADDS    R0,R0,#8                ;2 whole words to do?
+               BLT     %04insert_reserve
+               STMIA   R1!,{R2,R3}             ;Blank out 2 words
+               BEQ     %90insert_reserve       ;Done -- return then
+               SUB     R0,R0,#8
+
+04             ADDS    R0,R0,#4                ;1 word to do?
+               BLT     %05insert_reserve
+               STR     R2,[R1],#4              ;Blank out 1 word
+               BEQ     %90insert_reserve       ;Done -- return then
+               SUB     R0,R0,#4
+
+05             ADDS    R0,R0,#4
+               BEQ     %90insert_reserve       ;Done -- return then
+
+06             STRB    R2,[R1],#1              ;Save 1 byte
+               SUBS    R2,R2,#1
+               BGT     %06insert_reserve
+
+90             LDMFD   R13!,{R0-R9,R12,PC}^    ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/s/lit b/StraySrc/Libraries/BAS/src/s/lit
new file mode 100644 (file)
index 0000000..ab34dee
--- /dev/null
@@ -0,0 +1,242 @@
+;
+; lit.s
+;
+; Literal pool management
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.aofGen
+               GET     sh.bas
+               GET     sh.fastMove
+               GET     sh.flex
+               GET     sh.insert
+               GET     sh.workspace
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |BAS$$Code|,CODE,READONLY
+
+; --- lit_add ---
+;
+; On entry:    R0 == address of literal data
+;              R1 == size of literal data
+;              R2 == word align flag
+;
+; On exit:     R0 set up as described below.
+;
+; Use:         Adds the given data to the current literal pool.  On the
+;              first pass, it returns the value of P% in R0.  On the
+;              second pass, it returns the address of the literal item.
+
+               EXPORT  lit_add
+lit_add                ROUT
+
+               STMFD   R13!,{R1-R5,R12,R14}    ;Save some registers
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Find my workspace
+               MOV     R3,R0                   ;Keep the start address
+               MOV     R4,R1                   ;And the size of the block
+
+               BL      aof_firstPass           ;Is this the first pass?
+               BCS     %50lit_add              ;Yes -- behave totally oddly
+
+               ; --- Handle word aligning ---
+
+               CMP     R2,#0                   ;Is the word align flag on?
+               BEQ     %10lit_add              ;No -- don't bother then
+               LDR     R1,lit__contents+4      ;Load the current size
+               ANDS    R1,R1,#3                ;Get the nonwordalignedness
+               BEQ     %10lit_add              ;No excess -- skip on then
+               RSB     R1,R1,#4                ;Find how much we have to add
+               ADR     R0,lit__contents        ;Point to the contents block
+               BL      aof_ensure              ;Get the memory area
+               MOV     R14,#0                  ;A nice zero byte
+05lit_add      STRB    R14,[R0],#1             ;Store it in the block
+               SUBS    R1,R1,#1                ;Decrement the counter
+               BGT     %05lit_add              ;And carry on round
+
+               ; --- Now add the contents ---
+
+10lit_add      LDR     R5,lit__contents+4      ;Load offset of literal item
+               ADR     R0,lit__contents        ;Point to the contents block
+               MOV     R1,R4                   ;Get the block size
+               BL      aof_ensure              ;Make sure it's big enough
+               MOV     R1,R3                   ;Point to caller's block
+               MOV     R2,R4                   ;Get the size
+               BL      fastMove                ;Copy it over PDQ
+
+               ; --- Now return the correct address ---
+
+               LDR     R14,lit__next           ;Find next literal index
+               LDR     R0,lit__table           ;Find the literal table
+               LDR     R0,[R0,R14]             ;Load the pool base address
+               ADD     R0,R0,R5                ;And add the item offset
+               LDMFD   R13!,{R1-R5,R12,PC}^    ;And return to caller
+
+               ; --- Handle a literal pool request on first pass ---
+
+50lit_add      LDR     R3,lit__contents+4      ;Load the current size
+               CMP     R2,#0                   ;Are we word aligning?
+               ADDNE   R3,R3,#3                ;If so, word align this
+               BICNE   R3,R3,#3                ;In time-honoured fashion
+               ADD     R3,R3,R1                ;Add on size of item
+               STR     R3,lit__contents+4      ;Save the new size back
+               LDR     R0,be__percents         ;Find the % variables
+               LDR     R0,[R0,#('P'-'A')*4]    ;Load current P% value
+               LDMFD   R13!,{R1-R5,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- lit_ltorg ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Inserts a literal pool at the current position.
+
+               EXPORT  lit_ltorg
+lit_ltorg      ROUT
+
+               STMFD   R13!,{R0-R4,R12,R14}    ;Save some registers
+               STR     R12,[R7,#:INDEX:be__line] ;Store line value
+               MOV     R12,R7                  ;Find my workspace
+               BL      insert_align            ;Word align current pos
+
+               LDR     R14,lit__contents+4     ;Any data in literal pool?
+               CMP     R14,#0                  ;If so, this won't be 0
+               BEQ     %90lit_ltorg            ;No -- just align then
+
+               LDR     R4,be__percents         ;Find the % variables
+
+               BL      aof_firstPass           ;Is this the first pass?
+               BCC     %20lit_ltorg            ;No -- do the copying then
+
+               ; --- Add an entry into the literal table ---
+
+               LDR     R2,[R4,#('P'-'A')*4]    ;Load current P% value
+               ADR     R0,lit__table           ;Find the literal table
+               MOV     R1,#4                   ;Entries are 1 word long
+               BL      aof_ensure              ;Make the space for it
+               STR     R2,[R0],#4              ;Store address in the block
+               B       %50lit_ltorg            ;Do the rest of the LTORG op
+
+               ; --- Copy the data in the pool over ---
+
+20lit_ltorg    LDR     R0,[R4,#('O'-'A')*4]    ;Load current O% value
+               ADR     R1,lit__contents        ;Find the pool contents
+               LDMIA   R1,{R1,R2}              ;Load address and size
+               BL      fastMove                ;Copy the data over
+
+               ADR     R0,lit__contents        ;Point to the anchor
+               MOV     R1,#256                 ;Reduce it in size again
+               BL      flex_extend             ;Put the block back again
+               STR     R1,lit__contents+8      ;Save this as the block size
+
+               LDR     R14,lit__next           ;Load next literal pool index
+               ADD     R14,R14,#4              ;Bump it along one word
+               STR     R14,lit__next           ;Save it back again
+
+               ; --- Now move on P% and O% ---
+
+50lit_ltorg    LDR     R0,lit__contents+4      ;Load the pool size
+               ADD     R1,R4,#('O'-'A')*4      ;Point to current O% value
+               LDMIA   R1,{R2,R3}              ;Load O% and P% out
+               ADD     R2,R2,R0                ;Bump O% along
+               ADD     R3,R3,R0                ;Bump P% along
+               STMIA   R1,{R2,R3}              ;Save adjusted values back
+
+               MOV     R0,#0                   ;Next literal pool is clear
+               STR     R0,lit__contents+4      ;So reset its size to 0
+
+90lit_ltorg    BL      insert_align            ;Word align location
+
+               LDMFD   R13!,{R0-R4,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- lit_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises things for the Literal Manager.
+
+               EXPORT  lit_init
+lit_init       ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               MOV     R2,#0                   ;Blocks currently empty
+               MOV     R3,#256                 ;Initial size is 256
+               MOV     R1,#256                 ;Allocate to 256 bytes
+
+               ADR     R0,lit__table           ;Point to lit table anchor
+               BL      flex_alloc              ;Try to allocate memory
+               STMCCIB R0,{R2,R3}              ;Save size information
+               ADRCC   R0,lit__contents        ;Point to lit contents anchor
+               BLCC    flex_alloc              ;Try to allocate memory
+               STMCCIB R0,{R2,R3}              ;Save size information
+               BCS     bas_noMem               ;If no memory, die horridly
+
+               MOV     R14,#0                  ;No current lit pool index
+               STR     R14,lit__next           ;So save 0 as index
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+; --- lit_end ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Tidies up the Literal Manager after saving an AOF file.
+
+               EXPORT  lit_end
+lit_end                ROUT
+
+               STMFD   R13!,{R0,R7,R14}        ;Save some registers
+               MOV     R7,R12                  ;For technical reasons
+               LDR     R12,be__line            ;Keep the line number right
+               BL      lit_ltorg               ;Insert final literal pool
+               MOV     R12,R7                  ;Restore the workspace ptr
+               ADR     R0,lit__table           ;Point to table anchor
+               BL      flex_free               ;Free the memory
+               ADR     R0,lit__contents        ;Point to contents block
+               BL      flex_free               ;Free the memory
+               LDMFD   R13!,{R0,R7,PC}^        ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/s/string b/StraySrc/Libraries/BAS/src/s/string
new file mode 100644 (file)
index 0000000..a9c7803
--- /dev/null
@@ -0,0 +1,338 @@
+;
+; string.s
+;
+; String handling routines (control terminated)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.workspace
+
+;----- Main code ------------------------------------------------------------
+;
+; No string routine corrupts the scratchpad.
+
+               AREA    |BAS$$Code|,CODE,READONLY
+
+; --- str_cpy ---
+;
+; On entry:    R0 == destination string
+;              R1 == source string
+;
+; On exit:     R0 == pointer to terminator of destination
+;
+; Use:         Copies a string from one block to another.  It leaves the
+;              destination pointer at the end of the string so that any
+;              subsequent copies concatenate other bits on the same string.
+;              Single characters can of course be appended with
+;
+;                      MOV     Rx,#&cc
+;                      STRB    Rx,[R0],#1
+
+               EXPORT  str_cpy
+str_cpy                ROUT
+
+               STMFD   R13!,{R1,R14}           ;Keep return address safe
+00str_cpy      LDRB    R14,[R1],#1             ;Get a byte from source
+               CMP     R14,#' '                ;Is it a control character
+               MOVLT   R14,#0                  ;Yes -- translate to a 0
+               STRB    R14,[R0],#1             ;Store in destination
+               BGE     %00str_cpy              ;No -- copy another byte
+               SUB     R0,R0,#1                ;Point back at terminator
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- str_len ---
+;
+; On entry:    R0 == pointer to string
+;
+; On exit:     R0 == length of the string
+;
+; Use:         Calculates the length of a string.
+
+               EXPORT  str_len
+str_len                ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               MOV     R14,R0                  ;Point to the string
+               MOV     R0,#0                   ;Current length is 0
+00str_len      LDRB    R1,[R14],#1             ;Get a byte from the string
+               CMP     R1,#' '                 ;Is it the end yet?
+               LDMLTFD R13!,{R1,PC}^           ;Yes -- return
+               ADD     R0,R0,#1                ;Bump the length counter
+               B       %00str_len              ;And go back for more
+
+               LTORG
+
+; --- str_cmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         Case-sensitively compares two strings.  You can use the
+;              normal ARM condition codes after the compare, so you can
+;              treat this fairly much like a normal CMP.
+
+               EXPORT  str_cmp
+str_cmp                ROUT
+
+               STMFD   R13!,{R0,R1,R3,R4,R14}
+00str_cmp      LDRB    R3,[R0],#1              ;Get a character from A
+               LDRB    R4,[R1],#1              ;And one from B
+               CMP     R3,#&20                 ;Is that the end of A?
+               MOVLT   R3,#0                   ;Yes -- pretend it's null
+               CMP     R4,#&20                 ;Is that the end of B?
+               MOVLT   R4,#0                   ;Yes -- pretend it's null
+               CMP     R3,R4                   ;How do they match up?
+               LDMNEFD R13!,{R0,R1,R3,R4,PC}   ;If NE, return condition
+               CMP     R3,#0                   ;Is this the end?
+               BNE     %00str_cmp              ;No -- loop again
+               LDMFD   R13!,{R0,R1,R3,R4,PC}   ;Return to caller
+
+; --- str_icmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         As for str_cmp above, but case-insensitive.
+
+               EXPORT  str_icmp
+str_icmp       ROUT
+
+               STMFD   R13!,{R0,R1,R3,R4,R14}
+00str_icmp     LDRB    R3,[R0],#1              ;Get a character from A
+               LDRB    R4,[R1],#1              ;And one from B
+               SUB     R14,R3,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R3,R3,#&20              ;Yes -- convert to upper
+               SUB     R14,R4,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R4,R4,#&20              ;Yes -- convert to upper
+               CMP     R3,#&20                 ;Is that the end of A?
+               MOVLT   R3,#0                   ;Yes -- pretend it's null
+               CMP     R4,#&20                 ;Is that the end of B?
+               MOVLT   R4,#0                   ;Yes -- pretend it's null
+               CMP     R3,R4                   ;How do they match up?
+               LDMNEFD R13!,{R0,R1,R3,R4,PC}   ;If NE, return condition
+               CMP     R3,#0                   ;Is this the end?
+               BNE     %00str_icmp             ;No -- loop again
+               LDMFD   R13!,{R0,R1,R3,R4,PC}   ;Return to caller
+
+               LTORG
+
+; --- str_subst ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R1 == Pointer to output buffer
+;              R2-R11 == Pointer to filler strings (optional)
+;
+; On exit:     R0 == Pointer to start of buffer
+;              R1 == Pointer to terminating null
+;
+; Use:         Performs string substitution, filling in a skeleton string
+;              containing placeholders with `filler' strings.  The
+;              placeholders are actually rather powerful.  The syntax of
+;              these is as follows:
+;
+;                      `%' [<type>] <digit>
+;
+;              (spaces are for clarity -- in fact you must not include
+;              spaces in the format string.)
+;
+;              <digit> is any charater between `0' and `9'.  It refers to
+;              registers R2-R11 (so `0' means R2, `5' is R7 etc.)  How the
+;              value is interpreted is determined by <type>.
+;
+;              <type> is one of:
+;
+;              s       String.  This is the default.  The register is
+;                      considered to be a pointer to an ASCII string
+;                      (control terminated).
+;
+;              i       Integer.  The (signed) decimal representation is
+;                      inserted.  Leading zeros are suppressed.
+;
+;              x       Hex fullword.  The hexadecimal representation of the
+;                      register is inserted.  Leading zeros are included.
+;
+;              b       Hex byte.  The hexadecimal representation of the
+;                      least significant byte is inserted.  Leading zeros
+;                      are included.
+;
+;              c       Character.  The ASCII character corresponding to the
+;                      least significant byte is inserted.
+
+               EXPORT  str_subst
+str_subst      ROUT
+
+               STMFD   R13!,{R1-R11,R14}
+
+               ; --- Move arguments into more amenable registers ---
+
+               MOV     R11,R0                  ;Pointer to skeleton string
+
+               ; --- Main `get a character' loop ---
+
+00str_subst    LDRB    R14,[R11],#1            ;Get an input character
+               CMP     R14,#'%'                ;Is it a `%' sign?
+               BEQ     %01str_subst            ;Yes -- deal with it
+02str_subst    CMP     R14,#&20                ;Is it the end of input?
+               MOVLT   R14,#0                  ;Yes -- null terminate it
+               STRB    R14,[R1],#1             ;Not special, so store it
+               BGE     %00str_subst            ;No -- get another one
+               SUB     R1,R1,#1                ;Point to null terminator
+               LDMFD   R13!,{R0,R2-R11,PC}^    ;And return to caller
+
+               ; --- Found a `%' sign, so find out what to substitute ---
+
+01str_subst    LDRB    R14,[R11],#1            ;Get the next character
+
+               ; --- Now find out what we're substituting ---
+
+               ORR     R9,R14,#&20             ;Convert it to lowercase
+               CMP     R9,#'s'                 ;Is it a string?
+               CMPNE   R9,#'i'                 ;Or an integer?
+               CMPNE   R9,#'x'                 ;Or a fullword hex number?
+               CMPNE   R9,#'b'                 ;Or a single byte in hex?
+               CMPNE   R9,#'c'                 ;Or an ASCII character?
+               LDREQB  R14,[R11],#1            ;And get another character
+
+               ; --- Now find which filler it is ---
+
+               CMP     R14,#'0'                ;Is it a digit?
+               BLT     %02str_subst            ;No -- just ignore the `%'
+               CMP     R14,#'9'                ;Make sure it's small enough
+               BGT     %02str_subst            ;No -- just ignore the `%'
+               SUB     R14,R14,#'0'-1          ;Convert to binary (1..10)
+               LDR     R0,[R13,R14,LSL #2]     ;Load appropriate register
+
+               ; --- Now find out how to substitute this argument ---
+
+               MOV     R2,#256                 ;Buffer size -- saves space
+
+               CMP     R9,#'s'                 ;Is it meant to be a string?
+               BEQ     %03str_subst            ;Yes -- a quick copy loop
+               CMP     R9,#'i'                 ;A decimal integer?
+               BEQ     %04str_subst            ;Yes -- go ahead to convert
+               CMP     R9,#'x'                 ;A hex fullword?
+               BEQ     %05str_subst            ;Yes -- convert that
+               CMP     R9,#'b'                 ;A hex byte?
+               BEQ     %06str_subst            ;Yes -- convert that
+               CMP     R9,#'c'                 ;A character?
+               BEQ     %07str_subst            ;Yes -- convert that
+
+               ; --- String substitution copy-loop ---
+
+03str_subst    LDRB    R14,[R0],#1             ;Get an input byte
+               CMP     R14,#&20                ;Is it the end of the string?
+               BLT     %00str_subst            ;Yes -- read main string
+               STRB    R14,[R1],#1             ;No -- store it in output
+               B       %03str_subst            ;... and get another one
+
+               ; --- Decimal integer conversion ---
+
+04str_subst    SWI     OS_ConvertInteger4      ;Convert and update nicely
+               B       %00str_subst            ;And rejoin the main loop
+
+               ; --- Hexadecimal fullword conversion ---
+
+05str_subst    SWI     OS_ConvertHex8          ;Convert and update nicely
+               B       %00str_subst            ;And rejoin the main loop
+
+               ; --- Hexadecimal byte conversion ---
+
+06str_subst    SWI     OS_ConvertHex2          ;Convert and update nicely
+               B       %00str_subst            ;And rejoin the main loop
+
+               ; --- ASCII character conversion ---
+
+07str_subst    STRB    R0,[R1],#1              ;Store the byte in
+               B       %00str_subst            ;And rejoin the main loop
+
+               LTORG
+
+; --- str_error ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R2-R11 == Pointers to fillin strings
+;
+; On exit:     R0 == Pointer to error in buffer
+;              R1 == Pointer to terminator
+;
+; Use:         Fills in an error skeleton (containing a 4 byte error number
+;              and a control terminated skeleton string as for str_subst)
+;              and returns the address of the filled in error block.  The
+;              error block is stored in a buffer obtained from str_buffer.
+;
+;              Filler strings may be held in the scratchpad.
+
+               EXPORT  str_error
+str_error      ROUT
+
+               STMFD   R13!,{R14}              ;Store the link register
+               BL      str_buffer              ;Find a spare buffer
+               LDR     R14,[R0],#4             ;Get the error number
+               STR     R14,[R1],#4             ;Output it too
+               BL      str_subst               ;Do the string substitution
+               SUB     R0,R0,#4                ;Point to the error start
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; ---- str_buffer ---
+;
+; On entry:    --
+;
+; On exit:     R1 == pointer to the next free buffer
+;
+; Use:         Returns a pointer to a 256-byte buffer.  There are at present
+;              2 buffers, which are returned alternately.
+
+               EXPORT  str_buffer
+str_buffer     ROUT
+
+               STMFD   R13!,{R14}              ;Save a work register
+               LDR     R14,str__buffNum        ;Get the current buffer
+               ADD     R14,R14,#1              ;Bump the buffer count
+               CMP     R14,#3                  ;Have we gone too far?
+               MOVCS   R14,#0                  ;Yes -- go back then
+               STR     R14,str__buffNum        ;Store the new one back
+               ADRL    R1,str__buffer          ;Point to the actual buffer
+               ADD     R1,R1,R14,LSL #8        ;Point to correct buffer
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/s/vars b/StraySrc/Libraries/BAS/src/s/vars
new file mode 100644 (file)
index 0000000..53802e0
--- /dev/null
@@ -0,0 +1,151 @@
+;
+; vars.s
+;
+; Setting up useful variables for BAS
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.bas
+               GET     sh.basTalk
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |BAS$$Code|,CODE,READONLY
+
+; --- vars__setAscending ---
+;
+; On entry:    R3 == pointer to a name table
+;
+; On exit:     R3 points past the table
+;
+; Use:         Sets the variables named in the given table to have integer
+;              values from 0 upwards.  The table contains null-terminated
+;              strings and is terminated by a null string.
+
+vars__setAscending ROUT
+
+               STMFD   R13!,{R0-R2,R4,R14}     ;Save some registers
+               MOV     R4,#0                   ;Start counting at 0
+00             MOV     R0,R3                   ;Point at the string
+               MOV     R2,R4                   ;Get the next value to set
+               LDRB    R14,[R3],#1             ;Load first byte from string
+               CMP     R14,#0                  ;Is it the end of the table?
+               LDMEQFD R13!,{R0-R2,R4,PC}^     ;Yes -- we've finished then
+               ADD     R4,R4,#1                ;Increment the counter
+10             LDRB    R14,[R3],#1             ;Load next byte from string
+               CMP     R14,#1                  ;Alternative name?
+               SUBEQ   R4,R4,#1                ;Yes -- don't bump counter
+               CMPNE   R14,#0                  ;Is it the end yet?
+               BNE     %10vars__setAscending   ;No -- go round for more
+               BL      bTalk_create            ;Create the variable
+               BL      bTalk_store             ;Store the value away
+               B       %00vars__setAscending   ;Set the next variable
+
+               LTORG
+
+; --- vars_set ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets up variable names for registers (normal and APCS) and
+;              also for condition codes.
+
+               EXPORT  vars_set
+vars_set       ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               ADR     R3,vars__names          ;Point to big name table
+               BL      vars__setAscending      ;Standard registers
+               BL      vars__setAscending      ;APCS registers
+               BL      vars__setAscending      ;Standard condition names
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+vars__names    DCB     "R0",1,"r0",0
+               DCB     "R1",1,"r1",0
+               DCB     "R2",1,"r2",0
+               DCB     "R3",1,"r3",0
+               DCB     "R4",1,"r4",0
+               DCB     "R5",1,"r5",0
+               DCB     "R6",1,"r6",0
+               DCB     "R7",1,"r7",0
+               DCB     "R8",1,"r8",0
+               DCB     "R9",1,"r9",0
+               DCB     "R10",1,"r10",0
+               DCB     "R11",1,"r11",0
+               DCB     "R12",1,"r12",0
+               DCB     "R13",1,"SP",1,"r13",1,"sp",0
+               DCB     "R14",1,"LR",1,"LK",1,"r14",1,"lr",1,"lk",0
+               DCB     "R15",1,"PC",1,"r15",1,"pc",0
+               DCB     0
+
+               DCB     "a1",0
+               DCB     "a2",0
+               DCB     "a3",0
+               DCB     "a4",0
+               DCB     "v1",0
+               DCB     "v2",0
+               DCB     "v3",0
+               DCB     "v4",0
+               DCB     "v5",0
+               DCB     "v6",1,"sb",0
+               DCB     "v7",1,"sl",0
+               DCB     "fp",0
+               DCB     "ip",0
+               DCB     "sp",0
+               DCB     "lr",0
+               DCB     "pc",0
+               DCB     0
+
+               DCB     "EQ",1,"eq",1,"ZS",1,"zs",0
+               DCB     "NE",1,"ne",1,"ZC",1,"zc",0
+               DCB     "CS",1,"cs",1,"HS",1,"hs",0
+               DCB     "CC",1,"cc",1,"LO",1,"lo",0
+               DCB     "MI",1,"mi",1,"NS",1,"ns",0
+               DCB     "PL",1,"pl",1,"NC",1,"nc",0
+               DCB     "VS",1,"vs",0
+               DCB     "VC",1,"vc",0
+               DCB     "HI",1,"hi",0
+               DCB     "LS",1,"ls",0
+               DCB     "GE",1,"ge",0
+               DCB     "LT",1,"lt",0
+               DCB     "GT",1,"gt",0
+               DCB     "LE",1,"le",0
+               DCB     "AL",1,"al",0
+               DCB     "NV",1,"nv",0
+               DCB     0
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/scripts/crunchit,feb b/StraySrc/Libraries/BAS/src/scripts/crunchit,feb
new file mode 100644 (file)
index 0000000..48a5024
--- /dev/null
@@ -0,0 +1,38 @@
+|
+| crunchit
+|
+| Build a crunched BAS
+|
+| © 1998 Straylight
+|
+
+Set Alias$x echo %%*0|m%%*0
+
+| --- Initial processing ---
+|
+| I want to do some preprocessing with `sed', which means that BAS has
+| got to be converted to text.
+
+exec scripts.execit
+basic -load b.bas
+| saves work.bastext as text and work.basconst
+x sed -f scripts.preproc -f work.basconst work.bastext >work.stage-1
+
+| --- Crunching ---
+|
+| Now I've got to convert the text file back to BASIC binary format and
+| compress it.
+
+basic -load work.stage-1
+| saves work.stage-2 back as basic
+x ccrunch -r2 -xscripts.exports work.stage-2 work.stage-3
+
+| --- Set up the magic number ---
+|
+| I now need to set the length word in the header, and word-align the
+| result.
+
+basic -load work.stage-3
+| saves bc.bas
+
+Unset Alias$x
diff --git a/StraySrc/Libraries/BAS/src/scripts/execit,ffe b/StraySrc/Libraries/BAS/src/scripts/execit,ffe
new file mode 100644 (file)
index 0000000..940bc8a
--- /dev/null
@@ -0,0 +1,13 @@
+TEXTSAVE "work.bastext"
+PROCbas_saveconst
+QUIT
+SAVE "work.stage-2"
+QUIT
+RENUMBER 0,1
+!(PAGE + &44) = (TOP - PAGE + 7) AND -4
+SAVE "bc.bas"
+f% = OPENUP "bc.bas"
+PTR #f% = EXT #f%
+WHILE EXT #f% AND 3: BPUT#f%, 0: ENDWHILE
+CLOSE #f%
+QUIT
diff --git a/StraySrc/Libraries/BAS/src/scripts/exports b/StraySrc/Libraries/BAS/src/scripts/exports
new file mode 100644 (file)
index 0000000..9ae3f86
--- /dev/null
@@ -0,0 +1,56 @@
+bas_init
+bas_aofInit
+bas_aofSaveAs
+bas_aofSave
+pass
+import
+importAs
+importWeak
+importWeakAs
+export
+exportAs
+exportStrong
+exportStrongAs
+get
+bas_lib
+area
+reloc
+noReloc
+entry
+litStart
+litw
+lits
+litmagic
+litsz
+literr
+literal
+litAlign
+ltorg
+align
+reserve
+bin
+fSize
+ws_start
+ws_base
+ws
+ws_align
+ws_word
+ws_byte
+adrl
+adrccl
+addl
+addccl
+ldrl
+ldrccl
+ldrrl
+ldrrccl
+bas_a
+bas_b
+bas_c
+bas_d
+bas_e
+bas_f
+bas_g
+bas_h
+bas_i
+bas_j
diff --git a/StraySrc/Libraries/BAS/src/scripts/preproc b/StraySrc/Libraries/BAS/src/scripts/preproc
new file mode 100644 (file)
index 0000000..d218dad
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# preproc
+#
+# Preprocessing the BAS basic library
+#
+# © 1994-1998 Straylight
+#
+
+# first of all, delete lines marked for stripping
+
+/\[del]/,/\[edel]/ d
+/\[dl]/d
+
+# replace long global variable names by short versions
+
+/bas_workspace/s//bas_a/g
+/bas_scratch/s//bas_b/g
+/bas_code/s//bas_c/g
+/bas_asmCode/s//bas_d/g
+/bas_R/s//bas_e/g
+/bas_fileName/s//bas_f/g
+/bas_call/s//bas_g/g
+/bas_port/s//bas_h/g
+/bas_litStart/s//bas_i/g
+/bas_savedOpt/s//bas_j/g
diff --git a/StraySrc/Libraries/BAS/src/sh/aofGen b/StraySrc/Libraries/BAS/src/sh/aofGen
new file mode 100644 (file)
index 0000000..8ba91f5
--- /dev/null
@@ -0,0 +1,202 @@
+;
+; aofGen.sh
+;
+; Generate AOF files from BASIC
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  aof_init
+;  aof_pass
+;  aof_firstPass
+;  aof_ensure
+;  aof_area
+;  aof_entry
+;  aof_import
+;  aof_iImport
+;  aof_export
+;  aof_reloc
+;  aof_noReloc
+;  aof_save
+
+               [       :LNOT::DEF:aofGen__dfn
+               GBLL    aofGen__dfn
+
+; --- aof_init ---
+;
+; On entry:    R7 == address of workspace
+;              R8-R12 set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: asmCode%
+;
+; Use:         Initialises workspace for generation of AOF code.  Remembers
+;              that code generation will start at asmCode%.
+
+               IMPORT  aof_init
+
+; --- aof_pass ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Signals the start of a new assembly pass.
+
+               IMPORT  aof_pass
+
+; --- aof_firstPass ---
+;
+; On entry:    --
+;
+; On exit:     CS if on first pass, CC otherwise
+;
+; Use:         Informs the caller whether we're on the first or second pass.
+
+               IMPORT  aof_firstPass
+
+; --- aof_ensure ---
+;
+; On entry:    R0 == address of anchor and size info
+;              R1 == free space required
+;
+; On exit:     R0 == address of first free byte in area
+;
+; Use:         Ensures that there is the requested quantity of memory free
+;              in the given block.  If not, bas_noMem is called.
+
+               IMPORT  aof_ensure
+
+; --- aof_area ---
+;
+; On entry:    R0 == AREA attributes word
+;              R7 == address of workspace
+;              R8-R12 set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: name$
+;
+; Use:         Makes a new AREA start at the current location.
+
+               IMPORT  aof_area
+
+; --- aof_entry ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets the image entry point to be the current location.
+
+               IMPORT  aof_entry
+
+; --- aof_import ---
+;
+; On entry:    R0 == pointer to variable name
+;              R1 == pointer to symbol name
+;              R3 == attribute bits (not including bits 0,1)
+;
+; On exit:     --
+;
+; Use:         Imports a symbol, and sets the given variable to point to
+;              it.  If the symbol is already imported, another alias is
+;              set up, but no actual symbol is created.
+
+               IMPORT  aof_import
+
+; --- aof_iImport ---
+;
+; On entry:    R0 == WEAK flag
+;              R7 == address of workspace
+;              R8-R12 set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: name$,alias$
+;
+; Use:         Imports a symbol name$, and makes the variable whose name
+;              is in alias$ refer to it.
+
+               IMPORT  aof_iImport
+
+; --- aof_export ---
+;
+; On entry:    R0 == STRONG flag
+;              R7 == pointer to workspace
+;              R8-R12 as set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: alias$,name$
+;
+; Use:         Exports the value held in the given alias as the symbol
+;              name$.
+
+               IMPORT  aof_export
+
+; --- aof_reloc ---
+;
+; On entry:    R7 == workspace address
+;
+; On exit:     --
+;
+; Use:         Marks the current address as being the start of a relocation
+;              block.  If a relocation block is current, this is a no-op.
+
+               IMPORT  aof_reloc
+
+; --- aof_noReloc ---
+;
+; On entry:    R7 == workspace address
+;
+; On exit:     --
+;
+; Use:         Marks the current address as being the start of a non-
+;              relocation block.  If a non-relocation block is current,
+;              this is a no-op.
+
+               IMPORT  aof_noReloc
+
+; --- aof_save ---
+;
+; On entry:    R7 == workspace address
+;              R8-R12 set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: file$
+;
+; Use:         Saves the current AOF file.  It also resets all the AOF
+;              state, so that another AOF file can be built subsequently.
+
+               IMPORT  aof_save
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/sh/bas b/StraySrc/Libraries/BAS/src/sh/bas
new file mode 100644 (file)
index 0000000..4a832ed
--- /dev/null
@@ -0,0 +1,73 @@
+;
+; bas.sh
+;
+; Base code for BAS
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  bas_argString
+;  bas_badCall
+;  bas_noMem
+
+; --- bas_argString ---
+;
+; On entry:    R1 == address of destination buffer
+;              R9 == pointer to argument entry
+;              R10 == number of arguments left
+;
+; On exit:     R9 increased by 8
+;              R10 decreased by 1
+;
+; Use:         Reads a string argument into a buffer and null terminates
+;              it sensibly so we can use it.
+
+               IMPORT  bas_argString
+
+; --- bas_badCall ---
+;
+; On entry:    --
+;
+; On exit:     Generates an error
+;
+; Use:         Generates an error about bad arguments.  It saves space to
+;              just have this here.
+
+               IMPORT  bas_badCall
+
+; --- bas_noMem ---
+;
+; On entry:    --
+;
+; On exit:     Generates an error
+;
+; Use:         Generates an error about not having any memory left.
+
+
+               IMPORT  bas_noMem
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/sh/basTalk b/StraySrc/Libraries/BAS/src/sh/basTalk
new file mode 100644 (file)
index 0000000..bfad984
--- /dev/null
@@ -0,0 +1,115 @@
+;
+; basTalk.sh
+;
+; Interface to BASIC's weird routines
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  bTalk_lvblnk
+;  bTalk_create
+;  bTalk_store
+;  bTalk_load
+;  bTalk_eval
+;  bTalk_match
+
+               [       :LNOT::DEF:basTalk__dfn
+               GBLL    basTalk__dfn
+
+; --- bTalk_lvblnk ---
+;
+; On entry:    R0 == pointer to variable name to find (not tokenised)
+;
+; On exit:     R0 == address of lvalue
+;              R1 == type of lvalue
+;
+; Use:         Tries to locate the given BASIC variable.
+
+               IMPORT  bTalk_lvblnk
+
+; --- bTalk_create ---
+;
+; On entry:    R0 == pointer to name of variable
+;
+; On exit:     R0 == address of variable lvalue
+;              R1 == type of variable created
+;
+; Use:         Creates a variable, if it doesn't already exist.  Otherwise
+;              a pointer to the existing variable is returned.
+
+               IMPORT  bTalk_create
+
+; --- bTalk_store ---
+;
+; On entry:    R0 == lvalue in which to store
+;              R1 == type of lvalue
+;              R2 == (integer) value to store
+;
+; On exit:     --
+;
+; Use:         Stores an integer value in a BASIC variable.  The value is
+;              converted to floating point if required (without loss of
+;              precision).
+
+               IMPORT  bTalk_store
+
+; --- bTalk_load ---
+;
+; On entry:    R0 == address of lvalue
+;              R1 == type of lvalue
+;
+; On exit:     R2 == integer value of lvalue
+;
+; Use:         Loads an integer variable from an lvalue.
+
+               IMPORT  bTalk_load
+
+; --- bTalk_eval ---
+;
+; On entry:    R1 == pointer to a control-terminated string
+;
+; On exit:     R0 == value of expression
+;
+; Use:         Evaluates a BASIC expression.
+
+               IMPORT  bTalk_eval
+
+; --- bTalk_match ---
+;
+; On entry:    R1 == ctrl terminated string
+;              R2 == destination pointer
+;
+; On exit:     --
+;
+; Use:         Tokenises the given sting, and puts the result in the
+;              destination buffer given.
+
+               IMPORT  bTalk_match
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/sh/basicEnv b/StraySrc/Libraries/BAS/src/sh/basicEnv
new file mode 100644 (file)
index 0000000..a44dca1
--- /dev/null
@@ -0,0 +1,150 @@
+;
+; basicEnv.sh
+;
+; Useful things in the BASIC environment
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+; --- Notes ---
+;
+; This file contains symbolic names for the useful bits which BASIC puts
+; after R14 when it CALLs a piece of code.
+
+               ^       0
+
+               ; --- Miscellaneous useful things ---
+
+bEnv_return    #       4                       ;Return address after CALL
+
+               ; --- Offsets from ARGP (in R8 of all places) ---
+
+bEnv_strAcc    #       4                       ;Ptr to string accumulator
+bEnv_page      #       4                       ;Current program PAGE
+bEnv_top       #       4                       ;Current program TOP
+bEnv_loMem     #       4                       ;Current variable start
+bEnv_hiMem     #       4                       ;Current stack end
+bEnv_memLimit  #       4                       ;Limit of available memory
+bEnv_fsa       #       4                       ;Free space start
+bEnv_tally     #       4                       ;Value of COUNT
+bEnv_timeOff   #       4                       ;Diff tween TIME and OS_Word
+bEnv_escWord   #       4                       ;Exception flag word
+bEnv_widthLoc  #       4                       ;Value of width-1
+
+               ; --- Internal routines ---
+               ;
+               ; Some corruptions documented.  Bear in mind that there may
+               ; be others, though.
+
+bEnv_varind    #       4                       ;Return value of lvalue
+                                               ;Entry: R0 == address of lv
+                                               ;       R9 == type of lv
+                                               ;       R12 == LINE
+                                               ;Exit:  R0-R3 == value
+                                               ;       R9 == magic type
+                                               ;        0 == str in STRACC
+                                               ;        4<<28 == int in R0
+                                               ;        8<<28 == fp in R0-R3
+
+bEnv_storea    #       4                       ;Store a value in lvalue
+                                               ;Entry: R0-R3 == value
+                                               ;       R4 == address of lv
+                                               ;       R5 == type of lv
+                                               ;       R8 == ARGP
+                                               ;       R9 == type of value
+                                               ;       R12 == LINE
+                                               ;Exit:  R0-R7 corrupted
+
+bEnv_ststore   #       4                       ;Stores a string in variable
+                                               ;Entry: Can't remember
+                                               ;Exit:  Can't remember
+
+bEnv_lvblnk    #       4                       ;Find a named lvalue
+                                               ;Entry: R8 == ARGP
+                                               ;       R11 == ptr to name
+                                               ;       R12 == LINE
+                                               ;Exit:  R0 == address of lv
+                                               ;       R9 == type
+                                               ;       NE => found var OK
+                                               ;       EQ, CS => bad name
+                                               ;       EQ, CC => use CREATE
+
+bEnv_create    #       4                       ;Creates a variable
+                                               ;Entry: Set up from LVBLNK
+                                               ;Exit:  R0 == address of lv
+                                               ;       R9 == type
+
+bEnv_expr      #       4                       ;Evaluates an expression
+                                               ;Entry: R8 == ARGP
+                                               ;       R11 points to string
+                                               ;Exit:  As for VARIND
+                                               ;       EQ => read string
+                                               ;       NE, MI => fp value
+                                               ;       NE, PL => int value
+
+bEnv_match     #       4                       ;Tokenises a string
+                                               ;Entry: R1 == cr term string
+                                               ;       R2 == dest pointer
+                                               ;       R3 == 0 (parse lval)
+                                               ;             1 (parse rval)
+                                               ;       R4 == 0/&8D (line no)
+                                               ;Exit:  R0, R3, R4 corrupted
+                                               ;       R1 == ptr past cr
+                                               ;       R2 == ptr past cr
+                                               ;       R5 == status:
+                                               ;        >=&1000 mis-()
+                                               ;        bit 8 => bad line no
+                                               ;        lsb==1 => mis-""
+
+bEnv_tokenAddr #       4                       ;Untokenises a string
+                                               ;Entry: R0 == token
+                                               ;       R12 == ptr to next ch
+                                               ;Exit:  R1 == ptr to string
+                                               ;             (term >&7f)
+                                               ;       R12 modified
+                                               ;       R0 corrupted
+
+               ; --- Floating point routines ---
+               ;
+               ; * means R4-R7 corrupted, and errors (e.g. overflow)
+               ; possible.
+               ;
+               ; In all cases, (R0-R3) may be modified, although the FP
+               ; value will be preserved (e.g. for normalisation).
+               ;
+               ; In FIX and FLOAT, R9 is changed to indicate the new type.
+
+               #       8                       ;Ask Roger/Sophie!
+bEnv_fSta      #       4                       ;[R9] <- (R0-R3)
+bEnv_fLda      #       4                       ;(R0-R3) <- [R9]
+
+bEnv_fAdd      #       4                       ;(R0-R3) <- [R9] + (R0-R3)  *
+bEnv_fSub      #       4                       ;(R0-R3) <- [R9] - (R0-R3)  *
+bEnv_fMul      #       4                       ;(R0-R3) <- [R9] * (R0-R3)  *
+bEnv_fDiv      #       4                       ;(R0-R3) <- [R9] / (R0-R3)  *
+
+bEnv_float     #       4                       ;(R0-R3) <- R0, R9 <- FLOAT
+bEnv_fix       #       4                       ;R0 <- (R0-R3), R9 <- INT
+bEnv_fSqrt     #       4                       ;(R0-R3) <- sqrt(R0-R3)     *
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/sh/fastMove b/StraySrc/Libraries/BAS/src/sh/fastMove
new file mode 100644 (file)
index 0000000..9b98ffb
--- /dev/null
@@ -0,0 +1 @@
+               LNK     libs:sh.fastMove
diff --git a/StraySrc/Libraries/BAS/src/sh/flex b/StraySrc/Libraries/BAS/src/sh/flex
new file mode 100644 (file)
index 0000000..7328c99
--- /dev/null
@@ -0,0 +1,10 @@
+;
+; flex.sh
+;
+; Flexible memory handling
+;
+; © 1998 Straylight
+;
+
+               GBLL    FLEX_STACK
+               LNK     libs:sh.flex
diff --git a/StraySrc/Libraries/BAS/src/sh/get b/StraySrc/Libraries/BAS/src/sh/get
new file mode 100644 (file)
index 0000000..17c5d68
--- /dev/null
@@ -0,0 +1,54 @@
+;
+; get.sh
+;
+; Parsing of simple objasm header files
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  get
+
+               [       :LNOT::DEF:get__dfn
+               GBLL    get__dfn
+
+; --- get ---
+;
+; On entry:    R7 == pointer to workspace
+;              R8-R12 as set up by BASIC
+;
+; On exit:     --
+;
+; CALL syntax: filename
+;
+; Use:         Parses a Straylight format objasm header file and sets up
+;              BASIC variables appropriately.
+
+               IMPORT  get
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/sh/insert b/StraySrc/Libraries/BAS/src/sh/insert
new file mode 100644 (file)
index 0000000..31919d2
--- /dev/null
@@ -0,0 +1,58 @@
+;
+; insert.sh
+;
+; Insert zero-filled chunks of data
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  insert_align
+;  insert_reserve
+
+; --- insert_align ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Inserts `0' bytes to align O% and P% to the next word
+;              boundary.
+
+               IMPORT  insert_align
+
+; --- insert_reserve ---
+;
+; On entry:    R0 == amount of memory to reserve
+;
+; On exit:     --
+;
+; Use:         Reserves R0 bytes of memory at the current position.  The
+;              memory is filled with 0s.
+
+               IMPORT  insert_reserve
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/sh/lit b/StraySrc/Libraries/BAS/src/sh/lit
new file mode 100644 (file)
index 0000000..0d0e36c
--- /dev/null
@@ -0,0 +1,82 @@
+;
+; lit.sh
+;
+; Literal pool management
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  lit_add
+;  lit_ltorg
+;  lit_init
+;  lit_end
+
+; --- lit_add ---
+;
+; On entry:    R0 == address of literal data
+;              R1 == size of literal data
+;              R2 == word align flag
+;
+; On exit:     R0 set up as described below.
+;
+; Use:         Adds the given data to the current literal pool.  On the
+;              first pass, it returns the value of P% in R0.  On the
+;              second pass, it returns the address of the literal item.
+
+               IMPORT  lit_add
+
+; --- lit_ltorg ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Inserts a literal pool at the current position.
+
+               IMPORT  lit_ltorg
+
+; --- lit_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises things for the Literal Manager.
+
+               IMPORT  lit_init
+
+; --- lit_end ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Tidies up the Literal Manager after saving an AOF file.
+
+               IMPORT  lit_end
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/sh/messages b/StraySrc/Libraries/BAS/src/sh/messages
new file mode 100644 (file)
index 0000000..1cb985c
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Message symbols [generated by msgAOF]
+;
+
+               [       :LNOT::DEF:msg__dfn
+               GBLL    msg__dfn
+
+               IMPORT  msg_errBadArg
+               IMPORT  msg_errNoMoreMem
+               IMPORT  msg_errBadLValue
+               IMPORT  msg_errVarNotFound
+               IMPORT  msg_errOddString
+               IMPORT  msg_errInitTwice
+               IMPORT  msg_errNoAreas
+               IMPORT  msg_errNotInArea
+               IMPORT  msg_errNoArea
+               IMPORT  msg_errMultiEntry
+               IMPORT  msg_errExpImported
+               IMPORT  msg_errNotDone
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/sh/string b/StraySrc/Libraries/BAS/src/sh/string
new file mode 100644 (file)
index 0000000..e5edd85
--- /dev/null
@@ -0,0 +1,164 @@
+;
+; string.sh
+;
+; String handling routines (control terminated)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  str_cpy
+;  str_len
+;  str_cmp
+;  str_icmp
+;  str_subst
+;  str_error
+;  str_buffer
+
+; --- str_cpy ---
+;
+; On entry:    R0 == destination string
+;              R1 == source string
+;
+; On exit:     R0 == pointer to terminator of destination
+;
+; Use:         Copies a string from one block to another.  It leaves the
+;              destination pointer at the end of the string so that any
+;              subsequent copies concatenate other bits on the same string.
+;              Single characters can of course be appended with
+;
+;                      MOV     Rx,#&cc
+;                      STRB    Rx,[R0],#1
+
+               IMPORT  str_cpy
+
+; --- str_len ---
+;
+; On entry:    R0 == pointer to string
+;
+; On exit:     R0 == length of the string
+;
+; Use:         Calculates the length of a string.
+
+               IMPORT  str_len
+
+; --- str_cmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         Case-sensitively compares two strings.  You can use the
+;              normal ARM condition codes after the compare, so you can
+;              treat this fairly much like a normal CMP.
+
+               IMPORT  str_cmp
+
+; --- str_icmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         As for str_cmp above, but case-insensitive.
+
+               IMPORT  str_icmp
+
+; --- str_subst ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R1 == Pointer to output buffer
+;              R2-R11 == Pointer to filler strings (optional)
+;
+; On exit:     R0 == Pointer to start of buffer
+;              R1 == Pointer to terminating null
+;
+; Use:         Performs string substitution, filling in a skeleton string
+;              containing placeholders with `filler' strings.  The
+;              placeholders are actually rather powerful.  The syntax of
+;              these is as follows:
+;
+;                      `%' [<type>] <digit>
+;
+;              (spaces are for clarity -- in fact you must not include
+;              spaces in the format string.)
+;
+;              <digit> is any charater between `0' and `9'.  It refers to
+;              registers R2-R11 (so `0' means R2, `5' is R7 etc.)  How the
+;              value is interpreted is determined by <type>.
+;
+;              <type> is one of:
+;
+;              s       String.  This is the default.  The register is
+;                      considered to be a pointer to an ASCII string
+;                      (control terminated).
+;
+;              i       Integer.  The (signed) decimal representation is
+;                      inserted.  Leading zeros are suppressed.
+;
+;              x       Hex fullword.  The hexadecimal representation of the
+;                      register is inserted.  Leading zeros are included.
+;
+;              b       Hex byte.  The hexadecimal representation of the
+;                      least significant byte is inserted.  Leading zeros
+;                      are included.
+;
+;              c       Character.  The ASCII character corresponding to the
+;                      least significant byte is inserted.
+
+               IMPORT  str_subst
+
+; --- str_error ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R2-R11 == Pointers to fillin strings
+;
+; On exit:     R0 == Pointer to error in buffer
+;              R1 == Pointer to terminator
+;
+; Use:         Fills in an error skeleton (containing a 4 byte error number
+;              and a control terminated skeleton string as for str_subst)
+;              and returns the address of the filled in error block.  The
+;              error block is stored in a buffer obtained from str_buffer.
+;
+;              Filler strings may be held in the scratchpad.
+
+               IMPORT  str_error
+
+; ---- str_buffer ---
+;
+; On entry:    --
+;
+; On exit:     R1 == pointer to the next free buffer
+;
+; Use:         Returns a pointer to a 256-byte buffer.  There are at present
+;              2 buffers, which are returned alternately.
+
+               IMPORT  str_buffer
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/sh/vars b/StraySrc/Libraries/BAS/src/sh/vars
new file mode 100644 (file)
index 0000000..c1374ab
--- /dev/null
@@ -0,0 +1,46 @@
+;
+; vars.sh
+;
+; Setting up useful variables for BAS
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  vars_set
+
+; --- vars_set ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets up variable names for registers (normal and APCS) and
+;              also for condition codes.
+
+               IMPORT  vars_set
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/BAS/src/sh/workspace b/StraySrc/Libraries/BAS/src/sh/workspace
new file mode 100644 (file)
index 0000000..517e65c
--- /dev/null
@@ -0,0 +1,76 @@
+;
+; workspace.sh
+;
+; Global workspace for BAS
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's BASIC Assembler Supplement.
+;
+; BAS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; BAS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with BAS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               ^       0,R12
+
+bas_wStart     #       0
+
+               ; --- BASIC environment ---
+
+be__interface  #       4                       ;BASIC interface block (R14)
+be__argp       #       4                       ;BASIC's workspace pointer
+be__percents   #       4                       ;Address of A%-Z% variables
+be__line       #       4                       ;Value of LINE passed in
+
+               ; --- String handling ---
+
+str__buffNum   #       4                       ;Which string buffer's next
+
+               ; --- AOF generation ---
+
+aof__relocCount        #       4                       ;Relocation disable counter
+aof__base      #       4                       ;Base address of code area
+aof__limit     #       4                       ;Address of first free byte
+aof__nextImport        #       4                       ;Next index for import
+aof__area      #       4                       ;Index of current area
+aof__pass      #       4                       ;Number of the current pass
+aof__objHead   #       12                      ;Header anchor/size
+aof__objReloc  #       12                      ;Relocations anchor/size
+aof__objSymT   #       12                      ;Symbol table anchor/size
+aof__objStrT   #       12                      ;String table anchor/size
+aof__imports   #       12                      ;Imports table anchor/size
+aof__noReloc   #       12                      ;Non-relocation table
+
+               ; --- Literal pool management ---
+
+lit__table     #       12                      ;Literal pool address table
+lit__contents  #       12                      ;Current pool contents
+lit__next      #       4                       ;Index of next literal pool
+
+               ; --- flex memory manager ---
+
+               GBLL    FLEXWS_STACK
+               GET     libs:sh.flexws
+
+               ; --- Various large buffers ---
+
+str__buffer    #       256*3                   ;A buffer for string handling
+
+bas_wSize      EQU     {VAR}-bas_wStart
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/AOF/Makefile,fe1 b/StraySrc/Libraries/Core/AOF/Makefile,fe1
new file mode 100644 (file)
index 0000000..2ab8bbd
--- /dev/null
@@ -0,0 +1,106 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: o.aof
+
+o.aof: o._aof
+       $(AR) -c o.aof o._aof
+o._aof: c.aof
+       $(COMPILE) c.aof
+
+install:
+
+clean:
+       -$(RM) o.*
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o._aof:        c.aof
+o._aof:        h.aof
+o._aof:        h.chunk
diff --git a/StraySrc/Libraries/Core/AOF/README b/StraySrc/Libraries/Core/AOF/README
new file mode 100644 (file)
index 0000000..6184c62
--- /dev/null
@@ -0,0 +1,8 @@
+AOFlib
+~~~~~~
+
+This is a trivial library of definitions and simple functions used for
+generating AOF files.  It's not worth documenting; just to point out
+that it's used in `cdll' and `setdate'.
+--
+[mdw]
diff --git a/StraySrc/Libraries/Core/AOF/c/aof b/StraySrc/Libraries/Core/AOF/c/aof
new file mode 100644 (file)
index 0000000..98ed5a7
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * aof.c
+ *
+ * Creating AOF files
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's AOF library (aoflib).
+ *
+ * Aoflib is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Aoflib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aoflib.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "aof.h"
+#include "chunk.h"
+
+extern void aof_error(void);
+
+int aof_fillBlock(void *p,size_t offset,size_t l,aof_chunkinfo *i)
+{
+  void *xp;
+  if (offset+l>i->size)
+  {
+    i->size=(offset+l+255)&~255;
+    xp=realloc(i->p,i->size);
+    if (!xp)
+      aof_error();
+    i->p=xp;
+  }
+  memcpy(i->p+offset,p,l);
+  return (offset);
+}
+
+int aof_addBlock(void *p,size_t l,aof_chunkinfo *i)
+{
+  aof_fillBlock(p,i->next,l,i);
+  i->next+=l;
+  return (i->next-l);
+}
+
+int aof_branch(int from,int to)
+{
+  return (0xEA000000 | (((to-from-8) & 0x03FFFFFC) >> 2));
+}
+
+void aof_reloc(char *name,int offset,int weak,aof_file *f)
+{
+  aof_symbol sym={0};
+  aof_relocstr r={0};
+  sym.name=aof_string(name,f->strt);
+  sym.defined=0;
+  sym.export=1;
+  sym.weak=weak;
+  r.offset=offset;
+  r.t.type_1.symbol=aof_add(sym,f->symt)/sizeof(aof_symbol);
+  r.t.type_1.field=aof_FULLWORD;
+  r.t.type_1.type=aof_ADDITIVE;
+  r.t.type_1.symreloc=1;
+
+  aof_add(r,f->reloc);
+}
+
+void aof_reloc_b(char *name,int offset,aof_file *f)
+{
+  aof_symbol sym={0};
+  aof_relocstr r={0};
+  sym.name=aof_string(name,f->strt);
+  sym.defined=0;
+  sym.export=1;
+  r.offset=offset;
+  r.t.type_1.symbol=aof_add(sym,f->symt)/sizeof(aof_symbol);
+  r.t.type_1.field=aof_FULLWORD;
+  r.t.type_1.type=aof_PCRELATIVE;
+  r.t.type_1.symreloc=1;
+  aof_add(r,f->reloc);
+}
+
+void aof_roff(int offset,aof_file *f)
+{
+  aof_relocstr r={0};
+  r.offset=offset;
+  r.t.type_1.field=aof_FULLWORD;
+  r.t.type_1.type=aof_ADDITIVE;
+  r.t.type_1.symreloc=0;
+  aof_add(r,f->reloc);
+}
+
+void aof_addsym(char *name,int offset,int local,int area,aof_file *f)
+{
+  aof_symbol sym={0};
+  sym.name=aof_string(name,f->strt);
+  sym.defined=1;
+  sym.export=!local;
+  sym.value=offset;
+  sym.area=area;
+  aof_add(sym,f->symt);
+}
diff --git a/StraySrc/Libraries/Core/AOF/h/alf b/StraySrc/Libraries/Core/AOF/h/alf
new file mode 100644 (file)
index 0000000..dbf7f13
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * alf.h
+ *
+ * Definitions about Acorn Library Format
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's AOF library (aoflib).
+ *
+ * Aoflib is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Aoflib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aoflib.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __alf_h
+#define __alf_h
+
+typedef struct
+{
+  int chunkIndex;                      /* Chunk index of actual AOF    */
+  int entryLength;                     /* Length of this entry         */
+  int dataLength;                      /* Length of the data string    */
+  char data[1];                                /* Unsized data array           */
+}
+alf_symTable;
+
+#endif
diff --git a/StraySrc/Libraries/Core/AOF/h/aof b/StraySrc/Libraries/Core/AOF/h/aof
new file mode 100644 (file)
index 0000000..c0cc53b
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * aof.h
+ *
+ * Definitions for Acorn Object Format
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's AOF library (aoflib).
+ *
+ * Aoflib is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Aoflib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aoflib.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __aof_h
+#define __aof_h
+
+#define aof_RELOC (0xC5E2D080ul)       /* Relocatable object type      */
+
+typedef struct
+{
+  unsigned long type;                  /* Type of object file          */
+  int version;                         /* Version number of the format */
+  int areas;                           /* Number of AREAs defined      */
+  int symbols;                         /* Number of symbols in table   */
+  int entryArea;                       /* Index of AREA with ENTRY att */
+  int entryOff;                                /* Offset in AREA for ENTRY     */
+}
+aof_fixedHeader;
+
+typedef struct
+{
+  int name;                            /* AREA name (OBJ_STRT offset)  */
+
+  int alignment                        :8;     /* AREA alignment (must be 2)   */
+
+  int                          :1;     /* Reserved bit                 */
+  int code                     :1;     /* AREA contains code           */
+  int common                   :1;     /* Common AREA definition       */
+  int commonRef                        :1;     /* Reference to common AREA     */
+  int zinit                    :1;     /* AREA is zero-initialised     */
+  int readonly                 :1;     /* AREA is (sort-of) readonly   */
+  int                          :1;     /* Reserved bit                 */
+  int debug                    :1;     /* AREA contains debug tables   */
+  int                          :16;    /* Reserved shortword           */
+
+  int size;                            /* Size of this AREA            */
+  int relocs;                          /* Number of relocations        */
+  int                          :32;    /* Reserved word                */
+}
+aof_areaEntry;
+
+typedef struct
+{
+  aof_fixedHeader hdr;                 /* The fixed header info        */
+  aof_areaEntry table[1];              /* AREA table (unsized array)   */
+}
+aof_header;
+
+typedef struct
+{
+  int name;                            /* Name string table entry      */
+
+  int defined                  :1;     /* Symbol defined in file       */
+  int export                   :1;     /* Symbol is exported globally  */
+  int absolute                 :1;     /* Symbol not relative to AREA  */
+  int ignoreCase               :1;     /* Symbol is not case sensitive */
+  int weak                     :1;     /* Symbol is weak external ref  */
+  int strong                   :1;     /* Symbol is strong global      */
+  int common                   :1;     /* Symbol is in a common AREA   */
+  int                          :32-7;  /* Pad out to integer boundary  */
+
+  int value;                           /* Value of the symbol          */
+  int area;                            /* Offset of AREA name          */
+}
+aof_symbol;
+
+typedef struct
+{
+  int offset;                          /* Offset of word to relocate   */
+  union
+  {
+    struct
+    {
+      int symbol               :16;    /* Symbol to relocate by/to     */
+      int field                        :2;     /* Field size to alter          */
+      int type                 :1;     /* Relocation type              */
+      int symreloc             :1;     /* Relocation is symbol-relative*/
+      int                      :12;    /* Reserved bits                */
+    }
+    type_1;                            /* Type 1 relocation directive  */
+
+    struct
+    {
+      int symbol               :24;    /* Symbol to relocate by/to     */
+      int field                        :2;     /* Field size to alter          */
+      int type                 :1;     /* Relocation type              */
+      int symreloc             :1;     /* Relocation is symbol-relative*/
+      int                      :3;     /* Reserved bits                */
+      int set_me               :1;     /* Set this bit for type 2      */
+    }
+    type_2;                            /* Type 2 relocation directive  */
+  }
+  t;
+}
+aof_relocstr;
+
+enum
+{
+  aof_BYTE,
+  aof_HALFWORD,
+  aof_FULLWORD
+};
+
+enum
+{
+  aof_ADDITIVE,
+  aof_PCRELATIVE
+};
+
+typedef struct
+{
+  char *p;                             /* Pointer to string table      */
+  int size;                            /* Current allocated size       */
+  int next;                            /* Next position to fill        */
+}
+aof_chunkinfo;
+
+typedef struct
+{
+  aof_chunkinfo *area;
+  aof_chunkinfo *symt;
+  aof_chunkinfo *strt;
+  aof_chunkinfo *reloc;
+}
+aof_file;
+
+int aof_fillBlock(void *p,size_t offset,size_t l,aof_chunkinfo *i);
+
+int aof_addBlock(void *p,size_t l,aof_chunkinfo *i);
+
+#define aof_string(string,i) \
+  (aof_addBlock(string,strlen(string)+1,i))
+#define aof_add(z,i) \
+  (aof_addBlock(&(z),sizeof(z),i))
+#define aof_fill(z,o,i) \
+  (aof_fillBlock(&(z),o,sizeof(z),i))
+#define aof_int(x,i) \
+  (aof_addBlock((o=x,&o),sizeof(int),i))
+#define aof_byte(x,i) \
+  (aof_addBlock((o=x,&o),1,i))
+#define aof_align(i) \
+  (aof_addBlock((o=0,&o),(4-i.next)&3,&i))
+
+int aof_branch(int from,int to);
+
+void aof_reloc(char *name,int offset,int weak,aof_file *f);
+
+void aof_reloc_b(char *name,int offset,aof_file *f);
+
+void aof_roff(int offset,aof_file *f);
+
+void aof_addsym(char *name,int offset,int local,int area,aof_file *f);
+
+#endif
diff --git a/StraySrc/Libraries/Core/AOF/h/chunk b/StraySrc/Libraries/Core/AOF/h/chunk
new file mode 100644 (file)
index 0000000..f16e6a0
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * chunk.h
+ *
+ * Chunk file format definitions
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's AOF library (aoflib).
+ *
+ * Aoflib is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Aoflib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Aoflib.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __chunk_h
+#define __chunk_h
+
+
+#define chunk_MAGIC (0xC3CBC6C5ul)
+
+typedef struct
+{
+  char chunkName[8];                   /* The name of this chunk       */
+  int offset;                          /* Offset of chunk data in file */
+  int size;                            /* Size of the chunk data       */
+}
+chunk_tableEntry;
+
+typedef struct
+{
+  unsigned long id;                    /* Chunk file magic number      */
+  int maxChunks;                       /* Number of chunks allocated   */
+  int numChunks;                       /* Number of chunks used        */
+}
+chunk_fixedHeader;
+
+typedef struct
+{
+  chunk_fixedHeader hdr;               /* The file's header info       */
+  chunk_tableEntry table[1];           /* Chunk entries (unsized array)*/
+}
+chunk_header;
+
+#endif
diff --git a/StraySrc/Libraries/Core/EmbTemp/Makefile,fe1 b/StraySrc/Libraries/Core/EmbTemp/Makefile,fe1
new file mode 100644 (file)
index 0000000..1110c30
--- /dev/null
@@ -0,0 +1,98 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: o.embtemp
+
+install:
+
+clean:
+       -$(RM) o.*
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/Libraries/Core/EmbTemp/README b/StraySrc/Libraries/Core/EmbTemp/README
new file mode 100644 (file)
index 0000000..acff938
--- /dev/null
@@ -0,0 +1,49 @@
+Embedded Templates
+~~~~~~~~~~~~~~~~~~
+
+For small programs, it's irritating to have a separate templates file
+hanging around.  Separate files aren't necessary for sprites or messages,
+so templates become rather annoying.  An `embedded template' is a
+position-independent in-memory representation of a window template which
+has had some extra information added to make it particularly easy to
+construct a real window definition.  (The idea of adding relocation
+offsets is admittedly based on the Toolbox resource format.)  This
+trivial library unpacks embedded templates.
+
+The format of an embedded template is (I think) as follows:
+
+Offset   Size          Value
+
+   0       4           Offset to window definition ($w$)
+   4       4           Offset to indirected data ($i$)
+   8       4           Offset to limit of the template ($l$)
+  12   $w - 12$        Relocation directives
+
+ $w$    $i - w$        Template window definition (as in template files)
+
+ $i$    $l - i$        Initialisation strings for indirected icons and
+                       window titles.  This will be copied literally
+                       into the application's indirected data space.
+
+Each relocation directive consists of a single word; the top four bits of
+a relocation directive determine the `type'; the bottom twenty-eight bits
+give the `offset'.
+
+Currently defined types are:
+
+Type   Meaning
+
+  0    Add the address of the indirected data area to the word at the
+               given offset into the window definition.
+  1    Store the `window sprite area' in the word at the given offset
+               into the window definition.
+  2    Store the `icon sprite area' in the word at the given offset
+               into the window definition.
+
+Embedded templates are not meant to be built by hand.  Instead, the
+programs `templAOF' and `resGen' will build AOF files containing embedded
+template defintions from standard template files.  These can be linked
+into applications and modules.
+
+--
+[mdw]
diff --git a/StraySrc/Libraries/Core/EmbTemp/s/embTemp b/StraySrc/Libraries/Core/EmbTemp/s/embTemp
new file mode 100644 (file)
index 0000000..d103544
--- /dev/null
@@ -0,0 +1,126 @@
+;
+; embTemp.s
+;
+; Handle embedded templates
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core libraries (corelib).
+;
+; Corelib is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Corelib is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Corelib.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Resources$$Code|,CODE,READONLY
+
+; --- embTemp_extract ---
+;
+; On entry:    R0 == pointer to template block
+;              R1 == pointer to window definition block
+;              R2 == pointer to indirection space
+;              R3 == pointer to end of indirection space
+;              R4 == pointer to window sprite area
+;              R5 == pointer to icon sprite area
+;
+; On exit:     R2 == updated
+;
+; Use:         Loads an embedded template (generated by templAOF) into a
+;              block.
+
+               EXPORT  embTemp_extract
+embTemp_extract        ROUT
+
+               STMFD   R13!,{R0,R1,R3-R12,R14} ;Save some registers
+               MOV     R12,R0                  ;Look after this pointer
+               LDMIA   R0!,{R9-R11}            ;Load offsets from block
+               ADD     R9,R9,R12               ;Relocate window offset
+               ADD     R10,R10,R12             ;And the indirected offset
+               ADD     R11,R11,R12             ;And the limit offset
+
+               ; --- Copy the window block over --
+
+               MOV     R0,R1                   ;Point to destination block
+00             LDMIA   R9!,{R6-R8,R14}         ;Load 16 words
+               STMIA   R0!,{R6-R8,R14}         ;And blat them out again
+               CMP     R9,R10                  ;Have we finished yet?
+               BCC     %b00                    ;No -- keep on going then
+
+               ; --- Now copy the indirected data ---
+
+               SUB     R14,R3,R2               ;Find how much room we have
+               SUB     R9,R11,R10              ;And how much there is
+               CMP     R14,R9                  ;Do we have enough?
+               ADRCC   R0,embTemp_noRoom       ;No -- complain then
+               SWICC   OS_GenerateError        ;Really make a go of it
+               MOV     R0,R2                   ;Get a copy of output pointer
+
+00             SUBS    R9,R9,#16               ;Knock another 16 bytes off
+               LDMCSIA R10!,{R6-R8,R14}        ;If OK, load lots of data
+               STMCSIA R2!,{R6-R8,R14}         ;And store it out again
+               BCS     %b00                    ;And loop back for more
+
+               ADD     R9,R9,#16               ;Now we overshot a bit
+00             SUBS    R9,R9,#1                ;Knock one byte off
+               LDRCSB  R14,[R10],#1            ;Load a byte out
+               STRCSB  R14,[R2],#1             ;Store it out again
+               BCS     %b00                    ;And loop back for more
+               ADD     R2,R2,#3                ;Word align output pointer
+               BIC     R2,R2,#3                ;To make next call nice
+
+               ; --- Now do the relocation ---
+
+               ADD     R10,R12,#12             ;Point to relocation table
+               LDR     R11,[R12,#0]            ;Find end of relocations
+               ADD     R11,R11,R12             ;Relocate that nicely
+
+00             CMP     R10,R11                 ;Reached the end yet?
+               LDMCSFD R13!,{R0,R1,R3-R12,PC}^ ;Yes -- that's it then
+               LDR     R14,[R10],#4            ;Load next directive
+               BIC     R3,R14,#&F0000000       ;Just leave the offset
+               ADD     PC,PC,R14,LSR #26       ;Jump table time
+               DCB     "MDW!"
+               B       %10embTemp_extract      ;Handle indirect data reloc
+               B       %20embTemp_extract      ;Handle window sprite reloc
+               B       %30embTemp_extract      ;Handle icon sprite reloc
+
+10             LDR     R14,[R1,R3]             ;Load the word
+               ADD     R14,R14,R0              ;Relocate by indirected space
+               STR     R14,[R1,R3]             ;Store it back again
+               B       %b00                    ;And loop
+
+20             STR     R4,[R1,R3]              ;Store window sprite area
+               B       %b00                    ;And loop
+
+30             STR     R5,[R1,R3]              ;Store icon sprite area
+               B       %b00                    ;And loop
+
+embTemp_noRoom DCD     1
+               DCB     "No memory for indirected data",0
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/EmbTemp/sh/embTemp b/StraySrc/Libraries/Core/EmbTemp/sh/embTemp
new file mode 100644 (file)
index 0000000..810c1c9
--- /dev/null
@@ -0,0 +1,38 @@
+;
+; embTemp.sh
+;
+; Handle embedded templates
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  embTemp_extract
+
+               [       :LNOT::DEF:embTemp__dfn
+               GBLL    embTemp__dfn
+
+; --- embTemp_extract ---
+;
+; On entry:    R0 == pointer to template block
+;              R1 == pointer to window definition block
+;              R2 == pointer to indirection space
+;              R3 == pointer to end of indirection space
+;              R4 == pointer to window sprite area
+;              R5 == pointer to icon sprite area
+;
+; On exit:     R2 == updated
+;
+; Use:         Loads an embedded template (generated by templAOF) into a
+;              block.
+
+               IMPORT  embTemp_extract
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/Makefile,fe1 b/StraySrc/Libraries/Core/Makefile,fe1
new file mode 100644 (file)
index 0000000..03096e7
--- /dev/null
@@ -0,0 +1,163 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+STUBS = o.astubs o.asstubs o.mstubs o.msstubs o.dstubs
+
+STUB_ENTRY = o.xentry o.xentry_swi o.xsmall o.xsmall_swi
+STUB_PERSONALITY = o.xapp o.xdll o.xmodule
+STUB_OTHER = o.xcommon o.xdata
+
+#----- Compiling things -----------------------------------------------------
+
+all: o.rdump o.swiv $(STUBS)
+       submake *.Makefile
+
+# --- The `rdump' library ---
+
+o.rdump: o._rdump
+       $(AR) -c o.rdump o._rdump
+o._rdump: s.rdump
+       $(ASSEMBLE) s.rdump
+
+# --- Various flavours of C library stubs ---
+
+ASTUBS_OBJ = o.xapp o.xsmall $(STUB_OTHER)
+o.astubs: $(ASTUBS_OBJ)
+       $(LD_AOF) $(ASTUBS_OBJ)
+       $(FIXLINK)
+
+ASSTUBS_OBJ = o.xapp o.xsmall_swi $(STUB_OTHER)
+o.asstubs: $(ASSTUBS_OBJ)
+       $(LD_AOF) $(ASSTUBS_OBJ)
+       $(FIXLINK)
+
+DSTUBS_OBJ = o.xdll o.xentry
+o.dstubs: $(DSTUBS_OBJ)
+       $(LD_AOF) $(DSTUBS_OBJ)
+       $(FIXLINK)
+
+MSTUBS_OBJ = o.xmodule o.xentry $(STUB_OTHER)
+o.mstubs: $(MSTUBS_OBJ)
+       $(LD_AOF) $(MSTUBS_OBJ)
+       $(FIXLINK)
+
+MSSTUBS_OBJ = o.xmodule o.xentry_swi $(STUB_OTHER)
+o.msstubs: $(MSSTUBS_OBJ)
+       $(LD_AOF) $(MSSTUBS_OBJ)
+       $(FIXLINK)
+
+# --- Installation ---
+
+install:
+       submake *.Makefile -- install
+
+# --- Cleaning up ---
+
+clean:
+       -$(RM) o.*
+       submake *.Makefile -- clean
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.xsmall: s.xentry
+o.xapp: libs:header
+o.xapp: libs:swis
+o.xsmall_swi: s.xentry
+o.xmodule: libs:header
+o.xmodule: libs:swis
+o.xentry_swi: s.xentry
+o.xcommon: libs:header
+o.xdll: libs:header
+o.xdll: libs:swis
+o._rdump: libs:header
+o._rdump: libs:swis
+o.swiv: libs:header
+o.swiv: libs:swis
+o.swiv: libs:s.xswi
+o.swiv: libs:s.swihack
diff --git a/StraySrc/Libraries/Core/TearSupt/Makefile,fe1 b/StraySrc/Libraries/Core/TearSupt/Makefile,fe1
new file mode 100644 (file)
index 0000000..5343fae
--- /dev/null
@@ -0,0 +1,102 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: o.tearSupt tt
+
+tt: o.tt o.tearSupt
+       $(LD_APP) o.tt o.tearSupt
+       $(SET_APP)
+
+install:
+
+clean:
+       -$(RM) o.* tt
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/Libraries/Core/TearSupt/README b/StraySrc/Libraries/Core/TearSupt/README
new file mode 100644 (file)
index 0000000..c8ba56d
--- /dev/null
@@ -0,0 +1,92 @@
+Tearoff Menu System
+~~~~~~~~~~~~~~~~~~~
+
+A while ago, as Tim was leaving after a hacking session, I mentioned how
+nice it would be if only RISC OS allowed menus to be tearoffable, like
+OpenLook menus are.  He pointed out that impossibility shouldn't be much
+of a barrier to us, and we got coding.
+
+Tearoff menus look just like normal menus, except there's a grey bar
+along the top, just below the title, with a `Tear' button in it.  When
+the user clicks the `Tear' button, the rest of the menu tree goes away,
+leaving the tornoff menu behind, so that options can be chosen from it
+whenever the user needs to.  Tornoff menus have two buttons in their
+grey bar area: `Close' closes the menu, and `Fold' hides the menu part
+away, leaving just the title behind, a bit like Corel's rollups (only
+without the irritating animation).
+
+The main support code was written as part of STEEL, in C.  It handles
+the obvious (but quite difficult) stuff related to highlighting the
+right items, opening the right submenus, and drawing the windows, and
+Tim wrote it all.  (He later wrote the corresponding Sapphire code --
+the user- and programmer-visible bits of our tearoff support are
+entirely written by him.)
+
+There's one aspect of tearoff handling which can't be handled from an
+application: making the main menu tree `transient'.  There are three
+times when the Wimp closes a transient window `silently':
+
+  * when the user clicks outside of the menu tree;
+  * when the user presses the `Escape' key; and
+  * when an application calls Wimp_CreateMenu.
+
+In the first case, the mouse click is passed on to the receiving window;
+in the second, the keypress is swallowed by the Wimp.
+
+These three cases are handled by some vector interceptions.  Normally
+this would be done by a module.  Tim wanted the vector traps to be hard
+to extract, though, and a small module would be easy for other
+programmers to reverse engineer and implement their own tearoffs.  The
+`tearoff support code' is statically linked into the application which
+uses it, and copied into an RMA block if it's not there already.
+
+The interface to the TearSupt code is simple:
+
+  * ts_init initialises the support code.
+
+  * ts_opened says that the application has opened a transient window,
+    and wants to be notified about events which might cause it to be
+    closed.
+
+  * ts_closed says that the transient window has been closed.
+
+  * ts_switch switches Wimp_CreateMenu trapping on and off (an
+    implemention detail requires this).
+
+  * ts_unload removes the tearoff support code from memory.
+
+Tearoff Support traps several vectors.  One is trapped all the time:
+
+  * ChangeEnvironmentV is trapped, as part of a particularly hacky way
+    of communicating with the TearSupt code.  It traps a call with R0 =
+    -1 and returns its address and version number.  This is very nasty.
+
+Others are only trapped while there's a `fake transient' open, and cause
+Wimp messages to be sent to the owner of the window:
+
+  * MouseV is trapped: all mouse clicks are picked up, and passed on as
+    messages.
+
+  * InsV is trapped: insertion of an `escape' keypress into the keyboard
+    buffer causes a message to be sent.
+
+  * The hardware SWI vector is trapped: a call to Wimp_CreateMenu causes
+    a message to be sent.
+
+Just to make life more awkward, the code is encrypted (very weakly: it's
+not worth the effort and code space of doing it properly).  I considered
+removing the encryption code, but (a) I preferred to leave everything
+the way it was (more or less) as a record of the nasty things Straylight
+sometimes do, and (b) I couldn't be bothered.
+
+Anyway, all the code is really nasty.  I'd recommend that you avoid
+reading it too closely.  Oh, the SWI patch may be instructive to those
+who've not seen the job done before: I think it works properly in all
+circumstances.
+
+Of course, anyone's allowed to use tearoff menus.  You're even allowed
+to use our code to implement them, as long as you stick to the GPL.  And
+finally, if someone comes up with a SWI chunk, I may be convinced to
+permit binary distribution of a tearoff support module using our code.
+--
+[mdw]
diff --git a/StraySrc/Libraries/Core/TearSupt/UnLoad,ffb b/StraySrc/Libraries/Core/TearSupt/UnLoad,ffb
new file mode 100644 (file)
index 0000000..8c2607e
Binary files /dev/null and b/StraySrc/Libraries/Core/TearSupt/UnLoad,ffb differ
diff --git a/StraySrc/Libraries/Core/TearSupt/bs/tearSupt,ffb b/StraySrc/Libraries/Core/TearSupt/bs/tearSupt,ffb
new file mode 100644 (file)
index 0000000..afd6462
Binary files /dev/null and b/StraySrc/Libraries/Core/TearSupt/bs/tearSupt,ffb differ
diff --git a/StraySrc/Libraries/Core/TearSupt/h/tearSupt b/StraySrc/Libraries/Core/TearSupt/h/tearSupt
new file mode 100644 (file)
index 0000000..706d1ee
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * tearSupt.h
+ *
+ * Tearoff support code
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Tearoff Menu System (TMS), but it's
+ * distributed with Straylight's core libraries (corelib).
+ *
+ * TMS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * TMS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Corelib.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __tearSupport_h
+#define __tearSupport_h
+
+/* --- tearSupport_init --- *
+ *
+ * Arguments:  --
+ *
+ * Returns:    --
+ *
+ * Use:                Initialises tearSupport
+ */
+
+void tearSupport_init(void);
+
+/* --- tearSupport_opened --- *
+ *
+ * Arguments:  task == task handle of task which opened tearoff menu
+ *
+ * Returns:    --
+ *
+ * Use:                Informs TearSupport that a transient tearoff menu has been
+ *             opened, and which task owns the menu.
+ */
+
+void tearSupport_opened(int task);
+
+/* --- tearSupport_closed --- *
+ *
+ * Arguments:  --
+ *
+ * Returns:    --
+ *
+ * Use:                Informs TearSupport that the transient tearoff menu has been
+ *             closed, and that support is no longer required for it.
+ */
+
+void tearSupport_closed(void);
+
+/* --- tearSupport_switch ---
+ *
+ * Arguments:  sw == 1 to disable, 0 to enable trapping
+ *
+ * Returns:    --
+ *
+ * Use:                Enables or disables trapping of Wimp_CreateMenu while a
+ *             transient tearoff menu is open.  This is intended to allow
+ *             use of Wimp_CreateMenu by the transient tearoff owner while
+ *             a transient tearoff is open (e.g. to close Wimp menus).
+ */
+
+void tearSupport_switch(int sw);
+
+#endif
diff --git a/StraySrc/Libraries/Core/TearSupt/s/tt b/StraySrc/Libraries/Core/TearSupt/s/tt
new file mode 100644 (file)
index 0000000..d004bf7
--- /dev/null
@@ -0,0 +1,22 @@
+ GET libs:header
+ GET libs:swis
+
+ IMPORT tearSupport_init
+
+ AREA |foo$$code|,CODE,READONLY
+
+ ENTRY
+
+
+main
+ MOV R13,#&9000
+ BL tearSupport_init
+ ADR R0,message
+ SWI OS_GenerateError
+ SWI OS_Exit
+
+message
+ DCD 1
+ DCB "Tearoff support code installed OK",0
+
+ END
diff --git a/StraySrc/Libraries/Core/TearSupt/sh/tearSupt b/StraySrc/Libraries/Core/TearSupt/sh/tearSupt
new file mode 100644 (file)
index 0000000..6252a8e
--- /dev/null
@@ -0,0 +1,75 @@
+;
+; tearSupt.sh
+;
+; Tearoff support code
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Tearoff Menu System (TMS), but it's
+; distributed with Straylight's core libraries (corelib).
+;
+; TMS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; TMS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Corelib.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+; --- tearSupport_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises tearSupport
+
+               IMPORT  tearSupport_init
+
+; --- tearSupport_opened ---
+;
+; On entry:    R0 == task handle of task which opened tearoff menu
+;
+; On exit:     --
+;
+; Use:         Informs TearSupport that a transient tearoff menu has been
+;              opened, and which task owns the menu.
+
+               IMPORT  tearSupport_opened
+
+; --- tearSupport_closed ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Informs TearSupport that the transient tearoff menu has been
+;              closed, and that support is no longer required for it.
+
+               IMPORT  tearSupport_closed
+
+; --- tearSupport_switch ---
+;
+; On entry:    R0 == 1 to disable, 0 to enable trapping
+;
+; On exit:     --
+;
+; Use:         Enables or disables trapping of Wimp_CreateMenu while a
+;              transient tearoff menu is open.  This is intended to allow
+;              use of Wimp_CreateMenu by the transient tearoff owner while
+;              a transient tearoff is open (e.g. to close Wimp menus).
+
+               IMPORT  tearSupport_switch
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/dump b/StraySrc/Libraries/Core/dump
new file mode 100644 (file)
index 0000000..dd7aa97
--- /dev/null
@@ -0,0 +1,167 @@
+;
+; dump
+;
+; Dump a register block
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core library (corelib).
+;
+; Corelib is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Corelib is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Corelib.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+; dump
+;
+; Standard routine - displays contents of a register save block.  May be
+; used in SVC mode.
+;
+; Parameters:     R0 == pointer to block of 16 words, for value of R0-R15
+;                 R1 == pointer to string to display
+;
+; On exit:        Most registers corrupted.
+;
+; Notes:          Use DUMP macro to set up the call.  This will preserve all
+;                 registers and set up the save block etc.  This code will
+;                 be inserted only if necessary.
+
+               ROUT
+
+               [       hdr_incDump
+
+hdr_regDump    MOV     R8,R14                  ;Store link
+               SWI     XOS_IntOn
+               MOV     R9,R0                   ;Point to reg dump
+               MOV     R10,#0                  ;Register number
+               SWI     XOS_WriteS              ;Display header
+               DCB     6,26,4,12
+               DCB     "------------------------------------------"
+               DCB     13,10,10
+               DCB     "Register dump follows...",0
+               ALIGN
+               MOV     R0,R1                   ;Show message from macro
+               SWI     XOS_Write0              ;Show it
+               SWI     XOS_WriteS
+               DCB     13,10,10
+               DCB     "------------------------------------------"
+               DCB     13,10,10,0
+               ALIGN
+00             ADRL    R0,%f89                 ;Point to reg name table
+               ADD     R0,R0,R10,LSL #2        ;Point to correct one
+               SWI     XOS_Write0              ;Print on the screen
+               SWI     XOS_WriteS              ;Display next bit
+               DCB     " == ",0                ;What to display
+               ALIGN
+               LDR     R0,[R9,R10,LSL #2]      ;Get register contents
+               CMP     R10,#15                 ;Is this the PC?
+               BICEQ   R0,R0,#&FC000003        ;Yes - clear out PSR
+               ADRL    R1,%f88                 ;Buffer
+               MOV     R2,#16                  ;Length of buffer
+               SWI     XOS_ConvertHex8         ;Convert
+               SWI     XOS_Write0              ;Show on screen
+               SWI     XOS_NewLine             ;Start a new line
+               CMP     R10,#15                 ;Have we finished?
+               ADDNE   R10,R10,#1              ;No: move to next register
+               BNE     %b00
+
+               SWI     XOS_NewLine
+               SWI     XOS_WriteS              ;Display a message
+               DCB     "Processor mode: ",0
+               ALIGN
+               LDR     R7,[R9,R10,LSL #2]      ;Get the number again
+               AND     R1,R7,#&3               ;Get the processor mode
+               ADR     R0,%f87                 ;Point to message table
+               ADD     R0,R0,R1,LSL #2         ;Get appropriate one
+               SWI     XOS_Write0
+               SWI     XOS_NewLine
+               SWI     XOS_WriteS
+               DCB     "FIQ ",0
+               ALIGN
+               TST     R7,#FIQ_disable
+               ADREQ   R0,%f85
+               ADRNE   R0,%f86
+               SWI     XOS_Write0
+               SWI     XOS_WriteS
+               DCB     "IRQ ",0
+               ALIGN
+               TST     R7,#IRQ_disable
+               ADREQ   R0,%f85
+               ADRNE   R0,%f86
+               SWI     XOS_Write0
+               SWI     XOS_WriteS
+               DCB     "Other flags: ",0
+               ALIGN
+               TST     R7,#N_flag
+               MOVEQ   R0,#'n'
+               MOVNE   R0,#'N'
+               SWI     XOS_WriteC
+               TST     R7,#Z_flag
+               MOVEQ   R0,#'z'
+               MOVNE   R0,#'Z'
+               SWI     XOS_WriteC
+               TST     R7,#C_flag
+               MOVEQ   R0,#'c'
+               MOVNE   R0,#'C'
+               SWI     XOS_WriteC
+               TST     R7,#V_flag
+               MOVEQ   R0,#'v'
+               MOVNE   R0,#'V'
+               SWI     XOS_WriteC
+               SWI     XOS_WriteS
+               DCB     13,10,10
+               DCB     "Press any key to continue execution...",0
+               ALIGN
+               SWI     XOS_ReadC
+               CMP     R0,#17                  ;^Q
+               SWIEQ   OS_BreakPt
+               MOVS    PC,R8
+
+85
+               DCB     "enabled",13,10,0
+86
+               DCB     "disabled",13,10,0
+
+87
+               DCB     "USR",0
+               DCB     "FIQ",0
+               DCB     "IRQ",0
+               DCB     "SVC",0
+
+88
+               %       16                      ;Block for translation
+
+89
+               DCB     " R0",0
+               DCB     " R1",0
+               DCB     " R2",0
+               DCB     " R3",0
+               DCB     " R4",0
+               DCB     " R5",0
+               DCB     " R6",0
+               DCB     " R7",0
+               DCB     " R8",0
+               DCB     " R9",0
+               DCB     "R10",0
+               DCB     "R11",0
+               DCB     "R12",0
+               DCB     "R13",0
+               DCB     "R14",0
+               DCB     " PC",0
+               ALIGN
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Core/h/_time b/StraySrc/Libraries/Core/h/_time
new file mode 100644 (file)
index 0000000..f3293e0
--- /dev/null
@@ -0,0 +1,5 @@
+/*
+ * _time.h
+ */
+
+extern char _time[];
diff --git a/StraySrc/Libraries/Core/h/swis b/StraySrc/Libraries/Core/h/swis
new file mode 100644 (file)
index 0000000..cf827b6
--- /dev/null
@@ -0,0 +1,2724 @@
+/*
+ * swis.h
+ *
+ * SWI names from numbers [generated 24 January 1998 by SWIList]
+ * You may freely distribute and modify this file.
+ */
+
+#pragma force_top_level
+#pragma include_only_once
+
+#ifndef SWIS_H
+#define SWIS_H
+
+/* --- Kernel SWIs --- */
+
+#define OS_WriteI 0x00000100
+#define XOS_WriteI 0x00020100
+
+/* --- Kernel SWIs --- */
+
+#define OS_WriteC 0x00000000
+#define XOS_WriteC 0x00020000
+#define OS_WriteS 0x00000001
+#define XOS_WriteS 0x00020001
+#define OS_Write0 0x00000002
+#define XOS_Write0 0x00020002
+#define OS_NewLine 0x00000003
+#define XOS_NewLine 0x00020003
+#define OS_ReadC 0x00000004
+#define XOS_ReadC 0x00020004
+#define OS_CLI 0x00000005
+#define XOS_CLI 0x00020005
+#define OS_Byte 0x00000006
+#define XOS_Byte 0x00020006
+#define OS_Word 0x00000007
+#define XOS_Word 0x00020007
+#define OS_File 0x00000008
+#define XOS_File 0x00020008
+#define OS_Args 0x00000009
+#define XOS_Args 0x00020009
+#define OS_BGet 0x0000000A
+#define XOS_BGet 0x0002000A
+#define OS_BPut 0x0000000B
+#define XOS_BPut 0x0002000B
+#define OS_GBPB 0x0000000C
+#define XOS_GBPB 0x0002000C
+#define OS_Find 0x0000000D
+#define XOS_Find 0x0002000D
+#define OS_ReadLine 0x0000000E
+#define XOS_ReadLine 0x0002000E
+#define OS_Control 0x0000000F
+#define XOS_Control 0x0002000F
+#define OS_GetEnv 0x00000010
+#define XOS_GetEnv 0x00020010
+#define OS_Exit 0x00000011
+#define XOS_Exit 0x00020011
+#define OS_SetEnv 0x00000012
+#define XOS_SetEnv 0x00020012
+#define OS_IntOn 0x00000013
+#define XOS_IntOn 0x00020013
+#define OS_IntOff 0x00000014
+#define XOS_IntOff 0x00020014
+#define OS_CallBack 0x00000015
+#define XOS_CallBack 0x00020015
+#define OS_EnterOS 0x00000016
+#define XOS_EnterOS 0x00020016
+#define OS_BreakPt 0x00000017
+#define XOS_BreakPt 0x00020017
+#define OS_BreakCtrl 0x00000018
+#define XOS_BreakCtrl 0x00020018
+#define OS_UnusedSWI 0x00000019
+#define XOS_UnusedSWI 0x00020019
+#define OS_UpdateMEMC 0x0000001A
+#define XOS_UpdateMEMC 0x0002001A
+#define OS_SetCallBack 0x0000001B
+#define XOS_SetCallBack 0x0002001B
+#define OS_Mouse 0x0000001C
+#define XOS_Mouse 0x0002001C
+#define OS_Heap 0x0000001D
+#define XOS_Heap 0x0002001D
+#define OS_Module 0x0000001E
+#define XOS_Module 0x0002001E
+#define OS_Claim 0x0000001F
+#define XOS_Claim 0x0002001F
+#define OS_Release 0x00000020
+#define XOS_Release 0x00020020
+#define OS_ReadUnsigned 0x00000021
+#define XOS_ReadUnsigned 0x00020021
+#define OS_GenerateEvent 0x00000022
+#define XOS_GenerateEvent 0x00020022
+#define OS_ReadVarVal 0x00000023
+#define XOS_ReadVarVal 0x00020023
+#define OS_SetVarVal 0x00000024
+#define XOS_SetVarVal 0x00020024
+#define OS_GSInit 0x00000025
+#define XOS_GSInit 0x00020025
+#define OS_GSRead 0x00000026
+#define XOS_GSRead 0x00020026
+#define OS_GSTrans 0x00000027
+#define XOS_GSTrans 0x00020027
+#define OS_BinaryToDecimal 0x00000028
+#define XOS_BinaryToDecimal 0x00020028
+#define OS_FSControl 0x00000029
+#define XOS_FSControl 0x00020029
+#define OS_ChangeDynamicArea 0x0000002A
+#define XOS_ChangeDynamicArea 0x0002002A
+#define OS_GenerateError 0x0000002B
+#define XOS_GenerateError 0x0002002B
+#define OS_ReadEscapeState 0x0000002C
+#define XOS_ReadEscapeState 0x0002002C
+#define OS_EvaluateExpression 0x0000002D
+#define XOS_EvaluateExpression 0x0002002D
+#define OS_SpriteOp 0x0000002E
+#define XOS_SpriteOp 0x0002002E
+#define OS_ReadPalette 0x0000002F
+#define XOS_ReadPalette 0x0002002F
+#define OS_ServiceCall 0x00000030
+#define XOS_ServiceCall 0x00020030
+#define OS_ReadVduVariables 0x00000031
+#define XOS_ReadVduVariables 0x00020031
+#define OS_ReadPoint 0x00000032
+#define XOS_ReadPoint 0x00020032
+#define OS_UpCall 0x00000033
+#define XOS_UpCall 0x00020033
+#define OS_CallAVector 0x00000034
+#define XOS_CallAVector 0x00020034
+#define OS_ReadModeVariable 0x00000035
+#define XOS_ReadModeVariable 0x00020035
+#define OS_RemoveCursors 0x00000036
+#define XOS_RemoveCursors 0x00020036
+#define OS_RestoreCursors 0x00000037
+#define XOS_RestoreCursors 0x00020037
+#define OS_SWINumberToString 0x00000038
+#define XOS_SWINumberToString 0x00020038
+#define OS_SWINumberFromString 0x00000039
+#define XOS_SWINumberFromString 0x00020039
+#define OS_ValidateAddress 0x0000003A
+#define XOS_ValidateAddress 0x0002003A
+#define OS_CallAfter 0x0000003B
+#define XOS_CallAfter 0x0002003B
+#define OS_CallEvery 0x0000003C
+#define XOS_CallEvery 0x0002003C
+#define OS_RemoveTickerEvent 0x0000003D
+#define XOS_RemoveTickerEvent 0x0002003D
+#define OS_InstallKeyHandler 0x0000003E
+#define XOS_InstallKeyHandler 0x0002003E
+#define OS_CheckModeValid 0x0000003F
+#define XOS_CheckModeValid 0x0002003F
+#define OS_ChangeEnvironment 0x00000040
+#define XOS_ChangeEnvironment 0x00020040
+#define OS_ClaimScreenMemory 0x00000041
+#define XOS_ClaimScreenMemory 0x00020041
+#define OS_ReadMonotonicTime 0x00000042
+#define XOS_ReadMonotonicTime 0x00020042
+#define OS_SubstituteArgs 0x00000043
+#define XOS_SubstituteArgs 0x00020043
+#define OS_PrettyPrint 0x00000044
+#define XOS_PrettyPrint 0x00020044
+#define OS_Plot 0x00000045
+#define XOS_Plot 0x00020045
+#define OS_WriteN 0x00000046
+#define XOS_WriteN 0x00020046
+#define OS_AddToVector 0x00000047
+#define XOS_AddToVector 0x00020047
+#define OS_WriteEnv 0x00000048
+#define XOS_WriteEnv 0x00020048
+#define OS_ReadArgs 0x00000049
+#define XOS_ReadArgs 0x00020049
+#define OS_ReadRAMFsLimits 0x0000004A
+#define XOS_ReadRAMFsLimits 0x0002004A
+#define OS_ClaimDeviceVector 0x0000004B
+#define XOS_ClaimDeviceVector 0x0002004B
+#define OS_ReleaseDeviceVector 0x0000004C
+#define XOS_ReleaseDeviceVector 0x0002004C
+#define OS_DelinkApplication 0x0000004D
+#define XOS_DelinkApplication 0x0002004D
+#define OS_RelinkApplication 0x0000004E
+#define XOS_RelinkApplication 0x0002004E
+#define OS_HeapSort 0x0000004F
+#define XOS_HeapSort 0x0002004F
+#define OS_ExitAndDie 0x00000050
+#define XOS_ExitAndDie 0x00020050
+#define OS_ReadMemMapInfo 0x00000051
+#define XOS_ReadMemMapInfo 0x00020051
+#define OS_ReadMemMapEntries 0x00000052
+#define XOS_ReadMemMapEntries 0x00020052
+#define OS_SetMemMapEntries 0x00000053
+#define XOS_SetMemMapEntries 0x00020053
+#define OS_AddCallBack 0x00000054
+#define XOS_AddCallBack 0x00020054
+#define OS_ReadDefaultHandler 0x00000055
+#define XOS_ReadDefaultHandler 0x00020055
+#define OS_SetECFOrigin 0x00000056
+#define XOS_SetECFOrigin 0x00020056
+#define OS_SerialOp 0x00000057
+#define XOS_SerialOp 0x00020057
+#define OS_ReadSysInfo 0x00000058
+#define XOS_ReadSysInfo 0x00020058
+#define OS_Confirm 0x00000059
+#define XOS_Confirm 0x00020059
+#define OS_ChangedBox 0x0000005A
+#define XOS_ChangedBox 0x0002005A
+#define OS_CRC 0x0000005B
+#define XOS_CRC 0x0002005B
+#define OS_ReadDynamicArea 0x0000005C
+#define XOS_ReadDynamicArea 0x0002005C
+#define OS_PrintChar 0x0000005D
+#define XOS_PrintChar 0x0002005D
+#define OS_ChangeRedirection 0x0000005E
+#define XOS_ChangeRedirection 0x0002005E
+#define OS_RemoveCallBack 0x0000005F
+#define XOS_RemoveCallBack 0x0002005F
+#define OS_FindMemMapEntries 0x00000060
+#define XOS_FindMemMapEntries 0x00020060
+#define OS_SetColour 0x00000061
+#define XOS_SetColour 0x00020061
+#define OS_ClaimSWI 0x00000062
+#define XOS_ClaimSWI 0x00020062
+#define OS_ReleaseSWI 0x00000063
+#define XOS_ReleaseSWI 0x00020063
+#define OS_Pointer 0x00000064
+#define XOS_Pointer 0x00020064
+#define OS_ScreenMode 0x00000065
+#define XOS_ScreenMode 0x00020065
+#define OS_DynamicArea 0x00000066
+#define XOS_DynamicArea 0x00020066
+#define OS_AbortTrap 0x00000067
+#define XOS_AbortTrap 0x00020067
+#define OS_Memory 0x00000068
+#define XOS_Memory 0x00020068
+#define OS_ClaimProcessorVector 0x00000069
+#define XOS_ClaimProcessorVector 0x00020069
+#define OS_Reset 0x0000006A
+#define XOS_Reset 0x0002006A
+#define OS_MMUControl 0x0000006B
+#define XOS_MMUControl 0x0002006B
+#define OS_PlatformFeatures 0x0000006D
+#define XOS_PlatformFeatures 0x0002006D
+#define OS_SynchroniseCodeAreas 0x0000006E
+#define XOS_SynchroniseCodeAreas 0x0002006E
+#define OS_CallASWI 0x0000006F
+#define XOS_CallASWI 0x0002006F
+#define OS_AMBControl 0x00000070
+#define XOS_AMBControl 0x00020070
+#define OS_CallASWIR12 0x00000071
+#define XOS_CallASWIR12 0x00020071
+#define OS_ConvertStandardDateAndTime 0x000000C0
+#define XOS_ConvertStandardDateAndTime 0x000200C0
+#define OS_ConvertDateAndTime 0x000000C1
+#define XOS_ConvertDateAndTime 0x000200C1
+#define OS_ConvertHex1 0x000000D0
+#define XOS_ConvertHex1 0x000200D0
+#define OS_ConvertHex2 0x000000D1
+#define XOS_ConvertHex2 0x000200D1
+#define OS_ConvertHex4 0x000000D2
+#define XOS_ConvertHex4 0x000200D2
+#define OS_ConvertHex6 0x000000D3
+#define XOS_ConvertHex6 0x000200D3
+#define OS_ConvertHex8 0x000000D4
+#define XOS_ConvertHex8 0x000200D4
+#define OS_ConvertCardinal1 0x000000D5
+#define XOS_ConvertCardinal1 0x000200D5
+#define OS_ConvertCardinal2 0x000000D6
+#define XOS_ConvertCardinal2 0x000200D6
+#define OS_ConvertCardinal3 0x000000D7
+#define XOS_ConvertCardinal3 0x000200D7
+#define OS_ConvertCardinal4 0x000000D8
+#define XOS_ConvertCardinal4 0x000200D8
+#define OS_ConvertInteger1 0x000000D9
+#define XOS_ConvertInteger1 0x000200D9
+#define OS_ConvertInteger2 0x000000DA
+#define XOS_ConvertInteger2 0x000200DA
+#define OS_ConvertInteger3 0x000000DB
+#define XOS_ConvertInteger3 0x000200DB
+#define OS_ConvertInteger4 0x000000DC
+#define XOS_ConvertInteger4 0x000200DC
+#define OS_ConvertBinary1 0x000000DD
+#define XOS_ConvertBinary1 0x000200DD
+#define OS_ConvertBinary2 0x000000DE
+#define XOS_ConvertBinary2 0x000200DE
+#define OS_ConvertBinary3 0x000000DF
+#define XOS_ConvertBinary3 0x000200DF
+#define OS_ConvertBinary4 0x000000E0
+#define XOS_ConvertBinary4 0x000200E0
+#define OS_ConvertSpacedCardinal1 0x000000E1
+#define XOS_ConvertSpacedCardinal1 0x000200E1
+#define OS_ConvertSpacedCardinal2 0x000000E2
+#define XOS_ConvertSpacedCardinal2 0x000200E2
+#define OS_ConvertSpacedCardinal3 0x000000E3
+#define XOS_ConvertSpacedCardinal3 0x000200E3
+#define OS_ConvertSpacedCardinal4 0x000000E4
+#define XOS_ConvertSpacedCardinal4 0x000200E4
+#define OS_ConvertSpacedInteger1 0x000000E5
+#define XOS_ConvertSpacedInteger1 0x000200E5
+#define OS_ConvertSpacedInteger2 0x000000E6
+#define XOS_ConvertSpacedInteger2 0x000200E6
+#define OS_ConvertSpacedInteger3 0x000000E7
+#define XOS_ConvertSpacedInteger3 0x000200E7
+#define OS_ConvertSpacedInteger4 0x000000E8
+#define XOS_ConvertSpacedInteger4 0x000200E8
+#define OS_ConvertFixedNetStation 0x000000E9
+#define XOS_ConvertFixedNetStation 0x000200E9
+#define OS_ConvertNetStation 0x000000EA
+#define XOS_ConvertNetStation 0x000200EA
+#define OS_ConvertFixedFileSize 0x000000EB
+#define XOS_ConvertFixedFileSize 0x000200EB
+#define OS_ConvertFileSize 0x000000EC
+#define XOS_ConvertFileSize 0x000200EC
+
+/* --- Podule SWIs --- */
+
+#define Podule_ReadID 0x00040280
+#define XPodule_ReadID 0x00060280
+#define Podule_ReadHeader 0x00040281
+#define XPodule_ReadHeader 0x00060281
+#define Podule_EnumerateChunks 0x00040282
+#define XPodule_EnumerateChunks 0x00060282
+#define Podule_ReadChunk 0x00040283
+#define XPodule_ReadChunk 0x00060283
+#define Podule_ReadBytes 0x00040284
+#define XPodule_ReadBytes 0x00060284
+#define Podule_WriteBytes 0x00040285
+#define XPodule_WriteBytes 0x00060285
+#define Podule_CallLoader 0x00040286
+#define XPodule_CallLoader 0x00060286
+#define Podule_RawRead 0x00040287
+#define XPodule_RawRead 0x00060287
+#define Podule_RawWrite 0x00040288
+#define XPodule_RawWrite 0x00060288
+#define Podule_HardwareAddress 0x00040289
+#define XPodule_HardwareAddress 0x00060289
+#define Podule_EnumerateChunksWithInfo 0x0004028A
+#define XPodule_EnumerateChunksWithInfo 0x0006028A
+#define Podule_HardwareAddresses 0x0004028B
+#define XPodule_HardwareAddresses 0x0006028B
+#define Podule_ReturnNumber 0x0004028C
+#define XPodule_ReturnNumber 0x0006028C
+#define Podule_ReadInfo 0x0004028D
+#define XPodule_ReadInfo 0x0006028D
+#define Podule_SetSpeed 0x0004028E
+#define XPodule_SetSpeed 0x0006028E
+
+/* --- ResourceFS SWIs --- */
+
+#define ResourceFS_RegisterFiles 0x00041B40
+#define XResourceFS_RegisterFiles 0x00061B40
+#define ResourceFS_DeregisterFiles 0x00041B41
+#define XResourceFS_DeregisterFiles 0x00061B41
+
+/* --- MessageTrans SWIs --- */
+
+#define MessageTrans_FileInfo 0x00041500
+#define XMessageTrans_FileInfo 0x00061500
+#define MessageTrans_OpenFile 0x00041501
+#define XMessageTrans_OpenFile 0x00061501
+#define MessageTrans_Lookup 0x00041502
+#define XMessageTrans_Lookup 0x00061502
+#define MessageTrans_MakeMenus 0x00041503
+#define XMessageTrans_MakeMenus 0x00061503
+#define MessageTrans_CloseFile 0x00041504
+#define XMessageTrans_CloseFile 0x00061504
+#define MessageTrans_EnumerateTokens 0x00041505
+#define XMessageTrans_EnumerateTokens 0x00061505
+#define MessageTrans_ErrorLookup 0x00041506
+#define XMessageTrans_ErrorLookup 0x00061506
+#define MessageTrans_GSLookup 0x00041507
+#define XMessageTrans_GSLookup 0x00061507
+#define MessageTrans_CopyError 0x00041508
+#define XMessageTrans_CopyError 0x00061508
+#define MessageTrans_Dictionary 0x00041509
+#define XMessageTrans_Dictionary 0x00061509
+
+/* --- TerritoryManager SWIs --- */
+
+#define Territory_Number 0x00043040
+#define XTerritory_Number 0x00063040
+#define Territory_Register 0x00043041
+#define XTerritory_Register 0x00063041
+#define Territory_Deregister 0x00043042
+#define XTerritory_Deregister 0x00063042
+#define Territory_NumberToName 0x00043043
+#define XTerritory_NumberToName 0x00063043
+#define Territory_Exists 0x00043044
+#define XTerritory_Exists 0x00063044
+#define Territory_AlphabetNumberToName 0x00043045
+#define XTerritory_AlphabetNumberToName 0x00063045
+#define Territory_SelectAlphabet 0x00043046
+#define XTerritory_SelectAlphabet 0x00063046
+#define Territory_SetTime 0x00043047
+#define XTerritory_SetTime 0x00063047
+#define Territory_ReadCurrentTimeZone 0x00043048
+#define XTerritory_ReadCurrentTimeZone 0x00063048
+#define Territory_ConvertTimeToUTCOrdinals 0x00043049
+#define XTerritory_ConvertTimeToUTCOrdinals 0x00063049
+#define Territory_ReadTimeZones 0x0004304A
+#define XTerritory_ReadTimeZones 0x0006304A
+#define Territory_ConvertDateAndTime 0x0004304B
+#define XTerritory_ConvertDateAndTime 0x0006304B
+#define Territory_ConvertStandardDateAndTime 0x0004304C
+#define XTerritory_ConvertStandardDateAndTime 0x0006304C
+#define Territory_ConvertStandardDate 0x0004304D
+#define XTerritory_ConvertStandardDate 0x0006304D
+#define Territory_ConvertStandardTime 0x0004304E
+#define XTerritory_ConvertStandardTime 0x0006304E
+#define Territory_ConvertTimeToOrdinals 0x0004304F
+#define XTerritory_ConvertTimeToOrdinals 0x0006304F
+#define Territory_ConvertTimeStringToOrdinals 0x00043050
+#define XTerritory_ConvertTimeStringToOrdinals 0x00063050
+#define Territory_ConvertOrdinalsToTime 0x00043051
+#define XTerritory_ConvertOrdinalsToTime 0x00063051
+#define Territory_Alphabet 0x00043052
+#define XTerritory_Alphabet 0x00063052
+#define Territory_AlphabetIdentifier 0x00043053
+#define XTerritory_AlphabetIdentifier 0x00063053
+#define Territory_SelectKeyboardHandler 0x00043054
+#define XTerritory_SelectKeyboardHandler 0x00063054
+#define Territory_WriteDirection 0x00043055
+#define XTerritory_WriteDirection 0x00063055
+#define Territory_CharacterPropertyTable 0x00043056
+#define XTerritory_CharacterPropertyTable 0x00063056
+#define Territory_LowerCaseTable 0x00043057
+#define XTerritory_LowerCaseTable 0x00063057
+#define Territory_UpperCaseTable 0x00043058
+#define XTerritory_UpperCaseTable 0x00063058
+#define Territory_ControlTable 0x00043059
+#define XTerritory_ControlTable 0x00063059
+#define Territory_PlainTable 0x0004305A
+#define XTerritory_PlainTable 0x0006305A
+#define Territory_ValueTable 0x0004305B
+#define XTerritory_ValueTable 0x0006305B
+#define Territory_RepresentationTable 0x0004305C
+#define XTerritory_RepresentationTable 0x0006305C
+#define Territory_Collate 0x0004305D
+#define XTerritory_Collate 0x0006305D
+#define Territory_ReadSymbols 0x0004305E
+#define XTerritory_ReadSymbols 0x0006305E
+#define Territory_ReadCalendarInformation 0x0004305F
+#define XTerritory_ReadCalendarInformation 0x0006305F
+#define Territory_NameToNumber 0x00043060
+#define XTerritory_NameToNumber 0x00063060
+#define Territory_TransformString 0x00043061
+#define XTerritory_TransformString 0x00063061
+#define Territory_ConvertTextToString 0x00043075
+#define XTerritory_ConvertTextToString 0x00063075
+
+/* --- WindowManager SWIs --- */
+
+#define Wimp_Initialise 0x000400C0
+#define XWimp_Initialise 0x000600C0
+#define Wimp_CreateWindow 0x000400C1
+#define XWimp_CreateWindow 0x000600C1
+#define Wimp_CreateIcon 0x000400C2
+#define XWimp_CreateIcon 0x000600C2
+#define Wimp_DeleteWindow 0x000400C3
+#define XWimp_DeleteWindow 0x000600C3
+#define Wimp_DeleteIcon 0x000400C4
+#define XWimp_DeleteIcon 0x000600C4
+#define Wimp_OpenWindow 0x000400C5
+#define XWimp_OpenWindow 0x000600C5
+#define Wimp_CloseWindow 0x000400C6
+#define XWimp_CloseWindow 0x000600C6
+#define Wimp_Poll 0x000400C7
+#define XWimp_Poll 0x000600C7
+#define Wimp_RedrawWindow 0x000400C8
+#define XWimp_RedrawWindow 0x000600C8
+#define Wimp_UpdateWindow 0x000400C9
+#define XWimp_UpdateWindow 0x000600C9
+#define Wimp_GetRectangle 0x000400CA
+#define XWimp_GetRectangle 0x000600CA
+#define Wimp_GetWindowState 0x000400CB
+#define XWimp_GetWindowState 0x000600CB
+#define Wimp_GetWindowInfo 0x000400CC
+#define XWimp_GetWindowInfo 0x000600CC
+#define Wimp_SetIconState 0x000400CD
+#define XWimp_SetIconState 0x000600CD
+#define Wimp_GetIconState 0x000400CE
+#define XWimp_GetIconState 0x000600CE
+#define Wimp_GetPointerInfo 0x000400CF
+#define XWimp_GetPointerInfo 0x000600CF
+#define Wimp_DragBox 0x000400D0
+#define XWimp_DragBox 0x000600D0
+#define Wimp_ForceRedraw 0x000400D1
+#define XWimp_ForceRedraw 0x000600D1
+#define Wimp_SetCaretPosition 0x000400D2
+#define XWimp_SetCaretPosition 0x000600D2
+#define Wimp_GetCaretPosition 0x000400D3
+#define XWimp_GetCaretPosition 0x000600D3
+#define Wimp_CreateMenu 0x000400D4
+#define XWimp_CreateMenu 0x000600D4
+#define Wimp_DecodeMenu 0x000400D5
+#define XWimp_DecodeMenu 0x000600D5
+#define Wimp_WhichIcon 0x000400D6
+#define XWimp_WhichIcon 0x000600D6
+#define Wimp_SetExtent 0x000400D7
+#define XWimp_SetExtent 0x000600D7
+#define Wimp_SetPointerShape 0x000400D8
+#define XWimp_SetPointerShape 0x000600D8
+#define Wimp_OpenTemplate 0x000400D9
+#define XWimp_OpenTemplate 0x000600D9
+#define Wimp_CloseTemplate 0x000400DA
+#define XWimp_CloseTemplate 0x000600DA
+#define Wimp_LoadTemplate 0x000400DB
+#define XWimp_LoadTemplate 0x000600DB
+#define Wimp_ProcessKey 0x000400DC
+#define XWimp_ProcessKey 0x000600DC
+#define Wimp_CloseDown 0x000400DD
+#define XWimp_CloseDown 0x000600DD
+#define Wimp_StartTask 0x000400DE
+#define XWimp_StartTask 0x000600DE
+#define Wimp_ReportError 0x000400DF
+#define XWimp_ReportError 0x000600DF
+#define Wimp_GetWindowOutline 0x000400E0
+#define XWimp_GetWindowOutline 0x000600E0
+#define Wimp_PollIdle 0x000400E1
+#define XWimp_PollIdle 0x000600E1
+#define Wimp_PlotIcon 0x000400E2
+#define XWimp_PlotIcon 0x000600E2
+#define Wimp_SetMode 0x000400E3
+#define XWimp_SetMode 0x000600E3
+#define Wimp_SetPalette 0x000400E4
+#define XWimp_SetPalette 0x000600E4
+#define Wimp_ReadPalette 0x000400E5
+#define XWimp_ReadPalette 0x000600E5
+#define Wimp_SetColour 0x000400E6
+#define XWimp_SetColour 0x000600E6
+#define Wimp_SendMessage 0x000400E7
+#define XWimp_SendMessage 0x000600E7
+#define Wimp_CreateSubMenu 0x000400E8
+#define XWimp_CreateSubMenu 0x000600E8
+#define Wimp_SpriteOp 0x000400E9
+#define XWimp_SpriteOp 0x000600E9
+#define Wimp_BaseOfSprites 0x000400EA
+#define XWimp_BaseOfSprites 0x000600EA
+#define Wimp_BlockCopy 0x000400EB
+#define XWimp_BlockCopy 0x000600EB
+#define Wimp_SlotSize 0x000400EC
+#define XWimp_SlotSize 0x000600EC
+#define Wimp_ReadPixTrans 0x000400ED
+#define XWimp_ReadPixTrans 0x000600ED
+#define Wimp_ClaimFreeMemory 0x000400EE
+#define XWimp_ClaimFreeMemory 0x000600EE
+#define Wimp_CommandWindow 0x000400EF
+#define XWimp_CommandWindow 0x000600EF
+#define Wimp_TextColour 0x000400F0
+#define XWimp_TextColour 0x000600F0
+#define Wimp_TransferBlock 0x000400F1
+#define XWimp_TransferBlock 0x000600F1
+#define Wimp_ReadSysInfo 0x000400F2
+#define XWimp_ReadSysInfo 0x000600F2
+#define Wimp_SetFontColours 0x000400F3
+#define XWimp_SetFontColours 0x000600F3
+#define Wimp_GetMenuState 0x000400F4
+#define XWimp_GetMenuState 0x000600F4
+#define Wimp_RegisterFilter 0x000400F5
+#define XWimp_RegisterFilter 0x000600F5
+#define Wimp_AddMessages 0x000400F6
+#define XWimp_AddMessages 0x000600F6
+#define Wimp_RemoveMessages 0x000400F7
+#define XWimp_RemoveMessages 0x000600F7
+#define Wimp_SetColourMapping 0x000400F8
+#define XWimp_SetColourMapping 0x000600F8
+#define Wimp_TextOp 0x000400F9
+#define XWimp_TextOp 0x000600F9
+#define Wimp_SetWatchdogState 0x000400FA
+#define XWimp_SetWatchdogState 0x000600FA
+#define Wimp_Extend 0x000400FB
+#define XWimp_Extend 0x000600FB
+#define Wimp_ResizeIcon 0x000400FC
+#define XWimp_ResizeIcon 0x000600FC
+
+/* --- TaskManager SWIs --- */
+
+#define TaskManager_TaskNameFromHandle 0x00042680
+#define XTaskManager_TaskNameFromHandle 0x00062680
+#define TaskManager_EnumerateTasks 0x00042681
+#define XTaskManager_EnumerateTasks 0x00062681
+#define TaskManager_Shutdown 0x00042682
+#define XTaskManager_Shutdown 0x00062682
+
+/* --- BASICTrans SWIs --- */
+
+#define BASICTrans_HELP 0x00042C80
+#define XBASICTrans_HELP 0x00062C80
+#define BASICTrans_Error 0x00042C81
+#define XBASICTrans_Error 0x00062C81
+#define BASICTrans_Message 0x00042C82
+#define XBASICTrans_Message 0x00062C82
+
+/* --- BufferManager SWIs --- */
+
+#define Buffer_Create 0x00042940
+#define XBuffer_Create 0x00062940
+#define Buffer_Remove 0x00042941
+#define XBuffer_Remove 0x00062941
+#define Buffer_Register 0x00042942
+#define XBuffer_Register 0x00062942
+#define Buffer_Deregister 0x00042943
+#define XBuffer_Deregister 0x00062943
+#define Buffer_ModifyFlags 0x00042944
+#define XBuffer_ModifyFlags 0x00062944
+#define Buffer_LinkDevice 0x00042945
+#define XBuffer_LinkDevice 0x00062945
+#define Buffer_UnlinkDevice 0x00042946
+#define XBuffer_UnlinkDevice 0x00062946
+#define Buffer_GetInfo 0x00042947
+#define XBuffer_GetInfo 0x00062947
+#define Buffer_Threshold 0x00042948
+#define XBuffer_Threshold 0x00062948
+#define Buffer_InternalInfo 0x00042949
+#define XBuffer_InternalInfo 0x00062949
+
+/* --- Debugger SWIs --- */
+
+#define Debugger_Disassemble 0x00040380
+#define XDebugger_Disassemble 0x00060380
+
+/* --- DeviceFS SWIs --- */
+
+#define DeviceFS_Register 0x00042740
+#define XDeviceFS_Register 0x00062740
+#define DeviceFS_Deregister 0x00042741
+#define XDeviceFS_Deregister 0x00062741
+#define DeviceFS_RegisterObjects 0x00042742
+#define XDeviceFS_RegisterObjects 0x00062742
+#define DeviceFS_DeregisterObjects 0x00042743
+#define XDeviceFS_DeregisterObjects 0x00062743
+#define DeviceFS_CallDevice 0x00042744
+#define XDeviceFS_CallDevice 0x00062744
+#define DeviceFS_Threshold 0x00042745
+#define XDeviceFS_Threshold 0x00062745
+#define DeviceFS_ReceivedCharacter 0x00042746
+#define XDeviceFS_ReceivedCharacter 0x00062746
+#define DeviceFS_TransmitCharacter 0x00042747
+#define XDeviceFS_TransmitCharacter 0x00062747
+
+/* --- DMAManager SWIs --- */
+
+#define DMA_RegisterChannel 0x00046140
+#define XDMA_RegisterChannel 0x00066140
+#define DMA_DeregisterChannel 0x00046141
+#define XDMA_DeregisterChannel 0x00066141
+#define DMA_QueueTransfer 0x00046142
+#define XDMA_QueueTransfer 0x00066142
+#define DMA_TerminateTransfer 0x00046143
+#define XDMA_TerminateTransfer 0x00066143
+#define DMA_SuspendTransfer 0x00046144
+#define XDMA_SuspendTransfer 0x00066144
+#define DMA_ResumeTransfer 0x00046145
+#define XDMA_ResumeTransfer 0x00066145
+#define DMA_ExamineTransfer 0x00046146
+#define XDMA_ExamineTransfer 0x00066146
+
+/* --- DragASprite SWIs --- */
+
+#define DragASprite_Start 0x00042400
+#define XDragASprite_Start 0x00062400
+#define DragASprite_Stop 0x00042401
+#define XDragASprite_Stop 0x00062401
+
+/* --- Draw SWIs --- */
+
+#define Draw_ProcessPath 0x00040700
+#define XDraw_ProcessPath 0x00060700
+#define Draw_ProcessPathFP 0x00040701
+#define XDraw_ProcessPathFP 0x00060701
+#define Draw_Fill 0x00040702
+#define XDraw_Fill 0x00060702
+#define Draw_FillFP 0x00040703
+#define XDraw_FillFP 0x00060703
+#define Draw_Stroke 0x00040704
+#define XDraw_Stroke 0x00060704
+#define Draw_StrokeFP 0x00040705
+#define XDraw_StrokeFP 0x00060705
+#define Draw_StrokePath 0x00040706
+#define XDraw_StrokePath 0x00060706
+#define Draw_StrokePathFP 0x00040707
+#define XDraw_StrokePathFP 0x00060707
+#define Draw_FlattenPath 0x00040708
+#define XDraw_FlattenPath 0x00060708
+#define Draw_FlattenPathFP 0x00040709
+#define XDraw_FlattenPathFP 0x00060709
+#define Draw_TransformPath 0x0004070A
+#define XDraw_TransformPath 0x0006070A
+#define Draw_TransformPathFP 0x0004070B
+#define XDraw_TransformPathFP 0x0006070B
+
+/* --- FileCore SWIs --- */
+
+#define FileCore_DiscOp 0x00040540
+#define XFileCore_DiscOp 0x00060540
+#define FileCore_Create 0x00040541
+#define XFileCore_Create 0x00060541
+#define FileCore_Drives 0x00040542
+#define XFileCore_Drives 0x00060542
+#define FileCore_FreeSpace 0x00040543
+#define XFileCore_FreeSpace 0x00060543
+#define FileCore_FloppyStructure 0x00040544
+#define XFileCore_FloppyStructure 0x00060544
+#define FileCore_DescribeDisc 0x00040545
+#define XFileCore_DescribeDisc 0x00060545
+#define FileCore_DiscardReadSectorsCache 0x00040546
+#define XFileCore_DiscardReadSectorsCache 0x00060546
+#define FileCore_DiscFormat 0x00040547
+#define XFileCore_DiscFormat 0x00060547
+#define FileCore_LayoutStructure 0x00040548
+#define XFileCore_LayoutStructure 0x00060548
+#define FileCore_MiscOp 0x00040549
+#define XFileCore_MiscOp 0x00060549
+
+/* --- ADFS SWIs --- */
+
+#define ADFS_DiscOp 0x00040240
+#define XADFS_DiscOp 0x00060240
+#define ADFS_HDC 0x00040241
+#define XADFS_HDC 0x00060241
+#define ADFS_Drives 0x00040242
+#define XADFS_Drives 0x00060242
+#define ADFS_FreeSpace 0x00040243
+#define XADFS_FreeSpace 0x00060243
+#define ADFS_Retries 0x00040244
+#define XADFS_Retries 0x00060244
+#define ADFS_DescribeDisc 0x00040245
+#define XADFS_DescribeDisc 0x00060245
+#define ADFS_VetFormat 0x00040246
+#define XADFS_VetFormat 0x00060246
+#define ADFS_FlpProcessDCB 0x00040247
+#define XADFS_FlpProcessDCB 0x00060247
+#define ADFS_ControllerType 0x00040248
+#define XADFS_ControllerType 0x00060248
+#define ADFS_PowerControl 0x00040249
+#define XADFS_PowerControl 0x00060249
+#define ADFS_SetIDEController 0x0004024A
+#define XADFS_SetIDEController 0x0006024A
+#define ADFS_IDEUserOp 0x0004024B
+#define XADFS_IDEUserOp 0x0006024B
+#define ADFS_MiscOp 0x0004024C
+#define XADFS_MiscOp 0x0006024C
+#define ADFS_ECCSAndRetries 0x00040250
+#define XADFS_ECCSAndRetries 0x00060250
+
+/* --- FilerSWIs SWIs --- */
+
+#define FilerAction_SendSelectedDirectory 0x00040F80
+#define XFilerAction_SendSelectedDirectory 0x00060F80
+#define FilerAction_SendSelectedFile 0x00040F81
+#define XFilerAction_SendSelectedFile 0x00060F81
+#define FilerAction_SendStartOperation 0x00040F82
+#define XFilerAction_SendStartOperation 0x00060F82
+
+/* --- FSLock SWIs --- */
+
+#define FSLock_Version 0x00047780
+#define XFSLock_Version 0x00067780
+#define FSLock_Status 0x00047781
+#define XFSLock_Status 0x00067781
+#define FSLock_ChangeStatus 0x00047782
+#define XFSLock_ChangeStatus 0x00067782
+
+/* --- FontManager SWIs --- */
+
+#define Font_CacheAddr 0x00040080
+#define XFont_CacheAddr 0x00060080
+#define Font_FindFont 0x00040081
+#define XFont_FindFont 0x00060081
+#define Font_LoseFont 0x00040082
+#define XFont_LoseFont 0x00060082
+#define Font_ReadDefn 0x00040083
+#define XFont_ReadDefn 0x00060083
+#define Font_ReadInfo 0x00040084
+#define XFont_ReadInfo 0x00060084
+#define Font_StringWidth 0x00040085
+#define XFont_StringWidth 0x00060085
+#define Font_Paint 0x00040086
+#define XFont_Paint 0x00060086
+#define Font_Caret 0x00040087
+#define XFont_Caret 0x00060087
+#define Font_ConverttoOS 0x00040088
+#define XFont_ConverttoOS 0x00060088
+#define Font_Converttopoints 0x00040089
+#define XFont_Converttopoints 0x00060089
+#define Font_SetFont 0x0004008A
+#define XFont_SetFont 0x0006008A
+#define Font_CurrentFont 0x0004008B
+#define XFont_CurrentFont 0x0006008B
+#define Font_FutureFont 0x0004008C
+#define XFont_FutureFont 0x0006008C
+#define Font_FindCaret 0x0004008D
+#define XFont_FindCaret 0x0006008D
+#define Font_CharBBox 0x0004008E
+#define XFont_CharBBox 0x0006008E
+#define Font_ReadScaleFactor 0x0004008F
+#define XFont_ReadScaleFactor 0x0006008F
+#define Font_SetScaleFactor 0x00040090
+#define XFont_SetScaleFactor 0x00060090
+#define Font_ListFonts 0x00040091
+#define XFont_ListFonts 0x00060091
+#define Font_SetFontColours 0x00040092
+#define XFont_SetFontColours 0x00060092
+#define Font_SetPalette 0x00040093
+#define XFont_SetPalette 0x00060093
+#define Font_ReadThresholds 0x00040094
+#define XFont_ReadThresholds 0x00060094
+#define Font_SetThresholds 0x00040095
+#define XFont_SetThresholds 0x00060095
+#define Font_FindCaretJ 0x00040096
+#define XFont_FindCaretJ 0x00060096
+#define Font_StringBBox 0x00040097
+#define XFont_StringBBox 0x00060097
+#define Font_ReadColourTable 0x00040098
+#define XFont_ReadColourTable 0x00060098
+#define Font_MakeBitmap 0x00040099
+#define XFont_MakeBitmap 0x00060099
+#define Font_UnCacheFile 0x0004009A
+#define XFont_UnCacheFile 0x0006009A
+#define Font_SetFontMax 0x0004009B
+#define XFont_SetFontMax 0x0006009B
+#define Font_ReadFontMax 0x0004009C
+#define XFont_ReadFontMax 0x0006009C
+#define Font_ReadFontPrefix 0x0004009D
+#define XFont_ReadFontPrefix 0x0006009D
+#define Font_SwitchOutputToBuffer 0x0004009E
+#define XFont_SwitchOutputToBuffer 0x0006009E
+#define Font_ReadFontMetrics 0x0004009F
+#define XFont_ReadFontMetrics 0x0006009F
+#define Font_DecodeMenu 0x000400A0
+#define XFont_DecodeMenu 0x000600A0
+#define Font_ScanString 0x000400A1
+#define XFont_ScanString 0x000600A1
+#define Font_SetColourTable 0x000400A2
+#define XFont_SetColourTable 0x000600A2
+#define Font_CurrentRGB 0x000400A3
+#define XFont_CurrentRGB 0x000600A3
+#define Font_FutureRGB 0x000400A4
+#define XFont_FutureRGB 0x000600A4
+#define Font_ReadEncodingFilename 0x000400A5
+#define XFont_ReadEncodingFilename 0x000600A5
+#define Font_FindField 0x000400A6
+#define XFont_FindField 0x000600A6
+#define Font_ApplyFields 0x000400A7
+#define XFont_ApplyFields 0x000600A7
+#define Font_LookupFont 0x000400A8
+#define XFont_LookupFont 0x000600A8
+
+/* --- FPEmulator SWIs --- */
+
+#define FPEmulator_Version 0x00040480
+#define XFPEmulator_Version 0x00060480
+
+/* --- Free SWIs --- */
+
+#define Free_Register 0x000444C0
+#define XFree_Register 0x000644C0
+#define Free_DeRegister 0x000444C1
+#define XFree_DeRegister 0x000644C1
+
+/* --- Hourglass SWIs --- */
+
+#define Hourglass_On 0x000406C0
+#define XHourglass_On 0x000606C0
+#define Hourglass_Off 0x000406C1
+#define XHourglass_Off 0x000606C1
+#define Hourglass_Smash 0x000406C2
+#define XHourglass_Smash 0x000606C2
+#define Hourglass_Start 0x000406C3
+#define XHourglass_Start 0x000606C3
+#define Hourglass_Percentage 0x000406C4
+#define XHourglass_Percentage 0x000606C4
+#define Hourglass_LEDs 0x000406C5
+#define XHourglass_LEDs 0x000606C5
+#define Hourglass_Colours 0x000406C6
+#define XHourglass_Colours 0x000606C6
+
+/* --- IIC SWIs --- */
+
+#define IIC_Control 0x00000240
+#define XIIC_Control 0x00020240
+
+/* --- ParallelDeviceDriver SWIs --- */
+
+#define Parallel_HardwareAddress 0x00042EC0
+#define XParallel_HardwareAddress 0x00062EC0
+#define Parallel_Op 0x00042EC1
+#define XParallel_Op 0x00062EC1
+
+/* --- ScreenBlanker SWIs --- */
+
+#define ScreenBlanker_Control 0x00043100
+#define XScreenBlanker_Control 0x00063100
+
+/* --- ShellCLI SWIs --- */
+
+#define Shell_Create 0x000405C0
+#define XShell_Create 0x000605C0
+#define Shell_Destroy 0x000405C1
+#define XShell_Destroy 0x000605C1
+
+/* --- SoundDMA SWIs --- */
+
+#define Sound_Configure 0x00040140
+#define XSound_Configure 0x00060140
+#define Sound_Enable 0x00040141
+#define XSound_Enable 0x00060141
+#define Sound_Stereo 0x00040142
+#define XSound_Stereo 0x00060142
+#define Sound_Speaker 0x00040143
+#define XSound_Speaker 0x00060143
+
+/* --- SoundChannels SWIs --- */
+
+#define Sound_Volume 0x00040180
+#define XSound_Volume 0x00060180
+#define Sound_SoundLog 0x00040181
+#define XSound_SoundLog 0x00060181
+#define Sound_LogScale 0x00040182
+#define XSound_LogScale 0x00060182
+#define Sound_InstallVoice 0x00040183
+#define XSound_InstallVoice 0x00060183
+#define Sound_RemoveVoice 0x00040184
+#define XSound_RemoveVoice 0x00060184
+#define Sound_AttachVoice 0x00040185
+#define XSound_AttachVoice 0x00060185
+#define Sound_ControlPacked 0x00040186
+#define XSound_ControlPacked 0x00060186
+#define Sound_Tuning 0x00040187
+#define XSound_Tuning 0x00060187
+#define Sound_Pitch 0x00040188
+#define XSound_Pitch 0x00060188
+#define Sound_Control 0x00040189
+#define XSound_Control 0x00060189
+#define Sound_AttachNamedVoice 0x0004018A
+#define XSound_AttachNamedVoice 0x0006018A
+#define Sound_ReadControlBlock 0x0004018B
+#define XSound_ReadControlBlock 0x0006018B
+#define Sound_WriteControlBlock 0x0004018C
+#define XSound_WriteControlBlock 0x0006018C
+
+/* --- SoundScheduler SWIs --- */
+
+#define Sound_QInit 0x000401C0
+#define XSound_QInit 0x000601C0
+#define Sound_QSchedule 0x000401C1
+#define XSound_QSchedule 0x000601C1
+#define Sound_QRemove 0x000401C2
+#define XSound_QRemove 0x000601C2
+#define Sound_QFree 0x000401C3
+#define XSound_QFree 0x000601C3
+#define Sound_QSDispatch 0x000401C4
+#define XSound_QSDispatch 0x000601C4
+#define Sound_QTempo 0x000401C5
+#define XSound_QTempo 0x000601C5
+#define Sound_QBeat 0x000401C6
+#define XSound_QBeat 0x000601C6
+#define Sound_QInterface 0x000401C7
+#define XSound_QInterface 0x000601C7
+
+/* --- Squash SWIs --- */
+
+#define Squash_Compress 0x00042700
+#define XSquash_Compress 0x00062700
+#define Squash_Decompress 0x00042701
+#define XSquash_Decompress 0x00062701
+
+/* --- SuperSample SWIs --- */
+
+#define Super_Sample90 0x00040D80
+#define XSuper_Sample90 0x00060D80
+#define Super_Sample45 0x00040D81
+#define XSuper_Sample45 0x00060D81
+
+/* --- TaskWindow SWIs --- */
+
+#define TaskWindow_TaskInfo 0x00043380
+#define XTaskWindow_TaskInfo 0x00063380
+
+/* --- FilterManager SWIs --- */
+
+#define Filter_RegisterPreFilter 0x00042640
+#define XFilter_RegisterPreFilter 0x00062640
+#define Filter_RegisterPostFilter 0x00042641
+#define XFilter_RegisterPostFilter 0x00062641
+#define Filter_DeRegisterPreFilter 0x00042642
+#define XFilter_DeRegisterPreFilter 0x00062642
+#define Filter_DeRegisterPostFilter 0x00042643
+#define XFilter_DeRegisterPostFilter 0x00062643
+
+/* --- SharedCLibrary SWIs --- */
+
+#define SharedCLibrary_LibInitAPCS_A 0x00080680
+#define XSharedCLibrary_LibInitAPCS_A 0x000A0680
+#define SharedCLibrary_LibInitAPCS_R 0x00080681
+#define XSharedCLibrary_LibInitAPCS_R 0x000A0681
+#define SharedCLibrary_LibInitModule 0x00080682
+#define XSharedCLibrary_LibInitModule 0x000A0682
+
+/* --- DOSFS SWIs --- */
+
+#define DOSFS_DiscFormat 0x00044B00
+#define XDOSFS_DiscFormat 0x00064B00
+#define DOSFS_LayoutStructure 0x00044B01
+#define XDOSFS_LayoutStructure 0x00064B01
+
+/* --- ColourPicker SWIs --- */
+
+#define ColourPicker_RegisterModel 0x00047700
+#define XColourPicker_RegisterModel 0x00067700
+#define ColourPicker_DeregisterModel 0x00047701
+#define XColourPicker_DeregisterModel 0x00067701
+#define ColourPicker_OpenDialogue 0x00047702
+#define XColourPicker_OpenDialogue 0x00067702
+#define ColourPicker_CloseDialogue 0x00047703
+#define XColourPicker_CloseDialogue 0x00067703
+#define ColourPicker_UpdateDialogue 0x00047704
+#define XColourPicker_UpdateDialogue 0x00067704
+#define ColourPicker_ReadDialogue 0x00047705
+#define XColourPicker_ReadDialogue 0x00067705
+#define ColourPicker_SetColour 0x00047706
+#define XColourPicker_SetColour 0x00067706
+#define ColourPicker_HelpReply 0x00047707
+#define XColourPicker_HelpReply 0x00067707
+#define ColourPicker_ModelSWI 0x00047708
+#define XColourPicker_ModelSWI 0x00067708
+
+/* --- ScreenModes SWIs --- */
+
+#define ScreenModes_ReadInfo 0x000487C0
+#define XScreenModes_ReadInfo 0x000687C0
+
+/* --- SCSIDriver SWIs --- */
+
+#define SCSI_Version 0x000403C0
+#define XSCSI_Version 0x000603C0
+#define SCSI_Initialise 0x000403C1
+#define XSCSI_Initialise 0x000603C1
+#define SCSI_Control 0x000403C2
+#define XSCSI_Control 0x000603C2
+#define SCSI_Op 0x000403C3
+#define XSCSI_Op 0x000603C3
+#define SCSI_Status 0x000403C4
+#define XSCSI_Status 0x000603C4
+#define SCSI_ReadControlLines 0x000403C5
+#define XSCSI_ReadControlLines 0x000603C5
+#define SCSI_EEProm 0x000403C6
+#define XSCSI_EEProm 0x000603C6
+#define SCSI_Reserve 0x000403C7
+#define XSCSI_Reserve 0x000603C7
+#define SCSI_List 0x000403C8
+#define XSCSI_List 0x000603C8
+#define SCSI_Target 0x000403C9
+#define XSCSI_Target 0x000603C9
+
+/* --- SCSIFS SWIs --- */
+
+#define SCSIFS_DiscOp 0x00040980
+#define XSCSIFS_DiscOp 0x00060980
+#define SCSIFS_Drives 0x00040982
+#define XSCSIFS_Drives 0x00060982
+#define SCSIFS_FreeSpace 0x00040983
+#define XSCSIFS_FreeSpace 0x00060983
+#define SCSIFS_DescribeDisc 0x00040985
+#define XSCSIFS_DescribeDisc 0x00060985
+#define SCSIFS_TestReady 0x00040986
+#define XSCSIFS_TestReady 0x00060986
+#define SCSIFS_MapDrives 0x00040987
+#define XSCSIFS_MapDrives 0x00060987
+#define SCSIFS_MotorControl 0x00040988
+#define XSCSIFS_MotorControl 0x00060988
+#define SCSIFS_MiscOp 0x0004098C
+#define XSCSIFS_MiscOp 0x0006098C
+
+/* --- CDFS SWIs --- */
+
+#define CDFS_ConvertDriveToDevice 0x00041E80
+#define XCDFS_ConvertDriveToDevice 0x00061E80
+#define CDFS_SetBufferSize 0x00041E81
+#define XCDFS_SetBufferSize 0x00061E81
+#define CDFS_GetBufferSize 0x00041E82
+#define XCDFS_GetBufferSize 0x00061E82
+#define CDFS_SetNumberOfDrives 0x00041E83
+#define XCDFS_SetNumberOfDrives 0x00061E83
+#define CDFS_GetNumberOfDrives 0x00041E84
+#define XCDFS_GetNumberOfDrives 0x00061E84
+#define CDFS_GiveFileType 0x00041E85
+#define XCDFS_GiveFileType 0x00061E85
+#define CDFS_DescribeDisc 0x00041E86
+#define XCDFS_DescribeDisc 0x00061E86
+#define CDFS_WhereIsFile 0x00041E87
+#define XCDFS_WhereIsFile 0x00061E87
+#define CDFS_Truncation 0x00041E88
+#define XCDFS_Truncation 0x00061E88
+
+/* --- CDFSdriver SWIs --- */
+
+#define CD_Version 0x00041240
+#define XCD_Version 0x00061240
+#define CD_ReadData 0x00041241
+#define XCD_ReadData 0x00061241
+#define CD_SeekTo 0x00041242
+#define XCD_SeekTo 0x00061242
+#define CD_DriveStatus 0x00041243
+#define XCD_DriveStatus 0x00061243
+#define CD_DriveReady 0x00041244
+#define XCD_DriveReady 0x00061244
+#define CD_GetParameters 0x00041245
+#define XCD_GetParameters 0x00061245
+#define CD_SetParameters 0x00041246
+#define XCD_SetParameters 0x00061246
+#define CD_OpenDrawer 0x00041247
+#define XCD_OpenDrawer 0x00061247
+#define CD_EjectButton 0x00041248
+#define XCD_EjectButton 0x00061248
+#define CD_EnquireAddress 0x00041249
+#define XCD_EnquireAddress 0x00061249
+#define CD_EnquireDataMode 0x0004124A
+#define XCD_EnquireDataMode 0x0006124A
+#define CD_PlayAudio 0x0004124B
+#define XCD_PlayAudio 0x0006124B
+#define CD_PlayTrack 0x0004124C
+#define XCD_PlayTrack 0x0006124C
+#define CD_AudioPause 0x0004124D
+#define XCD_AudioPause 0x0006124D
+#define CD_EnquireTrack 0x0004124E
+#define XCD_EnquireTrack 0x0006124E
+#define CD_ReadSubChannel 0x0004124F
+#define XCD_ReadSubChannel 0x0006124F
+#define CD_CheckDrive 0x00041250
+#define XCD_CheckDrive 0x00061250
+#define CD_DiscChanged 0x00041251
+#define XCD_DiscChanged 0x00061251
+#define CD_StopDisc 0x00041252
+#define XCD_StopDisc 0x00061252
+#define CD_DiscUsed 0x00041253
+#define XCD_DiscUsed 0x00061253
+#define CD_AudioStatus 0x00041254
+#define XCD_AudioStatus 0x00061254
+#define CD_Inquiry 0x00041255
+#define XCD_Inquiry 0x00061255
+#define CD_DiscHasChanged 0x00041256
+#define XCD_DiscHasChanged 0x00061256
+#define CD_Control 0x00041257
+#define XCD_Control 0x00061257
+#define CD_Supported 0x00041258
+#define XCD_Supported 0x00061258
+#define CD_Prefetch 0x00041259
+#define XCD_Prefetch 0x00061259
+#define CD_Reset 0x0004125A
+#define XCD_Reset 0x0006125A
+#define CD_CloseDrawer 0x0004125B
+#define XCD_CloseDrawer 0x0006125B
+#define CD_IsDrawerLocked 0x0004125C
+#define XCD_IsDrawerLocked 0x0006125C
+#define CD_AudioControl 0x0004125D
+#define XCD_AudioControl 0x0006125D
+#define CD_LastError 0x0004125E
+#define XCD_LastError 0x0006125E
+#define CD_AudioLevel 0x0004125F
+#define XCD_AudioLevel 0x0006125F
+#define CD_Register 0x00041260
+#define XCD_Register 0x00061260
+#define CD_Unregister 0x00041261
+#define XCD_Unregister 0x00061261
+#define CD_ByteCopy 0x00041262
+#define XCD_ByteCopy 0x00061262
+#define CD_Identify 0x00041263
+#define XCD_Identify 0x00061263
+#define CD_ConvertToLBA 0x00041264
+#define XCD_ConvertToLBA 0x00061264
+#define CD_ConvertToMSF 0x00041265
+#define XCD_ConvertToMSF 0x00061265
+
+/* --- Sarah SWIs --- */
+
+#define Sarah_Cload 0x00057CC0
+#define XSarah_Cload 0x00077CC0
+#define Sarah_Csave 0x00057CC1
+#define XSarah_Csave 0x00077CC1
+#define Sarah_Eload 0x00057CC2
+#define XSarah_Eload 0x00077CC2
+#define Sarah_Esave 0x00057CC3
+#define XSarah_Esave 0x00077CC3
+#define Sarah_Envelope 0x00057CC4
+#define XSarah_Envelope 0x00077CC4
+#define Sarah_Prdump 0x00057CC5
+#define XSarah_Prdump 0x00077CC5
+#define Sarah_Zap 0x00057CC6
+#define XSarah_Zap 0x00077CC6
+
+/* --- DLLManager SWIs --- */
+
+#define DLL_Find 0x0004A300
+#define XDLL_Find 0x0006A300
+#define DLL_FindFromTable 0x0004A301
+#define XDLL_FindFromTable 0x0006A301
+#define DLL_Load 0x0004A302
+#define XDLL_Load 0x0006A302
+#define DLL_Lose 0x0004A303
+#define XDLL_Lose 0x0006A303
+#define DLL_AppDying 0x0004A304
+#define XDLL_AppDying 0x0006A304
+#define DLL_GiveCLibData 0x0004A305
+#define XDLL_GiveCLibData 0x0006A305
+#define DLL_FindCLibData 0x0004A306
+#define XDLL_FindCLibData 0x0006A306
+#define DLL_InstanceVars 0x0004A307
+#define XDLL_InstanceVars 0x0006A307
+#define DLL_SetInstanceVars 0x0004A308
+#define XDLL_SetInstanceVars 0x0006A308
+#define DLL_AppData 0x0004A309
+#define XDLL_AppData 0x0006A309
+#define DLL_Prologue 0x0004A30A
+#define XDLL_Prologue 0x0006A30A
+#define DLL_ReadStackPtr 0x0004A30B
+#define XDLL_ReadStackPtr 0x0006A30B
+#define DLL_SetStackPtr 0x0004A30C
+#define XDLL_SetStackPtr 0x0006A30C
+#define DLL_NameApp 0x0004A30D
+#define XDLL_NameApp 0x0006A30D
+#define DLL_Info 0x0004A30E
+#define XDLL_Info 0x0006A30E
+#define DLL_FindEntry 0x0004A30F
+#define XDLL_FindEntry 0x0006A30F
+#define DLL_SaveHandle 0x0004A310
+#define XDLL_SaveHandle 0x0006A310
+#define DLL_RestoreHandle 0x0004A311
+#define XDLL_RestoreHandle 0x0006A311
+#define DLL_FindInstanceVars 0x0004A312
+#define XDLL_FindInstanceVars 0x0006A312
+#define DLL_RegisterAppEntryTable 0x0004A313
+#define XDLL_RegisterAppEntryTable 0x0006A313
+#define DLL_FindAppEntry 0x0004A314
+#define XDLL_FindAppEntry 0x0006A314
+#define DLL_SetExtensionTable 0x0004A315
+#define XDLL_SetExtensionTable 0x0006A315
+
+/* --- ZapRedraw SWIs --- */
+
+#define ZapRedraw_RedrawArea 0x00048480
+#define XZapRedraw_RedrawArea 0x00068480
+#define ZapRedraw_GetPaletteEntry 0x00048481
+#define XZapRedraw_GetPaletteEntry 0x00068481
+#define ZapRedraw_RedrawRaster 0x00048482
+#define XZapRedraw_RedrawRaster 0x00068482
+#define ZapRedraw_ConvertBitmap 0x00048483
+#define XZapRedraw_ConvertBitmap 0x00068483
+#define ZapRedraw_PrepareDataLine 0x00048484
+#define XZapRedraw_PrepareDataLine 0x00068484
+#define ZapRedraw_AddCursor 0x00048485
+#define XZapRedraw_AddCursor 0x00068485
+#define ZapRedraw_FindCharacter 0x00048486
+#define XZapRedraw_FindCharacter 0x00068486
+#define ZapRedraw_MoveBytes 0x00048487
+#define XZapRedraw_MoveBytes 0x00068487
+#define ZapRedraw_CachedCharSize 0x00048488
+#define XZapRedraw_CachedCharSize 0x00068488
+#define ZapRedraw_ConvBitmapChar 0x00048489
+#define XZapRedraw_ConvBitmapChar 0x00068489
+#define ZapRedraw_CreatePalette 0x0004848A
+#define XZapRedraw_CreatePalette 0x0006848A
+#define ZapRedraw_InsertChar 0x0004848B
+#define XZapRedraw_InsertChar 0x0006848B
+#define ZapRedraw_ReadSystemChars 0x0004848C
+#define XZapRedraw_ReadSystemChars 0x0006848C
+#define ZapRedraw_ReverseBitmaps 0x0004848D
+#define XZapRedraw_ReverseBitmaps 0x0006848D
+#define ZapRedraw_ReadVduVars 0x0004848E
+#define XZapRedraw_ReadVduVars 0x0006848E
+#define ZapRedraw_GetRectangle 0x0004848F
+#define XZapRedraw_GetRectangle 0x0006848F
+#define ZapRedraw_AddVduBitmaps 0x00048490
+#define XZapRedraw_AddVduBitmaps 0x00068490
+#define ZapRedraw_CacheFontChars 0x00048491
+#define XZapRedraw_CacheFontChars 0x00068491
+#define ZapRedraw_SpriteSize 0x00048492
+#define XZapRedraw_SpriteSize 0x00068492
+#define ZapRedraw_RedrawWindow 0x00048493
+#define XZapRedraw_RedrawWindow 0x00068493
+
+/* --- 310Support SWIs --- */
+
+
+/* --- ABCLibrary SWIs --- */
+
+#define ABCLib_Init 0x00080B80
+#define XABCLib_Init 0x000A0B80
+#define ABCLib_Register 0x00080B81
+#define XABCLib_Register 0x000A0B81
+#define ABCLib_Profile 0x00080B82
+#define XABCLib_Profile 0x000A0B82
+#define ABCLib_WAC 0x00080B83
+#define XABCLib_WAC 0x000A0B83
+
+/* --- DDEUtils SWIs --- */
+
+#define DDEUtils_Prefix 0x00042580
+#define XDDEUtils_Prefix 0x00062580
+#define DDEUtils_SetCLSize 0x00042581
+#define XDDEUtils_SetCLSize 0x00062581
+#define DDEUtils_SetCL 0x00042582
+#define XDDEUtils_SetCL 0x00062582
+#define DDEUtils_GetCLSize 0x00042583
+#define XDDEUtils_GetCLSize 0x00062583
+#define DDEUtils_GetCl 0x00042584
+#define XDDEUtils_GetCl 0x00062584
+#define DDEUtils_ThrowbackRegister 0x00042585
+#define XDDEUtils_ThrowbackRegister 0x00062585
+#define DDEUtils_ThrowbackUnRegister 0x00042586
+#define XDDEUtils_ThrowbackUnRegister 0x00062586
+#define DDEUtils_ThrowbackStart 0x00042587
+#define XDDEUtils_ThrowbackStart 0x00062587
+#define DDEUtils_ThrowbackSend 0x00042588
+#define XDDEUtils_ThrowbackSend 0x00062588
+#define DDEUtils_ThrowbackEnd 0x00042589
+#define XDDEUtils_ThrowbackEnd 0x00062589
+
+/* --- DragAnObject SWIs --- */
+
+#define DragAnObject_Start 0x00049C40
+#define XDragAnObject_Start 0x00069C40
+#define DragAnObject_Stop 0x00049C41
+#define XDragAnObject_Stop 0x00069C41
+
+/* --- TinyStubs SWIs --- */
+
+#define TinySupport_Init 0x00082C40
+#define XTinySupport_Init 0x000A2C40
+#define TinySupport_Die 0x00082C41
+#define XTinySupport_Die 0x000A2C41
+#define TinySupport_Init2 0x00082C42
+#define XTinySupport_Init2 0x000A2C42
+#define TinySupport_Share 0x00082C43
+#define XTinySupport_Share 0x000A2C43
+
+/* --- ColourDbox SWIs --- */
+
+#define ColourDbox_ClassSWI 0x000829C0
+#define XColourDbox_ClassSWI 0x000A29C0
+#define ColourDbox_PostFilter 0x000829C1
+#define XColourDbox_PostFilter 0x000A29C1
+#define ColourDbox_PreFilter 0x000829C2
+#define XColourDbox_PreFilter 0x000A29C2
+
+/* --- ColourMenu SWIs --- */
+
+#define ColourMenu_ClassSWI 0x00082980
+#define XColourMenu_ClassSWI 0x000A2980
+#define ColourMenu_PostFilter 0x00082981
+#define XColourMenu_PostFilter 0x000A2981
+#define ColourMenu_PreFilter 0x00082982
+#define XColourMenu_PreFilter 0x000A2982
+
+/* --- DCS SWIs --- */
+
+#define DCS_ClassSWI 0x00082A80
+#define XDCS_ClassSWI 0x000A2A80
+#define DCS_PostFilter 0x00082A81
+#define XDCS_PostFilter 0x000A2A81
+#define DCS_PreFilter 0x00082A82
+#define XDCS_PreFilter 0x000A2A82
+
+/* --- DrawFile SWIs --- */
+
+#define DrawFile_Render 0x00045540
+#define XDrawFile_Render 0x00065540
+#define DrawFile_BBox 0x00045541
+#define XDrawFile_BBox 0x00065541
+#define DrawFile_DeclareFonts 0x00045542
+#define XDrawFile_DeclareFonts 0x00065542
+
+/* --- FileInfo SWIs --- */
+
+#define FileInfo_ClassSWI 0x00082AC0
+#define XFileInfo_ClassSWI 0x000A2AC0
+#define FileInfo_PostFilter 0x00082AC1
+#define XFileInfo_PostFilter 0x000A2AC1
+#define FileInfo_PreFilter 0x00082AC2
+#define XFileInfo_PreFilter 0x000A2AC2
+
+/* --- FontDbox SWIs --- */
+
+#define FontDbox_ClassSWI 0x00082A00
+#define XFontDbox_ClassSWI 0x000A2A00
+#define FontDbox_PostFilter 0x00082A01
+#define XFontDbox_PostFilter 0x000A2A01
+#define FontDbox_PreFilter 0x00082A02
+#define XFontDbox_PreFilter 0x000A2A02
+
+/* --- FontMenu SWIs --- */
+
+#define FontMenu_ClassSWI 0x00082A40
+#define XFontMenu_ClassSWI 0x000A2A40
+#define FontMenu_PostFilter 0x00082A41
+#define XFontMenu_PostFilter 0x000A2A41
+#define FontMenu_PreFilter 0x00082A42
+#define XFontMenu_PreFilter 0x000A2A42
+
+/* --- Iconbar SWIs --- */
+
+#define Iconbar_ClassSWI 0x00082900
+#define XIconbar_ClassSWI 0x000A2900
+#define Iconbar_PostFilter 0x00082901
+#define XIconbar_PostFilter 0x000A2901
+#define Iconbar_PreFilter 0x00082902
+#define XIconbar_PreFilter 0x000A2902
+
+/* --- Menu SWIs --- */
+
+#define Menu_ClassSWI 0x000828C0
+#define XMenu_ClassSWI 0x000A28C0
+#define Menu_PostFilter 0x000828C1
+#define XMenu_PostFilter 0x000A28C1
+#define Menu_PreFilter 0x000828C2
+#define XMenu_PreFilter 0x000A28C2
+#define Menu_UpdateTree 0x000828C3
+#define XMenu_UpdateTree 0x000A28C3
+
+/* --- PrintDbox SWIs --- */
+
+#define PrintDbox_ClassSWI 0x00082B00
+#define XPrintDbox_ClassSWI 0x000A2B00
+#define PrintDbox_PostFilter 0x00082B01
+#define XPrintDbox_PostFilter 0x000A2B01
+#define PrintDbox_PreFilter 0x00082B02
+#define XPrintDbox_PreFilter 0x000A2B02
+
+/* --- ProgInfo SWIs --- */
+
+#define ProgInfo_ClassSWI 0x00082B40
+#define XProgInfo_ClassSWI 0x000A2B40
+#define ProgInfo_PostFilter 0x00082B41
+#define XProgInfo_PostFilter 0x000A2B41
+#define ProgInfo_PreFilter 0x00082B42
+#define XProgInfo_PreFilter 0x000A2B42
+
+/* --- SaveAs SWIs --- */
+
+#define SaveAs_ClassSWI 0x00082BC0
+#define XSaveAs_ClassSWI 0x000A2BC0
+#define SaveAs_PostFilter 0x00082BC1
+#define XSaveAs_PostFilter 0x000A2BC1
+#define SaveAs_PreFilter 0x00082BC2
+#define XSaveAs_PreFilter 0x000A2BC2
+
+/* --- Scale SWIs --- */
+
+#define Scale_ClassSWI 0x00082C00
+#define XScale_ClassSWI 0x000A2C00
+#define Scale_PostFilter 0x00082C01
+#define XScale_PostFilter 0x000A2C01
+#define Scale_PreFilter 0x00082C02
+#define XScale_PreFilter 0x000A2C02
+
+/* --- Toolbox SWIs --- */
+
+#define Toolbox_CreateObject 0x00044EC0
+#define XToolbox_CreateObject 0x00064EC0
+#define Toolbox_DeleteObject 0x00044EC1
+#define XToolbox_DeleteObject 0x00064EC1
+#define Toolbox_CopyObject 0x00044EC2
+#define XToolbox_CopyObject 0x00064EC2
+#define Toolbox_ShowObject 0x00044EC3
+#define XToolbox_ShowObject 0x00064EC3
+#define Toolbox_HideObject 0x00044EC4
+#define XToolbox_HideObject 0x00064EC4
+#define Toolbox_GetObjectInfo 0x00044EC5
+#define XToolbox_GetObjectInfo 0x00064EC5
+#define Toolbox_ObjectMiscOp 0x00044EC6
+#define XToolbox_ObjectMiscOp 0x00064EC6
+#define Toolbox_SetClientHandle 0x00044EC7
+#define XToolbox_SetClientHandle 0x00064EC7
+#define Toolbox_GetClientHandle 0x00044EC8
+#define XToolbox_GetClientHandle 0x00064EC8
+#define Toolbox_GetObjectClass 0x00044EC9
+#define XToolbox_GetObjectClass 0x00064EC9
+#define Toolbox_GetParent 0x00044ECA
+#define XToolbox_GetParent 0x00064ECA
+#define Toolbox_GetAncestor 0x00044ECB
+#define XToolbox_GetAncestor 0x00064ECB
+#define Toolbox_GetTemplateName 0x00044ECC
+#define XToolbox_GetTemplateName 0x00064ECC
+#define Toolbox_RaiseToolboxEvent 0x00044ECD
+#define XToolbox_RaiseToolboxEvent 0x00064ECD
+#define Toolbox_GetSysInfo 0x00044ECE
+#define XToolbox_GetSysInfo 0x00064ECE
+#define Toolbox_Initialise 0x00044ECF
+#define XToolbox_Initialise 0x00064ECF
+#define Toolbox_LoadResources 0x00044ED0
+#define XToolbox_LoadResources 0x00064ED0
+#define Toolbox_TemplateLookUp 0x00044EFB
+#define XToolbox_TemplateLookUp 0x00064EFB
+#define Toolbox_GetInternalHandle 0x00044EFC
+#define XToolbox_GetInternalHandle 0x00064EFC
+#define Toolbox_RegisterPostFilter 0x00044EFD
+#define XToolbox_RegisterPostFilter 0x00064EFD
+#define Toolbox_RegisterPreFilter 0x00044EFE
+#define XToolbox_RegisterPreFilter 0x00064EFE
+#define Toolbox_RegisterObjectModule 0x00044EFF
+#define XToolbox_RegisterObjectModule 0x00064EFF
+
+/* --- Window SWIs --- */
+
+#define Window_ClassSWI 0x00082880
+#define XWindow_ClassSWI 0x000A2880
+#define Window_PostFilter 0x00082881
+#define XWindow_PostFilter 0x000A2881
+#define Window_PreFilter 0x00082882
+#define XWindow_PreFilter 0x000A2882
+#define Window_GetPointerInfo 0x00082883
+#define XWindow_GetPointerInfo 0x000A2883
+#define Window_WimpToToolbox 0x00082884
+#define XWindow_WimpToToolbox 0x000A2884
+#define Window_RegisterExternal 0x00082885
+#define XWindow_RegisterExternal 0x000A2885
+#define Window_DeregisterExternal 0x00082886
+#define XWindow_DeregisterExternal 0x000A2886
+#define Window_SupportExternal 0x00082887
+#define XWindow_SupportExternal 0x000A2887
+
+/* --- Hyphenator SWIs --- */
+
+#define Hyphenator_ResetDictionary 0x00081000
+#define XHyphenator_ResetDictionary 0x000A1000
+#define Hyphenator_CreateDictionary 0x00081001
+#define XHyphenator_CreateDictionary 0x000A1001
+#define Hyphenator_CopyDictionary 0x00081002
+#define XHyphenator_CopyDictionary 0x000A1002
+#define Hyphenator_EnquireDictionary 0x00081003
+#define XHyphenator_EnquireDictionary 0x000A1003
+#define Hyphenator_FindWord 0x00081004
+#define XHyphenator_FindWord 0x000A1004
+#define Hyphenator_AddWord 0x00081005
+#define XHyphenator_AddWord 0x000A1005
+#define Hyphenator_RemoveWord 0x00081006
+#define XHyphenator_RemoveWord 0x000A1006
+#define Hyphenator_Hyphenate 0x00081007
+#define XHyphenator_Hyphenate 0x000A1007
+#define Hyphenator_GetWords 0x00081008
+#define XHyphenator_GetWords 0x000A1008
+#define Hyphenator_EnumWord 0x00081009
+#define XHyphenator_EnumWord 0x000A1009
+
+/* --- ImpressionSpell SWIs --- */
+
+#define Spell_Typo 0x00080080
+#define XSpell_Typo 0x000A0080
+#define Spell_Anagram 0x00080081
+#define XSpell_Anagram 0x000A0081
+#define Spell_Fuzzy 0x00080082
+#define XSpell_Fuzzy 0x000A0082
+#define Spell_CheckWord 0x00080083
+#define XSpell_CheckWord 0x000A0083
+#define Spell_AddWord 0x00080084
+#define XSpell_AddWord 0x000A0084
+#define Spell_GetWord 0x00080085
+#define XSpell_GetWord 0x000A0085
+#define Spell_GetNextWord 0x00080086
+#define XSpell_GetNextWord 0x000A0086
+#define Spell_EnumWord 0x00080087
+#define XSpell_EnumWord 0x000A0087
+#define Spell_CreateUser 0x00080088
+#define XSpell_CreateUser 0x000A0088
+#define Spell_LoadUser 0x00080089
+#define XSpell_LoadUser 0x000A0089
+#define Spell_SaveUser 0x0008008A
+#define XSpell_SaveUser 0x000A008A
+#define Spell_UserToFile 0x0008008B
+#define XSpell_UserToFile 0x000A008B
+#define Spell_FileToUser 0x0008008C
+#define XSpell_FileToUser 0x000A008C
+#define Spell_GetDictionaryName 0x0008008D
+#define XSpell_GetDictionaryName 0x000A008D
+#define Spell_RemoveDictionary 0x0008008E
+#define XSpell_RemoveDictionary 0x000A008E
+#define Spell_DeleteWord 0x0008008F
+#define XSpell_DeleteWord 0x000A008F
+#define Spell_ResetIgnore 0x00080090
+#define XSpell_ResetIgnore 0x000A0090
+#define Spell_AddToIgnore 0x00080091
+#define XSpell_AddToIgnore 0x000A0091
+#define Spell_BrowseWindow 0x00080092
+#define XSpell_BrowseWindow 0x000A0092
+#define Spell_SpellOp 0x00080093
+#define XSpell_SpellOp 0x000A0093
+#define Spell_FindWord 0x00080094
+#define XSpell_FindWord 0x000A0094
+#define Spell_ImpressionInfo 0x00080095
+#define XSpell_ImpressionInfo 0x000A0095
+#define Spell_ImpressionQuickCheck 0x00080096
+#define XSpell_ImpressionQuickCheck 0x000A0096
+#define Spell_FileToFile 0x00080097
+#define XSpell_FileToFile 0x000A0097
+#define Spell_SaveDictionaryWithPath 0x00080098
+#define XSpell_SaveDictionaryWithPath 0x000A0098
+
+/* --- ABI SWIs --- */
+
+#define ABI_Initialise 0x00043300
+#define XABI_Initialise 0x00063300
+#define ABI_CloseDown 0x00043301
+#define XABI_CloseDown 0x00063301
+#define ABI_RenderSlab 0x00043302
+#define XABI_RenderSlab 0x00063302
+#define ABI_Reset 0x00043303
+#define XABI_Reset 0x00063303
+#define ABI_Kill 0x00043304
+#define XABI_Kill 0x00063304
+
+/* --- AudioManager SWIs --- */
+
+#define AudioManager_Info 0x00047B40
+#define XAudioManager_Info 0x00067B40
+#define AudioManager_Reset 0x00047B41
+#define XAudioManager_Reset 0x00067B41
+#define AudioManager_ListDrivers 0x00047B42
+#define XAudioManager_ListDrivers 0x00067B42
+#define AudioManager_Defaults 0x00047B43
+#define XAudioManager_Defaults 0x00067B43
+#define AudioManager_Driver 0x00047B44
+#define XAudioManager_Driver 0x00067B44
+#define AudioManager_SelectSampler 0x00047B45
+#define XAudioManager_SelectSampler 0x00067B45
+#define AudioManager_SamplerStatus 0x00047B46
+#define XAudioManager_SamplerStatus 0x00067B46
+#define AudioManager_StartSampling 0x00047B47
+#define XAudioManager_StartSampling 0x00067B47
+#define AudioManager_StopSampling 0x00047B48
+#define XAudioManager_StopSampling 0x00067B48
+#define AudioManager_DeselectSampler 0x00047B49
+#define XAudioManager_DeselectSampler 0x00067B49
+#define AudioManager_PlaySample 0x00047B4A
+#define XAudioManager_PlaySample 0x00067B4A
+#define AudioManager_FillBuffer 0x00047B4B
+#define XAudioManager_FillBuffer 0x00067B4B
+#define AudioManager_ReturnCursor 0x00047B4C
+#define XAudioManager_ReturnCursor 0x00067B4C
+#define AudioManager_KillSample 0x00047B4D
+#define XAudioManager_KillSample 0x00067B4D
+#define AudioManager_AdjustPlay 0x00047B4E
+#define XAudioManager_AdjustPlay 0x00067B4E
+#define AudioManager_ConvertPitch 0x00047B4F
+#define XAudioManager_ConvertPitch 0x00067B4F
+#define AudioManager_Stereo 0x00047B50
+#define XAudioManager_Stereo 0x00067B50
+#define AudioManager_AttachVoice 0x00047B51
+#define XAudioManager_AttachVoice 0x00067B51
+#define AudioManager_SoundPacked 0x00047B52
+#define XAudioManager_SoundPacked 0x00067B52
+#define AudioManager_Sound 0x00047B53
+#define XAudioManager_Sound 0x00067B53
+#define AudioManager_ReadCCB 0x00047B54
+#define XAudioManager_ReadCCB 0x00067B54
+#define AudioManager_WriteCCB 0x00047B55
+#define XAudioManager_WriteCCB 0x00067B55
+#define AudioManager_PlaySampleFromFile 0x00047B56
+#define XAudioManager_PlaySampleFromFile 0x00067B56
+#define AudioManager_QueueEvent 0x00047B57
+#define XAudioManager_QueueEvent 0x00067B57
+#define AudioManager_AddEvent 0x00047B58
+#define XAudioManager_AddEvent 0x00067B58
+#define AudioManager_RedirectVIDC 0x00047B59
+#define XAudioManager_RedirectVIDC 0x00067B59
+
+/* --- ArtworksRenderer SWIs --- */
+
+#define AWRender_FileInitAddress 0x00046080
+#define XAWRender_FileInitAddress 0x00066080
+#define AWRender_RenderAddress 0x00046081
+#define XAWRender_RenderAddress 0x00066081
+#define AWRender_DocBounds 0x00046082
+#define XAWRender_DocBounds 0x00066082
+#define AWRender_SendDefs 0x00046083
+#define XAWRender_SendDefs 0x00066083
+#define AWRender_ClaimVectors 0x00046084
+#define XAWRender_ClaimVectors 0x00066084
+#define AWRender_ReleaseVectors 0x00046085
+#define XAWRender_ReleaseVectors 0x00066085
+#define AWRender_FindFirstFont 0x00046086
+#define XAWRender_FindFirstFont 0x00066086
+#define AWRender_FindNextFont 0x00046087
+#define XAWRender_FindNextFont 0x00066087
+#define AWRender_MemoryNeeded 0x00046088
+#define XAWRender_MemoryNeeded 0x00066088
+
+/* --- StreamSquash SWIs --- */
+
+#define StreamSquash_Initialise 0x00044D40
+#define XStreamSquash_Initialise 0x00064D40
+#define StreamSquash_InfoCompress 0x00044D41
+#define XStreamSquash_InfoCompress 0x00064D41
+#define StreamSquash_OpenCompress 0x00044D42
+#define XStreamSquash_OpenCompress 0x00064D42
+#define StreamSquash_CompressBlock 0x00044D43
+#define XStreamSquash_CompressBlock 0x00064D43
+#define StreamSquash_CloseCompress 0x00044D44
+#define XStreamSquash_CloseCompress 0x00064D44
+#define StreamSquash_InfoDecompress 0x00044D45
+#define XStreamSquash_InfoDecompress 0x00064D45
+#define StreamSquash_OpenDecompress 0x00044D46
+#define XStreamSquash_OpenDecompress 0x00064D46
+#define StreamSquash_DecompressBlock 0x00044D47
+#define XStreamSquash_DecompressBlock 0x00064D47
+#define StreamSquash_CloseDecompress 0x00044D48
+#define XStreamSquash_CloseDecompress 0x00064D48
+#define StreamSquash_Exit 0x00044D49
+#define XStreamSquash_Exit 0x00064D49
+
+/* --- ColourExtend SWIs --- */
+
+#define ColourExtend_Info 0x00040F40
+#define XColourExtend_Info 0x00060F40
+#define ColourExtend_Control 0x00040F41
+#define XColourExtend_Control 0x00060F41
+#define ColourExtend_InvalidateCache 0x00040F42
+#define XColourExtend_InvalidateCache 0x00060F42
+
+/* --- DitherExtend SWIs --- */
+
+#define DitherExtend_SelectTable 0x00044580
+#define XDitherExtend_SelectTable 0x00064580
+#define DitherExtend_SelectGCOLTable 0x00044581
+#define XDitherExtend_SelectGCOLTable 0x00064581
+#define DitherExtend_ReturnGCOL 0x00044582
+#define XDitherExtend_ReturnGCOL 0x00064582
+#define DitherExtend_SetGCOL 0x00044583
+#define XDitherExtend_SetGCOL 0x00064583
+#define DitherExtend_ReturnColourNumber 0x00044584
+#define XDitherExtend_ReturnColourNumber 0x00064584
+#define DitherExtend_ReturnGCOLForMode 0x00044585
+#define XDitherExtend_ReturnGCOLForMode 0x00064585
+#define DitherExtend_ReturnColourNumberForMode 0x00044586
+#define XDitherExtend_ReturnColourNumberForMode 0x00064586
+#define DitherExtend_ReturnOppGCOL 0x00044587
+#define XDitherExtend_ReturnOppGCOL 0x00064587
+#define DitherExtend_SetOppGCOL 0x00044588
+#define XDitherExtend_SetOppGCOL 0x00064588
+#define DitherExtend_ReturnOppColourNumber 0x00044589
+#define XDitherExtend_ReturnOppColourNumber 0x00064589
+#define DitherExtend_ReturnOppGCOLForMode 0x0004458A
+#define XDitherExtend_ReturnOppGCOLForMode 0x0006458A
+#define DitherExtend_ReturnOppColourNumberForMode 0x0004458B
+#define XDitherExtend_ReturnOppColourNumberForMode 0x0006458B
+#define DitherExtend_GCOLToColourNumber 0x0004458C
+#define XDitherExtend_GCOLToColourNumber 0x0006458C
+#define DitherExtend_ColourNumberToGCOL 0x0004458D
+#define XDitherExtend_ColourNumberToGCOL 0x0006458D
+#define DitherExtend_Info 0x0004458E
+#define XDitherExtend_Info 0x0006458E
+#define DitherExtend_Control 0x0004458F
+#define XDitherExtend_Control 0x0006458F
+#define DitherExtend_ReturnColourPattern 0x00044590
+#define XDitherExtend_ReturnColourPattern 0x00064590
+#define DitherExtend_ReturnColourPatternTable 0x00044591
+#define XDitherExtend_ReturnColourPatternTable 0x00064591
+#define DitherExtend_InvalidatePalette 0x00044592
+#define XDitherExtend_InvalidatePalette 0x00064592
+#define DitherExtend_Antialias 0x00044593
+#define XDitherExtend_Antialias 0x00064593
+#define DitherExtend_ReadPalette 0x00044594
+#define XDitherExtend_ReadPalette 0x00064594
+#define DitherExtend_ReturnColourPatternArray 0x00044595
+#define XDitherExtend_ReturnColourPatternArray 0x00064595
+#define DitherExtend_SetHalftone 0x00044596
+#define XDitherExtend_SetHalftone 0x00064596
+#define DitherExtend_ReturnHalftone 0x00044597
+#define XDitherExtend_ReturnHalftone 0x00064597
+#define DitherExtend_SetHalftoneOrigin 0x00044598
+#define XDitherExtend_SetHalftoneOrigin 0x00064598
+#define DitherExtend_ReturnHalftoneOrigin 0x00044599
+#define XDitherExtend_ReturnHalftoneOrigin 0x00064599
+#define DitherExtend_SelectHalftoneTable 0x0004459A
+#define XDitherExtend_SelectHalftoneTable 0x0006459A
+#define DitherExtend_ReturnHalftoneIntensity 0x0004459B
+#define XDitherExtend_ReturnHalftoneIntensity 0x0006459B
+#define DitherExtend_ReturnHalftoneTable 0x0004459C
+#define XDitherExtend_ReturnHalftoneTable 0x0006459C
+#define DitherExtend_SetScreen 0x0004459D
+#define XDitherExtend_SetScreen 0x0006459D
+#define DitherExtend_CacheScreen 0x0004459E
+#define XDitherExtend_CacheScreen 0x0006459E
+#define DitherExtend_SelectColourPatternTable 0x0004459F
+#define XDitherExtend_SelectColourPatternTable 0x0006459F
+
+/* --- DocumentManager SWIs --- */
+
+#define DocumentManager_Open 0x000430C0
+#define XDocumentManager_Open 0x000630C0
+#define DocumentManager_Close 0x000430C1
+#define XDocumentManager_Close 0x000630C1
+#define DocumentManager_File 0x000430C2
+#define XDocumentManager_File 0x000630C2
+#define DocumentManager_Find 0x000430C3
+#define XDocumentManager_Find 0x000630C3
+#define DocumentManager_Args 0x000430C4
+#define XDocumentManager_Args 0x000630C4
+#define DocumentManager_GBPB 0x000430C5
+#define XDocumentManager_GBPB 0x000630C5
+#define DocumentManager_Compact 0x000430C6
+#define XDocumentManager_Compact 0x000630C6
+#define DocumentManager_Reset 0x000430C7
+#define XDocumentManager_Reset 0x000630C7
+#define DocumentManager_Stamp 0x000430C8
+#define XDocumentManager_Stamp 0x000630C8
+
+/* --- FontInstallSupport SWIs --- */
+
+#define FontInstall_GetFonts 0x00044FC0
+#define XFontInstall_GetFonts 0x00064FC0
+#define FontInstall_Reset 0x00044FC1
+#define XFontInstall_Reset 0x00064FC1
+
+/* --- FontDraw SWIs --- */
+
+#define FontDraw_FindFont 0x00046040
+#define XFontDraw_FindFont 0x00066040
+#define FontDraw_LoseFont 0x00046041
+#define XFontDraw_LoseFont 0x00066041
+#define FontDraw_Paint 0x00046042
+#define XFontDraw_Paint 0x00066042
+
+/* --- GDraw SWIs --- */
+
+#define GDraw_ProcessPath 0x00044540
+#define XGDraw_ProcessPath 0x00064540
+#define GDraw_ProcessPathFP 0x00044541
+#define XGDraw_ProcessPathFP 0x00064541
+#define GDraw_Fill 0x00044542
+#define XGDraw_Fill 0x00064542
+#define GDraw_FillFP 0x00044543
+#define XGDraw_FillFP 0x00064543
+#define GDraw_Stroke 0x00044544
+#define XGDraw_Stroke 0x00064544
+#define GDraw_StrokeFP 0x00044545
+#define XGDraw_StrokeFP 0x00064545
+#define GDraw_StrokePath 0x00044546
+#define XGDraw_StrokePath 0x00064546
+#define GDraw_StrokePathFP 0x00044547
+#define XGDraw_StrokePathFP 0x00064547
+#define GDraw_FlattenPath 0x00044548
+#define XGDraw_FlattenPath 0x00064548
+#define GDraw_FlattenPathFP 0x00044549
+#define XGDraw_FlattenPathFP 0x00064549
+#define GDraw_TransformPath 0x0004454A
+#define XGDraw_TransformPath 0x0006454A
+#define GDraw_TransformPathFP 0x0004454B
+#define XGDraw_TransformPathFP 0x0006454B
+#define GDraw_ProcessClipPath 0x0004454C
+#define XGDraw_ProcessClipPath 0x0006454C
+#define GDraw_ProcessClipPathFP 0x0004454D
+#define XGDraw_ProcessClipPathFP 0x0006454D
+#define GDraw_ClipPath 0x0004454E
+#define XGDraw_ClipPath 0x0006454E
+#define GDraw_ClipPathFP 0x0004454F
+#define XGDraw_ClipPathFP 0x0006454F
+#define GDraw_ClipPathToPath 0x00044550
+#define XGDraw_ClipPathToPath 0x00064550
+#define GDraw_ClipPathToPathFP 0x00044551
+#define XGDraw_ClipPathToPathFP 0x00064551
+#define GDraw_ClearClipRegion 0x00044552
+#define XGDraw_ClearClipRegion 0x00064552
+#define GDraw_SetClipRegion 0x00044553
+#define XGDraw_SetClipRegion 0x00064553
+#define GDraw_SetFillStyle 0x00044554
+#define XGDraw_SetFillStyle 0x00064554
+#define GDraw_FillRegion 0x00044555
+#define XGDraw_FillRegion 0x00064555
+#define GDraw_SetPrintFlag 0x00044556
+#define XGDraw_SetPrintFlag 0x00064556
+#define GDraw_ReadFillStyle 0x00044557
+#define XGDraw_ReadFillStyle 0x00064557
+#define GDraw_GetClipRegion 0x00044558
+#define XGDraw_GetClipRegion 0x00064558
+
+/* --- ImageExtend SWIs --- */
+
+#define ImageExtend_Info 0x00080E00
+#define XImageExtend_Info 0x000A0E00
+#define ImageExtend_PutSpriteTransformed 0x00080E01
+#define XImageExtend_PutSpriteTransformed 0x000A0E01
+#define ImageExtend_PutSpriteToBufferTransformed 0x00080E02
+#define XImageExtend_PutSpriteToBufferTransformed 0x000A0E02
+#define ImageExtend_PutStringTransformed 0x00080E03
+#define XImageExtend_PutStringTransformed 0x000A0E03
+#define ImageExtend_GetBBox 0x00080E04
+#define XImageExtend_GetBBox 0x000A0E04
+#define ImageExtend_GetImageBBox 0x00080E05
+#define XImageExtend_GetImageBBox 0x000A0E05
+#define ImageExtend_MakeMatrix 0x00080E06
+#define XImageExtend_MakeMatrix 0x000A0E06
+#define ImageExtend_MakeHalftoneTile 0x00080E07
+#define XImageExtend_MakeHalftoneTile 0x000A0E07
+#define ImageExtend_AddKernelToMatrix 0x00080E08
+#define XImageExtend_AddKernelToMatrix 0x000A0E08
+#define ImageExtend_MakeSimpleScreenTile 0x00080E09
+#define XImageExtend_MakeSimpleScreenTile 0x000A0E09
+
+/* --- Impulse SWIs --- */
+
+#define Impulse_Initialise 0x000428C0
+#define XImpulse_Initialise 0x000628C0
+#define Impulse_Decode 0x000428C1
+#define XImpulse_Decode 0x000628C1
+#define Impulse_SendMessage 0x000428C2
+#define XImpulse_SendMessage 0x000628C2
+#define Impulse_TransmitData 0x000428C3
+#define XImpulse_TransmitData 0x000628C3
+#define Impulse_FetchData 0x000428C4
+#define XImpulse_FetchData 0x000628C4
+#define Impulse_CloseDown 0x000428C5
+#define XImpulse_CloseDown 0x000628C5
+#define Impulse_DeferReply 0x000428C6
+#define XImpulse_DeferReply 0x000628C6
+
+/* --- OLESupport SWIs --- */
+
+#define OLE_Version 0x00047B00
+#define XOLE_Version 0x00067B00
+#define OLE_LinkFile 0x00047B01
+#define XOLE_LinkFile 0x00067B01
+#define OLE_DeLinkFile 0x00047B02
+#define XOLE_DeLinkFile 0x00067B02
+#define OLE_FileStatus 0x00047B03
+#define XOLE_FileStatus 0x00067B03
+#define OLE_Invalidate 0x00047B04
+#define XOLE_Invalidate 0x00067B04
+#define OLE_SimulateSession 0x00047B05
+#define XOLE_SimulateSession 0x00067B05
+
+/* --- GSpriteExtend SWIs --- */
+
+#define GSpriteExtend_PlotSprite 0x00041480
+#define XGSpriteExtend_PlotSprite 0x00061480
+#define GSpriteExtend_SwitchOutputToSprite 0x00041481
+#define XGSpriteExtend_SwitchOutputToSprite 0x00061481
+#define GSpriteExtend_ReadVariable 0x00041482
+#define XGSpriteExtend_ReadVariable 0x00061482
+
+/* --- Constrain SWIs --- */
+
+#define Constrain_Finish 0x0004A340
+#define XConstrain_Finish 0x0006A340
+#define Constrain_MousePos 0x0004A341
+#define XConstrain_MousePos 0x0006A341
+#define Constrain_Circle 0x0004A342
+#define XConstrain_Circle 0x0006A342
+#define Constrain_Disc 0x0004A343
+#define XConstrain_Disc 0x0006A343
+
+/* --- Sledgehammer SWIs --- */
+
+#define Sledgehammer_SetDissOptions 0x0004A380
+#define XSledgehammer_SetDissOptions 0x0006A380
+#define Sledgehammer_DissAddress 0x0004A381
+#define XSledgehammer_DissAddress 0x0006A381
+#define Sledgehammer_Disassemble 0x0004A382
+#define XSledgehammer_Disassemble 0x0006A382
+#define Sledgehammer_Assemble 0x0004A383
+#define XSledgehammer_Assemble 0x0006A383
+#define Sledgehammer_Step 0x0004A384
+#define XSledgehammer_Step 0x0006A384
+#define Sledgehammer_StepAddr 0x0004A385
+#define XSledgehammer_StepAddr 0x0006A385
+#define Sledgehammer_SetBP 0x0004A386
+#define XSledgehammer_SetBP 0x0006A386
+#define Sledgehammer_RemoveBP 0x0004A387
+#define XSledgehammer_RemoveBP 0x0006A387
+#define Sledgehammer_Translate 0x0004A388
+#define XSledgehammer_Translate 0x0006A388
+#define Sledgehammer_BreakPoint 0x0004A389
+#define XSledgehammer_BreakPoint 0x0006A389
+
+/* --- DDT SWIs --- */
+
+#define Debugger_DebugAIF 0x00041D40
+#define XDebugger_DebugAIF 0x00061D40
+#define Debugger_BeingDebugged 0x00041D41
+#define XDebugger_BeingDebugged 0x00061D41
+#define Debugger_StartDebug 0x00041D42
+#define XDebugger_StartDebug 0x00061D42
+#define Debugger_EndDebug 0x00041D43
+#define XDebugger_EndDebug 0x00061D43
+
+/* --- VDUStream SWIs --- */
+
+#define Stream_Enable 0x00081940
+#define XStream_Enable 0x000A1940
+#define Stream_Disable 0x00081941
+#define XStream_Disable 0x000A1941
+#define Stream_Kill 0x00081942
+#define XStream_Kill 0x000A1942
+#define Stream_UnKill 0x00081943
+#define XStream_UnKill 0x000A1943
+#define Stream_Intercept 0x00081944
+#define XStream_Intercept 0x000A1944
+#define Stream_NoIntercept 0x00081945
+#define XStream_NoIntercept 0x000A1945
+#define Stream_ShowCodes 0x00081946
+#define XStream_ShowCodes 0x000A1946
+#define Stream_NoCodes 0x00081947
+#define XStream_NoCodes 0x000A1947
+#define Stream_Reset 0x00081948
+#define XStream_Reset 0x000A1948
+#define Stream_FlushText 0x00081949
+#define XStream_FlushText 0x000A1949
+#define Stream_WriteC 0x0008194A
+#define XStream_WriteC 0x000A194A
+#define Stream_WriteS 0x0008194B
+#define XStream_WriteS 0x000A194B
+#define Stream_Write0 0x0008194C
+#define XStream_Write0 0x000A194C
+#define Stream_WriteN 0x0008194D
+#define XStream_WriteN 0x000A194D
+#define Stream_NewLine 0x0008194E
+#define XStream_NewLine 0x000A194E
+#define Stream_WriteT32 0x0008194F
+#define XStream_WriteT32 0x000A194F
+#define Stream_WriteT24 0x00081950
+#define XStream_WriteT24 0x000A1950
+#define Stream_WriteT16 0x00081951
+#define XStream_WriteT16 0x000A1951
+#define Stream_WriteT8 0x00081952
+#define XStream_WriteT8 0x000A1952
+#define Stream_WriteH32 0x00081953
+#define XStream_WriteH32 0x000A1953
+#define Stream_WriteH24 0x00081954
+#define XStream_WriteH24 0x000A1954
+#define Stream_WriteH16 0x00081955
+#define XStream_WriteH16 0x000A1955
+#define Stream_WriteH8 0x00081956
+#define XStream_WriteH8 0x000A1956
+#define Stream_WriteD32 0x00081957
+#define XStream_WriteD32 0x000A1957
+#define Stream_WriteD24 0x00081958
+#define XStream_WriteD24 0x000A1958
+#define Stream_WriteD16 0x00081959
+#define XStream_WriteD16 0x000A1959
+#define Stream_WriteD8 0x0008195A
+#define XStream_WriteD8 0x000A195A
+#define Stream_WriteB32 0x0008195B
+#define XStream_WriteB32 0x000A195B
+#define Stream_WriteB24 0x0008195C
+#define XStream_WriteB24 0x000A195C
+#define Stream_WriteB16 0x0008195D
+#define XStream_WriteB16 0x000A195D
+#define Stream_WriteB8 0x0008195E
+#define XStream_WriteB8 0x000A195E
+#define Stream_WriteRegs 0x0008195F
+#define XStream_WriteRegs 0x000A195F
+
+/* --- WimpExtension SWIs --- */
+
+#define WimpExt_Initialise 0x00045780
+#define XWimpExt_Initialise 0x00065780
+#define WimpExt_CloseDown 0x00045781
+#define XWimpExt_CloseDown 0x00065781
+#define WimpExt_SlabIcon 0x00045782
+#define XWimpExt_SlabIcon 0x00065782
+#define WimpExt_Redraw 0x00045783
+#define XWimpExt_Redraw 0x00065783
+#define WimpExt_Action 0x00045784
+#define XWimpExt_Action 0x00065784
+#define WimpExt_IconBarSprite 0x00045785
+#define XWimpExt_IconBarSprite 0x00065785
+#define WimpExt_IconBarText 0x00045786
+#define XWimpExt_IconBarText 0x00065786
+#define WimpExt_LinkWindows 0x00045787
+#define XWimpExt_LinkWindows 0x00065787
+#define WimpExt_OpenLinked 0x00045788
+#define XWimpExt_OpenLinked 0x00065788
+#define WimpExt_CloseLinked 0x00045789
+#define XWimpExt_CloseLinked 0x00065789
+#define WimpExt_UnLinkWindows 0x0004578A
+#define XWimpExt_UnLinkWindows 0x0006578A
+#define WimpExt_CurrentTask 0x0004578B
+#define XWimpExt_CurrentTask 0x0006578B
+#define WimpExt_LoadTemplates 0x0004578C
+#define XWimpExt_LoadTemplates 0x0006578C
+#define WimpExt_SetIconString 0x0004578D
+#define XWimpExt_SetIconString 0x0006578D
+#define WimpExt_OpenWindowTop 0x0004578E
+#define XWimpExt_OpenWindowTop 0x0006578E
+#define WimpExt_SetIcon 0x0004578F
+#define XWimpExt_SetIcon 0x0006578F
+#define WimpExt_GetIcon 0x00045790
+#define XWimpExt_GetIcon 0x00065790
+#define WimpExt_GetNumberIcon 0x00045791
+#define XWimpExt_GetNumberIcon 0x00065791
+#define WimpExt_SetNumberIcon 0x00045792
+#define XWimpExt_SetNumberIcon 0x00065792
+#define WimpExt_IncNumberIcon 0x00045793
+#define XWimpExt_IncNumberIcon 0x00065793
+#define WimpExt_DecNumberIcon 0x00045794
+#define XWimpExt_DecNumberIcon 0x00065794
+#define WimpExt_SetPointer 0x00045795
+#define XWimpExt_SetPointer 0x00065795
+#define WimpExt_Divide 0x00045796
+#define XWimpExt_Divide 0x00065796
+#define WimpExt_ColoursMenu 0x00045797
+#define XWimpExt_ColoursMenu 0x00065797
+#define WimpExt_AutoRedraw 0x00045798
+#define XWimpExt_AutoRedraw 0x00065798
+#define WimpExt_CentreWindow 0x00045799
+#define XWimpExt_CentreWindow 0x00065799
+#define WimpExt_DragIcon 0x0004579A
+#define XWimpExt_DragIcon 0x0006579A
+#define WimpExt_PutCaretIcon 0x0004579B
+#define XWimpExt_PutCaretIcon 0x0006579B
+#define WimpExt_OpenDialogue 0x0004579C
+#define XWimpExt_OpenDialogue 0x0006579C
+#define WimpExt_CheckWindowOpen 0x0004579D
+#define XWimpExt_CheckWindowOpen 0x0006579D
+#define WimpExt_CopyString 0x0004579E
+#define XWimpExt_CopyString 0x0006579E
+#define WimpExt_SetWindowTitle 0x0004579F
+#define XWimpExt_SetWindowTitle 0x0006579F
+#define WimpExt_SetIconStringN 0x000457A0
+#define XWimpExt_SetIconStringN 0x000657A0
+#define WimpExt_FindLeaf 0x000457A1
+#define XWimpExt_FindLeaf 0x000657A1
+#define WimpExt_LimitPointer 0x000457A2
+#define XWimpExt_LimitPointer 0x000657A2
+#define WimpExt_ReleasePointer 0x000457A3
+#define XWimpExt_ReleasePointer 0x000657A3
+#define WimpExt_OpenFullSize 0x000457A4
+#define XWimpExt_OpenFullSize 0x000657A4
+#define WimpExt_LoadRAMTemplate 0x000457A5
+#define XWimpExt_LoadRAMTemplate 0x000657A5
+#define WimpExt_OpenRequester 0x000457A6
+#define XWimpExt_OpenRequester 0x000657A6
+#define WimpExt_CloseRequester 0x000457A7
+#define XWimpExt_CloseRequester 0x000657A7
+#define WimpExt_HideLink 0x000457A8
+#define XWimpExt_HideLink 0x000657A8
+#define WimpExt_UnHideLink 0x000457A9
+#define XWimpExt_UnHideLink 0x000657A9
+#define WimpExt_SendHelp 0x000457AA
+#define XWimpExt_SendHelp 0x000657AA
+#define WimpExt_SendWimpHelp 0x000457AB
+#define XWimpExt_SendWimpHelp 0x000657AB
+#define WimpExt_CreateMenu 0x000457AC
+#define XWimpExt_CreateMenu 0x000657AC
+#define WimpExt_ReCreateMenu 0x000457AD
+#define XWimpExt_ReCreateMenu 0x000657AD
+#define WimpExt_ShadeEntry 0x000457AE
+#define XWimpExt_ShadeEntry 0x000657AE
+#define WimpExt_TickEntry 0x000457AF
+#define XWimpExt_TickEntry 0x000657AF
+#define WimpExt_SetIconColour 0x000457B0
+#define XWimpExt_SetIconColour 0x000657B0
+#define WimpExt_ShadeIcon 0x000457B1
+#define XWimpExt_ShadeIcon 0x000657B1
+#define WimpExt_PlotSprite 0x000457B2
+#define XWimpExt_PlotSprite 0x000657B2
+#define WimpExt_RedrawDraw 0x000457B3
+#define XWimpExt_RedrawDraw 0x000657B3
+#define WimpExt_PrePoll 0x000457B4
+#define XWimpExt_PrePoll 0x000657B4
+#define WimpExt_SetExtent 0x000457B5
+#define XWimpExt_SetExtent 0x000657B5
+#define WimpExt_MoveCaret 0x000457B6
+#define XWimpExt_MoveCaret 0x000657B6
+#define WimpExt_GetFontMenu 0x000457B7
+#define XWimpExt_GetFontMenu 0x000657B7
+#define WimpExt_DecodeFontMenu 0x000457B8
+#define XWimpExt_DecodeFontMenu 0x000657B8
+#define WimpExt_ControlImmediate 0x000457B9
+#define XWimpExt_ControlImmediate 0x000657B9
+#define WimpExt_Heap 0x000457BA
+#define XWimpExt_Heap 0x000657BA
+#define WimpExt_MemCopy 0x000457BB
+#define XWimpExt_MemCopy 0x000657BB
+#define WimpExt_DataSave 0x000457BC
+#define XWimpExt_DataSave 0x000657BC
+#define WimpExt_PlotBorder 0x000457BD
+#define XWimpExt_PlotBorder 0x000657BD
+#define WimpExt_CentreWindowV 0x000457BE
+#define XWimpExt_CentreWindowV 0x000657BE
+
+/* --- WimpExtShadow SWIs --- */
+
+#define WimpExt_Sort 0x00046380
+#define XWimpExt_Sort 0x00066380
+#define WimpExt_MemMove 0x00046381
+#define XWimpExt_MemMove 0x00066381
+#define WimpExt_MenuWidth 0x00046382
+#define XWimpExt_MenuWidth 0x00066382
+#define WimpExt_DataLoad 0x00046383
+#define XWimpExt_DataLoad 0x00066383
+#define WimpExt_MoveCaretIcon 0x00046384
+#define XWimpExt_MoveCaretIcon 0x00066384
+#define WimpExt_DrawOp 0x00046385
+#define XWimpExt_DrawOp 0x00066385
+#define WimpExt_SpriteOp 0x00046386
+#define XWimpExt_SpriteOp 0x00066386
+#define WimpExt_Intersect 0x00046387
+#define XWimpExt_Intersect 0x00066387
+#define WimpExt_BorderOp 0x00046388
+#define XWimpExt_BorderOp 0x00066388
+#define WimpExt_ManualLink 0x00046389
+#define XWimpExt_ManualLink 0x00066389
+#define WimpExt_MiscOp 0x0004638A
+#define XWimpExt_MiscOp 0x0006638A
+#define WimpExt_ViewIcon 0x0004638B
+#define XWimpExt_ViewIcon 0x0006638B
+#define WimpExt_SubstituteArgs 0x0004638C
+#define XWimpExt_SubstituteArgs 0x0006638C
+#define WimpExt_RedirectSprites 0x0004638D
+#define XWimpExt_RedirectSprites 0x0006638D
+#define WimpExt_LibraryOp 0x0004638E
+#define XWimpExt_LibraryOp 0x0006638E
+#define WimpExt_CallLibrary 0x0004638F
+#define XWimpExt_CallLibrary 0x0006638F
+#define WimpExt_BackgroundTask 0x00046390
+#define XWimpExt_BackgroundTask 0x00066390
+#define WimpExt_ServiceCall 0x00046391
+#define XWimpExt_ServiceCall 0x00066391
+#define WimpExt_CDA 0x00046392
+#define XWimpExt_CDA 0x00066392
+#define WimpExt_Slider 0x00046393
+#define XWimpExt_Slider 0x00066393
+#define WimpExt_DeleteLinked 0x00046394
+#define XWimpExt_DeleteLinked 0x00066394
+#define WimpExt_OpenWindowTopC 0x00046395
+#define XWimpExt_OpenWindowTopC 0x00066395
+
+/* --- PDriver SWIs --- */
+
+#define PDriver_Info 0x00080140
+#define XPDriver_Info 0x000A0140
+#define PDriver_SetInfo 0x00080141
+#define XPDriver_SetInfo 0x000A0141
+#define PDriver_CheckFeatures 0x00080142
+#define XPDriver_CheckFeatures 0x000A0142
+#define PDriver_PageSize 0x00080143
+#define XPDriver_PageSize 0x000A0143
+#define PDriver_SetPageSize 0x00080144
+#define XPDriver_SetPageSize 0x000A0144
+#define PDriver_SelectJob 0x00080145
+#define XPDriver_SelectJob 0x000A0145
+#define PDriver_CurrentJob 0x00080146
+#define XPDriver_CurrentJob 0x000A0146
+#define PDriver_FontSWI 0x00080147
+#define XPDriver_FontSWI 0x000A0147
+#define PDriver_EndJob 0x00080148
+#define XPDriver_EndJob 0x000A0148
+#define PDriver_AbortJob 0x00080149
+#define XPDriver_AbortJob 0x000A0149
+#define PDriver_Reset 0x0008014A
+#define XPDriver_Reset 0x000A014A
+#define PDriver_GiveRectangle 0x0008014B
+#define XPDriver_GiveRectangle 0x000A014B
+#define PDriver_DrawPage 0x0008014C
+#define XPDriver_DrawPage 0x000A014C
+#define PDriver_GetRectangle 0x0008014D
+#define XPDriver_GetRectangle 0x000A014D
+#define PDriver_CancelJob 0x0008014E
+#define XPDriver_CancelJob 0x000A014E
+#define PDriver_ScreenDump 0x0008014F
+#define XPDriver_ScreenDump 0x000A014F
+#define PDriver_EnumerateJobs 0x00080150
+#define XPDriver_EnumerateJobs 0x000A0150
+#define PDriver_SetPrinter 0x00080151
+#define XPDriver_SetPrinter 0x000A0151
+#define PDriver_CancelJobWithError 0x00080152
+#define XPDriver_CancelJobWithError 0x000A0152
+#define PDriver_SelectIllustration 0x00080153
+#define XPDriver_SelectIllustration 0x000A0153
+#define PDriver_InsertIllustration 0x00080154
+#define XPDriver_InsertIllustration 0x000A0154
+#define PDriver_DeclareFont 0x00080155
+#define XPDriver_DeclareFont 0x000A0155
+#define PDriver_DeclareDriver 0x00080156
+#define XPDriver_DeclareDriver 0x000A0156
+#define PDriver_RemoveDriver 0x00080157
+#define XPDriver_RemoveDriver 0x000A0157
+#define PDriver_SelectDriver 0x00080158
+#define XPDriver_SelectDriver 0x000A0158
+#define PDriver_EnumerateDrivers 0x00080159
+#define XPDriver_EnumerateDrivers 0x000A0159
+#define PDriver_MiscOp 0x0008015A
+#define XPDriver_MiscOp 0x000A015A
+#define PDriver_MiscOpForDriver 0x0008015B
+#define XPDriver_MiscOpForDriver 0x000A015B
+#define PDriver_SetDriver 0x0008015C
+#define XPDriver_SetDriver 0x000A015C
+
+/* --- PDumperSupport SWIs --- */
+
+#define PDumper_Info 0x00041B00
+#define XPDumper_Info 0x00061B00
+#define PDumper_Claim 0x00041B01
+#define XPDumper_Claim 0x00061B01
+#define PDumper_Free 0x00041B02
+#define XPDumper_Free 0x00061B02
+#define PDumper_Find 0x00041B03
+#define XPDumper_Find 0x00061B03
+#define PDumper_StartJob 0x00041B04
+#define XPDumper_StartJob 0x00061B04
+#define PDumper_TidyJob 0x00041B05
+#define XPDumper_TidyJob 0x00061B05
+#define PDumper_SetColour 0x00041B06
+#define XPDumper_SetColour 0x00061B06
+#define PDumper_PrepareStrip 0x00041B07
+#define XPDumper_PrepareStrip 0x00061B07
+#define PDumper_LookupError 0x00041B08
+#define XPDumper_LookupError 0x00061B08
+#define PDumper_CopyFilename 0x00041B09
+#define XPDumper_CopyFilename 0x00061B09
+
+/* --- RemotePrinterSupport SWIs --- */
+
+#define RemotePrinterSupport_ReadPollwordLocation 0x00047980
+#define XRemotePrinterSupport_ReadPollwordLocation 0x00067980
+#define RemotePrinterSupport_GetNextEvent 0x00047981
+#define XRemotePrinterSupport_GetNextEvent 0x00067981
+#define RemotePrinterSupport_ReadUniqueAddress 0x00047982
+#define XRemotePrinterSupport_ReadUniqueAddress 0x00067982
+#define RemotePrinterSupport_Enable 0x00047983
+#define XRemotePrinterSupport_Enable 0x00067983
+#define RemotePrinterSupport_Disable 0x00047984
+#define XRemotePrinterSupport_Disable 0x00067984
+#define RemotePrinterSupport_EnableUpcalls 0x00047985
+#define XRemotePrinterSupport_EnableUpcalls 0x00067985
+#define RemotePrinterSupport_DisableUpcalls 0x00047986
+#define XRemotePrinterSupport_DisableUpcalls 0x00067986
+
+/* --- Dynamite SWIs --- */
+
+#define Dynamite_Alloc 0x0004A3C0
+#define XDynamite_Alloc 0x0006A3C0
+#define Dynamite_Free 0x0004A3C1
+#define XDynamite_Free 0x0006A3C1
+#define Dynamite_FreeWithID 0x0004A3C2
+#define XDynamite_FreeWithID 0x0006A3C2
+#define Dynamite_BlockInfo 0x0004A3C3
+#define XDynamite_BlockInfo 0x0006A3C3
+#define Dynamite_ChangeID 0x0004A3C4
+#define XDynamite_ChangeID 0x0006A3C4
+#define Dynamite_Resize 0x0004A3C5
+#define XDynamite_Resize 0x0006A3C5
+#define Dynamite_MidExtend 0x0004A3C6
+#define XDynamite_MidExtend 0x0006A3C6
+#define Dynamite_Save 0x0004A3C7
+#define XDynamite_Save 0x0006A3C7
+#define Dynamite_Load 0x0004A3C8
+#define XDynamite_Load 0x0006A3C8
+#define Dynamite_Reduce 0x0004A3C9
+#define XDynamite_Reduce 0x0006A3C9
+#define Dynamite_Compact 0x0004A3CA
+#define XDynamite_Compact 0x0006A3CA
+#define Dynamite_Lock 0x0004A3CB
+#define XDynamite_Lock 0x0006A3CB
+#define Dynamite_Unlock 0x0004A3CC
+#define XDynamite_Unlock 0x0006A3CC
+#define Dynamite_ClaimAnchor 0x0004A3CD
+#define XDynamite_ClaimAnchor 0x0006A3CD
+#define Dynamite_ReleaseAnchor 0x0004A3CE
+#define XDynamite_ReleaseAnchor 0x0006A3CE
+#define Dynamite_ReadSpriteSize 0x0004A3CF
+#define XDynamite_ReadSpriteSize 0x0006A3CF
+#define Dynamite_Describe 0x0004A3D0
+#define XDynamite_Describe 0x0006A3D0
+#define Dynamite_IntegrityCheck 0x0004A3D1
+#define XDynamite_IntegrityCheck 0x0006A3D1
+#define Dynamite_ChangeAnchor 0x0004A3D2
+#define XDynamite_ChangeAnchor 0x0006A3D2
+
+/* --- GS_Support SWIs --- */
+
+#define GS_Support_PaintText 0x00042F40
+#define XGS_Support_PaintText 0x00062F40
+#define GS_Support_StringIdx 0x00042F41
+#define XGS_Support_StringIdx 0x00062F41
+#define GS_Support_SetCaret 0x00042F42
+#define XGS_Support_SetCaret 0x00062F42
+#define GS_Support_FindLines 0x00042F43
+#define XGS_Support_FindLines 0x00062F43
+#define GS_Support_wac 0x00042F44
+#define XGS_Support_wac 0x00062F44
+#define GS_Support_formtext 0x00042F45
+#define XGS_Support_formtext 0x00062F45
+#define GS_Support_PlaySample 0x00042F46
+#define XGS_Support_PlaySample 0x00062F46
+#define GS_Support_OverLap 0x00042F47
+#define XGS_Support_OverLap 0x00062F47
+#define GS_Support_OverLap2 0x00042F48
+#define XGS_Support_OverLap2 0x00062F48
+#define GS_Support_NamedObject 0x00042F49
+#define XGS_Support_NamedObject 0x00062F49
+#define GS_Support_NumberedObject 0x00042F4A
+#define XGS_Support_NumberedObject 0x00062F4A
+#define GS_Support_MenuObject 0x00042F4B
+#define XGS_Support_MenuObject 0x00062F4B
+#define GS_Support_FindResource 0x00042F4C
+#define XGS_Support_FindResource 0x00062F4C
+#define GS_Support_IsLinkDrag 0x00042F4D
+#define XGS_Support_IsLinkDrag 0x00062F4D
+#define GS_Support_LinkDrag 0x00042F4E
+#define XGS_Support_LinkDrag 0x00062F4E
+#define GS_Support_GetSample 0x00042F4F
+#define XGS_Support_GetSample 0x00062F4F
+#define GS_Support_FFTData 0x00042F50
+#define XGS_Support_FFTData 0x00062F50
+#define GS_Support_FFTSample 0x00042F51
+#define XGS_Support_FFTSample 0x00062F51
+#define GS_Support_SampleCtrl 0x00042F52
+#define XGS_Support_SampleCtrl 0x00062F52
+
+/* --- InterfaceManager SWIs --- */
+
+#define Interface_SlabButton 0x00081680
+#define XInterface_SlabButton 0x000A1680
+#define Interface_Render3dWindow 0x00081681
+#define XInterface_Render3dWindow 0x000A1681
+#define Interface_Initialise 0x00081682
+#define XInterface_Initialise 0x000A1682
+#define Interface_CloseDown 0x00081683
+#define XInterface_CloseDown 0x000A1683
+#define Interface_SetWorkareaPointer 0x00081684
+#define XInterface_SetWorkareaPointer 0x000A1684
+#define Interface_RemoveWorkareaPointer 0x00081685
+#define XInterface_RemoveWorkareaPointer 0x000A1685
+#define Interface_Poll 0x00081686
+#define XInterface_Poll 0x000A1686
+#define Interface_SendHelp 0x00081687
+#define XInterface_SendHelp 0x000A1687
+#define Interface_PreProcessKey 0x00081688
+#define XInterface_PreProcessKey 0x000A1688
+#define Interface_Plot3dIcon 0x00081689
+#define XInterface_Plot3dIcon 0x000A1689
+#define Interface_BoundingBox 0x0008168A
+#define XInterface_BoundingBox 0x000A168A
+
+/* --- Sculptrix SWIs --- */
+
+#define Sculptrix_RedrawWindow 0x0004A2C0
+#define XSculptrix_RedrawWindow 0x0006A2C0
+#define Sculptrix_DoSlab 0x0004A2C1
+#define XSculptrix_DoSlab 0x0006A2C1
+#define Sculptrix_SlabIcon 0x0004A2C2
+#define XSculptrix_SlabIcon 0x0006A2C2
+#define Sculptrix_UnslabIcon 0x0004A2C3
+#define XSculptrix_UnslabIcon 0x0006A2C3
+#define Sculptrix_BoundingBox 0x0004A2C4
+#define XSculptrix_BoundingBox 0x0006A2C4
+#define Sculptrix_PlotIcon 0x0004A2C5
+#define XSculptrix_PlotIcon 0x0006A2C5
+#define Sculptrix_PlotGroupBox 0x0004A2C6
+#define XSculptrix_PlotGroupBox 0x0006A2C6
+#define Sculptrix_SetSpriteArea 0x0004A2C7
+#define XSculptrix_SetSpriteArea 0x0006A2C7
+#define Sculptrix_UpdateIcon 0x0004A2C8
+#define XSculptrix_UpdateIcon 0x0006A2C8
+#define Sculptrix_SlabColour 0x0004A2C9
+#define XSculptrix_SlabColour 0x0006A2C9
+#define Sculptrix_SetConfig 0x0004A2CA
+#define XSculptrix_SetConfig 0x0006A2CA
+#define Sculptrix_ReadConfig 0x0004A2CB
+#define XSculptrix_ReadConfig 0x0006A2CB
+
+/* --- TermiteIP SWIs --- */
+
+#define TermiteIP_Initialise 0x0004AE40
+#define XTermiteIP_Initialise 0x0006AE40
+#define TermiteIP_Finalise 0x0004AE41
+#define XTermiteIP_Finalise 0x0006AE41
+#define TermiteIP_Register 0x0004AE42
+#define XTermiteIP_Register 0x0006AE42
+#define TermiteIP_DeRegister 0x0004AE43
+#define XTermiteIP_DeRegister 0x0006AE43
+#define TermiteIP_Bindings 0x0004AE44
+#define XTermiteIP_Bindings 0x0006AE44
+#define TermiteIP_SendIPPacket 0x0004AE45
+#define XTermiteIP_SendIPPacket 0x0006AE45
+#define TermiteIP_AllocatePort 0x0004AE46
+#define XTermiteIP_AllocatePort 0x0006AE46
+#define TermiteIP_CreateSocket 0x0004AE47
+#define XTermiteIP_CreateSocket 0x0006AE47
+#define TermiteIP_ClosePort 0x0004AE48
+#define XTermiteIP_ClosePort 0x0006AE48
+#define TermiteIP_SendTCPData 0x0004AE49
+#define XTermiteIP_SendTCPData 0x0006AE49
+#define TermiteIP_SendUDPData 0x0004AE4A
+#define XTermiteIP_SendUDPData 0x0006AE4A
+#define TermiteIP_IPProtocolNumberToName 0x0004AE4B
+#define XTermiteIP_IPProtocolNumberToName 0x0006AE4B
+#define TermiteIP_ReadIPProtocolEnable 0x0004AE4C
+#define XTermiteIP_ReadIPProtocolEnable 0x0006AE4C
+#define TermiteIP_ReadLinkStatus 0x0004AE4D
+#define XTermiteIP_ReadLinkStatus 0x0006AE4D
+#define TermiteIP_ChecksumData 0x0004AE4E
+#define XTermiteIP_ChecksumData 0x0006AE4E
+#define TermiteIP_ReadPacket 0x0004AE4F
+#define XTermiteIP_ReadPacket 0x0006AE4F
+#define TermiteIP_ReadInformation 0x0004AE50
+#define XTermiteIP_ReadInformation 0x0006AE50
+#define TermiteIP_ReadTCPData 0x0004AE51
+#define XTermiteIP_ReadTCPData 0x0006AE51
+#define TermiteIP_SendICMPMessage 0x0004AE52
+#define XTermiteIP_SendICMPMessage 0x0006AE52
+#define TermiteIP_ChecksumDataAndHeader 0x0004AE53
+#define XTermiteIP_ChecksumDataAndHeader 0x0006AE53
+#define TermiteIP_IPAddressToNumber 0x0004AE54
+#define XTermiteIP_IPAddressToNumber 0x0006AE54
+#define TermiteIP_NumberToIPAddress 0x0004AE55
+#define XTermiteIP_NumberToIPAddress 0x0006AE55
+#define TermiteIP_ReadNextEvent 0x0004AE56
+#define XTermiteIP_ReadNextEvent 0x0006AE56
+#define TermiteIP_NetToArcTime 0x0004AE57
+#define XTermiteIP_NetToArcTime 0x0006AE57
+#define TermiteIP_PortInformation 0x0004AE58
+#define XTermiteIP_PortInformation 0x0006AE58
+#define TermiteIP_DeleteSocket 0x0004AE59
+#define XTermiteIP_DeleteSocket 0x0006AE59
+#define TermiteIP_TCPStateToText 0x0004AE5A
+#define XTermiteIP_TCPStateToText 0x0006AE5A
+#define TermiteIP_DecodeICMPErrorMessage 0x0004AE5B
+#define XTermiteIP_DecodeICMPErrorMessage 0x0006AE5B
+#define TermiteIP_StartTCPConnection 0x0004AE5C
+#define XTermiteIP_StartTCPConnection 0x0006AE5C
+#define TermiteIP_ReadTCPStatus 0x0004AE5D
+#define XTermiteIP_ReadTCPStatus 0x0006AE5D
+#define TermiteIP_ConfigureTCP 0x0004AE5E
+#define XTermiteIP_ConfigureTCP 0x0006AE5E
+#define TermiteIP_ConvertPortNumber 0x0004AE5F
+#define XTermiteIP_ConvertPortNumber 0x0006AE5F
+#define TermiteIP_ResolveAddToCache 0x0004AE60
+#define XTermiteIP_ResolveAddToCache 0x0006AE60
+#define TermiteIP_ResolveReadCacheEntry 0x0004AE61
+#define XTermiteIP_ResolveReadCacheEntry 0x0006AE61
+#define TermiteIP_ResolveFindEntryInCache 0x0004AE62
+#define XTermiteIP_ResolveFindEntryInCache 0x0006AE62
+#define TermiteIP_RemoveTCPData 0x0004AE63
+#define XTermiteIP_RemoveTCPData 0x0006AE63
+#define TermiteIP_ExamineTCPData 0x0004AE64
+#define XTermiteIP_ExamineTCPData 0x0006AE64
+#define TermiteIP_SetTCPSocketWindow 0x0004AE65
+#define XTermiteIP_SetTCPSocketWindow 0x0006AE65
+#define TermiteIP_KickTCPSocket 0x0004AE66
+#define XTermiteIP_KickTCPSocket 0x0006AE66
+#define TermiteIP_CheckSocket 0x0004AE67
+#define XTermiteIP_CheckSocket 0x0006AE67
+#define TermiteIP_TelnetOp 0x0004AE68
+#define XTermiteIP_TelnetOp 0x0006AE68
+#define TermiteIP_ResolveOp 0x0004AE69
+#define XTermiteIP_ResolveOp 0x0006AE69
+#define TermiteIP_CloseTCPConnection 0x0004AE6A
+#define XTermiteIP_CloseTCPConnection 0x0006AE6A
+#define TermiteIP_ReadTCPPointers 0x0004AE6B
+#define XTermiteIP_ReadTCPPointers 0x0006AE6B
+#define TermiteIP_SetTCPSocketToListen 0x0004AE6C
+#define XTermiteIP_SetTCPSocketToListen 0x0006AE6C
+#define TermiteIP_ResolveChangeCacheEntry 0x0004AE6D
+#define XTermiteIP_ResolveChangeCacheEntry 0x0006AE6D
+#define TermiteIP_ResolveDeleteCacheEntry 0x0004AE6E
+#define XTermiteIP_ResolveDeleteCacheEntry 0x0006AE6E
+#define TermiteIP_EnumerateOp 0x0004AE6F
+#define XTermiteIP_EnumerateOp 0x0006AE6F
+#define TermiteIP_ClientInformation 0x0004AE70
+#define XTermiteIP_ClientInformation 0x0006AE70
+#define TermiteIP_SocketInformation 0x0004AE71
+#define XTermiteIP_SocketInformation 0x0006AE71
+#define TermiteIP_ResolveFindIPAddressForName 0x0004AE72
+#define XTermiteIP_ResolveFindIPAddressForName 0x0006AE72
+#define TermiteIP_ReadDomainName 0x0004AE73
+#define XTermiteIP_ReadDomainName 0x0006AE73
+#define TermiteIP_ClosePortSockets 0x0004AE74
+#define XTermiteIP_ClosePortSockets 0x0006AE74
+#define TermiteIP_DropTCPConnection 0x0004AE75
+#define XTermiteIP_DropTCPConnection 0x0006AE75
+#define TermiteIP_ProtocolOp 0x0004AE76
+#define XTermiteIP_ProtocolOp 0x0006AE76
+#define TermiteIP_ChangePortFlags 0x0004AE77
+#define XTermiteIP_ChangePortFlags 0x0006AE77
+#define TermiteIP_MiscOp 0x0004AE78
+#define XTermiteIP_MiscOp 0x0006AE78
+#define TermiteIP_SendEvent 0x0004AE79
+#define XTermiteIP_SendEvent 0x0006AE79
+#define TermiteIP_TCPBufferInfo 0x0004AE7A
+#define XTermiteIP_TCPBufferInfo 0x0006AE7A
+#define TermiteIP_SocketOp 0x0004AE7B
+#define XTermiteIP_SocketOp 0x0006AE7B
+#define TermiteIP_InterfaceOp 0x0004AE7C
+#define XTermiteIP_InterfaceOp 0x0006AE7C
+#define TermiteIP_RoutingOp 0x0004AE7D
+#define XTermiteIP_RoutingOp 0x0006AE7D
+#define TermiteIP_CDA 0x0004AE7E
+#define XTermiteIP_CDA 0x0006AE7E
+
+/* --- FreeNet SWIs --- */
+
+#define Socket_Creat 0x00041200
+#define XSocket_Creat 0x00061200
+#define Socket_Bind 0x00041201
+#define XSocket_Bind 0x00061201
+#define Socket_Listen 0x00041202
+#define XSocket_Listen 0x00061202
+#define Socket_Accept 0x00041203
+#define XSocket_Accept 0x00061203
+#define Socket_Connect 0x00041204
+#define XSocket_Connect 0x00061204
+#define Socket_Recv 0x00041205
+#define XSocket_Recv 0x00061205
+#define Socket_Recvfrom 0x00041206
+#define XSocket_Recvfrom 0x00061206
+#define Socket_Recvmsg 0x00041207
+#define XSocket_Recvmsg 0x00061207
+#define Socket_Send 0x00041208
+#define XSocket_Send 0x00061208
+#define Socket_Sendto 0x00041209
+#define XSocket_Sendto 0x00061209
+#define Socket_Sendmsg 0x0004120A
+#define XSocket_Sendmsg 0x0006120A
+#define Socket_Shutdown 0x0004120B
+#define XSocket_Shutdown 0x0006120B
+#define Socket_Setsockopt 0x0004120C
+#define XSocket_Setsockopt 0x0006120C
+#define Socket_Getsockopt 0x0004120D
+#define XSocket_Getsockopt 0x0006120D
+#define Socket_Getpeername 0x0004120E
+#define XSocket_Getpeername 0x0006120E
+#define Socket_Getsockname 0x0004120F
+#define XSocket_Getsockname 0x0006120F
+#define Socket_Close 0x00041210
+#define XSocket_Close 0x00061210
+#define Socket_Select 0x00041211
+#define XSocket_Select 0x00061211
+#define Socket_Ioctl 0x00041212
+#define XSocket_Ioctl 0x00061212
+#define Socket_Read 0x00041213
+#define XSocket_Read 0x00061213
+#define Socket_Write 0x00041214
+#define XSocket_Write 0x00061214
+#define Socket_Stat 0x00041215
+#define XSocket_Stat 0x00061215
+#define Socket_Readv 0x00041216
+#define XSocket_Readv 0x00061216
+#define Socket_Writev 0x00041217
+#define XSocket_Writev 0x00061217
+#define Socket_Gettsize 0x00041218
+#define XSocket_Gettsize 0x00061218
+#define Socket_Sendtosm 0x00041219
+#define XSocket_Sendtosm 0x00061219
+
+/* --- INetDB SWIs --- */
+
+#define Internet_GetHostByName 0x00046000
+#define XInternet_GetHostByName 0x00066000
+#define Internet_GetHostByAddr 0x00046001
+#define XInternet_GetHostByAddr 0x00066001
+
+/* --- ColourTrans SWIs --- */
+
+#define ColourTrans_SelectTable 0x00040740
+#define XColourTrans_SelectTable 0x00060740
+#define ColourTrans_SelectGCOLTable 0x00040741
+#define XColourTrans_SelectGCOLTable 0x00060741
+#define ColourTrans_ReturnGCOL 0x00040742
+#define XColourTrans_ReturnGCOL 0x00060742
+#define ColourTrans_SetGCOL 0x00040743
+#define XColourTrans_SetGCOL 0x00060743
+#define ColourTrans_ReturnColourNumber 0x00040744
+#define XColourTrans_ReturnColourNumber 0x00060744
+#define ColourTrans_ReturnGCOLForMode 0x00040745
+#define XColourTrans_ReturnGCOLForMode 0x00060745
+#define ColourTrans_ReturnColourNumberForMode 0x00040746
+#define XColourTrans_ReturnColourNumberForMode 0x00060746
+#define ColourTrans_ReturnOppGCOL 0x00040747
+#define XColourTrans_ReturnOppGCOL 0x00060747
+#define ColourTrans_SetOppGCOL 0x00040748
+#define XColourTrans_SetOppGCOL 0x00060748
+#define ColourTrans_ReturnOppColourNumber 0x00040749
+#define XColourTrans_ReturnOppColourNumber 0x00060749
+#define ColourTrans_ReturnOppGCOLForMode 0x0004074A
+#define XColourTrans_ReturnOppGCOLForMode 0x0006074A
+#define ColourTrans_ReturnOppColourNumberForMode 0x0004074B
+#define XColourTrans_ReturnOppColourNumberForMode 0x0006074B
+#define ColourTrans_GCOLToColourNumber 0x0004074C
+#define XColourTrans_GCOLToColourNumber 0x0006074C
+#define ColourTrans_ColourNumberToGCOL 0x0004074D
+#define XColourTrans_ColourNumberToGCOL 0x0006074D
+#define ColourTrans_ReturnFontColours 0x0004074E
+#define XColourTrans_ReturnFontColours 0x0006074E
+#define ColourTrans_SetFontColours 0x0004074F
+#define XColourTrans_SetFontColours 0x0006074F
+#define ColourTrans_InvalidateCache 0x00040750
+#define XColourTrans_InvalidateCache 0x00060750
+#define ColourTrans_SetCalibration 0x00040751
+#define XColourTrans_SetCalibration 0x00060751
+#define ColourTrans_ReadCalibration 0x00040752
+#define XColourTrans_ReadCalibration 0x00060752
+#define ColourTrans_ConvertDeviceColour 0x00040753
+#define XColourTrans_ConvertDeviceColour 0x00060753
+#define ColourTrans_ConvertDevicePalette 0x00040754
+#define XColourTrans_ConvertDevicePalette 0x00060754
+#define ColourTrans_ConvertRGBToCIE 0x00040755
+#define XColourTrans_ConvertRGBToCIE 0x00060755
+#define ColourTrans_ConvertCIEToRGB 0x00040756
+#define XColourTrans_ConvertCIEToRGB 0x00060756
+#define ColourTrans_WriteCalibrationToFile 0x00040757
+#define XColourTrans_WriteCalibrationToFile 0x00060757
+#define ColourTrans_ConvertRGBToHSV 0x00040758
+#define XColourTrans_ConvertRGBToHSV 0x00060758
+#define ColourTrans_ConvertHSVToRGB 0x00040759
+#define XColourTrans_ConvertHSVToRGB 0x00060759
+#define ColourTrans_ConvertRGBToCMYK 0x0004075A
+#define XColourTrans_ConvertRGBToCMYK 0x0006075A
+#define ColourTrans_ConvertCMYKToRGB 0x0004075B
+#define XColourTrans_ConvertCMYKToRGB 0x0006075B
+#define ColourTrans_ReadPalette 0x0004075C
+#define XColourTrans_ReadPalette 0x0006075C
+#define ColourTrans_WritePalette 0x0004075D
+#define XColourTrans_WritePalette 0x0006075D
+#define ColourTrans_SetColour 0x0004075E
+#define XColourTrans_SetColour 0x0006075E
+#define ColourTrans_MiscOp 0x0004075F
+#define XColourTrans_MiscOp 0x0006075F
+#define ColourTrans_WriteLoadingsToFile 0x00040760
+#define XColourTrans_WriteLoadingsToFile 0x00060760
+#define ColourTrans_SetTextColour 0x00040761
+#define XColourTrans_SetTextColour 0x00060761
+#define ColourTrans_SetOppTextColour 0x00040762
+#define XColourTrans_SetOppTextColour 0x00060762
+#define ColourTrans_GenerateTable 0x00040763
+#define XColourTrans_GenerateTable 0x00060763
+
+#endif
diff --git a/StraySrc/Libraries/Core/h/swiv b/StraySrc/Libraries/Core/h/swiv
new file mode 100644 (file)
index 0000000..c0c787d
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * swiv.h
+ *
+ * Interface to SWI veneer
+ *
+ * © 1997, 1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's core library (corelib).
+ *
+ * Corelib is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Corelib is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Corelib.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ___swis_h
+#define ___swis_h
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+#ifndef __kernel_h
+  #include "kernel.h"
+#endif
+
+/* --- SWI veneer functions --- *
+ *
+ * Arguments:  int swi == the SWI to call
+ *             unsigned flags == a definition of the SWIs registers
+ *
+ * Returns:    _swi returns the value of the `return' register in the flags
+ *             _swix returns 0, or a pointer to an error block
+ *
+ * Use:                Calls a SWI, passing it a collection of registers, and
+ *             filling in the registers as given in the function call.
+ *
+ *             Order of arguments is as follows:
+ *
+ *             Input registers:        One word for each input register
+ *             Output registers:       Address to store each reg value
+ *             Flags address:          Address to store PC+flags value
+ *             Block contents:         Build contents of local block at end
+ */
+
+extern int _swi(int /*swi*/, unsigned /*flags*/,...);
+extern _kernel_oserror *_swix(int /*swi*/, unsigned /*flags*/,...);
+
+/* --- Various flags settings --- *
+ *
+ * _in(n) -- declare Rn as an input register
+ * _inr(m, n) -- declare Rm--Rn as input registers
+ * _out(n) -- declare Rn as an output register
+ * _outr(m, n) -- declare Rm--Rn as output registers
+ * _return(n) -- return Rn from _swi
+ * _block(n) -- point Rn at block containing remaining arguments
+ */
+
+#ifndef _FLAGS
+
+  /* --- _flags -- return or output processor flags --- */
+
+  #define _flags       (0x10)
+
+  /* --- _in and _inr -- input a register, or a range of registers --- */
+
+  #define _in(r)       (1u << (r))
+  #define _inr(ra,rb)  (((~0) << (ra)) ^ ((~0) << ((rb)+1)))
+
+  /* --- _out and _outr -- output a register, or a range of registers --- */
+
+  #define _out(r)      (1u << (31-((r) == _flags ? 10 : (r))))
+  #define _outr(ra,rb) (((~0) << (31-(rb))) ^ ((~0) << (32-(ra))))
+
+  /* --- _block -- point a register at block built from arguments --- */
+
+  #define _block(r)    (((r) << 12) | 0x800)
+
+  /* --- _return -- return register from _swi (not _swix) --- */
+
+  #define _return(r)   ((r) == _flags ? 0xF0000 : (r) << 16)
+
+  /* --- Constants for ARM processor flags --- */
+
+  #define _n           (0x80000000u)
+  #define _z           (0x40000000u)
+  #define _c           (0x20000000u)
+  #define _v           (0x10000000u)
+
+  /* --- Acorn style capital-letter macros --- */
+
+  #define _FLAGS       _flags
+  #define _IN(x)       _in(x)
+  #define _INR(x,y)    _inr(x,y)
+  #define _OUT(x)      _out(x)
+  #define _OUTR(x,y)   _outr(x,y)
+  #define _BLOCK(x)    _block(x)
+  #define _RETURN(x)   _return(x)
+  #define _N           _n
+  #define _Z           _z
+  #define _C           _c
+  #define _V           _v
+
+#endif
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/StraySrc/Libraries/Core/header b/StraySrc/Libraries/Core/header
new file mode 100644 (file)
index 0000000..e901ec3
--- /dev/null
@@ -0,0 +1,195 @@
+;
+; header
+;
+; Standard header
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core library (corelib).
+;
+; Corelib is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Corelib is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Corelib.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               [       :LNOT::DEF:header__dfn
+               GBLL    header__dfn
+
+;----- Register names -------------------------------------------------------
+
+; --- The standard ones ---
+
+R0             RN      0
+R1             RN      1
+R2             RN      2
+R3             RN      3
+R4             RN      4
+R5             RN      5
+R6             RN      6
+R7             RN      7
+R8             RN      8
+R9             RN      9
+R10            RN      10
+R11            RN      11
+R12            RN      12
+R13            RN      13
+R14            RN      14
+R15            RN      15
+
+; --- Standard pseudonyms ---
+
+SP             RN      13
+LR             RN      14
+PC             RN      15
+
+; --- Lowercase version ---
+
+r0             RN      0
+r1             RN      1
+r2             RN      2
+r3             RN      3
+r4             RN      4
+r5             RN      5
+r6             RN      6
+r7             RN      7
+r8             RN      8
+r9             RN      9
+r10            RN      10
+r11            RN      11
+r12            RN      12
+r13            RN      13
+r14            RN      14
+r15            RN      15
+
+; --- APCS names ---
+
+a1             RN      0
+a2             RN      1
+a3             RN      2
+a4             RN      3
+v1             RN      4
+v2             RN      5
+v3             RN      6
+v4             RN      7
+v5             RN      8
+v6             RN      9
+sl             RN      10
+fp             RN      11
+ip             RN      12
+sp             RN      13
+lr             RN      14
+pc             RN      15
+
+; --- Floating point register names ---
+
+F0             FN      0
+F1             FN      1
+F2             FN      2
+F3             FN      3
+F4             FN      4
+F5             FN      5
+F6             FN      6
+F7             FN      7
+
+; --- Lowercase floating point names ---
+
+f0             FN      0
+f1             FN      1
+f2             FN      2
+f3             FN      3
+f4             FN      4
+f5             FN      5
+f6             FN      6
+f7             FN      7
+
+;----- ARM processor flags --------------------------------------------------
+
+; --- Processor flags ---
+
+FIQ_disable    EQU     1<<26
+IRQ_disable    EQU     1<<27
+
+V_flag         EQU     1<<28
+C_flag         EQU     1<<29
+Z_flag         EQU     1<<30
+N_flag         EQU     1<<31
+
+; --- Processor modes ---
+
+USR_mode       EQU     0
+FIQ_mode       EQU     1
+IRQ_mode       EQU     2
+SVC_mode       EQU     3
+
+;----- Various useful macros ------------------------------------------------
+
+; --- Macro: PAD ---
+;
+; Arguments:   len == length to pad to
+;              string == the string to write
+;              byte == byte to fill with (default == 0)
+;
+; Use:         Writes a string out, and pads it to a given length.  If the
+;              string is too long, it gets truncated.
+
+
+               MACRO
+$label         PAD     $len,$string,$byte
+               LCLA    b
+               LCLA    i
+
+               IF      "$len"=""
+b              SETA    0
+               ELSE
+b              SETA    $byte
+               ENDIF
+
+               ALIGN
+$label
+i              SETA    :LEN: "$string"
+
+               IF      i>$len
+               DCB     "$string" :LEFT: $len
+               ELSE
+               DCB     "$string"
+               WHILE   i<$len
+               DCB     b
+i              SETA    i+1
+               WEND
+               ENDIF
+
+               MEND
+
+; --- Macro: BARRIER ---
+;
+; Arguments:   --
+;
+; Use:         Inserts a cache barrier in the code (SWI &FF0000) for
+;              executing dynamically-generated code.
+
+               MACRO
+$label         BARRIER
+               ALIGN
+$label
+;              SWI     &F00000                 ;Covered by NDA currently
+               MEND
+
+;----- That's all, folks ----------------------------------------------------
+
+               ]
+
+               END
+
+
diff --git a/StraySrc/Libraries/Core/s/fastMove b/StraySrc/Libraries/Core/s/fastMove
new file mode 100644 (file)
index 0000000..09af999
--- /dev/null
@@ -0,0 +1,475 @@
+;
+; fastMove.s
+;
+; Fast memory manipulation (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core libraries (corelib).
+;
+; Corelib is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Corelib is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Corelib.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+;
+; None.
+
+;----- Main Code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- fastMove ---
+;
+; On entry:    R0 == destination pointer
+;              R1 == source pointer
+;              R2 == number of bytes to move
+;
+; On exit:     --
+;
+; Use:         A very fast block moving routine.  Word aligning is not
+;              necessary, and the blocks may overlap.  This is basically
+;              the routine from PRM 2, hacked to cope with overlapping.
+
+               EXPORT  fastMove
+fastMove       ROUT
+
+               ; --- Do we need to do it backwards? ---
+
+               CMP     R0,R1
+               MOVEQS  PC,R14
+               BGT     %49fastMove
+
+               ; --- Copy downwards ---
+
+               STMFD   R13!,{R0-R12,R14}       ;Stack some registers
+
+               TST     R0,#3                   ;Is destination word aligned
+               BNE     %10fastMove             ;No -- word align it
+
+00fastMove     TST     R1,#3                   ;Is source word aligned
+               BNE     %20fastMove             ;No -- word align that
+
+               ; --- Source and destination are now word aligned ---
+
+               SUBS    R2,R2,#16               ;4 or more words to do?
+               BLT     %03fastMove
+
+               SUBS    R2,R2,#16               ;8 or more words to do?
+               BLT     %02fastMove
+
+               ; --- 8 words at a time ---
+
+01fastMove     LDMIA   R1!,{R3-R9,R14}         ;Load 8 words
+               STMIA   R0!,{R3-R9,R14}         ;Move them
+                SUBS   R2,R2,#32               ;Decrement count
+                BGE    %01fastMove             ;Keep moving blocks if we can
+
+                CMP    R2,#-32                 ;Are we finished?
+                LDMEQFD        R13!,{R0-R12,PC}^       ;Yes -- return
+
+                ; --- 4 words at a time ---
+
+02fastMove     ADDS    R2,R2,#16               ;4 whole words to do?
+               BLT     %03fastMove
+
+               LDMIA   R1!,{R3-R6}             ;Load 4 words
+               STMIA   R0!,{R3-R6}             ;Move them
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#16
+
+               ; --- Less than 4 words left ---
+
+03fastMove     ADDS    R2,R2,#8                ;2 words to do?
+               BLT     %04fastMove
+
+               LDMIA   R1!,{R3,R4}             ;Load 2 words
+               STMIA   R0!,{R3,R4}             ;Move them
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#8
+
+               ; --- Less than 2 words left ---
+
+04fastMove     ADDS    R2,R2,#4                ;1 word to do?
+               BLT     %05fastMove
+
+               LDR     R3,[R1],#4              ;Load a word
+               STR     R3,[R0],#4              ;Move it
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#4
+
+               ; --- Less than 1 word! ---
+
+05fastMove     ADDS    R2,R2,#4
+               LDMEQFD R13!,{R0-R12,PC}^       ;Pointless?
+
+               ; --- 1, 2 or 3 bytes left ---
+
+               LDR     R14,[R1]
+06fastMove     STRB    R14,[R0],#1
+               MOV     R14,R14,LSR #8
+               SUBS    R2,R2,#1
+               BGT     %06fastMove
+               LDMFD   R13!,{R0-R12,PC}^       ;Finished at last!
+
+               ; --- Word align destination ---
+
+10fastMove     LDRB    R14,[R1],#1
+               STRB    R14,[R0],#1
+               SUBS    R2,R2,#1
+               LDMEQFD R13!,{R0-R12,PC}^
+
+               TST     R0,#3                   ;Is it word aligned?
+               BNE     %10fastMove             ;No -- keep going
+
+               B       %00fastMove             ;Move the rest
+
+               ; --- Word align source (Urggg... bloogle...) ---
+               ; --- PRM for documentation ---
+
+20fastMove     AND     R11,R1,#3
+               BIC     R1,R1,#3
+               MOV     R11,R11,LSL #3
+               RSB     R12,R11,#32
+               LDR     R3,[R1],#4
+               MOV     R3,R3,LSR R11
+
+               SUBS    R2,R2,#16               ;4 or more words to do?
+               BLT     %23fastMove
+
+               SUBS    R2,R2,#16               ;8 or more words to do?
+               BLT     %22fastMove
+
+               ; --- 8 words at a time ---
+
+21fastMove     LDMIA   R1!,{R4-R10,R14}        ;Load 8 words
+               ORR     R3,R3,R4,LSL R12
+
+               MOV     R4,R4,LSR R11
+               ORR     R4,R4,R5,LSL R12
+
+               MOV     R5,R5,LSR R11
+               ORR     R5,R5,R6,LSL R12
+
+               MOV     R6,R6,LSR R11
+               ORR     R6,R6,R7,LSL R12
+
+               MOV     R7,R7,LSR R11
+               ORR     R7,R7,R8,LSL R12
+
+               MOV     R8,R8,LSR R11
+               ORR     R8,R8,R9,LSL R12
+
+               MOV     R9,R9,LSR R11
+               ORR     R9,R9,R10,LSL R12
+
+               MOV     R10,R10,LSR R11
+               ORR     R10,R10,R14,LSL R12
+
+               STMIA   R0!,{R3-R10}            ;Move them
+               MOV     R3,R14,LSR R11
+                SUBS   R2,R2,#32               ;Decrement count
+                BGE    %21fastMove             ;Keep moving blocks if we can
+
+                CMP    R2,#-32                 ;Are we finished?
+                LDMEQFD        R13!,{R0-R12,PC}^       ;Yes -- return
+
+                ; --- 4 words at a time ---
+
+22fastMove     ADDS    R2,R2,#16               ;4 whole words to do?
+               BLT     %23fastMove
+
+               LDMIA   R1!,{R4-R7}             ;Load 4 words
+               ORR     R3,R3,R4,LSL R12
+
+               MOV     R4,R4,LSR R11
+               ORR     R4,R4,R5,LSL R12
+
+               MOV     R5,R5,LSR R11
+               ORR     R5,R5,R6,LSL R12
+
+               MOV     R6,R6,LSR R11
+               ORR     R6,R6,R7,LSL R12
+
+               STMIA   R0!,{R3-R6}             ;Move them
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#16
+               MOV     R3,R7,LSR R11
+
+               ; --- Less than 4 words left ---
+
+23fastMove     ADDS    R2,R2,#8                ;2 words to do?
+               BLT     %24fastMove
+
+               LDMIA   R1!,{R4,R5}             ;Load 2 words
+               ORR     R3,R3,R4,LSL R12
+
+               MOV     R4,R4,LSR R11
+               ORR     R4,R4,R5,LSL R12
+
+               STMIA   R0!,{R3,R4}             ;Move them
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#8
+               MOV     R3,R5,LSR R11
+
+               ; --- Less than 2 words left ---
+
+24fastMove     ADDS    R2,R2,#4                ;1 word to do?
+               BLT     %25fastMove
+
+               LDR     R4,[R1],#4              ;Load a word
+               ORR     R3,R3,R4,LSL R12
+
+               STR     R3,[R0],#4              ;Move it
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#4
+               MOV     R3,R4,LSR R11
+
+               ; --- Less than 1 word! ---
+
+25fastMove     ADDS    R2,R2,#4
+               LDMEQFD R13!,{R0-R12,PC}^       ;Pointless?
+
+               ; --- 1, 2 or 3 bytes left ---
+
+               LDR     R14,[R1]
+               ORR     R3,R3,R14,LSL R12
+26fastMove     STRB    R3,[R0],#1
+               MOV     R3,R3,LSR #8
+               SUBS    R2,R2,#1
+               BGT     %26fastMove
+
+               LDMFD   R13!,{R0-R12,PC}^       ;Finished at last!
+
+                ; --- Copy upwards ---
+
+49fastMove     STMFD   R13!,{R0-R12,R14}       ;Stack some registers
+               ADD     R0,R0,R2
+               ADD     R1,R1,R2
+
+               TST     R0,#3                   ;Is destination word aligned
+               BNE     %60fastMove             ;No -- word align it
+
+50fastMove     TST     R1,#3                   ;Is source word aligned
+               BNE     %70fastMove             ;No -- word align that
+
+               ; --- Source and destination are now word aligned ---
+
+               SUBS    R2,R2,#16               ;4 or more words to do?
+               BLT     %53fastMove
+
+               SUBS    R2,R2,#16               ;8 or more words to do?
+               BLT     %52fastMove
+
+               ; --- 8 words at a time ---
+
+51fastMove     LDMDB   R1!,{R3-R9,R14}         ;Load 8 words
+               STMDB   R0!,{R3-R9,R14}         ;Move them
+                SUBS   R2,R2,#32               ;Decrement count
+                BGE    %51fastMove             ;Keep moving blocks if we can
+
+                CMP    R2,#-32                 ;Are we finished?
+                LDMEQFD        R13!,{R0-R12,PC}^       ;Yes -- return
+
+                ; --- 4 words at a time ---
+
+52fastMove     ADDS    R2,R2,#16               ;4 whole words to do?
+               BLT     %53fastMove
+
+               LDMDB   R1!,{R3-R6}             ;Load 4 words
+               STMDB   R0!,{R3-R6}             ;Move them
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#16
+
+               ; --- Less than 4 words left ---
+
+53fastMove     ADDS    R2,R2,#8                ;2 words to do?
+               BLT     %54fastMove
+
+               LDMDB   R1!,{R3,R4}             ;Load 2 words
+               STMDB   R0!,{R3,R4}             ;Move them
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#8
+
+               ; --- Less than 2 words left ---
+
+54fastMove     ADDS    R2,R2,#4                ;1 word to do?
+               BLT     %55fastMove
+
+               LDR     R3,[R1,#-4]!            ;Load a word
+               STR     R3,[R0,#-4]!            ;Move it
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#4
+
+               ; --- Less than 1 word! ---
+
+55fastMove     ADDS    R2,R2,#4
+               LDMEQFD R13!,{R0-R12,PC}^       ;Pointless?
+
+               ; --- 1, 2 or 3 bytes left ---
+
+               LDR     R14,[R1,#-4]
+56fastMove     MOV     R3,R14,LSR #24
+               STRB    R3,[R0,#-1]!
+               MOV     R14,R14,LSL #8
+               SUBS    R2,R2,#1
+               BGT     %56fastMove
+
+               LDMFD   R13!,{R0-R12,PC}^       ;Finished at last!
+
+               ; --- Word align destination ---
+
+60fastMove     LDRB    R14,[R1,#-1]!
+               STRB    R14,[R0,#-1]!
+               SUBS    R2,R2,#1
+               LDMEQFD R13!,{R0-R12,PC}^
+
+               TST     R0,#3                   ;Is it word aligned?
+               BNE     %60fastMove             ;No -- keep going
+
+               B       %50fastMove             ;Move the rest
+
+               ; --- Word align source (Urggg... bloogle...) ---
+               ;
+               ; There are several oddnesses here.
+
+70fastMove     AND     R11,R1,#3
+               BIC     R1,R1,#3                ;Word align source
+               MOV     R11,R11,LSL #3          ;This is the right shift
+               RSB     R12,R11,#32             ;This is the left shift
+               LDR     R14,[R1],#-4
+               MOV     R14,R14,LSL R12         ;Get the odd bit
+
+               SUBS    R2,R2,#16               ;4 or more words to do?
+               BLT     %73fastMove
+
+               SUBS    R2,R2,#16               ;8 or more words to do?
+               BLT     %72fastMove
+
+               ; --- 8 words at a time ---
+
+71fastMove     LDMDA   R1!,{R3-R10}            ;Load 8 words
+               ORR     R14,R14,R10,LSR R11
+
+               MOV     R10,R10,LSL R12
+               ORR     R10,R10,R9,LSR R11
+
+               MOV     R9,R9,LSL R12
+               ORR     R9,R9,R8,LSR R11
+
+               MOV     R8,R8,LSL R12
+               ORR     R8,R8,R7,LSR R11
+
+               MOV     R7,R7,LSL R12
+               ORR     R7,R7,R6,LSR R11
+
+               MOV     R6,R6,LSL R12
+               ORR     R6,R6,R5,LSR R11
+
+               MOV     R5,R5,LSL R12
+               ORR     R5,R5,R4,LSR R11
+
+               MOV     R4,R4,LSL R12
+               ORR     R4,R4,R3,LSR R11
+
+               STMDB   R0!,{R4-R10,R14}        ;Move them
+               MOV     R14,R3,LSL R12
+                SUBS   R2,R2,#32               ;Decrement count
+                BGE    %71fastMove             ;Keep moving blocks if we can
+
+                CMP    R2,#-32                 ;Are we finished?
+                LDMEQFD        R13!,{R0-R12,PC}^       ;Yes -- return
+
+                ; --- 4 words at a time ---
+
+72fastMove     ADDS    R2,R2,#16               ;4 whole words to do?
+               BLT     %73fastMove
+
+               LDMDA   R1!,{R3-R6}             ;Load 4 words
+               ORR     R14,R14,R6,LSR R11
+
+               MOV     R6,R6,LSL R12
+               ORR     R6,R6,R5,LSR R11
+
+               MOV     R5,R5,LSL R12
+               ORR     R5,R5,R4,LSR R11
+
+               MOV     R4,R4,LSL R12
+               ORR     R4,R4,R3,LSR R11
+
+               STMDB   R0!,{R4-R6,R14}         ;Move them
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#16
+               MOV     R14,R3,LSL R12
+
+               ; --- Less than 4 words left ---
+
+73fastMove     ADDS    R2,R2,#8                ;2 words to do?
+               BLT     %74fastMove
+
+               LDMDA   R1!,{R3,R4}             ;Load 2 words
+               ORR     R14,R14,R4,LSR R11
+
+               MOV     R4,R4,LSL R12
+               ORR     R4,R4,R3,LSR R11
+
+               STMDB   R0!,{R4,R14}            ;Move them
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#8
+               MOV     R14,R3,LSL R12
+
+               ; --- Less than 2 words left ---
+
+74fastMove     ADDS    R2,R2,#4                ;1 word to do?
+               BLT     %75fastMove
+
+               LDR     R3,[R1],#-4             ;Load a word
+               ORR     R14,R14,R3,LSR R11
+
+               STR     R14,[R0,#-4]!           ;Move it
+               LDMEQFD R13!,{R0-R12,PC}^       ;Return if finished
+               SUB     R2,R2,#4
+               MOV     R14,R3,LSL R12
+
+               ; --- Less than 1 word! ---
+
+75fastMove     ADDS    R2,R2,#4
+               LDMEQFD R13!,{R0-R12,PC}^       ;Pointless?
+
+               ; --- 1, 2 or 3 bytes left ---
+
+               LDR     R3,[R1],#-4
+               ORR     R14,R14,R3,LSR R11
+76fastMove     MOV     R3,R14,LSR #24
+               STRB    R3,[R0,#-1]!
+               MOV     R14,R14,LSL #8
+               SUBS    R2,R2,#1
+               BGT     %76fastMove
+
+               LDMFD   R13!,{R0-R12,PC}^       ;Finished at last!
+
+;----- Workspace ------------------------------------------------------------
+;
+; None.
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/s/flex b/StraySrc/Libraries/Core/s/flex
new file mode 100644 (file)
index 0000000..a484a22
--- /dev/null
@@ -0,0 +1,1480 @@
+;
+; flex.s
+;
+; Flexible memory handling (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's flex.
+;
+; Flex is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Flex is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Flex.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- New unified version --------------------------------------------------
+;
+; I'm finally fed up of maintaining four different versions of this code.
+; From now on, there is only this one.
+;
+; Lots of options are supported:
+;
+; OPT_APCS     Generate an APCS-compatible version
+; OPT_SAPPHIRE Generate a Sapphire-compatible version
+; OPT_STEEL    Apply some STEEL-specific eccentricities
+; OPT_STANDALONE Build a standalone assembler version (default)
+; OPT_DUMP     Generate flex_dump code
+; OPT_DYNAREA  Generate dynamic-area handling code
+; OPT_STACK    Generate relocation stack handling code
+; OPT_DLL      Generate absolute address relocation for DLL code
+; OPT_ATEXIT   Register cleanup function with `atexit' for DLL code
+;
+;                                                              [mdw]
+
+;----- Set up some options --------------------------------------------------
+
+               MACRO
+               DCLOPT  $var
+               [       :DEF:$var
+$var           SETL    {TRUE}
+               |
+               GBLL    $var
+$var           SETL    {FALSE}
+               ]
+               MEND
+
+               DCLOPT  OPT_APCS
+               DCLOPT  OPT_SAPPHIRE
+               DCLOPT  OPT_STEEL
+               DCLOPT  OPT_STANDALONE
+               DCLOPT  OPT_DUMP
+               DCLOPT  OPT_DYNAREA
+               DCLOPT  OPT_STACK
+               DCLOPT  OPT_DLL
+               DCLOPT  OPT_ATEXIT
+
+       [ :LNOT:OPT_APCS:LAND::LNOT:OPT_SAPPHIRE:LAND::LNOT:OPT_STANDALONE
+               GBLL    OPT_STANDALONE
+OPT_STANDALONE SETL    {TRUE}
+       ]
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+       [ OPT_SAPPHIRE
+               GET     sapphire:fastMove
+               GET     sapphire:event
+               GET     sapphire:except
+               GET     sapphire:libOpts
+               GET     sapphire:roVersion
+               GET     sapphire:sapphire
+       |
+               IMPORT  fastMove
+       ]
+
+       [ OPT_DLL:LAND:OPT_APCS
+               IMPORT  atexit
+       ]
+
+;----- Workspace macros -----------------------------------------------------
+
+       [ OPT_APCS
+
+               MACRO
+$label         WSPACE  $addr,$reg
+               LCLS    r
+               [       "$reg"=""
+r              SETS    "R12"
+               |
+r              SETS    "$reg"
+               ]
+               ALIGN
+$label
+               LDR     $r,$addr
+               [       OPT_DLL
+               LDR     R14,[R10,#-536]
+               ADD     $r,R14,$r
+               ]
+               MEND
+
+       ]
+
+;----- Main code ------------------------------------------------------------
+
+       [ OPT_SAPPHIRE
+               AREA    |Sapphire$$Code|,CODE,READONLY
+       ]
+       [ OPT_APCS
+               AREA    |C$$Code|,CODE,READONLY
+       ]
+       [ OPT_STANDALONE
+               AREA    |Straylight$$Code|,CODE,READONLY
+       ]
+
+; --- flex__setslot ---
+;
+; On entry:    R0 == limit address of slot required, or -1 to read
+;
+; On exit:     R0 == actual address (after update)
+;              R1 == limit requested (R0 on entry)
+;
+; Use:         Sets the application's WimpSlot to a given value.  The value
+;              is given as an address, rather than as a size, which is
+;              the more normal way of doing things.
+;
+;              Since updated to cope with dynamic areas.
+
+flex__setslot  ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Save some registers
+               LDR     R14,flex__flags         ;Load interesting flags
+       [ OPT_DYNAREA
+               TST     R14,#fFlag__dynArea     ;Using a dynamic area?
+               BNE     %50flex__setslot        ;Yes -- do different things
+       ]
+
+               ; --- Change the WimpSlot ---
+               ;
+               ; Be careful -- we may be sharing memory space with another
+               ; application!
+
+               MOV     R5,R0                   ;Look after my argument
+               MOV     R0,#14                  ;Read app space value
+               MOV     R1,#0                   ;Read, rather than write
+               SWI     XOS_ChangeEnvironment   ;Read the value
+               MOV     R3,R1                   ;Keep hold of app space size
+
+               MOV     R0,#0                   ;Now read memory limit
+               MOV     R1,#0                   ;Read again, not write
+               SWI     XOS_ChangeEnvironment   ;Read memory limit
+               MOV     R6,R1                   ;Look after memory limit
+
+               CMP     R6,R3                   ;How does this shape up?
+               MOVLT   R1,R3                   ;If too low, extend mem limit
+               SWILT   XOS_ChangeEnvironment   ;Set memory limit
+
+               CMP     R5,#-1                  ;Does he want to read it?
+               MOVEQ   R0,R5                   ;Yes -- do that then
+               SUBNE   R0,R5,#&8000            ;Otherwise work out slot size
+               MOV     R1,#-1                  ;Not interested in next slot
+               SWI     XWimp_SlotSize          ;Change the WimpSlot value
+               MOV     R4,R0                   ;Look after updated value
+
+               CMP     R6,R3                   ;If we changed the mem limit
+               MOVLT   R1,R6                   ;Put it back the way it was
+               MOVLT   R0,#0                   ;Setting memory limit
+               SWILT   XOS_ChangeEnvironment   ;Restore memory limit
+
+               ADD     R0,R4,#&8000            ;New value of WimpSlot
+               MOV     R1,R5                   ;Return requested size too
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               ; --- Change a dynamic area size ---
+
+       [ OPT_DYNAREA
+
+50flex__setslot        MOV     R2,R0                   ;Look after address requested
+               LDR     R3,flex__end            ;Find the end address
+               SUBS    R1,R2,R3                ;Work out the difference
+               LDR     R0,flex__dynArea        ;Load dynamic area handle
+               SWI     XOS_ChangeDynamicArea   ;Try and change the size
+               ADDGT   R0,R3,R1                ;Get new limit address
+               SUBLE   R0,R3,R1                ;Irritatingly positive...
+               MOV     R1,R2                   ;And the caller's request
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+       ]
+
+               LTORG
+
+; --- flex__fixup ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Goes off and fixes up all the anchors currently pointing at
+;              blocks in the heap
+
+flex__fixup    ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Set up for the fixup loop ---
+
+               LDR     R1,flex__base           ;Find the base of the heap
+               LDR     R2,flex__free           ;Find end of the blocks
+
+               ; --- Now go through and fix things up ---
+
+00flex__fixup  CMP     R1,R2                   ;Have we reached the end yet?
+               LDMGEFD R13!,{R0-R3,PC}^        ;Return to caller if so
+               LDR     R3,[R1,#flex__bkanchor] ;Find the pointer to anchor
+               CMP     R3,#0                   ;Is the block currently free?
+               ADDNE   R14,R1,#flex__ohead     ;No -- bump aver the overhead
+               STRNE   R14,[R3]                ;And store in the anchor
+               LDR     R3,[R1,#flex__size]     ;Find the block's size
+               ADD     R3,R3,#flex__ohead+7    ;Add on the extra overhead
+               BIC     R3,R3,#7                ;And word align the size
+               ADD     R1,R1,R3                ;Bump along to the next block
+               B       %00flex__fixup          ;And fix that one up too
+
+               LTORG
+
+; --- flex__compact ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Try to compact the heap by one iteration
+;
+;              We troll through the blocks to find a free one and haul
+;              everything down a bit
+
+flex__compact  ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Save some registers
+
+               ; --- Set up for a loop through the data ---
+
+               LDR     R5,flex__base           ;Find the beginning of flex
+               LDR     R1,flex__free           ;Find the end too
+
+               ; --- Find a free block ---
+
+00flex__compact        CMP     R5,R1                   ;Are we at the end yet?
+               BGE     %10flex__compact        ;Yes -- the heap is compact
+
+               LDR     R2,[R5,#flex__bkanchor] ;Get the block's anchor addr
+               CMP     R2,#0                   ;Is the block free?
+               LDR     R2,[R5,#flex__size]     ;Get the block size
+               ADD     R2,R2,#flex__ohead+7    ;Add on the overhead bytes
+               BIC     R2,R2,#7                ;And word align the size
+               ADDNE   R5,R5,R2                ;No -- move on to next one
+               BNE     %00flex__compact        ;And go round for another one
+
+               ; --- We've found a free block ---
+
+01flex__compact        ADD     R6,R5,R2                ;Point to the next block
+               CMP     R6,R1                   ;Is that the end of the heap?
+               BGE     %05flex__compact        ;Yes -- reduce the free ptr
+
+               ; --- Check for two free blocks together ---
+
+               LDR     R0,[R6,#flex__bkanchor] ;Does this have an anchor?
+               CMP     R0,#0                   ;Check if it's free
+               BNE     %02flex__compact        ;No -- start swapping blocks
+
+               ; --- Join two adjacent free blocks together ---
+
+               LDR     R0,[R6,#flex__size]     ;Yes -- get its size
+               ADD     R2,R0,R2                ;Concatenate the two blocks
+               ADD     R2,R2,#flex__ohead+7    ;Add on the overhead bytes
+               BIC     R2,R2,#7                ;And word align the size
+               B       %01flex__compact        ;And check again...
+
+               ; --- There's a block to bring down ---
+
+02flex__compact        LDR     R4,[R6,#flex__size]     ;Get size of block to move
+               ADD     R4,R4,#flex__ohead+7    ;Add the flex overhead
+               BIC     R4,R4,#7                ;And word align the size
+               MOVS    R2,R4                   ;This is the size to move
+               MOV     R0,R5                   ;Where to move it to
+               MOV     R1,R6                   ;Where it is right now
+               BLNE    fastMove                ;Copy it down PDQ
+       [ OPT_STACK
+               BLNE    flex__reloc             ;Deal with the relocation
+       ]
+               ADD     R0,R5,R4                ;Point after block we moved
+               MOV     R1,#0                   ;Block doesn't have an anchor
+               STR     R1,[R0,#flex__bkanchor] ;Store that away for later
+               SUB     R1,R6,R5                ;Find the difference here
+               SUB     R1,R1,#flex__ohead      ;Don't count this size here
+               STR     R1,[R0,#flex__size]     ;Store the old size in free
+
+               ; --- We need to fix up the block we moved ---
+
+               LDR     R0,[R5,#flex__bkanchor] ;Get the anchor pointer
+               ADD     R1,R5,#flex__ohead      ;Point to the real data
+               STR     R1,[R0]                 ;Store client's new anchor
+
+               ; --- That's it -- return to caller ---
+
+               LDMFD   R13!,{R0-R6,PC}^        ;Return to caller
+
+               ; --- Merge the last block with the free area ---
+
+05flex__compact        STR     R5,flex__free           ;This is the new free area
+               LDR     R0,flex__chunk          ;Get the machine page size
+               SUB     R0,R0,#1                ;Turn into a bitmask
+               ADD     R5,R5,R0                ;Align this to page boundary
+               BIC     R0,R5,R0                ;And finish off the align
+               LDR     R1,flex__end            ;Find the end of the heap
+               CMP     R0,R1                   ;Are these different?
+               BLNE    flex__setslot           ;Yes -- free some memory
+               STRNE   R0,flex__end            ;Store the end away
+
+               ; --- That's it -- return ---
+
+               LDMFD   R13!,{R0-R6,PC}^        ;Return to caller
+
+               ; --- There wasn't anything to do -- we're compacted ---
+
+10flex__compact        LDR     R0,flex__flags
+               ORR     R0,R0,#fFlag__compact   ;We are now compacted
+               STR     R0,flex__flags
+               LDMFD   R13!,{R0-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- flex_reduce ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Compacts the flex heap by one iteration.
+
+               EXPORT  flex_reduce
+flex_reduce    ROUT
+
+               STMFD   R13!,{R0,R12,R14}       ;Stack some registers
+               WSPACE  flex__wSpace            ;Find my workspace
+
+               ; --- Check if it's compacted ---
+
+               LDR     R0,flex__flags          ;Get my nice flags word
+               TST     R0,#fFlag__compact      ;Is the heap compacted?
+               BLEQ    flex__compact           ;No -- compact it a bit
+               LDMFD   R13!,{R0,R12,PC}^       ;Return to caller now
+
+               LTORG
+
+; --- flex_compact ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Completely compacts the flex heap.
+
+               EXPORT  flex_compact
+flex_compact   ROUT
+
+               STMFD   R13!,{R0,R12,R14}       ;Save some registers
+               WSPACE  flex__wSpace            ;Find my workspace
+
+               ; --- Compaction loop ---
+
+00flex_compact LDR     R0,flex__flags          ;Get my nice flags word
+               TST     R0,#fFlag__compact      ;Is the heap compacted?
+               BLEQ    flex__compact           ;No -- compact another stage
+               BEQ     %00flex_compact         ;And go round again
+
+               ; --- The end -- return ---
+
+               LDMFD   R13!,{R0,R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- flex_free ---
+;
+; On entry:    R0 == pointer to the flex anchor
+;
+; On exit:     --
+;
+; Use:         Frees a flex block allocated by flex_alloc.
+
+               EXPORT  flex_free
+flex_free      ROUT
+
+               STMFD   R13!,{R0,R12,R14}       ;Save some registers
+               WSPACE  flex__wSpace
+
+               ; --- Mark the block as being free ---
+
+               LDR     R14,[R0]                ;Get pointer to actual block
+               MOV     R0,#0
+               STR     R0,[R14,#flex__bkanchor-flex__ohead]
+
+               ; --- Update the flags -- not compacted any more ---
+
+               LDR     R0,flex__flags          ;Get my nice flags word
+               BIC     R0,R0,#fFlag__compact   ;We are no longer compacted
+               STR     R0,flex__flags          ;Store it back
+
+               LDMFD   R13!,{R0,R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- flex_alloc ---
+;
+; On entry:    R0 == pointer to a flex anchor
+;              R1 == desired size of flex block
+;
+; On exit:     Sapphire: CS if no memory could be allocated, CC otherwise
+;              APCS: R0 zero if no memory, nonzero otherwise
+;
+; Use:         Allocates a block in the shifting heap.
+
+               EXPORT  flex_alloc
+flex_alloc     ROUT
+
+       [ OPT_APCS
+               STMFD   R13!,{R4,R5,R12,R14}    ;Save some registers
+       |
+               STMFD   R13!,{R0-R5,R12,R14}    ;Save some registers
+       ]
+
+               WSPACE  flex__wSpace
+
+               ; --- Round up the size etc. ---
+
+               MOV     R4,R0                   ;Keep the anchor pointer
+               MOV     R3,R1                   ;Keep the actual size wanted
+               ADD     R5,R1,#flex__ohead+7    ;Add on overhead for flex
+               BIC     R5,R5,#7                ;And word-align the size
+
+               ; --- See if there's enough space ---
+
+00flex_alloc   LDR     R0,flex__free           ;Get the free pointer
+               LDR     R2,flex__end            ;And the end of the block
+               SUB     R1,R2,R0                ;How much room is left
+               CMP     R1,R5                   ;Enough for the new block
+               BGE     %10flex_alloc           ;Set up the block
+
+               ; --- Not enough room in block - try to get some more ---
+
+               ADD     R0,R0,R5                ;Find the new slot limit
+               BL      flex__setslot           ;Set up the new slot
+               CMP     R0,R1                   ;Did we get enough
+               STRGE   R0,flex__end            ;Yes -- remember the new end
+               LDRGE   R0,flex__free           ;Find the free area again
+               BGE     %10flex_alloc           ;And allocate the memory
+
+               ; --- Can we compact the heap? ---
+
+               LDR     R0,flex__end            ;Get the old heap extent
+               BL      flex__setslot           ;Put the slot back again
+               LDR     R0,flex__flags          ;Get my current flags
+               TST     R0,#fFlag__compact      ;Is the heap compact?
+               BLEQ    flex_compact            ;No -- really compact it
+               BEQ     %00flex_alloc           ;And give it another go
+
+               ; --- We couldn't get enough memory at all ---
+
+       [ OPT_APCS
+               MOV     R0,#0
+               LDMFD   R13!,{R4,R5,R12,PC}^    ;Restore registers
+       |
+               LDMFD   R13!,{R0-R5,R12,R14}    ;Restore registers
+               ORRS    PC,R14,#C_flag          ;Set C flag to indicate fail
+       ]
+
+               ; --- Set up the block pointed to by R0
+
+10flex_alloc   STR     R4,[R0,#flex__bkanchor] ;Set up the back anchor
+               STR     R3,[R0,#flex__size]     ;Remember size of this block
+               ADD     R1,R0,#flex__ohead      ;Point to real data block
+               STR     R1,[R4]                 ;Let user know where block is
+               ADD     R1,R0,R5                ;Get the new free pointer
+               STR     R1,flex__free           ;Store the new free ptr
+
+               ; --- Return to the user ---
+
+       [ OPT_APCS
+               MOV     R0,#-1
+               LDMFD   R13!,{R4,R5,R12,PC}^
+       |
+               LDMFD   R13!,{R0-R5,R12,R14}
+               BICS    PC,R14,#C_flag
+       ]
+
+               LTORG
+
+; --- flex_size ---
+;
+; On entry:    R0 == pointer to flex anchor
+;
+; On exit:     R0 == size of allocated block
+;
+; Use:         Reads the size of a flex block.
+
+               EXPORT  flex_size
+flex_size      ROUT
+
+               LDR     R0,[R0]                 ;Get the flex block
+               LDR     R0,[R0,#flex__size-flex__ohead]
+               MOVS    PC,R14
+
+               LTORG
+
+; --- flex_extend ---
+;
+; On entry:    R0 == pointer to flex anchor
+;              R1 == new size of block to set
+;
+; On exit:     CS if it failed due to lack of memory, CC otherwise
+;
+; Use:         Alters the size of a block to the given value.
+
+               EXPORT  flex_extend
+flex_extend    ROUT
+
+               STMFD   R13!,{R1,R2,R14}
+
+               ; --- Be *very* careful to preserve the flags... ---
+
+               MOV     R2,R1
+               LDR     R1,[R0]
+               LDR     R1,[R1,#flex__size-flex__ohead]
+               SUB     R2,R2,R1
+               BL      flex_midExtend
+
+               ; --- Note ---
+               ;
+               ; We preserved the flags above, and midExtend should do
+               ; its bit to help, so we can just return with the flags
+               ; set by midExtend.  Easy, no?
+
+               LDMFD   R13!,{R1,R2,PC}
+
+               LTORG
+
+; --- flex_midExtend ---
+;
+; On entry:    R0 == pointer to a flex anchor
+;              R1 == `at' -- position in block to extend from
+;              R2 == `by' -- how many bytes to extend (may be -ve)
+;
+; On exit:     Sapphire: CS if not enough memory, CC otherwise
+;              APCS: R0 zero if not enough memory, nonzero otherwise
+;
+; Use:         Either creates a gap in a block (by>0) or deletes bytes
+;              from a block.  This is always done in such a way that the
+;              byte originally at offset `at' is now at offset `at'+`by'.
+
+               EXPORT  flex_midExtend
+               EXPORT  flex_midextend
+flex_midExtend ROUT
+flex_midextend
+
+               ; --- A bit of clever setting up ---
+
+       [ OPT_APCS
+               TEQ     R2,#0                   ;Move by zero bytes?
+               MOVEQ   R0,#-1                  ;Yes, it worked
+               MOVEQS  PC,R14                  ;And return
+               STMFD   R13!,{R12,R14}          ;Otherwise save registers
+       |
+               BIC     R14,R14,#C_flag         ;Clear C now
+               STMFD   R13!,{R12,R14}          ;Save R14 on the stack
+               TEQ     R2,#0                   ;Move by zero bytes?
+               LDMEQFD R13!,{R12,PC}^          ;Yes -- don't bother then
+       ]
+
+               ; --- Save some more registers and find workspace ---
+
+               WSPACE  flex__wSpace
+
+               ; --- Find out what we have to do depending on `by' ---
+
+               CMP     R2,#0                   ;Is it +ve or -ve?
+               BGT     %50flex_midExtend       ;If we must extend, do that
+
+               ; --- We reduce the block size -- easy ---
+
+       [ OPT_APCS
+               STMFD   R13!,{R4}
+       |
+               STMFD   R13!,{R0-R4}            ;Save some more registers
+       ]
+               MOV     R3,R2                   ;Keep the size safe
+               MOV     R14,R1                  ;Keep `at' safe too
+
+               LDR     R4,[R0]                 ;Get the actual block ptr
+               ADD     R1,R4,R14               ;Copy from `at'
+               ADD     R0,R1,R2                ;Copy to `at'-|`by'|
+               LDR     R2,[R4,#flex__size-flex__ohead]
+               SUBS    R2,R2,R14               ;Size of block - `at'
+               BLNE    fastMove                ;Copy the area down
+       [ OPT_STACK
+               BLNE    flex__reloc             ;And relocate the stack
+       ]
+
+               ; --- Find the new actual and logical sizes ---
+
+               SUB     R4,R4,#flex__ohead      ;Point to my actual data
+               LDR     R0,[R4,#flex__size]     ;Get the size of the block
+               ADD     R1,R0,R3                ;Find new adjusted size
+               STR     R1,[R4,#flex__size]     ;This is new logical size
+               ADD     R0,R0,#flex__ohead+7    ;Add the overhead to both...
+               ADD     R1,R1,#flex__ohead+7    ;... of these sizes and...
+               BIC     R0,R0,#7                ;... align to heap...
+               BIC     R1,R1,#7                ;... granularity nicely
+
+               ; --- If these are different, insert a free block ---
+
+               SUBS    R0,R0,R1                ;Is there space for free blk?
+               BLE     %00flex_midExtend       ;No -- just wrap up nicely
+
+               ; --- Insert the free block here ---
+
+               ADD     R2,R4,R1                ;Find the free block
+               SUB     R0,R0,#flex__ohead      ;Subtract the overhead
+               STR     R0,[R2,#flex__size]     ;And store `logical' size
+               MOV     R0,#0                   ;This block has no owner
+               STR     R0,[R2,#flex__bkanchor] ;So store a null anchor
+
+               ; --- There's a free block -- enable compaction ---
+
+               LDR     R1,flex__flags          ;Load my current flags
+               BIC     R1,R1,#fFlag__compact   ;We're not compact any more
+               STR     R1,flex__flags          ;Store the flags back again
+
+               ; --- Return to caller ---
+
+00flex_midExtend
+       [ OPT_APCS
+               MOV     R0,#-1
+               LDMFD   R13!,{R4,R12,PC}^
+       |
+               LDMFD   R13!,{R0-R4,R12,PC}^    ;Smile, smile, smile
+       ]
+
+               ; --- Work out how much extra space we need ---
+
+50flex_midExtend
+       [ OPT_APCS
+               STMFD   R13!,{R4-R9}
+       |
+               STMFD   R13!,{R0-R9}            ;Save yet more registers
+       ]
+
+               ; --- Take copies of the arguments ---
+
+               MOV     R4,R0
+               MOV     R5,R1
+               MOV     R6,R2
+
+               LDR     R7,[R4]                 ;Find the actual flex block
+               SUB     R7,R7,#flex__ohead      ;Point to my data
+               LDR     R3,[R7,#flex__size]     ;Find the size of the block
+
+               ADD     R2,R3,#7                ;Don't add in overhead
+               BIC     R2,R2,#7                ;How much space in this block
+               SUB     R1,R2,R3                ;R1 == dead space at the end
+               SUBS    R1,R6,R1                ;R1 == extra space needed
+
+               ; --- Can we do it within the block? ---
+
+               ADDLE   R3,R3,R6                ;Increase the size
+               STRLE   R3,[R7,#flex__size]     ;And store
+               BLE     %70flex_midExtend       ;Yes -- just shuffle it about
+
+               ; --- We need to find R1 more bytes from somewhere ---
+               ;
+               ; Our strategy here is fairly simple, really (although we
+               ; could refine it a lot, I suppose).
+               ;
+               ; 1. Find as many free blocks at the end of the midExtend
+               ;    block as possible, join them all together and see if
+               ;    that will do.
+               ;
+               ; 2. If not, we just flex_alloc a block of the right size
+               ;    and shift everything skywards.
+
+               ; --- This calls for some serious register allocation ---
+               ;
+               ; R1 == the amount of extra we need (round up to size)
+               ; R2 == pointer to blocks for loop
+               ;
+               ; R4 == address of anchor of midExtend block
+               ; R5 == point at which we need to extend it
+               ; R6 == how much we extend it by
+               ; R7 == pointer to the actual block
+               ; R8 == pointer to next block after midExtend one
+               ; R9 == the size we've accumulated so far
+
+               ; --- Start the loop (I want to get off) ---
+
+               ADD     R1,R1,#7                ;Align the size to multiple
+               BIC     R1,R1,#7
+               MOV     R9,#0                   ;We haven't found any yet
+               ADD     R8,R7,R2                ;Point almost to next block
+               ADD     R8,R8,#flex__ohead      ;Point to it properly
+               MOV     R2,R8                   ;Start the loop here
+
+               LDR     R3,flex__free           ;Find the free area start
+
+               ; --- Find free blocks now ---
+
+55flex_midExtend
+               CMP     R2,R3                   ;Are we at the end yet?
+               BGE     %65flex_midExtend       ;Oh, well -- we're stuffed
+               LDR     R14,[R2,#flex__bkanchor] ;Is this block free?
+               CMP     R14,#0                  ;Quick check McCheck
+               BNE     %65flex_midExtend       ;Oh, well -- we're stuffed
+               LDR     R14,[R2,#flex__size]    ;Get the block's size
+               ADD     R14,R14,#flex__ohead+7  ;Add on the overhead area
+               BIC     R14,R14,#7              ;And align to doubleword
+               ADD     R9,R9,R14               ;Accumulate the block size
+               CMP     R9,R1                   ;Have we got enough yet?
+               BGE     %60flex_midExtend       ;That's it -- we've got it
+               ADD     R2,R2,R14               ;Move onto the next block
+               B       %55flex_midExtend       ;And check the next one
+
+               ; --- We got enough free blocks to save us ---
+
+60flex_midExtend
+               LDR     R0,[R7,#flex__size]     ;Get the current size of this
+               ADD     R0,R0,R6                ;Add on the extended size
+               STR     R0,[R7,#flex__size]     ;And put it back again
+               BEQ     %70flex_midExtend       ;If perfect fit, don't create
+
+               ; --- Create a new free block to use up the space ---
+
+               ADD     R0,R8,R1                ;Point to the new free block
+               SUB     R2,R9,R1                ;Find out how much is over
+               SUB     R2,R2,#flex__ohead      ;Don't want to count that
+               STR     R2,[R0,#flex__size]     ;Store the size away
+               MOV     R2,#0                   ;This block is not used
+               STR     R2,[R0,#flex__bkanchor] ;So don't give it an anchor
+               B       %70flex_midExtend       ;And do the shuffling about
+
+               ; --- There wasn't enough space there, so allocate more ---
+
+65flex_midExtend
+               MOV     R9,R1                   ;Look after the size we want
+               SUB     R13,R13,#4              ;Create a flex anchor
+               MOV     R0,R13                  ;Point to it
+               SUB     R1,R1,#flex__ohead      ;We'll overwrite the overhead
+               BL      flex_alloc              ;Allocate some memory
+       [ OPT_APCS
+               CMP     R0,#0                   ;Did it fail?
+               ADDEQ   R13,R13,#1              ;Skip past stacked anchor
+               LDMEQFD R13!,{R4-R9,R12,PC}^
+       |
+               LDMCSFD R13!,{R0-R9,R12,R14}    ;If it failed, unstack...
+               ADDCS   R13,R13,#1              ;Skip past stacked anchor
+               ORRCSS  PC,R14,#C_flag          ;... and set carry
+       ]
+               LDR     R3,[R13],#4             ;Get pointer to new block
+
+               ; --- A reminder about the registers ---
+               ;
+               ; R0-R2 aren't interesting any more
+               ; R3 points flex__ohead bytes ahead of old flex__free
+               ; R4-R6 are still our arguments
+               ; R7,R8 aren't exciting any more
+               ; R9 is the amount of extra space we wanted
+
+               ; --- Our block may have moved -- recalculate next ptr ---
+
+               LDR     R7,[R4]                 ;Point to the block
+               SUB     R7,R7,#flex__ohead      ;Point to the overhead area
+               LDR     R8,[R7,#flex__size]     ;Get the size of the block
+               ADD     R8,R8,#flex__ohead+7    ;Bump over the overhead
+               BIC     R8,R8,#7                ;And align to multiple of 8
+
+               ; --- Move all the other blocks up a bit ---
+
+               ADD     R1,R7,R8                ;Start moving from here
+               ADD     R0,R1,R9                ;Move it to here
+               SUB     R2,R3,#flex__ohead      ;Find the old flex__free
+               SUBS    R2,R2,R1                ;Copy the right section up
+               BLNE    fastMove
+       [ OPT_STACK
+               BLNE    flex__reloc             ;And adjust any stacked ptrs
+       ]
+
+               ; --- Adjust the block size and anchors ---
+
+               LDR     R14,[R7,#flex__size]    ;Get the size of this block
+               ADD     R14,R14,R6              ;Add on the extension
+               STR     R14,[R7,#flex__size]    ;Store it back again
+               BL      flex__fixup             ;Fix up all the anchors again
+               ; Drop through to block shuffling
+
+               ; --- Create the gap in the flex block ---
+
+70flex_midExtend
+               LDR     R4,[R7,#flex__size]     ;Get the size of the block
+               SUB     R4,R4,R6                ;Find the old length
+               ADD     R1,R7,#flex__ohead      ;Point to the real data
+               ADD     R1,R1,R5                ;Find the `at' position
+               ADD     R0,R1,R6                ;Find the `at'+|`by'| posn
+               SUBS    R2,R4,R5                ;Find the length to move
+               BLNE    fastMove                ;Do the move
+       [ OPT_STACK
+               BLNE    flex__reloc             ;And adjust any stacked ptrs
+       ]
+
+       [ OPT_APCS
+               MOV     R0,#-1
+               LDMFD   R13!,{R4-R9,R12,PC}^
+       |
+               LDMFD   R13!,{R0-R9,R12,PC}^
+       ]
+
+               LTORG
+
+; --- flex_init ---
+;
+; On entry:    R0 == pointer to dynamic area name, or zero
+;              R1 == maximum allowed size of the area
+;                      (except Sapphire version)
+;
+; On exit:     --
+;
+; Use:         Initialises the flex heap for use.
+
+               EXPORT  flex_init
+               EXPORT  flex_dinit
+flex_init      ROUT
+
+       [ OPT_STEEL
+               MOV     R0,#0
+               MOV     R1,#1
+       ]
+
+flex_dinit     STMFD   R13!,{R0-R8,R12,R14}
+               WSPACE  flex__wSpace
+
+       [ :LNOT:OPT_STANDALONE
+
+               ; --- Prevent multiple initialisation ---
+
+               LDR     R14,flex__flags         ;Find my flags word
+               TST     R14,#fFlag__inited      ;Am I initialised yet?
+               LDMNEFD R13!,{R0-R8,R12,PC}^    ;Yes -- return right now
+
+       ]
+
+  [ OPT_DYNAREA
+
+               ; --- If this is Sapphire, find the options block ---
+
+       [ OPT_SAPPHIRE
+
+               BL      rov_init                ;Work out the RISC OS version
+               BL      rov_version             ;Get the version
+               CMP     R0,#348                 ;Is this RISC OS 3.5?
+               BCC     %10flex_init            ;No -- skip ahead then
+
+               LDR     R0,flex__optName        ;Get the magic marker word
+               BL      libOpts_find            ;Try to find the options
+               BCC     %10flex_init            ;Not there -- skip on then
+               LDR     R14,[R0,#0]             ;Load the flags out
+               TST     R14,#1                  ;Is the dynamic area flag on?
+               BEQ     %10flex_init            ;No -- don't do this then
+
+               ; --- See if we can create a dynamic area ---
+
+               TST     R14,#2                  ;Specified area size?
+               LDRNE   R5,[R0,#4]              ;Yes -- load from opts block
+               MOVEQ   R5,#16*1024*1024        ;16 meg maximum size
+               LDR     R8,sapph_appName        ;Find the application name
+
+       |
+
+               ; --- If this is APCS, then use the arguments ---
+
+               CMP     R0,#0                   ;Is a dynamic area wanted?
+               CMPNE   R1,#0                   ;Just check for stupidity
+               BEQ     %10flex_init            ;No -- then skip ahead
+               MOV     R8,R0                   ;Find the name pointer
+               MOV     R5,R1                   ;And the size requested
+
+               MOV     R0,#129                 ;Find the OS version
+               MOV     R1,#0                   ;Convoluted call for this...
+               MOV     R2,#255                 ;No idea why
+               SWI     OS_Byte                 ;Call the operating system
+               CMP     R1,#&A5                 ;Is it late enough?
+               BCC     %10flex_init            ;No -- ignore the request
+
+       ]
+
+               ; --- Create a dynamic area ---
+
+               MOV     R0,#0                   ;Create new dynamic area
+               MOV     R1,#-1                  ;Give me any old number
+               MOV     R2,#0                   ;Zero size initially
+               MOV     R3,#-1                  ;Don't care about base addr
+               MOV     R4,#(1<<7)              ;Don't let user drag the bar
+               MOV     R6,#0                   ;No dynamic area handler
+               MOV     R7,#0                   ;I wuz told to do this
+               SWI     XOS_DynamicArea         ;Try to create the area
+               BVS     %10flex_init            ;It failed -- use WimpSlot
+
+               ; --- Set up workspace for this ---
+
+               STR     R3,flex__base           ;Store base of the area
+               STR     R3,flex__free           ;The first free part
+               STR     R3,flex__end            ;And the end
+               STR     R1,flex__dynArea        ;Save dynamic area handle
+
+               MOV     R0,#fFlag__compact + fFlag__inited + fFlag__dynArea
+               STR     R0,flex__flags          ;Store the appropriate flags
+
+               ; --- Add in tidy-up routine to delete the area ---
+
+       [ OPT_SAPPHIRE
+               BL      except_init             ;We need to clear it up
+               ADR     R0,flex__exit           ;Point to exit handler
+               MOV     R1,R12                  ;Pass it my workspace
+               BL      except_atExit           ;Register the routine
+       ]
+
+       [ OPT_ATEXIT
+               ADR     R0,flex_die             ;Point to exit handler
+               BL      atexit                  ;And call that
+       ]
+
+               B       %20flex_init            ;And continue initialisation
+
+  ]
+
+               ; --- Find out the slot size ---
+
+10flex_init    MOV     R0,#-1                  ;Read current slot size
+               BL      flex__setslot           ;Do the slot thing
+
+               ; --- Store initial heap information ---
+
+               STR     R0,flex__base           ;The start of the heap
+               STR     R0,flex__free           ;The first free part
+               STR     R0,flex__end            ;And the end
+
+               MOV     R0,#fFlag__compact + fFlag__inited
+                                               ;Empty heaps is compact heaps
+               STR     R0,flex__flags
+
+               ; --- Get the page size of the machine ---
+
+20flex_init    SWI     OS_ReadMemMapInfo       ;Get page size (in R0)
+               STR     R0,flex__chunk          ;Store for future reference
+
+               ; --- Set up the flex relocation stack ---
+
+       [ OPT_STACK
+               ADR     R14,flex__relocStk      ;Point to the stack base
+               STR     R14,flex__relocSP       ;Save this as initial SP
+       ]
+
+               ; --- Register the flex compactor as a postfilter ---
+
+       [ OPT_SAPPHIRE
+               BL      event_init              ;Initialise event system
+               ADR     R0,flex__preFilter      ;Point to the prefilter
+               MOV     R1,R12                  ;Give it my workspace ptr
+               BL      event_preFilter         ;Add the filter into the list
+               ADR     R0,flex__postFilter     ;Point to the postfilter
+               MOV     R1,R12                  ;Give it my workspace ptr
+               BL      event_postFilter        ;Add the filter into the list
+       ]
+
+               LDMFD   R13!,{R0-R8,R12,PC}^
+
+       [ OPT_SAPPHIRE
+flex__optName  DCB     "FLEX"
+       ]
+
+               LTORG
+
+       [ OPT_SAPPHIRE
+flex__wSpace   DCD     0
+       ]
+
+       [ OPT_APCS
+flex__wSpace   DCD     flex__sSpace
+       ]
+
+; --- flex__preFilter ---
+;
+; On entry:    R0 == WIMP event mask
+;              R1 == pointer to event block
+;              R2 == time to return, or 0
+;              R3 == pointer to poll word if necessary
+;
+; On exit:     R0,R2 maybe updated to enable idle events
+;
+; Use:         Enables full idle events if the flex heap needs compacting.
+
+       [ OPT_SAPPHIRE
+
+flex__preFilter        ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,flex__flags         ;Find the flags word
+               TST     R14,#fFlag__compact     ;Is the heap compacted?
+               BICEQ   R0,R0,#1                ;No -- unmask idle events
+               MOVEQ   R2,#0                   ;And return immediately
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+       ]
+
+; --- flex__postFilter ---
+;
+; On entry:    R0 == WIMP reason code
+;              R1 == pointer to event block
+;              R2 == time to return or 0
+;              R3 == pointer to poll word or nothing really
+;
+; On exit:     Everything must be preserved
+;
+; Use:         Compacts the flex heap every idle event
+
+       [ OPT_SAPPHIRE
+
+flex__postFilter ROUT
+
+               CMP     R0,#0                   ;Is this an idle event?
+               MOVNES  PC,R14                  ;No -- then return right now
+               STMFD   R13!,{R0}               ;Save a register
+               LDR     R0,flex__flags          ;Find the flags word
+               TST     R0,#fFlag__compact      ;Is the heap compacted?
+               LDMFD   R13!,{R0}               ;Restore the register's value
+               MOVNES  PC,R14                  ;Return if it is
+               B       flex__compact           ;Go give the heap a nudge
+
+               LTORG
+
+       ]
+
+       [ OPT_APCS
+
+; --- flex_budge / flex_dont_budge ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Nothing.  Both of these do the same thing.
+
+               EXPORT  flex_budge
+               EXPORT  flex_dont_budge
+flex_budge     ROUT
+flex_dont_budge        MOV     R0,#0                   ;Refuse the budge
+               MOVS    PC,R14                  ;And return
+
+       ]
+
+; --- flex_die / flex__exit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Kills the dynamic area which we own.
+
+       [ OPT_DYNAREA
+
+       [ OPT_SAPPHIRE
+flex__exit     ROUT
+       |
+               EXPORT  flex_die
+flex_die       ROUT
+       ]
+
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+
+               ; --- The C library's `atexit' doesn't provide context ---
+
+       [ :LNOT:OPT_SAPPHIRE
+               WSPACE  flex__wSpace
+       ]
+
+               ; --- Now free the dynamic area ---
+
+               LDR     R1,flex__dynArea        ;Load the handle
+               CMP     R1,#0                   ;Is it defined?
+               MOVNE   R0,#1                   ;Yes -- remove it
+               SWINE   OS_DynamicArea          ;Do the remove job
+               MOVNE   R0,#0                   ;Now clear the handle
+               STRNE   R0,flex__dynArea        ;So we don't do it again
+               LDMFD   R13!,{R0,R1,PC}^        ;Finally, return to caller
+
+               LTORG
+
+       ]
+
+       [ OPT_STACK
+
+; --- flex_stackPtr ---
+;
+; On entry:    R0 == 0 to read, or value to set
+;
+; On exit:     R0 == old value
+;
+; Use:         Either reads or writes the flex stack pointer.  This sort
+;              of thing is useful in exception handlers etc.
+
+               EXPORT  flex_stackPtr
+flex_stackPtr  ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  flex__wSpace            ;Find the workspace
+               LDR     R14,flex__relocSP       ;Load the current value
+               CMP     R0,#0                   ;Does he want to write it?
+               STRNE   R0,flex__relocSP        ;Yes -- then write it
+               MOV     R0,R14                  ;Return the old value
+               LDMFD   R13!,{R12,PC}^          ;And return to caller
+
+               LTORG
+
+; --- flex_save ---
+;
+; On entry:    R0 == value to save, for APCS
+;
+; On exit:     --
+;
+; Use:         Saves some registers on the flex relocation stack.  R13
+;              and R14 cannot be saved -- these registers are corrupted
+;              during this routine's execution.
+;
+;              Values saved on the flex relocation stack are adjusted as
+;              flex moves blocks of memory around, so that they still point
+;              to the same thing as they did before.  Obviously, values
+;              which aren't pointers into flex blocks may be corrupted.
+;              Values pointing to objects deleted (either free blocks, or
+;              areas removed by flex_midExtend) may also be corrupted.
+;
+;              Since this routine takes no arguments, some other method has
+;              to be used.  The method chosen is to follow the call to
+;              flex_save with a LDM or STM instruction containing the
+;              registers to be saved.  This instruction is skipped by the
+;              routine, and thus not executed.
+;
+;              Note that if you give the LDM or STM the same condition code
+;              as the BL preceding it, it will never be executed, since
+;              flex_save skips it if the condition is true and it can't be
+;              executed if the condition is false.
+;
+;              (All the above is only true for the Sapphire version.)
+
+               EXPORT  flex_save
+flex_save      ROUT
+
+       [ :LNOT:OPT_APCS
+
+               ; --- StrongARM friendly version 1st October 1996 [mdw] ---
+
+               STMFD   R13!,{R10,R11,R12,R14}  ;Save some registers away
+               BIC     R10,R14,#&FC000003      ;Clear processor flags
+               WSPACE  flex__wSpace            ;Locate flex's workspace
+               LDR     R11,flex__relocSP       ;Load the stack pointer
+               LDR     R10,[R10,#0]            ;Load the instruction out
+
+               ; --- Rather optimised code ---
+               ;
+               ; Shift two bits at a time into C and N.  Leave early if
+               ; possible.
+
+               TST     R10,#&03F
+               BEQ     %f05
+               MOVS    R14,R10,LSL #31
+               STRMI   R0,[R11],#4
+               STRCS   R1,[R11],#4
+               MOVS    R14,R10,LSL #29
+               STRMI   R2,[R11],#4
+               STRCS   R3,[R11],#4
+               TST     R10,#&FF0
+               BEQ     %f05
+               MOVS    R14,R10,LSL #27
+               STRMI   R4,[R11],#4
+               STRCS   R5,[R11],#4
+               TST     R10,#&FC0
+               BEQ     %f00
+05             MOVS    R14,R10,LSL #25
+               STRMI   R6,[R11],#4
+               STRCS   R7,[R11],#4
+               MOVS    R14,R10,LSL #23
+               STRMI   R8,[R11],#4
+               STRCS   R9,[R11],#4
+               TST     R10,#&C00
+               BEQ     %f00
+               MOVS    R14,R10,LSL #21
+               LDRMI   R14,[R13,#0]
+               STRMI   R14,[R11],#4
+               LDRCS   R14,[R13,#4]
+               STRCS   R14,[R11],#4
+00
+               ; --- Tidy up and return home ---
+
+               STR     R11,flex__relocSP       ;Store new stack ptr
+               LDMFD   R13!,{R10,R11,R12,R14}  ;And return to caller
+               ADDS    PC,R14,#4
+
+       |
+
+               STMFD   R13!,{R12,R14}          ;Save registers
+               WSPACE  flex__wSpace            ;Find my workspace
+               LDR     R14,flex__relocSP       ;Load the current pointer
+               STR     R0,[R14],#4             ;Store the value away
+               STR     R14,flex__relocSP       ;Store the stack pointer
+               LDMFD   R13!,{R12,PC}^          ;And return to caller
+
+       ]
+
+               LTORG
+
+; --- flex_load ---
+;
+; On entry:    --
+;
+; On exit:     Registers loaded from relocation stack as requested
+;
+; Use:         Restores registers saved on flex's relocation stack.  See
+;              flex_save for calling information and details about the
+;              relocation stack.
+
+               EXPORT  flex_load
+flex_load      ROUT
+
+       [ :LNOT:OPT_APCS
+
+               ; --- StrongARM friendly version 1st October 1996 [mdw] ---
+
+               STMFD   R13!,{R10,R11,R12,R14}  ;Save some registers away
+               BIC     R10,R14,#&FC000003      ;Clear processor flags
+               WSPACE  flex__wSpace            ;Locate flex's workspace
+               LDR     R11,flex__relocSP       ;Load the stack pointer
+               LDR     R10,[R10,#0]            ;Load the instruction out
+
+               ; --- Rather optimised code ---
+               ;
+               ; Shift two bits at a time into C and N.  Leave early if
+               ; possible.  Do it backwards, because otherwise it doesn't
+               ; work.
+
+               TST     R10,#&FF0
+               BEQ     %f05
+               MOVS    R14,R10,LSL #21
+               LDRCS   R14,[R11,#-4]!
+               STRCS   R14,[R13,#4]
+               LDRMI   R14,[R11,#-4]!
+               STRMI   R14,[R13,#0]
+               MOVS    R14,R10,LSL #23
+               LDRCS   R9,[R11,#-4]!
+               LDRMI   R8,[R11,#-4]!
+               TST     R10,#&0FF
+               BEQ     %f00
+               MOVS    R14,R10,LSL #25
+               LDRCS   R7,[R11,#-4]!
+               LDRMI   R6,[R11,#-4]!
+               TST     R10,#&03F
+               BEQ     %f00
+               MOVS    R14,R10,LSL #27
+               LDRCS   R5,[R11,#-4]!
+               LDRMI   R4,[R11,#-4]!
+               TST     R10,#&00F
+               BEQ     %f00
+05             MOVS    R14,R10,LSL #29
+               LDRCS   R3,[R11,#-4]!
+               LDRMI   R2,[R11,#-4]!
+               MOVS    R14,R10,LSL #31
+               LDRCS   R1,[R11,#-4]!
+               LDRMI   R0,[R11,#-4]!
+00
+               ; --- Tidy up and return home ---
+
+               STR     R11,flex__relocSP       ;Store new stack ptr
+               LDMFD   R13!,{R10,R11,R12,R14}  ;And return to caller
+               ADDS    PC,R14,#4
+
+       |
+
+               STMFD   R13!,{R12,R14}          ;Save registers
+               WSPACE  flex__wSpace            ;Find my workspace
+               LDR     R14,flex__relocSP       ;Load the current pointer
+               LDR     R0,[R14,#-4]!           ;Load the value out
+               STR     R14,flex__relocSP       ;Store the stack pointer
+               LDMFD   R13!,{R12,PC}^          ;And return to caller
+
+       ]
+
+               LTORG
+
+; --- flex__reloc ---
+;
+; On entry:    R0 == destination pointer of move
+;              R1 == source pointer of move
+;              R2 == length of block to move
+;
+; On exit:     --
+;
+; Use:         Relocates the flex stack after a heap operation which moved
+;              memory.  The arguments are intentionally the same as those
+;              for fastMove, which should be called immediately before this
+;              routine.
+
+flex__reloc    ROUT
+
+               STMFD   R13!,{R3,R4,R14}        ;Save some registers
+
+               ; --- Set up initial values ---
+
+               ADR     R3,flex__relocStk       ;Point to the flex stack base
+               LDR     R4,flex__relocSP        ;Load the current stack ptr
+
+               ; --- Go through all the stack entries ---
+
+00flex__reloc  CMP     R3,R4                   ;Have we reached the end?
+               LDMGEFD R13!,{R3,R4,PC}^        ;Yes -- return to caller
+               LDR     R14,[R3],#4             ;Load the saved value
+               SUB     R14,R14,R1              ;Subtract the source base
+               CMP     R14,R2                  ;Is value within block?
+               ADDLO   R14,R14,R0              ;Yes -- add the destination
+               STRLO   R14,[R3,#-4]            ;Store pointer if it changed
+               B       %00flex__reloc          ;And go round for the rest
+
+               LTORG
+
+       ]
+
+; --- flex_dump ---
+
+       [ OPT_DUMP
+
+               EXPORT  flex_dump
+flex_dump      ROUT
+
+               STMFD   R13!,{R0-R12,R14}
+               SWI     XOS_NewLine
+               SWI     XOS_NewLine
+               SWI     XOS_Write0
+               SWI     XOS_NewLine
+
+               LDR     R11,=flex__data
+               LDR     R5,[R11,#flex__base]
+               LDR     R6,[R11,#flex__free]
+               LDR     R7,[R11,#flex__end]
+
+               SWI     XOS_WriteS
+               DCB     "Heap base: ",0
+               MOV     R0,R5
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10,"Heap free area: ",0
+               MOV     R0,R6
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10,"Heap end: ",0
+               MOV     R0,R7
+               BL      writeHex
+
+00             CMP     R5,R6
+               LDMGEFD R13!,{R0-R12,PC}^
+
+               SWI     XOS_WriteS
+               DCB     13,10,10,"Block address: ",0
+               MOV     R0,R5
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10,"  Size: ",0
+               LDR     R0,[R5,#flex__size]
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10,"  Anchor: ",0
+               LDR     R0,[R5,#flex__bkanchor]
+               BL      writeHex
+               LDR     R0,[R5,#flex__size]
+               ADD     R0,R0,#flex__ohead+7
+               BIC     R0,R0,#7
+               ADD     R5,R5,R0
+               B       %00
+
+writeHex       STMFD   R13!,{R1,R2,R14}
+               SUB     R1,R13,#256
+               MOV     R2,#256
+               SWI     XOS_ConvertHex8
+               SWI     XOS_Write0
+               LDMFD   R13!,{R1,R2,PC}^
+
+writeDec       STMFD   R13!,{R1,R2,R14}
+               SUB     R1,R13,#256
+               MOV     R2,#256
+               SWI     XOS_ConvertInteger4
+               SWI     XOS_Write0
+               LDMFD   R13!,{R1,R2,PC}^
+
+               LTORG
+
+       ]
+
+;----- Workspace ------------------------------------------------------------
+
+; --- Flags ---
+
+fFlag__inited  EQU     (1<<0)                  ;We are currently running
+fFlag__compact EQU     (1<<1)                  ;The heap is compact ATM
+
+       [ OPT_DYNAREA
+fFlag__dynArea EQU     (1<<2)                  ;Using a dynamic area
+       ]
+
+; --- Flex block format ---
+
+               ^       0
+flex__bkanchor #       4                       ;Back-pointer to flex anchor
+flex__size     #       4                       ;Size of this flex block
+flex__ohead    #       0                       ;The flex overhead on blocks
+
+; --- Static data ---
+
+       [ :LNOT:OPT_STANDALONE
+
+               ^       0,R12
+flex__wStart   #       0
+
+       [ OPT_DYNAREA
+               GBLL    FLEXWS_DYNAREA
+       ]
+
+       [ OPT_STACK
+               GBLL    FLEXWS_STACK
+       ]
+
+               GET     libs:sh.flexws
+
+flex__wSize    EQU     {VAR}-flex__wStart
+
+       ]
+
+       [ OPT_SAPPHIRE
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+               DCD     flex__wSize
+               DCD     flex__wSpace
+               DCD     0
+               DCD     flex_init
+       ]
+
+       [ OPT_APCS
+               AREA    |C$$zidata|,DATA,NOINIT
+flex__sSpace   %       flex__wSize
+       ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/s/heap b/StraySrc/Libraries/Core/s/heap
new file mode 100644 (file)
index 0000000..72230a3
--- /dev/null
@@ -0,0 +1,840 @@
+;
+; heap.s
+;
+; A resizing, nonshifting heap (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's heap.
+;
+; Heap is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Heap is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Heap.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- New unified version --------------------------------------------------
+;
+; I'm finally fed up of maintaining two different versions of this code.
+; From now on, there is only this one.
+;
+; Lots of options are supported:
+;
+; OPT_APCS     Generate an APCS-compatible version
+; OPT_SAPPHIRE Generate a Sapphire-compatible version
+; OPT_STANDALONE Build a standalone assembler version (default)
+; OPT_DLL      Generate absolute address relocation for DLL code
+;
+;                                                              [mdw]
+
+;----- Set up some options --------------------------------------------------
+
+               MACRO
+               DCLOPT  $var
+               [       :DEF:$var
+$var           SETL    {TRUE}
+               |
+               GBLL    $var
+$var           SETL    {FALSE}
+               ]
+               MEND
+
+               DCLOPT  OPT_APCS
+               DCLOPT  OPT_SAPPHIRE
+               DCLOPT  OPT_STANDALONE
+               DCLOPT  OPT_DLL
+
+       [ :LNOT:OPT_APCS:LAND::LNOT:OPT_SAPPHIRE:LAND::LNOT:OPT_STANDALONE
+               GBLL    OPT_STANDALONE
+OPT_STANDALONE SETL    {TRUE}
+       ]
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+       [ OPT_SAPPHIRE
+               GET     sapphire:alloc
+               GET     sapphire:flex
+               GET     sapphire:msgs
+               GET     sapphire:fastMove
+               GET     sapphire:sapphire
+       |
+               IMPORT  fastMove
+               IMPORT  flex_init
+               IMPORT  flex_alloc
+               IMPORT  flex_extend
+       ]
+
+;----- Workspace macros -----------------------------------------------------
+
+       [ OPT_APCS
+
+               MACRO
+$label         WSPACE  $addr,$reg
+               LCLS    r
+               [       "$reg"=""
+r              SETS    "R12"
+               |
+r              SETS    "$reg"
+               ]
+               ALIGN
+$label
+               LDR     $r,$addr
+               [       OPT_DLL
+               LDR     R14,[R10,#-536]
+               ADD     $r,R14,$r
+               ]
+               MEND
+
+       ]
+
+;----- External routines ----------------------------------------------------
+
+       [ OPT_SAPPHIRE
+               AREA    |Sapphire$$Code|,CODE,READONLY
+       ]
+       [ OPT_APCS
+               AREA    |C$$Code|,CODE,READONLY
+       ]
+       [ OPT_STANDALONE
+               AREA    |Straylight$$Code|,CODE,READONLY
+       ]
+
+; --- heap_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the heap system for use.
+
+               EXPORT  heap_init
+
+heap_init      ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Stash some registers
+               WSPACE  heap__wSpace            ;Find my workspace
+
+       [ OPT_SAPPHIRE
+               BL      msgs_init               ;Make sure msgs is going
+       ]
+               BL      flex_init               ;Make sure flex is up
+
+       [ :LNOT:OPT_STANDALONE
+
+               ; --- Ensure I'm not already initialised ---
+
+               LDR     R0,heap__flex           ;Get my flex pointer
+               CMP     R0,#0                   ;Is it a silly value?
+               LDMNEFD R13!,{R0,R1,R12,PC}^    ;Yes -- return now
+
+       ]
+
+               ; --- Read the machine chunk size ---
+
+               SWI     OS_ReadMemMapInfo       ;Get page size (in R0)
+               STR     R0,heap__chunkSize      ;Store for future reference
+
+               ; --- Allocate the base flex block ---
+
+               SUB     R1,R0,#8                ;Need to allocate memory
+               ADR     R0,heap__flex           ;Point to flex anchor
+               BL      flex_alloc              ;Hope it worked
+       [ OPT_APCS
+               CMP     R0,#0                   ;Check the result code
+               BEQ     %99heap_init            ;If it failed, go ahead
+       |
+               BCS     %99heap_init            ;If it failed, go ahead
+       ]
+
+               ; --- Initialise the rest of the workspace ---
+
+               MOV     R0,#0
+               STR     R0,heap__alloced
+               MOV     R0,#-1
+               STR     R0,heap__freeList
+               LDR     R0,heap__chunkSize
+               SUB     R0,R0,#8
+               STR     R0,heap__size
+               LDMFD   R13!,{R0,R1,R12,PC}^
+
+99heap_init    ADR     R0,heap__nomem          ;Point to the error block
+       [ OPT_SAPPHIRE
+               BL      msgs_error              ;Translate the message
+       ]
+               SWI     OS_GenerateError        ;And really moan about it
+
+heap__nomem    DCD     1
+       [ OPT_SAPPHIRE
+               DCB     "hpNEMI",0
+       |
+               DCB     "Not enough memory to build heap",0
+       ]
+               ALIGN
+
+       [ OPT_SAPPHIRE
+heap__wSpace   DCD     0
+       ]
+
+       [ OPT_APCS
+heap__wSpace   DCD     heap__sSpace
+       ]
+
+               LTORG
+
+       [ OPT_SAPPHIRE
+
+; --- heap_useHeap ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Registers the resizing heap as the current allocator.
+
+               EXPORT  heap_useHeap
+heap_useHeap   ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADR     R0,heap_alloc           ;Point to the allocator
+               ADR     R1,heap_free            ;And to the freer
+               MOV     R2,#0                   ;Don't care about workspace
+               BL      alloc_register          ;Make heap the allocator
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+       ]
+
+; --- heap_info ---
+;
+; On entry:    R0 == pointer to structure to fill in (APCS)
+;
+; On exit:     R0 == current heap size (Sapphire)
+;              R1 == amount of memory free in the heap (Sapphire)
+;              R2 == size of the largest block free (Sapphire)
+;
+; Use:         Describes the heap's current status.
+
+               EXPORT  heap_info
+heap_info      ROUT
+
+       [ OPT_APCS
+               STMFD   R13!,{R4,R5,R12,R14}
+               WSPACE  heap__wSpace
+               MOV     R5,R0
+       |
+               STMFD   R13!,{R3,R4,R12,R14}
+               WSPACE  heap__wSpace
+       ]
+
+               ; --- Set up some registers ---
+
+               LDR     R0,heap__size           ;Get size of heap
+
+               LDR     R4,heap__flex           ;Pointer to the heap
+               LDR     R14,heap__freeList      ;Offset to first free block
+               LDR     R2,heap__alloced        ;Length of allocated region
+               SUB     R1,R0,R2                ;This area is free
+               MOV     R2,R1                   ;Largest block found yet
+
+               ; --- Now we can proceed through the loop ---
+
+00heap_info    CMP     R14,#-1                 ;Is this the end of the list?
+               BEQ     %01heap_info            ;Yes - wrap things up nicely
+               ADD     R14,R14,R4              ;Convert to a pointer
+               LDR     R3,[R14,#0]             ;Get the length of this block
+               ADD     R1,R1,R3                ;Add to free size
+               CMP     R3,R2                   ;Is it the biggest one yet?
+               MOVGT   R2,R3                   ;Yes - remember it
+               LDR     R14,[R14,#4]            ;Get next offset
+               B       %00heap_info            ;And loop round again
+
+               ; --- Now return this information ---
+
+       [ OPT_APCS
+01heap_info    STMIA   R5,{R0-R2}
+               LDMFD   R13!,{R4,R5,R12,PC}^
+       |
+01heap_info    LDMFD   R13!,{R3,R4,R12,PC}^    ;Return to caller
+       ]
+
+               LTORG
+
+; --- heap_alloc ---
+;
+; On entry:    R0 == size of block wanted
+;
+; On exit:     Sapphire: CC if enough memory, R0 == address; CS if no
+;                      memory, R0 corrupted
+;              APCS: R0 == pointer to memory, or zero if not enough
+;
+; Use:         Allocates a block of at least a given size from a heap.  If
+;              the heap is not big enough, more is claimed from the
+;              operating system.
+
+               EXPORT  heap_alloc
+heap_alloc     ROUT
+
+               ; --- Make sure there's something to do ---
+
+               CMP     R0,#0                   ;Is the required size 0?
+               MOVEQS  PC,R14                  ;Yes -- return a NULL pointer
+
+               ; --- Start everything up then ---
+
+       [ :LNOT:OPT_APCS
+               BIC     R14,R14,#C_flag
+       ]
+               STMFD   R13!,{R1-R6,R12,R14}    ;Save a load of registers
+               WSPACE  heap__wSpace
+
+               ; --- First, set up parameters ---
+
+               ADD     R0,R0,#11               ;Add overhead and align to
+               BIC     R0,R0,#7                ; multiple of 8
+
+               ; --- Initialise for a loop through the free list ---
+
+               LDR     R6,heap__flex           ;Point to heap start
+               MOV     R5,#-1                  ;Previous block
+               LDR     R4,heap__freeList       ;Point to free list to scan
+
+               ; --- This is the free list scanning loop ---
+
+00heap_alloc   CMP     R4,#-1                  ;Is this the end?
+               BEQ     %02heap_alloc           ;Yes - try unallocated region
+               ADD     R4,R4,R6                ;Translate offset to address
+               LDR     R1,[R4,#0]              ;Get length word
+               CMP     R1,R0                   ;Check sizes
+               MOVCC   R5,R4                   ;Too small - set up prev ptr
+               LDRCC   R4,[R4,#4]              ;Get next pointer
+               BCC     %00heap_alloc           ;And try next block
+
+               ; --- If block is right size, remove from the chain ---
+
+               LDREQ   R2,[R4,#4]              ;Get next offset
+               ADDEQ   R2,R2,R6                ;Translate to address
+               BEQ     %01heap_alloc           ;And branch ahead
+
+               ; --- Now, we try to hack off the bit we need ---
+
+               STR     R0,[R4,#0]              ;Store block's new length
+               ADD     R2,R0,R4                ;R2 points to next block
+               SUB     R3,R1,R0                ;Space left in this block
+               STR     R3,[R2,#0]              ;Store in length field
+               LDR     R3,[R4,#4]              ;Now get next pointer
+               STR     R3,[R2,#4]              ;Store.
+
+               ; --- Now put in link from previous block and return ---
+
+01heap_alloc   SUB     R2,R2,R6                ;Translate back to an offset
+               CMP     R5,#-1                  ;Is there a previous block?
+               STRNE   R2,[R5,#4]              ;Store in previous block
+               STREQ   R2,heap__freeList       ;No - stick it in the front
+               ADD     R0,R4,#4                ;Leave out the length field
+               LDMFD   R13!,{R1-R6,R12,PC}^    ;And return to caller
+
+               ; --- Check the free area is big enough for the block ---
+
+02heap_alloc   LDR     R4,heap__alloced        ;Offset to free area
+               LDR     R5,heap__size           ;Current size of heap
+               ADD     R6,R4,R0                ;How big the area needs to be
+               CMP     R5,R6                   ;Is this sufficient?
+               BCS     %03heap_alloc           ;Yes - allocate block
+
+               ; --- We need more memory in the heap.  Call flex for it ---
+
+               MOV     R5,R0                   ;Preserve the caller's length
+               LDR     R1,heap__chunkSize      ;Units of allocation
+               SUB     R1,R1,#1                ;For alignment purposes
+               ADD     R6,R6,#8
+               ADD     R6,R6,R1                ;First step in alignment
+               BIC     R6,R6,R1                ;Second step
+               SUB     R6,R6,#8
+               ADR     R0,heap__flex           ;Point to anchor
+               MOV     R1,R6                   ;New size we want
+               BL      flex_extend             ;Try to get memory
+       [ OPT_APCS
+               CMP     R0,#0                   ;If it failed,
+               LDMEQFD R13!,{R1-R6,R12,PC}^    ;Return a null pointer
+       |
+               LDMCSFD R13!,{R1-R6,R12,R14}    ;If it failed, return with...
+               ORRCSS  PC,R14,#C_flag          ;...carry set
+       ]
+               STR     R6,heap__size           ;Store new heap size
+               MOV     R0,R5                   ;Restore the desired length
+
+               ; --- Now allocate a block from the free area properly ---
+
+03heap_alloc   LDR     R1,heap__flex           ;Point to start of heap
+               ADD     R2,R4,R1                ;R2 points to new block
+               STR     R0,[R2,#0]              ;Store the length
+               ADD     R4,R4,R0                ;Get new free offset
+               STR     R4,heap__alloced        ;Store permanently
+               ADD     R0,R2,#4                ;Point to free part of block
+               LDMFD   R13!,{R1-R6,R12,PC}^    ;Return flushed with success
+
+               LTORG
+
+; --- heap_free ---
+;
+; On entry:    R0 == pointer to a block created with heap_alloc
+;
+; On exit:     --
+;
+; Use:         Frees a block allocated using heap_alloc.  It tries to
+;              shrink the heap as much as possible afterwards.
+
+               EXPORT  heap_free
+heap_free      ROUT
+
+               ; --- Make sure the user's not being stupid ---
+
+               CMP     R0,#0
+               MOVEQS  PC,R14
+
+               ; --- Proceed as normal ---
+
+               STMFD   R13!,{R0-R8,R12,R14}
+               WSPACE  heap__wSpace
+
+               ; --- Scan the free list ---
+               ;
+               ; Now first we run through the free list trying to find
+               ; a free block (a) immediately before the current one and
+               ; (b) immediately after the current one.
+
+               SUB     R5,R0,#4                ;Point to real block start
+               LDR     R6,[R5,#0]              ;Get length of block
+               ADD     R6,R5,R6                ;R6 points off end of block
+               MOV     R7,#-1                  ;Haven't found preblock
+               MOV     R8,#-1                  ;Haven't found postblock
+               LDR     R4,heap__flex           ;Pointer to start of heap
+               MOV     R1,#0                   ;Previous block in the chain
+               LDR     R0,heap__freeList       ;Scan the free list
+
+               ; --- Now do the scanning loop ---
+
+00heap_free    CMP     R0,#-1                  ;Have we reached the end?
+               BEQ     %01heap_free            ;Yes - free the block
+               ADD     R0,R0,R4                ;Convert to a pointer
+               CMP     R0,R6                   ;Could this be postblock?
+               MOVEQ   R8,R1                   ;Yes - remember
+               LDR     R2,[R0,#0]              ;Get length
+               ADD     R2,R0,R2                ;R2 points past that block
+               CMP     R2,R5                   ;Is this preblock?
+               MOVEQ   R7,R1                   ;Yes - remember
+               MOV     R1,R0                   ;Shift prev block along
+               LDR     R0,[R0,#4]              ;And get next block in list
+               B       %00heap_free            ;Loop round until finished
+
+               ; --- Now try and coagulate the blocks ---
+
+01heap_free    CMP     R7,#-1                  ;Did we find preblock?
+               BEQ     %02heap_free            ;No - try postblock
+               CMP     R7,#0                   ;Is it the first block?
+               LDREQ   R0,heap__freeList       ;Yes - get offset
+               LDRNE   R0,[R7,#4]              ;No - get offset (!)
+               ADD     R0,R0,R4                ;Convert to a pointer
+               LDR     R1,[R0,#0]              ;Get block length
+               LDR     R2,[R5,#0]              ;Get length of block to free
+               ADD     R1,R1,R2                ;Add them together
+               STR     R1,[R0,#0]              ;Store back in block
+               LDR     R1,[R0,#4]              ;Get next block offset
+               CMP     R7,#0                   ;Is there a previous block?
+               STREQ   R1,heap__freeList       ;No - start the list with it
+               STRNE   R1,[R7,#4]              ;Yes - link in as normal
+               MOV     R5,R0                   ;This is the block to free
+
+               CMP     R8,R0                   ;Is this prev to postblock?
+               MOVEQ   R8,R7                   ;Yes - show we've delinked
+
+02heap_free    CMP     R8,#-1                  ;Did we find postblock?
+               BEQ     %03heap_free            ;No - free the block
+               CMP     R8,#0                   ;Is it the first block?
+               LDREQ   R0,heap__freeList       ;Yes - get offset
+               LDRNE   R0,[R8,#4]              ;No - get offset (!)
+               ADD     R0,R0,R4                ;Convert to a pointer
+               LDR     R1,[R0,#0]              ;Get block length
+               LDR     R2,[R5,#0]              ;Get length of block to free
+               ADD     R1,R1,R2                ;Add them together
+               STR     R1,[R5,#0]              ;Store back in block
+               LDR     R1,[R0,#4]              ;Get next block offset
+               CMP     R8,#0                   ;Is there a previous block?
+               STREQ   R1,heap__freeList       ;No - start the list with it
+               STRNE   R1,[R8,#4]              ;Yes - link in as normal
+
+               ; --- Now we try to reduce the allocated area ---
+
+03heap_free    LDR     R0,heap__alloced        ;Find end of allocated area
+               ADD     R1,R0,R4                ;Convert to a pointer
+               LDR     R2,[R5,#0]              ;Get length of our block
+               ADD     R3,R5,R2                ;Find the end of it
+               CMP     R3,R1                   ;Are they the same?
+               BNE     %04heap_free            ;No - old-fashioned method!
+               SUB     R0,R0,R2                ;Reduce the allocated region
+               STR     R0,heap__alloced        ;Remember this!
+               LDR     R1,heap__chunkSize      ;Get the chunk size
+               SUB     R1,R1,#1                ;More useful like this!
+               ADD     R0,R0,#8
+               ADD     R0,R0,R1                ;Alignment step 1
+               BIC     R7,R0,R1                ;Alignment step 2
+               SUB     R7,R7,#8
+               LDR     R2,heap__size           ;Get current heap size
+               CMP     R7,R2                   ;Are they the same?
+               LDMGEFD R13!,{R0-R8,R12,PC}^    ;Yes - nothing doing
+               ADR     R0,heap__flex           ;Point to flex anchor
+               MOV     R1,R7                   ;New size for block
+               BL      flex_extend             ;Try and reduce
+       [ OPT_APCS
+               CMP     R0,#0                   ;Did it fail (unlikely!)
+               STRNE   R7,heap__size           ;No - remember new size
+       |
+               STRCC   R7,heap__size
+       ]
+               LDMFD   R13!,{R0-R8,R12,PC}^    ;Return to sender
+
+               ; --- Now use the old fashioned method to link the block ---
+
+04heap_free    LDR     R0,heap__freeList       ;Get current first free block
+               STR     R0,[R5,#4]              ;Store in our block
+               SUB     R5,R5,R4                ;Turn back into an offset
+               STR     R5,heap__freeList       ;Store as new first free
+               LDMFD   R13!,{R0-R8,R12,PC}^    ;Return to sender
+
+               LTORG
+
+; --- heap_reAlloc ---
+;
+; On entry:    R0 == pointer to block whose size we want to change
+;              R1 == the new size of the block
+;
+; On exit:     Sapphire: CC and R0 == pointer to block if OK, CS if no mem
+;              APCS: R0 == pointer to block if OK, or null if no mem
+;
+; Use:         Changes the size of a heap block.  If possible, the block's
+;              position is unchanged, but this may not always be the case.
+;
+;              Note that changing a block's size to 0 is permitted.
+
+               EXPORT  heap_reAlloc
+               EXPORT  heap_realloc
+heap_reAlloc   ROUT
+heap_realloc
+
+               ; --- Some ANSI-compatible checks on the parameters ---
+
+               CMP     R0,#0                   ;If the pointer is NULL...
+               MOVEQ   R0,R1                   ;This should just do a malloc
+               BEQ     heap_alloc
+
+       [ :LNOT:OPT_APCS
+               BIC     R14,R14,#C_flag         ;Clr carry flag on offchance
+       ]
+               STMFD   R13!,{R1-R8,R12,R14}
+
+               CMP     R1,#0                   ;If new size is NULL
+               BLEQ    heap_free               ;This should just free it
+               MOVEQ   R0,#0                   ;Return a NULL pointer
+               LDMEQDB R13!,{R1-R8,R12,PC}^    ;And return to caller
+
+               ; --- First set things up nicely ---
+               ;
+               ; Make sure we actually have to do anything.
+
+               WSPACE  heap__wSpace            ;Get global heap data
+               ADD     R6,R1,#11               ;Add 4 bytes length and align
+               BIC     R6,R6,#7                ;to a multiple of 8
+               SUB     R5,R0,#4                ;Point to length word
+               LDR     R7,[R5,#0]              ;Get the length word
+               CMP     R7,R6                   ;Do we have to do any work?
+               LDMEQDB R13!,{R1-R8,R12,PC}^    ;No - don't then!
+
+               ; --- Try for some easy cases ---
+               ;
+               ; If this block is at the end of the allocated area, we
+               ; can just extend this area and the block size.  So check
+               ; for this case.
+
+               ADD     R2,R5,R7                ;Find end of the block
+               LDR     R8,heap__alloced        ;Offset of free space
+               LDR     R4,heap__flex           ;Pointer to start of heap
+               ADD     R3,R8,R4                ;Convert offset to pointer
+               CMP     R2,R3                   ;Are they the same?
+               BNE     %02heap_reAlloc         ;No - deal with other case
+
+               ; --- Just extend the area then ---
+               ;
+               ; Now we shall need to make sure that the free area is big
+               ; enough (or maybe reduce it!)  This may, of course, fail.
+
+               SUB     R8,R8,R7                ;Remove the original length
+               ADD     R8,R8,R6                ;And add the new length
+               ADD     R4,R8,#8                ;Add on flex's two words
+               LDR     R0,heap__chunkSize      ;Get the chunk size
+               SUB     R0,R0,#1                ;For aligning purposes
+               ADD     R4,R4,R0                ;Alignment step 1
+               BIC     R4,R4,R0                ;Alignment step 2
+               SUB     R4,R4,#8                ;Remove flex's words again
+               LDR     R0,heap__size           ;Find the heap's size
+               CMP     R0,R4                   ;How different are they?
+               BEQ     %00heap_reAlloc         ;If they're the same, no prob
+               ADR     R0,heap__flex           ;Point to block anchor
+               MOV     R1,R4                   ;Set up new size
+               BL      flex_extend             ;Try and change block size
+       [ OPT_APCS
+               CMP     R0,#0                   ;Did it fail?
+               BEQ     %01heap_reAlloc         ;Yes - try some other way
+       |
+               BCS     %01heap_reAlloc         ;Failed - try some other way
+       ]
+
+00heap_reAlloc STR     R4,heap__size           ;Remember new size
+               STR     R8,heap__alloced        ;And new free offset
+               STR     R6,[R5,#0]              ;Store new length
+               ADD     R0,R5,#4                ;Set up return pointer
+               B       %80heap_reAlloc         ;Return the pointer back
+
+               ; --- Try fiddling around inside the heap block ---
+               ;
+               ; This sets up all the registers again
+
+01heap_reAlloc LDR     R2,[R5,#0]              ;Get block length
+               ADD     R2,R5,R2                ;Point to end of block
+               LDR     R4,heap__flex           ;Point to heap base
+
+               ; --- It wasn't at the end ---
+               ;
+               ; Now, if the caller wants to reduce the block size, we can
+               ; manage that.
+
+02heap_reAlloc SUBS    R1,R7,R6                ;Is the old size bigger?
+               BLT     %03heap_reAlloc         ;No - we'll struggle on
+               ADD     R0,R5,R6                ;Point to end of (new) block
+               STR     R1,[R0,#0]              ;Store in there
+               STR     R6,[R5,#0]              ;Store also new size in block
+               ADD     R0,R0,#4                ;Point to second block
+               BL      heap_free               ;Attach in free chain
+               ADD     R0,R5,#4                ;Setup return pointer
+               B       %80heap_reAlloc         ;And return to the caller
+
+               ; --- We're extending the block ---
+               ;
+               ; Loop through, finding either preblock or postblock (as for
+               ; freeing).  If we can, merge these three together, and then
+               ; hope the result is big enough.
+               ;
+               ; At this point, some register usage notes might be handy:
+               ;
+               ;   R2 -> end of block
+               ;   R4 -> start of heap
+               ;   R5 -> block to resize
+               ;   R6 == new size wanted
+               ;
+               ; We will use:
+               ;
+               ;   R0 -> preblock
+               ;   R1 -> postblock
+               ;   R3 -> list ptr
+               ;
+               ; R7 will be previous block, R8 will be used as scratch
+               ; space
+               ;
+               ; So, onwards ever...
+
+03heap_reAlloc LDR     R3,heap__freeList       ;Set up list pointer
+               MOV     R0,#-1                  ;No preblock
+               MOV     R1,#-1                  ;Or postblock found yet
+               MOV     R7,#0                   ;Previous block invalid
+
+               ; --- Now for the loop ---
+
+04heap_reAlloc CMP     R3,#-1                  ;Is this the end?
+               BEQ     %05heap_reAlloc         ;Try and join the blocks
+               ADD     R3,R3,R4                ;Convert to an address
+               CMP     R3,R2                   ;Is this postblock?
+               MOVEQ   R0,R7                   ;Yes - remember it
+               LDR     R8,[R3,#0]              ;Get size of this block
+               ADD     R8,R3,R8                ;And point to the end
+               CMP     R5,R8                   ;Is this preblock?
+               MOVEQ   R1,R7                   ;Yes - remember
+               MOV     R7,R3                   ;Move previous pointer on
+               LDR     R3,[R3,#4]              ;Get next one in the list
+               B       %04heap_reAlloc         ;Loop round for another go
+
+               ; --- Now find out if it will help to join the blocks up ---
+
+05heap_reAlloc LDR     R2,[R5,#0]              ;Current size
+               CMP     R0,#-1                  ;Did we find preblock?
+               BEQ     %06heap_reAlloc         ;No - try postblock
+               CMP     R0,#0                   ;Is it first block in list?
+               LDREQ   R3,heap__freeList       ;Yes - get offset
+               LDRNE   R3,[R0,#4]              ;No - get offset (!)
+               LDR     R7,[R3,#0]              ;Get its size
+               ADD     R2,R2,R7                ;Add it onto our total
+06heap_reAlloc CMP     R1,#-1                  ;Did we find postblock?
+               BEQ     %07heap_reAlloc         ;No - check the total
+               CMP     R1,#0                   ;Is it first block in list?
+               LDREQ   R3,heap__freeList       ;Yes - get offset
+               LDRNE   R3,[R1,#4]              ;No - get offset (!)
+               LDR     R7,[R3,#0]              ;Get its size
+               ADD     R2,R2,R7                ;Add it onto our total
+07heap_reAlloc CMP     R2,R6                   ;Is this big enough?
+               BCC     %11heap_reAlloc         ;No -- do it the hard way
+
+               ; --- Now try and join on preblock ---
+               ;
+               ; Note - this is almost the same as the heap_free code, but
+               ; with different registers)
+
+08heap_reAlloc CMP     R0,#-1                  ;Did we find preblock?
+               BEQ     %09heap_reAlloc         ;No - try postblock
+               CMP     R0,#0                   ;Is it first block in list?
+               LDREQ   R3,heap__freeList       ;Yes - get offset
+               LDRNE   R3,[R0,#4]              ;No - get offset (!)
+               ADD     R3,R3,R4                ;Convert offset to pointer
+               LDR     R7,[R3,#0]              ;Get the length of the block
+               LDR     R8,[R5,#0]              ;Length of block to resize
+               ADD     R7,R7,R8                ;Add them together
+               STR     R7,[R3,#0]              ;Store the combined length
+               LDR     R7,[R3,#4]              ;Get next block in list
+               CMP     R0,#0                   ;Is there a previous block?
+               STREQ   R7,heap__freeList       ;No - start the list with it
+               STRNE   R7,[R0,#4]              ;Yes - link in as normal
+
+               ; --- Now shift the data down into the bigger block ---
+
+               STMFD   R13!,{R0-R3}            ;Store registers
+               ADD     R0,R3,#4                ;Destination data start
+               ADD     R1,R5,#4                ;Source destination start
+               LDR     R2,[R5,#0]              ;Size of the source block
+               SUBS    R2,R2,#4                ;We don't need to copy this
+               BLNE    fastMove                ;Does the Right Thing when
+                                               ;the blocks overlap
+               LDMFD   R13!,{R0-R3}            ;Restore our registers
+
+               ; --- Some fiddling before handling postblock ---
+
+               MOV     R5,R3                   ;This is now block to size
+
+               CMP     R1,R3                   ;Is this prev to postblock?
+               MOVEQ   R1,R0                   ;Yes - show we've delinked
+
+               ; --- Now process postblock in the same way ---
+
+09heap_reAlloc CMP     R1,#-1                  ;Did we find postblock?
+               BEQ     %10heap_reAlloc         ;No - try and resize
+               CMP     R1,#0                   ;Is it first block in list?
+               LDREQ   R3,heap__freeList       ;Yes - get offset
+               LDRNE   R3,[R1,#4]              ;No - get offset (!)
+               ADD     R3,R3,R4                ;Convert offset to pointer
+               LDR     R7,[R3,#0]              ;Get the length of the block
+               LDR     R8,[R5,#0]              ;Length of block to resize
+               ADD     R7,R7,R8                ;Add them together
+               STR     R7,[R5,#0]              ;Store the combined length
+               LDR     R7,[R3,#4]              ;Get next block in list
+               CMP     R0,#0                   ;Is there a previous block?
+               STREQ   R7,heap__freeList       ;No - start the list with it
+               STRNE   R7,[R0,#4]              ;Yes - link in as normal
+
+               ; --- Now take off the bit we need ---
+               ;
+               ; We've already checked that it's big enough).  We do the
+               ; freeing ourselves, to avoid a pointless loop in heap_free
+
+10heap_reAlloc LDR     R7,[R5,#0]              ;Get the new length
+               SUB     R1,R7,R6                ;Get difference in sizes
+               ADD     R0,R5,R6                ;Point to end of (new) block
+               STR     R1,[R0,#0]              ;Store in there
+               STR     R6,[R5,#0]              ;Store also new size in block
+               LDR     R1,heap__freeList       ;Get the first block in list
+               STR     R1,[R0,#4]              ;Store in the new free block
+               SUB     R0,R0,R4                ;Convert pointer to an offset
+               STR     R0,heap__freeList       ;It's now linked in
+               ADD     R0,R5,#4                ;Setup return pointer
+               B       %80heap_reAlloc         ;Return to caller nicely
+
+               ; --- Well, we did our best ---
+               ;
+               ; All we can do now is to try and allocate a new block, copy
+               ; the data, and free the old one, causing massive
+               ; fragmentation :-(
+
+11heap_reAlloc SUB     R0,R6,#4                ;Size of block for heap_alloc
+               BL      heap_alloc              ;Try and allocate
+       [ OPT_APCS
+               CMP     R0,#0                   ;Did it fail?
+               BEQ     %90heap_reAlloc         ;Yes -- then return null
+       |
+               BCS     %90heap_reAlloc         ;Failed -- return C set
+       ]
+               MOV     R7,R0                   ;Remeber this pointer
+               ADD     R1,R5,#4                ;Source of data to copy
+               LDR     R2,[R5,#0]              ;Length of stuff to copy
+               SUBS    R2,R2,#4                ;Remove length word first
+               BLNE    fastMove                ;Move the data across
+               ADD     R0,R5,#4                ;Now free the old block
+               BL      heap_free               ;Do the freeing business
+               MOV     R0,R7                   ;Give caller his pointer
+
+               ; --- Return, preserving R0 to give to the caller ---
+
+80heap_reAlloc LDMFD   R13!,{R1-R8,R12,PC}^
+
+               ; --- Return, setting the C flag ---
+
+       [ OPT_APCS
+90heap_reAlloc MOV     R0,#0
+               LDMFD   R13!,{R1-R8,R12,PC}^
+       |
+90heap_reAlloc LDMFD   R13!,{R1-R8,R12,R14}
+               ORRS    PC,R14,#C_flag
+       ]
+
+               LTORG
+
+;----- Data definitions -----------------------------------------------------
+
+       [ :LNOT:OPT_STANDALONE
+
+               ^       0,R12
+heap__wStart   #       0
+
+               GET     libs:sh.heapws
+
+heap__wSize    EQU     {VAR}-heap__wStart
+
+       ]
+
+       [ OPT_SAPPHIRE
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+               DCD     heap__wSize
+               DCD     heap__wSpace
+               DCD     0
+               DCD     heap_init
+       ]
+
+       [ OPT_APCS
+               AREA    |C$$zidata|,DATA,NOINIT
+heap__sSpace   %       heap__wSize
+       ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/s/oxswi b/StraySrc/Libraries/Core/s/oxswi
new file mode 100644 (file)
index 0000000..4e2f691
--- /dev/null
@@ -0,0 +1,163 @@
+;
+; oxswi.s
+;
+; Original version of _swi[x] SWI veneers
+;
+; © 1994 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's C library stubs (xstubs).
+;
+; xstubs is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; xstubs is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with xstubs.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |C$$code|,CODE,READONLY
+
+; --- _swi, _swix ---
+;
+; On entry:    R0 == SWI number
+;              R1 == flags
+;              R2,R3 == arguments
+;              More arguments on stack
+;
+; On exit:     R0 == output register, if any
+;
+; Use:         Generalised SWI veneer, compatible with Acorn's latest.
+
+               EXPORT  |_swi|
+               EXPORT  |_swix|
+
+swi            ROUT
+
+|_swi|         MOV     R12,R13                 ;Keep stack pointer safe
+               STMFD   R13!,{R2,R3}            ;Save variadic args on stack
+               STMFD   R13!,{R4-R12,R14}       ;Save loads of other regs
+               ADR     R10,%20swi              ;Go to the SWI return pt
+               B       %00swi                  ;Do the main job thing
+
+|_swix|                MOV     R12,R13                 ;Keep stack pointer safe
+               STMFD   R13!,{R2,R3}            ;Save variadic args on stack
+               STMFD   R13!,{R4-R12,R14}       ;Save loads of other regs
+               ORR     R0,R0,#&20000           ;Set the SWI's X bit
+               BIC     R1,R1,#&000F0000        ;Make it return R0
+               ADR     R10,%10swi              ;Go to the SWIX return pt
+
+               ; --- Build entry stack frame ---
+
+00swi          MOV     R2,R1,LSL #22           ;Get the input registers
+               MOVS    R2,R2,LSR #22
+               ORRNE   R2,R2,#&E8000000        ;Build that as an LDMIA
+               ORRNE   R2,R2,#&00BC0000        ;Based on R12 (ip)
+
+               ANDS    R3,R1,#&800             ;Does he want a local block?
+               BLNE    %80swi                  ;Yes -- better find it then
+
+               ORR     R4,R0,#&EF000000        ;Build the SWI instruction
+
+               MOV     R6,#&E1000000           ;Build a MOV skeleton
+               ORR     R6,R6,#&00A00000
+
+               AND     R5,R1,#&000F0000        ;Get return register value
+               ORR     R5,R6,R5,LSR #16        ;Put in the source register
+               ORR     R5,R5,#&0000E000        ;Put in destination
+
+               ORR     R6,R6,#&0000F000        ;Set up return instruction
+               ORR     R6,R6,#&0000000A
+
+               SUB     R12,R12,#8              ;Find variadic arguments
+               STMFD   R13!,{R2-R6}            ;Build SWI-calling frame
+
+               BARRIER
+               MOV     R11,R1                  ;Look after the flags word
+               MOV     PC,R13                  ;And call the stack code
+
+               ; --- Process a return from the SWI ---
+
+10swi          MOVVC   R14,#0                  ;If no error, return 0
+20swi          STR     PC,[R13,#0]             ;Save my program counter
+
+               ; --- Output the output registers ---
+
+               MOVS    R11,R11,LSL #1          ;Shift bits to C and N
+               LDRCS   R10,[R12],#4            ;If we write R0, find addr
+               STRCS   R0,[R10,#0]             ;And write it out
+               LDRMI   R10,[R12],#4            ;If we write R1, find addr
+               STRMI   R1,[R10,#0]             ;And write it out
+
+               MOVS    R11,R11,LSL #2          ;Move next two bits out
+               LDRCS   R10,[R12],#4            ;If we write R2, find addr
+               STRCS   R2,[R10,#0]             ;And write it out
+               LDRMI   R10,[R12],#4            ;If we write R3, find addr
+               STRMI   R3,[R10,#0]             ;And write it out
+               TST     R11,#&7F000000          ;Any more to do?
+               BEQ     %30swi                  ;No -- save 16 cycles
+
+               MOVS    R11,R11,LSL #2          ;Move next two bits out
+               LDRCS   R10,[R12],#4            ;If we write R4, find addr
+               STRCS   R4,[R10,#0]             ;And write it out
+               LDRMI   R10,[R12],#4            ;If we write R5, find addr
+               STRMI   R5,[R10,#0]             ;And write it out
+
+               MOVS    R11,R11,LSL #2          ;Move next two bits out
+               LDRCS   R10,[R12],#4            ;If we write R6, find addr
+               STRCS   R6,[R10,#0]             ;And write it out
+               LDRMI   R10,[R12],#4            ;If we write R7, find addr
+               STRMI   R7,[R10,#0]             ;And write it out
+
+               MOVS    R11,R11,LSL #2          ;Move next two bits out
+               LDRCS   R10,[R12],#4            ;If we write R8, find addr
+               STRCS   R8,[R10,#0]             ;And write it out
+               LDRMI   R10,[R12],#4            ;If we write R9, find addr
+               STRMI   R9,[R10,#0]             ;And write it out
+
+               TST     R11,#&40000000          ;Is the `write PC' bit set?
+               LDRNE   R0,[R13,#0]             ;Yes -- load the one I saved
+               LDRNE   R10,[R12],#4            ;Load the address
+               STRNE   R0,[R10,#0]             ;And write the PC value out
+
+30swi          ADD     R13,R13,#20             ;Restore the stack pointer
+               MOV     R0,R14                  ;Get the return value
+               LDMFD   R13!,{R4-R11,R13,PC}^   ;And return to caller
+
+               ; --- Work out address of literal block ---
+
+80swi          MOVS    R4,R1,LSL #1            ;Look after flags word
+               MOV     R5,#6                   ;Simple counter thingy
+               AND     R3,R1,#&0000F000        ;Get the block register
+               ORR     R3,R3,#&E2000000        ;Build into ADD instruction
+               ORR     R3,R3,#&008C0000
+
+85swi          ADDCS   R3,R3,#4                ;Move pointer on for each reg
+               ADDMI   R3,R3,#4
+               SUBS    R5,R5,#1                ;Decrement counter too
+               MOVLE   PC,R14                  ;If finished, return
+               MOVS    R4,R4,LSL #2            ;Shift next two bits out
+               B       %85swi                  ;And loop round again
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/s/rdump b/StraySrc/Libraries/Core/s/rdump
new file mode 100644 (file)
index 0000000..6e6017f
--- /dev/null
@@ -0,0 +1,165 @@
+;
+; rdump.s
+;
+; Displays a register dump (sends it to VDUStream)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core libraries (corelib)
+;
+; Corelib is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Corelib is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Corelib.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Debug$$Code|,CODE,READONLY
+
+; --- stream_regDump ---
+;
+; On entry:    R0 == pointer to saved R0-R15
+;              R13 == pointer to full descending stack
+;
+; On exit:     R0-R14 corrupted
+;
+; Use:         Displays a register dump.
+
+               EXPORT  stream_regDump
+stream_regDump ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+
+               ; --- Start the main display loop ---
+
+               MOV     R12,R0                  ;Keep pointer to dump block
+               ADR     R11,stream__regNames    ;Point to register name tbl
+               MOV     R10,#0                  ;Which register we're on
+
+               ; --- Display a register ---
+
+00             ADD     R0,R11,R10,LSL #2       ;Point to the string
+               SWI     Stream_Write0           ;Display register name
+               SWI     Stream_WriteS           ;Display immediate string
+               DCB     " == &",0               ;A separater string
+               LDR     R0,[R12,R10,LSL #2]     ;Load the register value
+               SWI     Stream_WriteH32         ;Display register value
+               SWI     Stream_WriteS           ;Display more immediate
+               DCB     "   ",0                 ;Just some spaces
+               ADD     R10,R10,#1              ;Increment register count
+               TST     R10,#3                  ;Now a multiple of 4?
+               SWIEQ   Stream_NewLine          ;Yes -- new line then
+               CMP     R10,#16                 ;Finished all registers?
+               BLT     %00stream_regDump       ;No -- do some more then
+
+               ; --- Now display R14 and R15 with PSR bits testually ---
+
+               SWI     Stream_NewLine          ;Another newline
+               SWI     Stream_WriteS           ;Display immediate stuff
+               DCB     "R14 == &",0
+               LDR     R9,[R12,#14*4]          ;Load the R14 value
+               BL      stream__psr             ;Display all the PSR bits
+               SWI     Stream_NewLine          ;Another newline
+               SWI     Stream_WriteS           ;Display immediate stuff
+               DCB     " PC == &",0
+               LDR     R9,[R12,#15*4]          ;Load the PC value
+               BL      stream__psr             ;Display all the PSR bits
+               SWI     Stream_NewLine          ;Another newline
+               SWI     Stream_NewLine          ;And one more for luck
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+stream__regNames
+               DCB     " R0",0
+               DCB     " R1",0
+               DCB     " R2",0
+               DCB     " R3",0
+               DCB     " R4",0
+               DCB     " R5",0
+               DCB     " R6",0
+               DCB     " R7",0
+               DCB     " R8",0
+               DCB     " R9",0
+               DCB     "R10",0
+               DCB     "R11",0
+               DCB     "R12",0
+               DCB     "R13",0
+               DCB     "R14",0
+               DCB     " PC",0
+
+; --- stream__psr ---
+;
+; On entry:    R9 == value to display
+;
+; On exit:     R0-R12 corrupted, maybe
+;
+; Use:         Displays R9 with PSR bits stripped away, and then with
+;              all the PSR bits described too.
+
+stream__psr    ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+               BIC     R0,R9,#&FC000003        ;Get the PC bits only
+               SWI     Stream_WriteH32         ;Display them in hex
+
+               SWI     Stream_WriteS           ;Some more spaces
+               DCB     ", flags == ",0
+               MOV     R0,#'N'                 ;First do the `N' flag
+               TST     R9,#N_flag              ;Is it set
+               ORREQ   R0,R0,#&20              ;No -- force to lower case
+               SWI     Stream_WriteT8          ;Display the character
+               MOV     R0,#'Z'                 ;First do the `N' flag
+               TST     R9,#Z_flag              ;Is it set
+               ORREQ   R0,R0,#&20              ;No -- force to lower case
+               SWI     Stream_WriteT8          ;Display the character
+               MOV     R0,#'C'                 ;First do the `N' flag
+               TST     R9,#C_flag              ;Is it set
+               ORREQ   R0,R0,#&20              ;No -- force to lower case
+               SWI     Stream_WriteT8          ;Display the character
+               MOV     R0,#'V'                 ;First do the `N' flag
+               TST     R9,#V_flag              ;Is it set
+               ORREQ   R0,R0,#&20              ;No -- force to lower case
+               SWI     Stream_WriteT8          ;Display the character
+
+               SWI     Stream_WriteS           ;Yet more stuff
+               DCB     ", mode == ",0
+               ADR     R0,stream__modes        ;Point to the mode strings
+               AND     R14,R9,#3               ;Get the mode bits
+               ADD     R0,R0,R14,LSL #2        ;Point to the correct string
+               SWI     Stream_Write0           ;Display the mode setting
+
+               TST     R9,#IRQ_disable         ;Is the IRQ bit on or off?
+               ADREQ   R0,stream__irqOn        ;If off, point to message
+               SWIEQ   Stream_Write0           ;And display the string
+               TST     R9,#FIQ_disable         ;Is the FIQ bit on or off?
+               ADREQ   R0,stream__fiqOn        ;If off, point to message
+               SWIEQ   Stream_Write0           ;And display the string
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+stream__modes  DCB     "USR",0
+               DCB     "FIQ",0
+               DCB     "IRQ",0
+               DCB     "SVC",0
+
+stream__irqOn  DCB     ", IRQ",0
+stream__fiqOn  DCB     ", FIQ",0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/s/swihack b/StraySrc/Libraries/Core/s/swihack
new file mode 100644 (file)
index 0000000..246542c
--- /dev/null
@@ -0,0 +1,80 @@
+;
+; swihack
+;
+; Calling SWIs under all versions of RISC OS
+;
+; © 1996-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core libraries (corelib)
+;
+; Corelib is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Corelib is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Corelib.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               [       :LNOT::DEF:swihack__dfn
+
+;----- Main code ------------------------------------------------------------
+
+; --- |_swihack| ---
+;
+; On entry:    Registers for SWI call
+;              R10 == SWI number to call
+;
+; On exit:     As from the SWI
+;
+; Use:         On first call, works out the right way to call SWIs.  On
+;              subsequent calls, the vector is snapped to the right place.
+
+|_swihack|     DCD     |__swihack|
+
+               ; --- Initial sorting out and dispatching routine ---
+
+|__swihack|    STMFD   R13!,{R0,R1,R14}        ;Store some registers away
+               MOV     R0,#0                   ;Read feature flags
+               SWI     XOS_PlatformFeatures    ;Read the features then
+               ADRVC   R0,|_swihack_call|      ;If SWI there, call directly
+               ADRVS   R0,|_swihack_build|     ;Otherwise build the call
+               STR     R0,|_swihack|           ;Store the value away
+               LDMFD   R13!,{R0,R1,R14}        ;Restore the registers
+               TEQP    R14,#0                  ;Reset flags from R14
+               LDR     PC,|_swihack|           ;And snap the pointer
+
+               ; --- Dispatch to OS_CallASWI ---
+
+|_swihack_call|        MOV     R12,R14                 ;Save the return address
+               SWI     OS_CallASWI             ;Just call the SWI: easy
+|_ret_R12|     MOV     PC,R12                  ;And return to caller
+
+               ; --- Dispatch by building code dynamically ---
+
+|_swihack_build|
+               STMFD   R13!,{R14}              ;Save the return address
+               BIC     R10,R10,#&FF000000      ;Clear the opcode byte
+               ORR     R10,R10,#&EF000000      ;And make it SWIAL
+               LDR     R14,|_ret_R12|          ;And load the return instr
+               STMFD   R13!,{R10,R14}          ;Save code on the stack
+               MOV     R12,PC                  ;Set up return address
+               MOV     PC,R13                  ;And call the code
+               ADD     R13,R13,#8              ;Reclaim stack space
+               LDMFD   R13!,{PC}               ;And return with SWI's flags
+
+               LTORG
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/s/swiv b/StraySrc/Libraries/Core/s/swiv
new file mode 100644 (file)
index 0000000..77d6a6b
--- /dev/null
@@ -0,0 +1,5 @@
+               GET     libs:header
+               GET     libs:swis
+
+               AREA    |C$$Code|,CODE,READONLY
+               LNK     libs:s.xswi
diff --git a/StraySrc/Libraries/Core/s/xapp b/StraySrc/Libraries/Core/s/xapp
new file mode 100644 (file)
index 0000000..923c8cd
--- /dev/null
@@ -0,0 +1,133 @@
+;
+; xapp.s
+;
+; SDLS stubs for applications
+;
+; © 1993-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's C library stubs (xstubs).
+;
+; xstubs is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; xstubs is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with xstubs.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  |_kernel_init|
+               IMPORT  |Image$$RO$$Base|
+               IMPORT  |Image$$RW$$Limit|
+               IMPORT  |RTSK$$Data$$Base|
+               IMPORT  |RTSK$$Data$$Limit|
+               IMPORT  |__root_stack_size|,WEAK
+
+               IMPORT  xstub__ktable
+               IMPORT  xstub__ektable
+               IMPORT  xstub__ctable
+               IMPORT  xstub__ectable
+               IMPORT  xstub__kdata
+               IMPORT  xstub__ekdata
+               IMPORT  xstub__cdata
+               IMPORT  xstub__ecdata
+
+;----- Exports --------------------------------------------------------------
+
+               EXPORT  |__main|
+
+;----- Initialise the library -----------------------------------------------
+
+               AREA    |Stub$$Code|,CODE,READONLY
+
+xstub__stack   EQU     4096                    ;Standard stack size thing
+xstub__error   EQU     &800E90                 ;Error number base
+xstub__version EQU     5                       ;Version number of stubs
+
+               ENTRY                           ;Start here :-)
+
+|__main|       SWI     OS_GetEnv               ;Get information about me
+               MOV     R2,R1                   ;Keep memory limit thing
+               LDR     R1,=|Image$$RW$$Limit|  ;Point to end of program
+               MOV     R3,#-1                  ;As required
+               MOV     R4,#0                   ;As required
+               MOV     R5,#-1                  ;As required
+               ADR     R0,xstub__stubs         ;Point to stub descriptions
+               LDR     R6,=|__root_stack_size| ;Load root stack size
+               CMP     R6,#0                   ;Has it been specified?
+               MOVEQ   R6,#xstub__stack        ;No -- substitute a default
+               LDRNE   R6,[R6]                 ;Otherwise, read the size
+               MOV     R6,R6,ASR #10           ;Convert to kilobytes
+               MOV     R6,R6,LSL #16           ;And shift to top halfword
+               SWI     XSharedCLibrary_LibInitAPCS_R ;Init C library
+               ADRVS   R0,xstub__noCLib        ;If failed, claim CLib gone
+               SWIVS   OS_GenerateError        ;And generate the error
+               CMP     R6,#xstub__version      ;Check returned version
+               MOVGE   R4,R0                   ;Point to workspae limit
+               ADRGE   R0,xstub__kernel        ;Point to _kernel_init block
+               MOVGE   R3,#0                   ;Say we're an application
+               BGE     |_kernel_init|          ;Start up the kernel!
+               ADR     R0,xstub__oldCLib       ;Point to error message
+               SWI     OS_GenerateError        ;Complain about old CLib
+
+xstub__noCLib  DCD     xstub__error+&00        ;Error number (official)
+               DCB     "Couldn't find Shared C Library",0
+               ALIGN
+
+xstub__oldCLib DCD     xstub__error+&01        ;Error number (also official)
+               DCB     "Shared C Library is out of date",0
+               ALIGN
+
+;----- Stub description block -----------------------------------------------
+
+xstub__stubs
+
+               ; --- Magic numbers ---
+
+xstub__krnlID  EQU     1                       ;Kernel's chunk ID
+xstub__clibID  EQU     2                       ;C library's chunk ID
+
+               ; --- Kernel section ---
+
+               DCD     xstub__krnlID
+               DCD     xstub__ktable
+               DCD     xstub__ektable
+               DCD     xstub__kdata
+               DCD     xstub__ekdata
+
+               ; --- C library section ---
+
+               DCD     xstub__clibID
+               DCD     xstub__ctable
+               DCD     xstub__ectable
+               DCD     xstub__cdata
+               DCD     xstub__ecdata
+
+               DCD     -1                      ;Terminate the table
+
+;----- Kernel description block ---------------------------------------------
+
+xstub__kernel
+
+               DCD     |Image$$RO$$Base|
+               DCD     |RTSK$$Data$$Base|
+               DCD     |RTSK$$Data$$Limit|
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/s/xcommon b/StraySrc/Libraries/Core/s/xcommon
new file mode 100644 (file)
index 0000000..7027bcc
--- /dev/null
@@ -0,0 +1,129 @@
+;
+; xcommon.s
+;
+; Common stuff for application and module stubs
+;
+; © 1993-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's C library stubs (xstubs).
+;
+; xstubs is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; xstubs is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with xstubs.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  |_clib_initialise|
+               IMPORT  |_main|
+               IMPORT  TrapHandler
+               IMPORT  UncaughtTrapHandler
+               IMPORT  EventHandler
+               IMPORT  UnhandledEventHandler
+               IMPORT  |_kernel_command_string|
+               IMPORT  |_stub_kallocExtendsWS|
+               IMPORT  |C$$code$$Base|
+               IMPORT  |C$$code$$Limit|
+               IMPORT  main,WEAK
+               IMPORT  |DLL$$ExternalTable$$Base|,WEAK
+               IMPORT  |DLL$$ExternalTable$$Limit|,WEAK
+               IMPORT  |_dll_findall|,WEAK
+               IMPORT  |_dll_appspace|,WEAK
+               IMPORT  |_dll_clibdata|,WEAK
+               IMPORT  |_dll_appEntryStubs|,WEAK
+               IMPORT  |_dll_appEntryNames|,WEAK
+               IMPORT  |_dll_regAppEntry|,WEAK
+
+;----- Run-time support information -----------------------------------------
+
+               AREA    |RTSK$$Data|,CODE,READONLY
+
+xstub__startDef        DCD     xstub__endDef-xstub__startDef
+               DCD     |C$$code$$Base|
+               DCD     |C$$code$$Limit|
+               DCD     xstub__c
+               DCD     xstub__initC
+               DCD     0
+               DCD     TrapHandler
+               DCD     UncaughtTrapHandler
+               DCD     EventHandler
+               DCD     UnhandledEventHandler
+xstub__endDef
+
+;----- C library initialisation ---------------------------------------------
+
+               AREA    |C$$code|,CODE,READONLY
+
+               ; --- Magic numbers ---
+
+xstub__c       DCB     "C",0                   ;Language name
+               ALIGN
+
+xstub__initC   LDR     a1,=|_stub_kallocExtendsWS| ;Get flag offset
+               LDR     ip,[sl,#-536]           ;Get client reloc
+               ADD     a1,ip,a1                ;Relocate the offset
+               MOV     a2,#1                   ;Set the flag
+               STRB    a2,[a1]                 ;Yup.  Tha's it
+               STMFD   sp!,{lr}                ;Preserve link register
+               BL      |_clib_initialise|      ;Initialise C library
+               LDR     a1,=main                ;Try and find main routine
+               CMP     a1,#0                   ;Was it found?
+               ADRNE   a1,xstub__goGoGo        ;Insert own initialisation
+               LDMFD   sp!,{pc}^
+
+               LTORG
+
+xstub__goGoGo  MOV     ip,sp                   ;Standard stack frame stuff
+               STMFD   sp!,{fp,ip,lr,pc}
+               SUB     fp,ip,#4
+
+               ; --- DLL initialisation stuff ---
+               ;
+               ; Find start and end of external DLL table.  If they're
+               ; equal, there's no table, and we don't care if the routine
+               ; to load them exists or not :-)
+
+               LDR     a1,=|DLL$$ExternalTable$$Base|
+               LDR     a2,=|DLL$$ExternalTable$$Limit|
+               CMP     a1,a2
+               BEQ     appentry
+               BL      |_dll_findall|
+               BL      |_dll_appspace|
+               BL      |_dll_clibdata|
+
+               ; Next, see if we can register the application as having
+               ; an external entry table.  If so, do it.
+
+appentry       LDR     a1,=|_dll_appEntryStubs|
+               LDR     a2,=|_dll_appEntryNames|
+               CMP     a1,a2
+               BLNE    |_dll_regAppEntry|
+
+               ; --- Start C program from main ---
+
+nodlls         BL      |_kernel_command_string| ;Find the command line
+               LDR     R1,=main                ;Find user's main program
+               BL      |_main|                 ;Call it with correct args
+               LDMDB   fp,{fp,sp,pc}^
+
+               LTORG
+
+;----- That's all for this one ----------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/s/xdata b/StraySrc/Libraries/Core/s/xdata
new file mode 100644 (file)
index 0000000..9e64254
--- /dev/null
@@ -0,0 +1,138 @@
+;
+; xdata
+;
+; Static data for the Shared C Library
+;
+; © 1993-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's C library stubs (xstubs).
+;
+; xstubs is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; xstubs is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with xstubs.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Setting up the macros ------------------------------------------------
+
+               GBLA    current
+current                SETA    0
+
+               MACRO
+$label         OFFSET  $off
+               ASSERT  $off>=current
+               %       $off-current
+$label
+current                SETA    $off
+               MEND
+
+;----- The data definitions -------------------------------------------------
+
+                               AREA    |Stub$$Data|,DATA,NOINIT
+
+                               EXPORT  xstub__kdata
+                               EXPORT  xstub__ekdata
+                               EXPORT  xstub__cdata
+                               EXPORT  xstub__ecdata
+
+                               EXPORT  |_stub_kallocExtendsWS|
+                               EXPORT  |__iob|
+                               EXPORT  |__ctype|
+                               EXPORT  |__errno|
+                               EXPORT  |__huge_val|
+
+;----- Kernel data ----------------------------------------------------------
+
+xstub__kdata
+
+|_stub_imageBase|              OFFSET  &0000
+|_stub_rtsDataBase|            OFFSET  &0004
+|_stub_rtsDataLimit|           OFFSET  &0008
+|_stub_errorR12|               OFFSET  &000c
+|_stub_errorBuffer|            OFFSET  &0010
+|_stub_errorNumber|            OFFSET  &0014
+|_stub_errorString|            OFFSET  &0018
+|_stub_registerDump|           OFFSET  &007c
+|_stub_oldAbortHandlers|       OFFSET  &00bc
+|_stub_oldExitHandler|         OFFSET  &00cc
+|_stub_oldMemoryLimit|         OFFSET  &00d4
+|_stub_oldErrorHandler|                OFFSET  &00d8
+|_stub_oldErrorR0|             OFFSET  &00dc
+|_stub_oldErrorBuffer|         OFFSET  &00e0
+|_stub_oldCallBackHandler|     OFFSET  &00e4
+|_stub_oldEscapeHandler|       OFFSET  &00f0
+|_stub_oldEventHandler|                OFFSET  &00f8
+|_stub_oldUpCallHandler|       OFFSET  &0100
+|_stub_languageEnvSave|                OFFSET  &0108
+|_stub_hadEscape|              OFFSET  &0114
+|_stub_kallocExtendsWS|                OFFSET  &0115
+|_stub_inTrapHandler|          OFFSET  &0116
+|_stub_beingDebugged|          OFFSET  &0117
+|_stub_fpPresent|              OFFSET  &0118
+|_stub_initialised|            OFFSET  &0119
+|_stub_callbackInactive|       OFFSET  &011a
+|_stub_unused_byte_2|          OFFSET  &011b
+|_stub_IIHandlerInData|                OFFSET  &011c
+|_stub_PAHandlerInData|                OFFSET  &0128
+|_stub_DAHandlerInData|                OFFSET  &0134
+|_stub_AEHandlerInData|                OFFSET  &0140
+|_stub_eventCode|              OFFSET  &014c
+|_stub_eventUserR13|           OFFSET  &0150
+|_stub_eventRegisters|         OFFSET  &0154
+|_stub_fastEventStack|         OFFSET  &0184
+|_stub_fastEventStackEnd|      OFFSET  &0284
+|_stub_heapTop|                        OFFSET  &0284
+|_stub_heapLimit|              OFFSET  &0288
+|_stub_allocProc|              OFFSET  &028c
+|_stub_freeProc|               OFFSET  &0290
+|_stub_returnCode|             OFFSET  &0294
+|_stub_moduleDataWord|         OFFSET  &0298
+|_stub_APCS_A_Client|          OFFSET  &029c
+|_stub_escapeSeen|             OFFSET  &029d
+|_stub_unwinding|              OFFSET  &029e
+|_stub_underDesktop|           OFFSET  &029f
+|_stub_heapBase|               OFFSET  &02a0
+|_stub_ArgString|              OFFSET  &02a4
+|_stub_heapExtender|           OFFSET  &02a8
+|_stub_knownSlotSize|          OFFSET  &02ac
+|_stub_initSlotSize|           OFFSET  &02b0
+|_stub_lk_RestoreOSHandlers|   OFFSET  &02b4
+|_stub_extendChunk|            OFFSET  &02b8
+|_stub_rootStackChunk|         OFFSET  &02bc
+|_stub_returnCodeLimit|                OFFSET  &02c0
+|_stub_unused|                 OFFSET  &02cc
+
+|_stub_kernelSpace|            OFFSET  &031c
+
+xstub__ekdata
+
+;----- C library data -------------------------------------------------------
+
+xstub__cdata
+
+|__errno|                      OFFSET  &031c
+|__iob|                                OFFSET  &0320
+|_interrupts_off|              OFFSET  &05a0
+|_stub__saved_interrupt|       OFFSET  &05a4
+|_stub_ctype_eof|              OFFSET  &05a8
+|__ctype|                      OFFSET  &05ac
+|__huge_val|                   OFFSET  &06ac
+|_stub_stack_o_flag|           OFFSET  &06b4
+|_stub_inSignalHandler|                OFFSET  &06b5
+|_stub_|                       OFFSET  &06b6
+|_stub_ClibSpace|              OFFSET  &0e64
+
+xstub__ecdata
+
+                               END
diff --git a/StraySrc/Libraries/Core/s/xdll b/StraySrc/Libraries/Core/s/xdll
new file mode 100644 (file)
index 0000000..a1968e2
--- /dev/null
@@ -0,0 +1,55 @@
+;
+; xdll.s
+;
+; Special bits for dynamic link libraries
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's C library stubs (xstubs).
+;
+; xstubs is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; xstubs is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with xstubs.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard bit at the top ----------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Export things to C compiler ------------------------------------------
+
+               EXPORT  |_Lib$Reloc$Off|
+               EXPORT  |_Mod$Reloc$Off|
+               EXPORT  |_Lib$Reloc$Off$DP|
+
+|_Lib$Reloc$Off|       EQU     &21c
+|_Mod$Reloc$Off|       EQU     &218
+|_Lib$Reloc$Off$DP|    EQU     &f87
+
+;----- Dummy code for silly __main calls ------------------------------------
+
+               AREA    |C$$code|,CODE,READONLY
+
+               EXPORT  |__main|
+
+|__main|       ADR     R0,error
+               SWI     OS_GenerateError
+
+error          DCD     0
+               DCB     "__main called in DLL",0
+               ALIGN
+
+               END
diff --git a/StraySrc/Libraries/Core/s/xentry b/StraySrc/Libraries/Core/s/xentry
new file mode 100644 (file)
index 0000000..57628a9
--- /dev/null
@@ -0,0 +1,324 @@
+;
+; xentry.s
+;
+; C library entry points
+;
+; © 1993-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's C library stubs (xstubs).
+;
+; xstubs is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; xstubs is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with xstubs.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               [       :DEF:xentry_small
+               AREA    |Stub$$Entries|,NOINIT
+               |
+               AREA    |Stub$$Entries|,CODE,READONLY
+               ]
+
+PC             RN      15
+
+;----- Misc things ----------------------------------------------------------
+
+               EXPORT  |__SIG_DFL|
+               EXPORT  |__SIG_ERR|
+               EXPORT  |__SIG_IGN|
+
+|__SIG_DFL|    EQU     -1
+|__SIG_ERR|    EQU     -2
+|__SIG_IGN|    EQU     -3
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+               XENTRY  $name,$synonym
+               ALIGN
+               EXPORT  $name
+$name
+               [       "$synonym"<>""
+               EXPORT  $synonym
+$synonym
+               ]
+
+               [       :DEF:xentry_small
+               DCD     0
+               |
+               MOV     PC,#0
+               ]
+
+               MEND
+
+;----- Kernel entry points --------------------------------------------------
+;
+; I've taken these directly from a dump of the original stubs, so they
+; should be fairly accurate.
+;
+
+               EXPORT  xstub__ktable
+               EXPORT  xstub__ektable
+
+xstub__ktable
+
+               XENTRY  |_kernel_init|
+               XENTRY  |_kernel_exit|
+               XENTRY  |_kernel_setreturncode|
+               XENTRY  |_kernel_exittraphandler|
+               XENTRY  |_kernel_unwind|
+               XENTRY  |_kernel_procname|
+               XENTRY  |_kernel_language|
+               XENTRY  |_kernel_command_string|
+               XENTRY  |_kernel_hostos|
+               XENTRY  |_kernel_swi|
+               XENTRY  |_kernel_osbyte|
+               XENTRY  |_kernel_osrdch|
+               XENTRY  |_kernel_oswrch|
+               XENTRY  |_kernel_osbget|
+               XENTRY  |_kernel_osbput|
+               XENTRY  |_kernel_osgbpb|
+               XENTRY  |_kernel_osword|
+               XENTRY  |_kernel_osfind|
+               XENTRY  |_kernel_osfile|
+               XENTRY  |_kernel_osargs|
+               XENTRY  |_kernel_oscli|
+               XENTRY  |_kernel_last_oserror|
+               XENTRY  |_kernel_system|
+               XENTRY  |_kernel_getenv|
+               XENTRY  |_kernel_setenv|
+               XENTRY  |_kernel_register_allocs|
+               XENTRY  |_kernel_alloc|
+               XENTRY  |_kernel_stkovf_split_0frame|
+               XENTRY  |_kernel_stkovf_split|
+               XENTRY  |_kernel_stkovf_copyargs|
+               XENTRY  |_kernel_stkovf_copy0args|
+               XENTRY  |_kernel_udiv|
+               XENTRY  |_kernel_urem|
+               XENTRY  |_kernel_udiv10|,|__rt_udiv10|
+               XENTRY  |_kernel_sdiv|
+               XENTRY  |_kernel_srem|
+               XENTRY  |_kernel_sdiv10|,|__rt_sdiv10|
+               XENTRY  |_kernel_fpavailable|
+               XENTRY  |_kernel_moduleinit|
+               XENTRY  |_kernel_irqs_on|
+               XENTRY  |_kernel_irqs_off|
+               XENTRY  |_kernel_irqs_disabled|
+               XENTRY  |_kernel_entermodule|
+               XENTRY  |_kernel_escape_seen|
+               XENTRY  |_kernel_current_stack_chunk|
+               XENTRY  |_kernel_swi_c|
+               XENTRY  |_kernel_register_slotextend|
+               XENTRY  |_kernel_raise_error|
+
+xstub__ektable
+
+;----- C library entry points -----------------------------------------------
+
+               EXPORT  xstub__ctable
+               EXPORT  xstub__ectable
+
+xstub__ctable
+
+               XENTRY  TrapHandler
+               XENTRY  UncaughtTrapHandler
+               XENTRY  EventHandler
+               XENTRY  UnhandledEventHandler
+               XENTRY  |x$stack_overflow|,|__rt_stkovf_split_small|
+               XENTRY  |x$stack_overflow_1|,|__rt_stkovf_split_big|
+               XENTRY  |x$udivide|,|__rt_udiv|
+               XENTRY  |x$uremainder|
+               XENTRY  |x$divide|,|__rt_sdiv|
+               XENTRY  |x$divtest|,|__rt_divtest|
+               XENTRY  |x$remainder|
+               XENTRY  |x$multiply|
+               XENTRY  |_rd1chk|,|__rt_rd1chk|
+               XENTRY  |_rd2chk|,|__rt_rd2chk|
+               XENTRY  |_rd4chk|,|__rt_rd4chk|
+               XENTRY  |_wr1chk|,|__rt_wr1chk|
+               XENTRY  |_wr2chk|,|__rt_wr2chk|
+               XENTRY  |_wr4chk|,|__rt_wr4chk|
+               XENTRY  |_main|
+               XENTRY  |_exit|
+               XENTRY  |_clib_initialise|
+               XENTRY  |_backtrace|
+               XENTRY  |_count|
+               XENTRY  |_count1|
+               XENTRY  |_stfp|
+               XENTRY  |_ldfp|
+               XENTRY  |_printf|
+               XENTRY  |_fprintf|
+               XENTRY  |_sprintf|
+               XENTRY  clock
+               XENTRY  difftime
+               XENTRY  mktime
+               XENTRY  time
+               XENTRY  asctime
+               XENTRY  ctime
+               XENTRY  gmtime
+               XENTRY  localtime
+               XENTRY  strftime
+               XENTRY  memcpy
+               XENTRY  memmove
+               XENTRY  strcpy
+               XENTRY  strncpy
+               XENTRY  strcat
+               XENTRY  strncat
+               XENTRY  memcmp
+               XENTRY  strcmp
+               XENTRY  strncmp
+               XENTRY  memchr
+               XENTRY  strchr
+               XENTRY  strcspn
+               XENTRY  strpbrk
+               XENTRY  strrchr
+               XENTRY  strspn
+               XENTRY  strstr
+               XENTRY  strtok
+               XENTRY  memset
+               XENTRY  strerror
+               XENTRY  strlen
+               XENTRY  atof
+               XENTRY  atoi
+               XENTRY  atol
+               XENTRY  strtod
+               XENTRY  strtol
+               XENTRY  strtoul
+               XENTRY  rand
+               XENTRY  srand
+               XENTRY  calloc
+               XENTRY  free
+               XENTRY  malloc
+               XENTRY  realloc
+               XENTRY  abort
+               XENTRY  atexit
+               XENTRY  exit
+               XENTRY  getenv
+               XENTRY  system
+               XENTRY  bsearch
+               XENTRY  qsort
+               XENTRY  abs
+               XENTRY  div
+               XENTRY  labs
+               XENTRY  ldiv
+               XENTRY  remove
+               XENTRY  rename
+               XENTRY  tmpfile
+               XENTRY  |__old_tmpnam|
+               XENTRY  fclose
+               XENTRY  fflush
+               XENTRY  fopen
+               XENTRY  freopen
+               XENTRY  setbuf
+               XENTRY  setvbuf
+               XENTRY  printf
+               XENTRY  fprintf
+               XENTRY  sprintf
+               XENTRY  scanf
+               XENTRY  fscanf
+               XENTRY  sscanf
+               XENTRY  vprintf
+               XENTRY  vfprintf
+               XENTRY  vsprintf
+               XENTRY  |_vfprintf|
+               XENTRY  fgetc
+               XENTRY  fgets
+               XENTRY  fputc
+               XENTRY  fputs
+               XENTRY  |__filbuf|
+               XENTRY  getc
+               XENTRY  getchar
+               XENTRY  gets
+               XENTRY  |__flsbuf|
+               XENTRY  putc
+               XENTRY  putchar
+               XENTRY  puts
+               XENTRY  ungetc
+               XENTRY  fread
+               XENTRY  fwrite
+               XENTRY  fgetpos
+               XENTRY  fseek
+               XENTRY  fsetpos
+               XENTRY  ftell
+               XENTRY  rewind
+               XENTRY  clearerr
+               XENTRY  feof
+               XENTRY  ferror
+               XENTRY  perror
+               XENTRY  |__ignore_signal_handler|
+               XENTRY  |__default_signal_handler|
+               XENTRY  |__error_signal_marker|
+               XENTRY  signal
+               XENTRY  raise
+               XENTRY  setjmp
+               XENTRY  longjmp
+               XENTRY  acos
+               XENTRY  asin
+               XENTRY  atan
+               XENTRY  atan2
+               XENTRY  cos
+               XENTRY  sin
+               XENTRY  tan
+               XENTRY  cosh
+               XENTRY  sinh
+               XENTRY  tanh
+               XENTRY  exp
+               XENTRY  frexp
+               XENTRY  ldexp
+               XENTRY  log
+               XENTRY  log10
+               XENTRY  modf
+               XENTRY  pow
+               XENTRY  sqrt
+               XENTRY  ceil
+               XENTRY  fabs
+               XENTRY  floor
+               XENTRY  fmod
+               XENTRY  setlocale
+               XENTRY  isalnum
+               XENTRY  isalpha
+               XENTRY  iscntrl
+               XENTRY  isdigit
+               XENTRY  isgraph
+               XENTRY  islower
+               XENTRY  isprint
+               XENTRY  ispunct
+               XENTRY  isspace
+               XENTRY  isupper
+               XENTRY  isxdigit
+               XENTRY  tolower
+               XENTRY  toupper
+               XENTRY  |__assert|
+               XENTRY  |_memcpy|
+               XENTRY  |_memset|
+               XENTRY  localeconv
+               XENTRY  mblen
+               XENTRY  mbtowc
+               XENTRY  wctomb
+               XENTRY  mbstowcs
+               XENTRY  wcstombs
+               XENTRY  strxfrm
+               XENTRY  strcoll
+               XENTRY  |_clib_finalisemodule|
+               XENTRY  |_clib_version|
+               XENTRY  Finalise
+               XENTRY  tmpnam
+               [       :DEF:xentry_swi
+               XENTRY  |_swi|
+               XENTRY  |_swix|
+               ]
+
+xstub__ectable
+
+               END
diff --git a/StraySrc/Libraries/Core/s/xentry_swi b/StraySrc/Libraries/Core/s/xentry_swi
new file mode 100644 (file)
index 0000000..4e50604
--- /dev/null
@@ -0,0 +1,2 @@
+               GBLL    xentry_swi
+               LNK     s.xentry
diff --git a/StraySrc/Libraries/Core/s/xmodule b/StraySrc/Libraries/Core/s/xmodule
new file mode 100644 (file)
index 0000000..310d783
--- /dev/null
@@ -0,0 +1,190 @@
+;
+; xmodule.s
+;
+; CLib stubs replacement
+;
+; © 1993-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's C library stubs (xstubs).
+;
+; xstubs is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; xstubs is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with xstubs.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  |_kernel_moduleinit|
+               IMPORT  |_kernel_entermodule|
+               IMPORT  |_clib_initialise|
+
+               IMPORT  |Image$$RO$$Base|
+               IMPORT  |Image$$RW$$Base|
+               IMPORT  |Image$$RW$$Limit|
+               IMPORT  |Image$$ZI$$Base|
+               IMPORT  |RTSK$$Data$$Base|
+               IMPORT  |RTSK$$Data$$Limit|
+               IMPORT  |__RelocCode|,WEAK
+
+               IMPORT  xstub__ktable
+               IMPORT  xstub__ektable
+               IMPORT  xstub__ctable
+               IMPORT  xstub__ectable
+               IMPORT  xstub__kdata
+               IMPORT  xstub__ekdata
+               IMPORT  xstub__cdata
+               IMPORT  xstub__ecdata
+               IMPORT  |__root_stack_size|,WEAK
+
+;----- Exports from this file -----------------------------------------------
+
+               EXPORT  |_clib_entermodule|
+               EXPORT  |_clib_initialisemodule|
+               EXPORT  |Stub$$Code|
+               EXPORT  |_Lib$Reloc$Off|
+               EXPORT  |_Mod$Reloc$Off|
+               EXPORT  |_Lib$Reloc$Off$DP|
+               EXPORT  |__main|
+
+;----- Initialise the library -----------------------------------------------
+
+               AREA    |Stub$$Code|,CODE,READONLY
+
+xstub__stack   EQU     4096                    ;Standard stack size thing
+xstub__error   EQU     &800E90                 ;Error number base
+xstub__version EQU     5                       ;Version number of stubs
+
+|_Lib$Reloc$Off|       EQU     &21c
+|_Mod$Reloc$Off|       EQU     &218
+|_Lib$Reloc$Off$DP|    EQU     &f87
+
+|_clib_initialisemodule|
+               STMFD   R13!,{R14}              ;Look after R14
+               BL      xstub__initMod          ;Try and initialise myself
+               LDMVSIA R13!,{PC}               ;If it failed, stop there now
+               STMFD   R13!,{R9}               ;Weird.  Must be done, though
+               BL      |_clib_initialise|      ;Start up the C library now
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+|_clib_entermodule|
+|__main|
+               ADR     R0,xstub__kernel        ;Point to kernel descriptor
+               MOV     R8,R12                  ;Look after private word
+               MOV     R12,#-1                 ;Dunno
+               LDR     R6,=|__root_stack_size| ;Load root stack size
+               CMP     R6,#0                   ;Has it been specified?
+               MOVEQ   R6,#xstub__stack        ;No -- substitute a default
+               LDRNE   R6,[R6]                 ;Otherwise, read the size
+               B       |_kernel_entermodule|   ;Start the module up now
+
+xstub__initMod STMFD   R13!,{R14}              ;Look after our link register
+               MOV     R9,R0                   ;R9 corrupted by relocation
+               BL      |__RelocCode|           ;Relocate myself properly
+               MOV     R4,#0
+               MOV     R5,#0
+               CMP     R9,#0
+               MOVEQ   R3,#12                  ;Need 12 bytes for relocation
+               LDRNE   R4,=|Image$$RW$$Base|   ;Point to base of data
+               LDRNE   R5,=|Image$$RW$$Limit|  ;Point to end of data
+               SUBNE   R3,R5,R4                ;Calculate the difference...
+               ADDNE   R3,R3,#12               ;And add on that 12 bytes
+               MOV     R0,#6                   ;Allocate some memory
+               SWI     XOS_Module              ;Do the allocation
+               LDMVSFD R13!,{PC}               ;If it squeals, let it go
+               STR     R2,[R12]                ;Store this in private word
+               STR     R3,[R2]                 ;Remember the data size
+               MOV     R9,R12                  ;Keep hold of priv word ptr
+               MOV     R12,R2                  ;Point R12 at workspace now
+               ADD     R1,R12,#12              ;Point past relocation stuff
+               ADD     R2,R3,R1                ;Point R2 at end of workspace
+               LDR     R3,=|Image$$ZI$$Base|   ;Point R3 at zero inited bit
+               ADR     R0,xstub__stubs         ;Point to stub descriptions
+               LDR     R6,=|__root_stack_size| ;Load root stack size
+               CMP     R6,#0                   ;Has it been specified?
+               MOVEQ   R6,#xstub__stack        ;No -- substitute a default
+               LDRNE   R6,[R6]                 ;Otherwise, read the size
+               MOV     R6,R6,ASR #10           ;Convert to kilobytes
+               MOV     R6,R6,LSL #16           ;And shift to top halfword
+               SWI     XSharedCLibrary_LibInitModule ;Initialise everything
+               BVS     xstub__errMod           ;Error in initialisation
+               CMP     R6,#xstub__version      ;Ensure version number
+               BLT     xstub__errMod           ;Mark this as an error
+               ADD     R8,R1,#20               ;Point to relocs in the stack
+               LDMIA   R8,{R7,R8}              ;Get relocated words
+               STMIB   R12,{R7,R8}             ;Store in workspace
+               MOV     R4,R0                   ;Point to workspace limit
+               ADR     R0,xstub__kernel        ;Point to kernel info block
+               B       |_kernel_moduleinit|    ;Start the kernel up now
+
+xstub__noCLib  DCD     xstub__error+&00        ;Error number (official)
+               DCB     "Couldn't find Shared C Library",0
+               ALIGN
+
+xstub__oldCLib DCD     xstub__error+&01        ;Error number (also official)
+               DCB     "Shared C Library is out of date",0
+               ALIGN
+
+xstub__errMod  ADRVS   R1,xstub__noCLib        ;If error, assume no library
+               ADRVC   R1,xstub__oldCLib       ;If not, assume version prob
+               MOV     R0,#7                   ;Ready to free workspace
+               MOV     R2,R12                  ;Point to workspace
+               SWI     XOS_Module              ;Free the workspace
+               MOV     R0,R1                   ;Get the error pointer
+               LDMFD   R13!,{R14}              ;Get return address
+               ORRS    PC,R14,#V_flag          ;Set V flag on exit
+
+;----- Stub description block -----------------------------------------------
+
+xstub__stubs
+
+               ; --- Magic numbers ---
+
+xstub__krnlID  EQU     1                       ;Kernel's chunk ID
+xstub__clibID  EQU     2                       ;C library's chunk ID
+
+               ; --- Kernel section ---
+
+               DCD     xstub__krnlID
+               DCD     xstub__ktable
+               DCD     xstub__ektable
+               DCD     xstub__kdata
+               DCD     xstub__ekdata
+
+               ; --- C library section ---
+
+               DCD     xstub__clibID
+               DCD     xstub__ctable
+               DCD     xstub__ectable
+               DCD     xstub__cdata
+               DCD     xstub__ecdata
+
+               DCD     -1                      ;Terminate the table
+
+;----- Kernel description block ---------------------------------------------
+
+xstub__kernel
+
+               DCD     |Image$$RO$$Base|
+               DCD     |RTSK$$Data$$Base|
+               DCD     |RTSK$$Data$$Limit|
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/s/xsmall b/StraySrc/Libraries/Core/s/xsmall
new file mode 100644 (file)
index 0000000..601c0ce
--- /dev/null
@@ -0,0 +1,2 @@
+               GBLL    xentry_small
+               LNK     s.xentry
diff --git a/StraySrc/Libraries/Core/s/xsmall_swi b/StraySrc/Libraries/Core/s/xsmall_swi
new file mode 100644 (file)
index 0000000..271aa36
--- /dev/null
@@ -0,0 +1,3 @@
+               GBLL    xentry_small
+               GBLL    xentry_swi
+               LNK     s.xentry
diff --git a/StraySrc/Libraries/Core/s/xswi b/StraySrc/Libraries/Core/s/xswi
new file mode 100644 (file)
index 0000000..1fc9561
--- /dev/null
@@ -0,0 +1,347 @@
+;
+; xswi.s
+;
+; SWI and routine veneers
+;
+; © 1996-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core libraries (corelib)
+;
+; Corelib is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Corelib is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Corelib.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Options provided -----------------------------------------------------
+;
+; OPT_CALL     Build code for calling local assembler code
+; OPT_SAPPHIRE Do Sapphire R11/sl veneering
+
+               MACRO
+               DCLOPT  $var
+               [       :DEF:$var
+$var           SETL    {TRUE}
+               |
+               GBLL    $var
+$var           SETL    {FALSE}
+               ]
+               MEND
+
+               DCLOPT  OPT_CALL
+               DCLOPT  OPT_SAPPHIRE
+
+;----- Main code ------------------------------------------------------------
+
+               GET     libs:s.swihack
+               [       :LNOT::DEF:swix__dfn
+
+; --- _swi, _swix, _call, _callx ---
+;
+; On entry:    R0 == SWI number (for _swi[x]) or address (for _call[x])
+;              R1 == feature flags:
+;                       0--9  == input registers
+;                        11   == local block flag
+;                      12--15 == local block register
+;                      16--19 == return register (_call and _swi only)
+;                      31--22 == output registers
+;              R2, R3 and stack contain other arguments
+;
+; On exit:     R0 == return value, or error indicator
+;
+; Use:         Calls a SWI or assembler routine.
+
+               EXPORT  |_swi|
+               EXPORT  |_swix|
+
+               ; --- How this works ---
+               ;
+               ; The old version of this code used to build some neat code
+               ; on the stack and then execute it.  This new spiffy version
+               ; just saves data on the stack, because building code is a
+               ; major no-no on the StrongARM.
+               ;
+               ; The data stacked is as follows:
+               ;
+               ;         PC   -- address to call
+               ;         R14  -- return address
+               ;         R12  -- saved R12 value
+               ;         R11  -- maybe Sapphire application context
+               ;         R10  -- maybe the SWI number
+               ;
+               ; Because I can't use dynamic code at all, I'm having to
+               ; use some really nasty speed hacks here.
+
+               ; --- SWI entries ---
+
+|_swi|         STMFD   R13!,{R2,R3}            ;Stack all variable args
+               STMFD   R13!,{R4-R12,R14}       ;Save other registers
+               ADR     R12,|_swi_nonx|         ;Point to non-X entry point
+               MOV     R9,R0                   ;Fetch the SWI number
+               LDR     R0,|_swihack|           ;Point to SWI calling routine
+               B       |_swi_main|             ;Skip onwards to main code
+
+|_swix|                STMFD   R13!,{R2,R3}            ;Stack all variable args
+               STMFD   R13!,{R4-R12,R14}       ;Save other registers
+               BIC     R1,R1,#&000F0000        ;Return R0 value no matter
+               ADR     R12,|_swi_x|            ;Point to X entry point
+               ORR     R9,R0,#&20000           ;Set the X bit on the SWI
+               LDR     R0,|_swihack|           ;Point to SWI calling routine
+               B       |_swi_main|             ;Skip onwards to main code
+
+               ; --- Code entries ---
+
+       [ OPT_CALL
+
+               EXPORT  |_call|
+               EXPORT  |_callx|
+
+|_call|                STMFD   R13!,{R2,R3}            ;Stack all variable args
+               STMFD   R13!,{R4-R12,R14}       ;Save other registers
+               ADR     R12,|_swi_nonx|         ;Point to non-X entry point
+         [ OPT_SAPPHIRE
+               MOV     R11,R10                 ;Get scratchpad for Sapphire
+         ]
+               B       |_swi_main|             ;Skip onwards to main code
+
+|_callx|       STMFD   R13!,{R2,R3}            ;Stack all variable args
+               STMFD   R13!,{R4-R12,R14}       ;Save other registers
+               BIC     R1,R1,#&000F0000        ;Return R0 value no matter
+               ADR     R12,|_swi_x|            ;Point to X entry point
+         [ OPT_SAPPHIRE
+               MOV     R11,R10                 ;Get scratchpad for Sapphire
+         ]
+               B       |_swi_main|             ;Skip onwards to main code
+
+       ]
+
+               ; --- First job is to set up the call address ---
+
+|_swi_main|    MOV     R14,PC                  ;Get the current CPU flags
+               AND     R14,R14,#&0C000003      ;Leave interrupts and mode
+               ORR     R12,R12,R14             ;Set the return address
+               ORR     R14,R0,R14              ;And the call address
+               SUB     R13,R13,#8              ;Make a hole in the stack
+               STMFD   R13!,{R9-R12,R14}       ;Save R10-R12 and PC (fake)
+
+               ; --- Set up the input registers ---
+               ;
+               ; Unrolled loop to do two registers at a time.  There are
+               ; frequent exits while scanning the early registers to
+               ; speed up common cases, petering out towards the end.
+
+               MOV     R10,R1                  ;Fetch the feature flags
+               ADD     R12,R13,#68             ;Point to arguments
+
+               MOVS    R14,R10,LSL #31
+               LDRMI   R0,[R12],#4
+               LDRCS   R1,[R12],#4
+               TST     R10,#&3FC
+               BEQ     %f00
+               MOVS    R14,R10,LSL #29
+               LDRMI   R2,[R12],#4
+               LDRCS   R3,[R12],#4
+               TST     R10,#&3F0
+               BEQ     %f00
+               MOVS    R14,R10,LSL #27
+               LDRMI   R4,[R12],#4
+               LDRCS   R5,[R12],#4
+               TST     R10,#&3C0
+               BEQ     %f00
+               MOVS    R14,R10,LSL #25
+               LDRMI   R6,[R12],#4
+               LDRCS   R7,[R12],#4
+               MOVS    R14,R10,LSL #23
+               LDRMI   R8,[R12],#4
+               LDRCS   R9,[R12],#4
+00
+               ; --- Now sort out block arguments ---
+
+               ADD     R14,R13,#20             ;Find the hole in the stack
+               STMIA   R14,{R10,R12}           ;Save important context
+               TST     R10,#&800               ;Do we have a block argument?
+               BNE     |_swi_block|            ;Yes -- sort out out-of-line
+               LDMFD   R13!,{R10-R12,R14,PC}^  ;And call the routine
+
+               ; --- X-type return ---
+
+|_swi_x|       LDMFD   R13!,{R10,R12}          ;Reload important context
+               MOVVC   R14,#0                  ;If no error, return zero
+               MOVVS   R14,R0                  ;Otherwise point to the error
+               STR     R14,[R13,#-4]!          ;Store as return value
+               B       |_swi_output|           ;And skip on a little
+
+               ; --- Non-X-type return ---
+               ;
+               ; Pick out the correct register with a branch table.  Also
+               ; invert the table to pick out common case of return R0.
+
+|_swi_nonx|    LDMFD   R13!,{R10,R12}          ;Reload important context
+               MOV     R14,#&F                 ;A nice bitmask
+               AND     R14,R14,R10,LSR #16     ;So mask the return register
+               RSB     R14,R14,#&F             ;Invert range hackily
+               ADD     PC,PC,R14,LSL #3        ;And dispatch nicely
+               DCB     "hack"
+
+               STR     PC,[R13,#-4]!
+               B       |_swi_output|
+               STR     R14,[R13,#-4]!
+               B       |_swi_output|
+               STR     R13,[R13,#-4]!
+               B       |_swi_output|
+               STR     R12,[R13,#-4]!
+               B       |_swi_output|
+               STR     R11,[R13,#-4]!
+               B       |_swi_output|
+               STR     R10,[R13,#-4]!
+               B       |_swi_output|
+               STR     R9,[R13,#-4]!
+               B       |_swi_output|
+               STR     R8,[R13,#-4]!
+               B       |_swi_output|
+               STR     R7,[R13,#-4]!
+               B       |_swi_output|
+               STR     R6,[R13,#-4]!
+               B       |_swi_output|
+               STR     R5,[R13,#-4]!
+               B       |_swi_output|
+               STR     R4,[R13,#-4]!
+               B       |_swi_output|
+               STR     R3,[R13,#-4]!
+               B       |_swi_output|
+               STR     R2,[R13,#-4]!
+               B       |_swi_output|
+               STR     R1,[R13,#-4]!
+               B       |_swi_output|
+               STR     R0,[R13,#-4]!
+
+               ; --- Now handle output parameters ---
+               ;
+               ; Same style as the input parameters, with early exits
+               ; placed conveniently.
+
+|_swi_output|  MOV     R11,PC                  ;Get the CPU flags
+
+               TST     R10,#&FF000000          ;Are there any output args?
+               TSTEQ   R10,#&00E00000
+               BEQ     %f10                    ;No -- skip onwards then
+
+               MOVS    R14,R10,LSL #1
+               LDRCS   R14,[R12],#4
+               STRCS   R0,[R14,#0]
+               LDRMI   R14,[R12],#4
+               STRMI   R1,[R14,#0]
+               MOVS    R14,R10,LSL #3
+               LDRCS   R14,[R12],#4
+               STRCS   R2,[R14,#0]
+               LDRMI   R14,[R12],#4
+               STRMI   R3,[R14,#0]
+               TST     R10,#&0FC00000
+               BEQ     %f00
+               MOVS    R14,R10,LSL #5
+               LDRCS   R14,[R12],#4
+               STRCS   R4,[R14,#0]
+               LDRMI   R14,[R12],#4
+               STRMI   R5,[R14,#0]
+               TST     R10,#&03C00000
+               BEQ     %f00
+               MOVS    R14,R10,LSL #7
+               LDRCS   R14,[R12],#4
+               STRCS   R6,[R14,#0]
+               LDRMI   R14,[R12],#4
+               STRMI   R7,[R14,#0]
+               MOVS    R14,R10,LSL #9
+               LDRCS   R14,[R12],#4
+               STRCS   R8,[R14,#0]
+               LDRMI   R14,[R12],#4
+               STRMI   R9,[R14,#0]
+00
+               ; --- Handle returning flags ---
+
+               TST     R10,#&00200000
+               LDRNE   R14,[R12],#4
+               STRNE   R11,[R14,#0]
+10
+               LDMFD   R13!,{R0,R4-R12,R14}
+               ADD     R13,R13,#8
+               MOVS    PC,R14
+
+               ; --- Handle block arguments ---
+               ;
+               ; Shift output registers to the right to find the block.
+               ; Then dispatch through a branch table to store in the right
+               ; register.  All the registers from R10 upwards are on the
+               ; stack so they can be restored easily.
+
+|_swi_block|   MOV     R11,R10,LSR #22         ;Mask off output registers
+               MOV     R11,R11,LSL #21         ;Shift down one place
+               MOV     R14,R12                 ;Preserve R12 here
+00             MOVS    R11,R11,LSL #2          ;Shift into C and N flags
+               ADDCS   R14,R14,#4              ;If C set, bump counter
+               ADDMI   R14,R14,#4              ;If N set, bump counter
+               BNE     %b00                    ;And loop back until done
+               AND     R11,R10,#&0000F000      ;Fetch the right argument
+               ADD     PC,PC,R11,LSR #9        ;Dispatch through branch tbl
+               DCB     "hack"
+
+               ; --- Main dispatch table ---
+               ;
+               ; This is now just a branch off the main routine, so I
+               ; can just call the SWI/routine appropriately rather than
+               ; returning to the caller.  This gives me an extra register
+               ; to play with above, which helps.
+
+               MOV     R0,R14
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               MOV     R1,R14
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               MOV     R2,R14
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               MOV     R3,R14
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               MOV     R4,R14
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               MOV     R5,R14
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               MOV     R6,R14
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               MOV     R7,R14
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               MOV     R8,R14
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               MOV     R9,R14
+               LDMFD   R13!,{R10-R12,R14,PC}^
+
+               ; --- For safety, handle daft values of the parameter ---
+
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               DCB     "daft"
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               DCB     "daft"
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               DCB     "daft"
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               DCB     "daft"
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               DCB     "daft"
+               LDMFD   R13!,{R10-R12,R14,PC}^
+               DCB     "daft"
+
+               LTORG
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/sh/fastMove b/StraySrc/Libraries/Core/sh/fastMove
new file mode 100644 (file)
index 0000000..ece1ba4
--- /dev/null
@@ -0,0 +1,49 @@
+;
+; fastMove.sh
+;
+; Fast memory manipulation
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core libraries (corelib).
+;
+; Corelib is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Corelib is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Corelib.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  fastMove
+
+; --- fastMove ---
+;
+; On entry:    R0 == destination pointer
+;              R1 == source pointer
+;              R2 == number of bytes to move
+;
+; On exit:     --
+;
+; Use:         A very fast block moving routine.  Word aligning is not
+;              necessary, and the blocks may overlap.  This is basically
+;              the routine from PRM 2, hacked to cope with overlapping.
+
+               IMPORT  fastMove
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/sh/flex b/StraySrc/Libraries/Core/sh/flex
new file mode 100644 (file)
index 0000000..f3a6e82
--- /dev/null
@@ -0,0 +1,232 @@
+;
+; flex.sh
+;
+; Flexible memory handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Flex.
+;
+; Flex is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Flex is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Flex.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  flex_reduce
+;  flex_compact
+;  flex_free
+;  flex_alloc
+;  flex_size
+;  flex_extend
+;  flex_midExtend
+;  flex_init
+;  flex_save
+;  flex_load
+;  flex_dump
+;
+; Macros provided:
+;
+;   FSAVE
+;   FLOAD
+
+;+             LIB     sapphire:^.bsh.flex
+
+; --- flex_reduce ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Compacts the flex heap by one iteration.
+
+               IMPORT  flex_reduce
+
+; --- flex_compact ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Completely compacts the flex heap.
+
+               IMPORT  flex_compact
+
+; --- flex_free ---
+;
+; On entry:    R0 == pointer to the flex anchor
+;
+; On exit:     --
+;
+; Use:         Frees a flex block allocated by flex_alloc.
+
+               IMPORT  flex_free
+
+; --- flex_alloc ---
+;
+; On entry:    R0 == pointer to a flex anchor
+;              R1 == desired size of flex block
+;
+; On exit:     CS if no memory could be allocated, CC otherwise
+;
+; Use:         Allocates a block in the shifting heap.
+
+               IMPORT  flex_alloc
+
+; --- flex_size ---
+;
+; On entry:    R0 == pointer to flex anchor
+;
+; On exit:     R0 == size of allocated block
+;
+; Use:         Reads the size of a flex block.
+
+               IMPORT  flex_size
+
+; --- flex_extend ---
+;
+; On entry:    R0 == pointer to flex anchor
+;              R1 == new size of block to set
+;
+; On exit:     CS if it failed due to lack of memory, CC otherwise
+;
+; Use:         Alters the size of a block to the given value.
+
+               IMPORT  flex_extend
+
+; --- flex_midExtend ---
+;
+; On entry:    R0 == pointer to a flex anchor
+;              R1 == `at' -- position in block to extend from
+;              R2 == `by' -- how many bytes to extend (may be -ve)
+;
+; On exit:     CS if it failed due to lack of memory, CC otherwise
+;
+; Use:         Either creates a gap in a block (by>0) or deletes bytes
+;              from a block.  This is always done in such a way that the
+;              byte originally at offset `at' is now at offset `at'+`by'.
+
+               IMPORT  flex_midExtend
+
+; --- flex_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the flex heap for use.
+
+               IMPORT  flex_init
+
+; --- flex_save ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Saves some registers on the flex relocation stack.  R13
+;              and R14 cannot be saved -- these registers are corrupted
+;              during this routine's execution.
+;
+;              Values saved on the flex relocation stack are adjusted as
+;              flex moves blocks of memory around, so that they still point
+;              to the same thing as they did before.  Obviously, values
+;              which aren't pointers into flex blocks may be corrupted.
+;              Values pointing to objects deleted (either free blocks, or
+;              areas removed by flex_midExtend) may also be corrupted.
+;
+;              Since this routine takes no arguments, some other method has
+;              to be used.  The method chosen is to follow the call to
+;              flex_save with a LDM or STM instruction containing the
+;              registers to be saved.  This instruction is skipped by the
+;              routine, and thus not executed.
+;
+;              Note that if you give the LDM or STM the same condition code
+;              as the BL preceding it, it will never be executed, since
+;              flex_save skips it if the condition is true and it can't be
+;              executed if the condition is false.
+
+               [       :DEF:FLEX_STACK
+               IMPORT  flex_save
+               ]
+
+; --- flex_load ---
+;
+; On entry:    --
+;
+; On exit:     Registers loaded from relocation stack as requested
+;
+; Use:         Restores registers saved on flex's relocation stack.  See
+;              flex_save for calling information and details about the
+;              relocation stack.
+
+               [       :DEF:FLEX_STACK
+               IMPORT  flex_load
+               ]
+
+;----- Useful macros --------------------------------------------------------
+
+; --- Macro: FSAVE ---
+;
+; Arguments:   rList == quoted register list to save on relocation stack
+;
+; Use:         Assembles code to write the given register list on the
+;              flex relocation stack.  The register list should be in the
+;              same form as that for an STM or LDM instruction.
+;
+;              For full details about the flex relocation stack, see
+;              flex_save.
+
+               [       :DEF:FLEX_STACK
+
+               MACRO
+$label         FSAVE   $rList
+
+               BL      flex_save
+               STMEA   R14!,{$rList}
+
+               MEND
+
+               ]
+
+; --- Macro: FLOAD ---
+;
+; Arguments:   rList == quoted register list to read from relocation stack
+;
+; Use:         Assembles code to read the given register list from the
+;              flex relocation stack.  The register list should be in the
+;              same form as that for an STM or LDM instruction.
+;
+;              For full details about the flex relocation stack, see
+;              flex_save.
+
+               [       :DEF:FLEX_STACK
+
+               MACRO
+$label         FLOAD   $rList
+
+               BL      flex_load
+               LDMEA   R14!,{$rList}
+
+               MEND
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/sh/flexws b/StraySrc/Libraries/Core/sh/flexws
new file mode 100644 (file)
index 0000000..4534560
--- /dev/null
@@ -0,0 +1,51 @@
+;
+; flexws.sh
+;
+; Flexible memory handling workspace (MDW)
+;
+; © 1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's flex.
+;
+; Flex is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Flex is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Flex.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Options --------------------------------------------------------------
+;
+; Options must be defined, although the value is irrelevant.
+;
+; FLEXWS_DYNAREA       Define workspace for dynamic area support
+; FLEXWS_STACK         Define workspace for relocation stack support
+
+flex__flags    #       4                       ;Various interesting flags
+flex__base     #       4                       ;Base of the flex area
+flex__free     #       4                       ;Start of free area
+flex__end      #       4                       ;End of the flex area
+flex__chunk    #       4                       ;Page size to allocate in
+
+               [       :DEF:FLEXWS_DYNAREA
+flex__dynArea  #       4                       ;Dynamic area handle
+               ]
+
+               [       :DEF:FLEXWS_STACK
+flex__relocSP  #       4                       ;Stack ptr for relocation stk
+flex__relocStk #       256*4                   ;Make space for 256 entries
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/sh/heapws b/StraySrc/Libraries/Core/sh/heapws
new file mode 100644 (file)
index 0000000..aa6fcac
--- /dev/null
@@ -0,0 +1,35 @@
+;
+; heap.s
+;
+; A resizing, nonshifting heap workspace (MDW)
+;
+; © 1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's heap.
+;
+; Heap is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Heap is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Heap.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+heap__flex     #       4                       ;Pointer to flex block
+heap__chunkSize        #       4                       ;Size to allocate chunks in
+heap__freeList #       4                       ;Offset to free list, or 0
+heap__alloced  #       4                       ;Offset to unallocated area
+heap__size     #       4                       ;Current size of heap
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/stream b/StraySrc/Libraries/Core/stream
new file mode 100644 (file)
index 0000000..a23a033
--- /dev/null
@@ -0,0 +1,227 @@
+;
+; stream
+;
+; Debugging with VDUStream
+;   VDUStream is copyright Computer Concepts.  Distribution terms appear to
+;   be ambiguous.
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core library (corelib).
+;
+; Corelib is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Corelib is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Corelib.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Macros provided:
+;
+;   SAVE
+;   LOAD
+;   BPT
+;   S
+;   REGH
+;   REGD
+;   REGS
+;   REGC
+;   RDUMP
+
+; --- Macro: SAVE ---
+;
+; Arguments:   --
+;
+; Use:         Saves R0, R14 and the current flags so that they can be
+;              restored by a subsequent LOAD.
+
+               MACRO
+$label         SAVE
+$label         STMFD   R13!,{R0,R14}
+               STMFD   R13!,{PC}
+               MEND
+
+; --- Macro: LOAD ---
+;
+; Arguments:   --
+;
+; Use:         Restores R0, R14 and the flags after a SAVE.
+
+               MACRO
+$label         LOAD
+$label         LDMFD   R13!,{R14}
+               TEQP    R14,#0
+               LDMFD   R13!,{R0,R14}
+               MEND
+
+; --- Macro: BPT ---
+;
+; Arguments:   msg == message to print
+;              cc == condition
+;
+; Use:         Inserts a Sledgehammer breakpoint in the code.
+
+               MACRO
+$label         BPT     $msg,$cc
+$label
+               [       "$cc"<>""
+               ADD$cc  PC,PC,#0
+               ADD     PC,PC,#(36+:LEN:"$msg"+4) :AND: -4
+               ]
+               SAVE
+               SWI     XOS_WriteI+26
+               SWI     XOS_WriteI+4
+               SWI     XOS_WriteI+12
+               SWI     XOS_WriteS
+               DCB     "$msg",0
+               SWI     XOS_NewLine
+               SWI     Sledgehammer_BreakPoint
+               LOAD
+               MEND
+
+; --- Macro: S ---
+;
+; Arguments:   str == a string to display
+;
+; Use:         Writes a given string to VDUStream.
+
+               MACRO
+$label         S       $str
+$label         SAVE
+               SWI     Stream_WriteS
+               DCB     "$str",13,10,0
+               LOAD
+               MEND
+
+; --- Macro: REGH ---
+;
+; Arguments:   r == the register symbol to display
+;              str == an optional name for the value
+;
+; Use:         Writes to VDUStream the value of the given register as
+;              a hex value.
+
+               MACRO
+$label         REGH    $r,$str
+$label         SAVE
+               MOV     R0,$r
+               SWI     Stream_WriteS
+               [ "$str" <> ""
+               DCB     "$str == &",0
+               |
+               DCB     "$r == &",0
+               ]
+               SWI     Stream_WriteH32
+               SWI     Stream_NewLine
+               LOAD
+               MEND
+
+; --- Macro: REGC ---
+;
+; Arguments:   r == the register symbol to display
+;              str == an optional name for the value
+;
+; Use:         Writes to VDUStream the value of the given register as
+;              a character.
+
+               MACRO
+$label         REGC    $r,$str
+$label         SAVE
+               MOV     R0,$r
+               SWI     Stream_WriteS
+               [ "$str" <> ""
+               DCB     "$str == `",0
+               |
+               DCB     "$r == `",0
+               ]
+               SWI     Stream_WriteT8
+               MOV     R0,#'''
+               SWI     Stream_WriteT8
+               SWI     Stream_NewLine
+               LOAD
+               MEND
+
+; --- Macro: REGD ---
+;
+; Arguments:   r == the register symbol to display
+;              str == an optional name for the value
+;
+; Use:         Writes to VDUStream the value of the given register as
+;              a decimal value.
+
+               MACRO
+$label         REGD    $r,$str
+$label         SAVE
+               MOV     R0,$r
+               SWI     Stream_WriteS
+               [ "$str" <> ""
+               DCB     "$str == ",0
+               |
+               DCB     "$r == ",0
+               ]
+               SWI     Stream_WriteD32
+               SWI     Stream_NewLine
+               LOAD
+               MEND
+
+; --- Macro: REGS ---
+;
+; Arguments:   r == the register symbol to display
+;              str == an optional name for the value
+;
+; Use:         Writes to VDUStream the null terminated string pointed to
+;              by the given register.
+
+               MACRO
+$label         REGS    $r,$str
+$label         SAVE
+               MOV     R0,$r
+               SWI     Stream_WriteS
+               [ "$str" <> ""
+               DCB     "$str == `",0
+               |
+               DCB     "$r == `",0
+               ]
+               SWI     Stream_Write0
+               MOV     R0,#'''
+               SWI     Stream_WriteT8
+               SWI     Stream_NewLine
+               LOAD
+               MEND
+
+; --- Macro: RDUMP ---
+;
+; Arguments:   str == an optional heading string for the register dump
+;
+; Use:         Displays a total register dump.
+
+               MACRO
+$label         RDUMP   $str
+               IMPORT  stream_regDump
+$label         STMFD   R13!,{R0-PC}
+               ADD     R0,R13,#16*4
+               STR     R0,[R13,#13*4]
+               [       "$str" <> ""
+               SWI     Stream_WriteS
+               DCB     "$str",10,13,0
+               ]
+               MOV     R0,R13
+               BL      stream_regDump
+               LDMIA   R13,{R0-R14}
+               MEND
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Core/swis b/StraySrc/Libraries/Core/swis
new file mode 100644 (file)
index 0000000..c593b0f
--- /dev/null
@@ -0,0 +1,1521 @@
+;
+; swis.sh
+;
+; SWI names from numbers [generated 24 January 1998 by SWIList]
+; You may freely distribute and modify this file.
+;
+
+               [       :LNOT::DEF:swis__dfn
+               GBLL    swis__dfn
+
+               MACRO
+               SWIDEF  $name,$number
+$name          EQU     $number
+X$name         EQU     $number :OR: &20000
+               MEND
+
+               ; --- Kernel SWIs ---
+
+               SWIDEF  OS_WriteI,&00000100
+
+               ; --- Kernel SWIs ---
+
+               SWIDEF  OS_WriteC,&00000000
+               SWIDEF  OS_WriteS,&00000001
+               SWIDEF  OS_Write0,&00000002
+               SWIDEF  OS_NewLine,&00000003
+               SWIDEF  OS_ReadC,&00000004
+               SWIDEF  OS_CLI,&00000005
+               SWIDEF  OS_Byte,&00000006
+               SWIDEF  OS_Word,&00000007
+               SWIDEF  OS_File,&00000008
+               SWIDEF  OS_Args,&00000009
+               SWIDEF  OS_BGet,&0000000A
+               SWIDEF  OS_BPut,&0000000B
+               SWIDEF  OS_GBPB,&0000000C
+               SWIDEF  OS_Find,&0000000D
+               SWIDEF  OS_ReadLine,&0000000E
+               SWIDEF  OS_Control,&0000000F
+               SWIDEF  OS_GetEnv,&00000010
+               SWIDEF  OS_Exit,&00000011
+               SWIDEF  OS_SetEnv,&00000012
+               SWIDEF  OS_IntOn,&00000013
+               SWIDEF  OS_IntOff,&00000014
+               SWIDEF  OS_CallBack,&00000015
+               SWIDEF  OS_EnterOS,&00000016
+               SWIDEF  OS_BreakPt,&00000017
+               SWIDEF  OS_BreakCtrl,&00000018
+               SWIDEF  OS_UnusedSWI,&00000019
+               SWIDEF  OS_UpdateMEMC,&0000001A
+               SWIDEF  OS_SetCallBack,&0000001B
+               SWIDEF  OS_Mouse,&0000001C
+               SWIDEF  OS_Heap,&0000001D
+               SWIDEF  OS_Module,&0000001E
+               SWIDEF  OS_Claim,&0000001F
+               SWIDEF  OS_Release,&00000020
+               SWIDEF  OS_ReadUnsigned,&00000021
+               SWIDEF  OS_GenerateEvent,&00000022
+               SWIDEF  OS_ReadVarVal,&00000023
+               SWIDEF  OS_SetVarVal,&00000024
+               SWIDEF  OS_GSInit,&00000025
+               SWIDEF  OS_GSRead,&00000026
+               SWIDEF  OS_GSTrans,&00000027
+               SWIDEF  OS_BinaryToDecimal,&00000028
+               SWIDEF  OS_FSControl,&00000029
+               SWIDEF  OS_ChangeDynamicArea,&0000002A
+               SWIDEF  OS_GenerateError,&0000002B
+               SWIDEF  OS_ReadEscapeState,&0000002C
+               SWIDEF  OS_EvaluateExpression,&0000002D
+               SWIDEF  OS_SpriteOp,&0000002E
+               SWIDEF  OS_ReadPalette,&0000002F
+               SWIDEF  OS_ServiceCall,&00000030
+               SWIDEF  OS_ReadVduVariables,&00000031
+               SWIDEF  OS_ReadPoint,&00000032
+               SWIDEF  OS_UpCall,&00000033
+               SWIDEF  OS_CallAVector,&00000034
+               SWIDEF  OS_ReadModeVariable,&00000035
+               SWIDEF  OS_RemoveCursors,&00000036
+               SWIDEF  OS_RestoreCursors,&00000037
+               SWIDEF  OS_SWINumberToString,&00000038
+               SWIDEF  OS_SWINumberFromString,&00000039
+               SWIDEF  OS_ValidateAddress,&0000003A
+               SWIDEF  OS_CallAfter,&0000003B
+               SWIDEF  OS_CallEvery,&0000003C
+               SWIDEF  OS_RemoveTickerEvent,&0000003D
+               SWIDEF  OS_InstallKeyHandler,&0000003E
+               SWIDEF  OS_CheckModeValid,&0000003F
+               SWIDEF  OS_ChangeEnvironment,&00000040
+               SWIDEF  OS_ClaimScreenMemory,&00000041
+               SWIDEF  OS_ReadMonotonicTime,&00000042
+               SWIDEF  OS_SubstituteArgs,&00000043
+               SWIDEF  OS_PrettyPrint,&00000044
+               SWIDEF  OS_Plot,&00000045
+               SWIDEF  OS_WriteN,&00000046
+               SWIDEF  OS_AddToVector,&00000047
+               SWIDEF  OS_WriteEnv,&00000048
+               SWIDEF  OS_ReadArgs,&00000049
+               SWIDEF  OS_ReadRAMFsLimits,&0000004A
+               SWIDEF  OS_ClaimDeviceVector,&0000004B
+               SWIDEF  OS_ReleaseDeviceVector,&0000004C
+               SWIDEF  OS_DelinkApplication,&0000004D
+               SWIDEF  OS_RelinkApplication,&0000004E
+               SWIDEF  OS_HeapSort,&0000004F
+               SWIDEF  OS_ExitAndDie,&00000050
+               SWIDEF  OS_ReadMemMapInfo,&00000051
+               SWIDEF  OS_ReadMemMapEntries,&00000052
+               SWIDEF  OS_SetMemMapEntries,&00000053
+               SWIDEF  OS_AddCallBack,&00000054
+               SWIDEF  OS_ReadDefaultHandler,&00000055
+               SWIDEF  OS_SetECFOrigin,&00000056
+               SWIDEF  OS_SerialOp,&00000057
+               SWIDEF  OS_ReadSysInfo,&00000058
+               SWIDEF  OS_Confirm,&00000059
+               SWIDEF  OS_ChangedBox,&0000005A
+               SWIDEF  OS_CRC,&0000005B
+               SWIDEF  OS_ReadDynamicArea,&0000005C
+               SWIDEF  OS_PrintChar,&0000005D
+               SWIDEF  OS_ChangeRedirection,&0000005E
+               SWIDEF  OS_RemoveCallBack,&0000005F
+               SWIDEF  OS_FindMemMapEntries,&00000060
+               SWIDEF  OS_SetColour,&00000061
+               SWIDEF  OS_ClaimSWI,&00000062
+               SWIDEF  OS_ReleaseSWI,&00000063
+               SWIDEF  OS_Pointer,&00000064
+               SWIDEF  OS_ScreenMode,&00000065
+               SWIDEF  OS_DynamicArea,&00000066
+               SWIDEF  OS_AbortTrap,&00000067
+               SWIDEF  OS_Memory,&00000068
+               SWIDEF  OS_ClaimProcessorVector,&00000069
+               SWIDEF  OS_Reset,&0000006A
+               SWIDEF  OS_MMUControl,&0000006B
+               SWIDEF  OS_PlatformFeatures,&0000006D
+               SWIDEF  OS_SynchroniseCodeAreas,&0000006E
+               SWIDEF  OS_CallASWI,&0000006F
+               SWIDEF  OS_AMBControl,&00000070
+               SWIDEF  OS_CallASWIR12,&00000071
+               SWIDEF  OS_ConvertStandardDateAndTime,&000000C0
+               SWIDEF  OS_ConvertDateAndTime,&000000C1
+               SWIDEF  OS_ConvertHex1,&000000D0
+               SWIDEF  OS_ConvertHex2,&000000D1
+               SWIDEF  OS_ConvertHex4,&000000D2
+               SWIDEF  OS_ConvertHex6,&000000D3
+               SWIDEF  OS_ConvertHex8,&000000D4
+               SWIDEF  OS_ConvertCardinal1,&000000D5
+               SWIDEF  OS_ConvertCardinal2,&000000D6
+               SWIDEF  OS_ConvertCardinal3,&000000D7
+               SWIDEF  OS_ConvertCardinal4,&000000D8
+               SWIDEF  OS_ConvertInteger1,&000000D9
+               SWIDEF  OS_ConvertInteger2,&000000DA
+               SWIDEF  OS_ConvertInteger3,&000000DB
+               SWIDEF  OS_ConvertInteger4,&000000DC
+               SWIDEF  OS_ConvertBinary1,&000000DD
+               SWIDEF  OS_ConvertBinary2,&000000DE
+               SWIDEF  OS_ConvertBinary3,&000000DF
+               SWIDEF  OS_ConvertBinary4,&000000E0
+               SWIDEF  OS_ConvertSpacedCardinal1,&000000E1
+               SWIDEF  OS_ConvertSpacedCardinal2,&000000E2
+               SWIDEF  OS_ConvertSpacedCardinal3,&000000E3
+               SWIDEF  OS_ConvertSpacedCardinal4,&000000E4
+               SWIDEF  OS_ConvertSpacedInteger1,&000000E5
+               SWIDEF  OS_ConvertSpacedInteger2,&000000E6
+               SWIDEF  OS_ConvertSpacedInteger3,&000000E7
+               SWIDEF  OS_ConvertSpacedInteger4,&000000E8
+               SWIDEF  OS_ConvertFixedNetStation,&000000E9
+               SWIDEF  OS_ConvertNetStation,&000000EA
+               SWIDEF  OS_ConvertFixedFileSize,&000000EB
+               SWIDEF  OS_ConvertFileSize,&000000EC
+
+               ; --- Podule SWIs ---
+
+               SWIDEF  Podule_ReadID,&00040280
+               SWIDEF  Podule_ReadHeader,&00040281
+               SWIDEF  Podule_EnumerateChunks,&00040282
+               SWIDEF  Podule_ReadChunk,&00040283
+               SWIDEF  Podule_ReadBytes,&00040284
+               SWIDEF  Podule_WriteBytes,&00040285
+               SWIDEF  Podule_CallLoader,&00040286
+               SWIDEF  Podule_RawRead,&00040287
+               SWIDEF  Podule_RawWrite,&00040288
+               SWIDEF  Podule_HardwareAddress,&00040289
+               SWIDEF  Podule_EnumerateChunksWithInfo,&0004028A
+               SWIDEF  Podule_HardwareAddresses,&0004028B
+               SWIDEF  Podule_ReturnNumber,&0004028C
+               SWIDEF  Podule_ReadInfo,&0004028D
+               SWIDEF  Podule_SetSpeed,&0004028E
+
+               ; --- ResourceFS SWIs ---
+
+               SWIDEF  ResourceFS_RegisterFiles,&00041B40
+               SWIDEF  ResourceFS_DeregisterFiles,&00041B41
+
+               ; --- MessageTrans SWIs ---
+
+               SWIDEF  MessageTrans_FileInfo,&00041500
+               SWIDEF  MessageTrans_OpenFile,&00041501
+               SWIDEF  MessageTrans_Lookup,&00041502
+               SWIDEF  MessageTrans_MakeMenus,&00041503
+               SWIDEF  MessageTrans_CloseFile,&00041504
+               SWIDEF  MessageTrans_EnumerateTokens,&00041505
+               SWIDEF  MessageTrans_ErrorLookup,&00041506
+               SWIDEF  MessageTrans_GSLookup,&00041507
+               SWIDEF  MessageTrans_CopyError,&00041508
+               SWIDEF  MessageTrans_Dictionary,&00041509
+
+               ; --- TerritoryManager SWIs ---
+
+               SWIDEF  Territory_Number,&00043040
+               SWIDEF  Territory_Register,&00043041
+               SWIDEF  Territory_Deregister,&00043042
+               SWIDEF  Territory_NumberToName,&00043043
+               SWIDEF  Territory_Exists,&00043044
+               SWIDEF  Territory_AlphabetNumberToName,&00043045
+               SWIDEF  Territory_SelectAlphabet,&00043046
+               SWIDEF  Territory_SetTime,&00043047
+               SWIDEF  Territory_ReadCurrentTimeZone,&00043048
+               SWIDEF  Territory_ConvertTimeToUTCOrdinals,&00043049
+               SWIDEF  Territory_ReadTimeZones,&0004304A
+               SWIDEF  Territory_ConvertDateAndTime,&0004304B
+               SWIDEF  Territory_ConvertStandardDateAndTime,&0004304C
+               SWIDEF  Territory_ConvertStandardDate,&0004304D
+               SWIDEF  Territory_ConvertStandardTime,&0004304E
+               SWIDEF  Territory_ConvertTimeToOrdinals,&0004304F
+               SWIDEF  Territory_ConvertTimeStringToOrdinals,&00043050
+               SWIDEF  Territory_ConvertOrdinalsToTime,&00043051
+               SWIDEF  Territory_Alphabet,&00043052
+               SWIDEF  Territory_AlphabetIdentifier,&00043053
+               SWIDEF  Territory_SelectKeyboardHandler,&00043054
+               SWIDEF  Territory_WriteDirection,&00043055
+               SWIDEF  Territory_CharacterPropertyTable,&00043056
+               SWIDEF  Territory_LowerCaseTable,&00043057
+               SWIDEF  Territory_UpperCaseTable,&00043058
+               SWIDEF  Territory_ControlTable,&00043059
+               SWIDEF  Territory_PlainTable,&0004305A
+               SWIDEF  Territory_ValueTable,&0004305B
+               SWIDEF  Territory_RepresentationTable,&0004305C
+               SWIDEF  Territory_Collate,&0004305D
+               SWIDEF  Territory_ReadSymbols,&0004305E
+               SWIDEF  Territory_ReadCalendarInformation,&0004305F
+               SWIDEF  Territory_NameToNumber,&00043060
+               SWIDEF  Territory_TransformString,&00043061
+               SWIDEF  Territory_ConvertTextToString,&00043075
+
+               ; --- WindowManager SWIs ---
+
+               SWIDEF  Wimp_Initialise,&000400C0
+               SWIDEF  Wimp_CreateWindow,&000400C1
+               SWIDEF  Wimp_CreateIcon,&000400C2
+               SWIDEF  Wimp_DeleteWindow,&000400C3
+               SWIDEF  Wimp_DeleteIcon,&000400C4
+               SWIDEF  Wimp_OpenWindow,&000400C5
+               SWIDEF  Wimp_CloseWindow,&000400C6
+               SWIDEF  Wimp_Poll,&000400C7
+               SWIDEF  Wimp_RedrawWindow,&000400C8
+               SWIDEF  Wimp_UpdateWindow,&000400C9
+               SWIDEF  Wimp_GetRectangle,&000400CA
+               SWIDEF  Wimp_GetWindowState,&000400CB
+               SWIDEF  Wimp_GetWindowInfo,&000400CC
+               SWIDEF  Wimp_SetIconState,&000400CD
+               SWIDEF  Wimp_GetIconState,&000400CE
+               SWIDEF  Wimp_GetPointerInfo,&000400CF
+               SWIDEF  Wimp_DragBox,&000400D0
+               SWIDEF  Wimp_ForceRedraw,&000400D1
+               SWIDEF  Wimp_SetCaretPosition,&000400D2
+               SWIDEF  Wimp_GetCaretPosition,&000400D3
+               SWIDEF  Wimp_CreateMenu,&000400D4
+               SWIDEF  Wimp_DecodeMenu,&000400D5
+               SWIDEF  Wimp_WhichIcon,&000400D6
+               SWIDEF  Wimp_SetExtent,&000400D7
+               SWIDEF  Wimp_SetPointerShape,&000400D8
+               SWIDEF  Wimp_OpenTemplate,&000400D9
+               SWIDEF  Wimp_CloseTemplate,&000400DA
+               SWIDEF  Wimp_LoadTemplate,&000400DB
+               SWIDEF  Wimp_ProcessKey,&000400DC
+               SWIDEF  Wimp_CloseDown,&000400DD
+               SWIDEF  Wimp_StartTask,&000400DE
+               SWIDEF  Wimp_ReportError,&000400DF
+               SWIDEF  Wimp_GetWindowOutline,&000400E0
+               SWIDEF  Wimp_PollIdle,&000400E1
+               SWIDEF  Wimp_PlotIcon,&000400E2
+               SWIDEF  Wimp_SetMode,&000400E3
+               SWIDEF  Wimp_SetPalette,&000400E4
+               SWIDEF  Wimp_ReadPalette,&000400E5
+               SWIDEF  Wimp_SetColour,&000400E6
+               SWIDEF  Wimp_SendMessage,&000400E7
+               SWIDEF  Wimp_CreateSubMenu,&000400E8
+               SWIDEF  Wimp_SpriteOp,&000400E9
+               SWIDEF  Wimp_BaseOfSprites,&000400EA
+               SWIDEF  Wimp_BlockCopy,&000400EB
+               SWIDEF  Wimp_SlotSize,&000400EC
+               SWIDEF  Wimp_ReadPixTrans,&000400ED
+               SWIDEF  Wimp_ClaimFreeMemory,&000400EE
+               SWIDEF  Wimp_CommandWindow,&000400EF
+               SWIDEF  Wimp_TextColour,&000400F0
+               SWIDEF  Wimp_TransferBlock,&000400F1
+               SWIDEF  Wimp_ReadSysInfo,&000400F2
+               SWIDEF  Wimp_SetFontColours,&000400F3
+               SWIDEF  Wimp_GetMenuState,&000400F4
+               SWIDEF  Wimp_RegisterFilter,&000400F5
+               SWIDEF  Wimp_AddMessages,&000400F6
+               SWIDEF  Wimp_RemoveMessages,&000400F7
+               SWIDEF  Wimp_SetColourMapping,&000400F8
+               SWIDEF  Wimp_TextOp,&000400F9
+               SWIDEF  Wimp_SetWatchdogState,&000400FA
+               SWIDEF  Wimp_Extend,&000400FB
+               SWIDEF  Wimp_ResizeIcon,&000400FC
+
+               ; --- TaskManager SWIs ---
+
+               SWIDEF  TaskManager_TaskNameFromHandle,&00042680
+               SWIDEF  TaskManager_EnumerateTasks,&00042681
+               SWIDEF  TaskManager_Shutdown,&00042682
+
+               ; --- BASICTrans SWIs ---
+
+               SWIDEF  BASICTrans_HELP,&00042C80
+               SWIDEF  BASICTrans_Error,&00042C81
+               SWIDEF  BASICTrans_Message,&00042C82
+
+               ; --- BufferManager SWIs ---
+
+               SWIDEF  Buffer_Create,&00042940
+               SWIDEF  Buffer_Remove,&00042941
+               SWIDEF  Buffer_Register,&00042942
+               SWIDEF  Buffer_Deregister,&00042943
+               SWIDEF  Buffer_ModifyFlags,&00042944
+               SWIDEF  Buffer_LinkDevice,&00042945
+               SWIDEF  Buffer_UnlinkDevice,&00042946
+               SWIDEF  Buffer_GetInfo,&00042947
+               SWIDEF  Buffer_Threshold,&00042948
+               SWIDEF  Buffer_InternalInfo,&00042949
+
+               ; --- Debugger SWIs ---
+
+               SWIDEF  Debugger_Disassemble,&00040380
+
+               ; --- DeviceFS SWIs ---
+
+               SWIDEF  DeviceFS_Register,&00042740
+               SWIDEF  DeviceFS_Deregister,&00042741
+               SWIDEF  DeviceFS_RegisterObjects,&00042742
+               SWIDEF  DeviceFS_DeregisterObjects,&00042743
+               SWIDEF  DeviceFS_CallDevice,&00042744
+               SWIDEF  DeviceFS_Threshold,&00042745
+               SWIDEF  DeviceFS_ReceivedCharacter,&00042746
+               SWIDEF  DeviceFS_TransmitCharacter,&00042747
+
+               ; --- DMAManager SWIs ---
+
+               SWIDEF  DMA_RegisterChannel,&00046140
+               SWIDEF  DMA_DeregisterChannel,&00046141
+               SWIDEF  DMA_QueueTransfer,&00046142
+               SWIDEF  DMA_TerminateTransfer,&00046143
+               SWIDEF  DMA_SuspendTransfer,&00046144
+               SWIDEF  DMA_ResumeTransfer,&00046145
+               SWIDEF  DMA_ExamineTransfer,&00046146
+
+               ; --- DragASprite SWIs ---
+
+               SWIDEF  DragASprite_Start,&00042400
+               SWIDEF  DragASprite_Stop,&00042401
+
+               ; --- Draw SWIs ---
+
+               SWIDEF  Draw_ProcessPath,&00040700
+               SWIDEF  Draw_ProcessPathFP,&00040701
+               SWIDEF  Draw_Fill,&00040702
+               SWIDEF  Draw_FillFP,&00040703
+               SWIDEF  Draw_Stroke,&00040704
+               SWIDEF  Draw_StrokeFP,&00040705
+               SWIDEF  Draw_StrokePath,&00040706
+               SWIDEF  Draw_StrokePathFP,&00040707
+               SWIDEF  Draw_FlattenPath,&00040708
+               SWIDEF  Draw_FlattenPathFP,&00040709
+               SWIDEF  Draw_TransformPath,&0004070A
+               SWIDEF  Draw_TransformPathFP,&0004070B
+
+               ; --- FileCore SWIs ---
+
+               SWIDEF  FileCore_DiscOp,&00040540
+               SWIDEF  FileCore_Create,&00040541
+               SWIDEF  FileCore_Drives,&00040542
+               SWIDEF  FileCore_FreeSpace,&00040543
+               SWIDEF  FileCore_FloppyStructure,&00040544
+               SWIDEF  FileCore_DescribeDisc,&00040545
+               SWIDEF  FileCore_DiscardReadSectorsCache,&00040546
+               SWIDEF  FileCore_DiscFormat,&00040547
+               SWIDEF  FileCore_LayoutStructure,&00040548
+               SWIDEF  FileCore_MiscOp,&00040549
+
+               ; --- ADFS SWIs ---
+
+               SWIDEF  ADFS_DiscOp,&00040240
+               SWIDEF  ADFS_HDC,&00040241
+               SWIDEF  ADFS_Drives,&00040242
+               SWIDEF  ADFS_FreeSpace,&00040243
+               SWIDEF  ADFS_Retries,&00040244
+               SWIDEF  ADFS_DescribeDisc,&00040245
+               SWIDEF  ADFS_VetFormat,&00040246
+               SWIDEF  ADFS_FlpProcessDCB,&00040247
+               SWIDEF  ADFS_ControllerType,&00040248
+               SWIDEF  ADFS_PowerControl,&00040249
+               SWIDEF  ADFS_SetIDEController,&0004024A
+               SWIDEF  ADFS_IDEUserOp,&0004024B
+               SWIDEF  ADFS_MiscOp,&0004024C
+               SWIDEF  ADFS_ECCSAndRetries,&00040250
+
+               ; --- FilerSWIs SWIs ---
+
+               SWIDEF  FilerAction_SendSelectedDirectory,&00040F80
+               SWIDEF  FilerAction_SendSelectedFile,&00040F81
+               SWIDEF  FilerAction_SendStartOperation,&00040F82
+
+               ; --- FSLock SWIs ---
+
+               SWIDEF  FSLock_Version,&00047780
+               SWIDEF  FSLock_Status,&00047781
+               SWIDEF  FSLock_ChangeStatus,&00047782
+
+               ; --- FontManager SWIs ---
+
+               SWIDEF  Font_CacheAddr,&00040080
+               SWIDEF  Font_FindFont,&00040081
+               SWIDEF  Font_LoseFont,&00040082
+               SWIDEF  Font_ReadDefn,&00040083
+               SWIDEF  Font_ReadInfo,&00040084
+               SWIDEF  Font_StringWidth,&00040085
+               SWIDEF  Font_Paint,&00040086
+               SWIDEF  Font_Caret,&00040087
+               SWIDEF  Font_ConverttoOS,&00040088
+               SWIDEF  Font_Converttopoints,&00040089
+               SWIDEF  Font_SetFont,&0004008A
+               SWIDEF  Font_CurrentFont,&0004008B
+               SWIDEF  Font_FutureFont,&0004008C
+               SWIDEF  Font_FindCaret,&0004008D
+               SWIDEF  Font_CharBBox,&0004008E
+               SWIDEF  Font_ReadScaleFactor,&0004008F
+               SWIDEF  Font_SetScaleFactor,&00040090
+               SWIDEF  Font_ListFonts,&00040091
+               SWIDEF  Font_SetFontColours,&00040092
+               SWIDEF  Font_SetPalette,&00040093
+               SWIDEF  Font_ReadThresholds,&00040094
+               SWIDEF  Font_SetThresholds,&00040095
+               SWIDEF  Font_FindCaretJ,&00040096
+               SWIDEF  Font_StringBBox,&00040097
+               SWIDEF  Font_ReadColourTable,&00040098
+               SWIDEF  Font_MakeBitmap,&00040099
+               SWIDEF  Font_UnCacheFile,&0004009A
+               SWIDEF  Font_SetFontMax,&0004009B
+               SWIDEF  Font_ReadFontMax,&0004009C
+               SWIDEF  Font_ReadFontPrefix,&0004009D
+               SWIDEF  Font_SwitchOutputToBuffer,&0004009E
+               SWIDEF  Font_ReadFontMetrics,&0004009F
+               SWIDEF  Font_DecodeMenu,&000400A0
+               SWIDEF  Font_ScanString,&000400A1
+               SWIDEF  Font_SetColourTable,&000400A2
+               SWIDEF  Font_CurrentRGB,&000400A3
+               SWIDEF  Font_FutureRGB,&000400A4
+               SWIDEF  Font_ReadEncodingFilename,&000400A5
+               SWIDEF  Font_FindField,&000400A6
+               SWIDEF  Font_ApplyFields,&000400A7
+               SWIDEF  Font_LookupFont,&000400A8
+
+               ; --- FPEmulator SWIs ---
+
+               SWIDEF  FPEmulator_Version,&00040480
+
+               ; --- Free SWIs ---
+
+               SWIDEF  Free_Register,&000444C0
+               SWIDEF  Free_DeRegister,&000444C1
+
+               ; --- Hourglass SWIs ---
+
+               SWIDEF  Hourglass_On,&000406C0
+               SWIDEF  Hourglass_Off,&000406C1
+               SWIDEF  Hourglass_Smash,&000406C2
+               SWIDEF  Hourglass_Start,&000406C3
+               SWIDEF  Hourglass_Percentage,&000406C4
+               SWIDEF  Hourglass_LEDs,&000406C5
+               SWIDEF  Hourglass_Colours,&000406C6
+
+               ; --- IIC SWIs ---
+
+               SWIDEF  IIC_Control,&00000240
+
+               ; --- ParallelDeviceDriver SWIs ---
+
+               SWIDEF  Parallel_HardwareAddress,&00042EC0
+               SWIDEF  Parallel_Op,&00042EC1
+
+               ; --- ScreenBlanker SWIs ---
+
+               SWIDEF  ScreenBlanker_Control,&00043100
+
+               ; --- ShellCLI SWIs ---
+
+               SWIDEF  Shell_Create,&000405C0
+               SWIDEF  Shell_Destroy,&000405C1
+
+               ; --- SoundDMA SWIs ---
+
+               SWIDEF  Sound_Configure,&00040140
+               SWIDEF  Sound_Enable,&00040141
+               SWIDEF  Sound_Stereo,&00040142
+               SWIDEF  Sound_Speaker,&00040143
+
+               ; --- SoundChannels SWIs ---
+
+               SWIDEF  Sound_Volume,&00040180
+               SWIDEF  Sound_SoundLog,&00040181
+               SWIDEF  Sound_LogScale,&00040182
+               SWIDEF  Sound_InstallVoice,&00040183
+               SWIDEF  Sound_RemoveVoice,&00040184
+               SWIDEF  Sound_AttachVoice,&00040185
+               SWIDEF  Sound_ControlPacked,&00040186
+               SWIDEF  Sound_Tuning,&00040187
+               SWIDEF  Sound_Pitch,&00040188
+               SWIDEF  Sound_Control,&00040189
+               SWIDEF  Sound_AttachNamedVoice,&0004018A
+               SWIDEF  Sound_ReadControlBlock,&0004018B
+               SWIDEF  Sound_WriteControlBlock,&0004018C
+
+               ; --- SoundScheduler SWIs ---
+
+               SWIDEF  Sound_QInit,&000401C0
+               SWIDEF  Sound_QSchedule,&000401C1
+               SWIDEF  Sound_QRemove,&000401C2
+               SWIDEF  Sound_QFree,&000401C3
+               SWIDEF  Sound_QSDispatch,&000401C4
+               SWIDEF  Sound_QTempo,&000401C5
+               SWIDEF  Sound_QBeat,&000401C6
+               SWIDEF  Sound_QInterface,&000401C7
+
+               ; --- Squash SWIs ---
+
+               SWIDEF  Squash_Compress,&00042700
+               SWIDEF  Squash_Decompress,&00042701
+
+               ; --- SuperSample SWIs ---
+
+               SWIDEF  Super_Sample90,&00040D80
+               SWIDEF  Super_Sample45,&00040D81
+
+               ; --- TaskWindow SWIs ---
+
+               SWIDEF  TaskWindow_TaskInfo,&00043380
+
+               ; --- FilterManager SWIs ---
+
+               SWIDEF  Filter_RegisterPreFilter,&00042640
+               SWIDEF  Filter_RegisterPostFilter,&00042641
+               SWIDEF  Filter_DeRegisterPreFilter,&00042642
+               SWIDEF  Filter_DeRegisterPostFilter,&00042643
+
+               ; --- SharedCLibrary SWIs ---
+
+               SWIDEF  SharedCLibrary_LibInitAPCS_A,&00080680
+               SWIDEF  SharedCLibrary_LibInitAPCS_R,&00080681
+               SWIDEF  SharedCLibrary_LibInitModule,&00080682
+
+               ; --- DOSFS SWIs ---
+
+               SWIDEF  DOSFS_DiscFormat,&00044B00
+               SWIDEF  DOSFS_LayoutStructure,&00044B01
+
+               ; --- ColourPicker SWIs ---
+
+               SWIDEF  ColourPicker_RegisterModel,&00047700
+               SWIDEF  ColourPicker_DeregisterModel,&00047701
+               SWIDEF  ColourPicker_OpenDialogue,&00047702
+               SWIDEF  ColourPicker_CloseDialogue,&00047703
+               SWIDEF  ColourPicker_UpdateDialogue,&00047704
+               SWIDEF  ColourPicker_ReadDialogue,&00047705
+               SWIDEF  ColourPicker_SetColour,&00047706
+               SWIDEF  ColourPicker_HelpReply,&00047707
+               SWIDEF  ColourPicker_ModelSWI,&00047708
+
+               ; --- ScreenModes SWIs ---
+
+               SWIDEF  ScreenModes_ReadInfo,&000487C0
+
+               ; --- SCSIDriver SWIs ---
+
+               SWIDEF  SCSI_Version,&000403C0
+               SWIDEF  SCSI_Initialise,&000403C1
+               SWIDEF  SCSI_Control,&000403C2
+               SWIDEF  SCSI_Op,&000403C3
+               SWIDEF  SCSI_Status,&000403C4
+               SWIDEF  SCSI_ReadControlLines,&000403C5
+               SWIDEF  SCSI_EEProm,&000403C6
+               SWIDEF  SCSI_Reserve,&000403C7
+               SWIDEF  SCSI_List,&000403C8
+               SWIDEF  SCSI_Target,&000403C9
+
+               ; --- SCSIFS SWIs ---
+
+               SWIDEF  SCSIFS_DiscOp,&00040980
+               SWIDEF  SCSIFS_Drives,&00040982
+               SWIDEF  SCSIFS_FreeSpace,&00040983
+               SWIDEF  SCSIFS_DescribeDisc,&00040985
+               SWIDEF  SCSIFS_TestReady,&00040986
+               SWIDEF  SCSIFS_MapDrives,&00040987
+               SWIDEF  SCSIFS_MotorControl,&00040988
+               SWIDEF  SCSIFS_MiscOp,&0004098C
+
+               ; --- CDFS SWIs ---
+
+               SWIDEF  CDFS_ConvertDriveToDevice,&00041E80
+               SWIDEF  CDFS_SetBufferSize,&00041E81
+               SWIDEF  CDFS_GetBufferSize,&00041E82
+               SWIDEF  CDFS_SetNumberOfDrives,&00041E83
+               SWIDEF  CDFS_GetNumberOfDrives,&00041E84
+               SWIDEF  CDFS_GiveFileType,&00041E85
+               SWIDEF  CDFS_DescribeDisc,&00041E86
+               SWIDEF  CDFS_WhereIsFile,&00041E87
+               SWIDEF  CDFS_Truncation,&00041E88
+
+               ; --- CDFSdriver SWIs ---
+
+               SWIDEF  CD_Version,&00041240
+               SWIDEF  CD_ReadData,&00041241
+               SWIDEF  CD_SeekTo,&00041242
+               SWIDEF  CD_DriveStatus,&00041243
+               SWIDEF  CD_DriveReady,&00041244
+               SWIDEF  CD_GetParameters,&00041245
+               SWIDEF  CD_SetParameters,&00041246
+               SWIDEF  CD_OpenDrawer,&00041247
+               SWIDEF  CD_EjectButton,&00041248
+               SWIDEF  CD_EnquireAddress,&00041249
+               SWIDEF  CD_EnquireDataMode,&0004124A
+               SWIDEF  CD_PlayAudio,&0004124B
+               SWIDEF  CD_PlayTrack,&0004124C
+               SWIDEF  CD_AudioPause,&0004124D
+               SWIDEF  CD_EnquireTrack,&0004124E
+               SWIDEF  CD_ReadSubChannel,&0004124F
+               SWIDEF  CD_CheckDrive,&00041250
+               SWIDEF  CD_DiscChanged,&00041251
+               SWIDEF  CD_StopDisc,&00041252
+               SWIDEF  CD_DiscUsed,&00041253
+               SWIDEF  CD_AudioStatus,&00041254
+               SWIDEF  CD_Inquiry,&00041255
+               SWIDEF  CD_DiscHasChanged,&00041256
+               SWIDEF  CD_Control,&00041257
+               SWIDEF  CD_Supported,&00041258
+               SWIDEF  CD_Prefetch,&00041259
+               SWIDEF  CD_Reset,&0004125A
+               SWIDEF  CD_CloseDrawer,&0004125B
+               SWIDEF  CD_IsDrawerLocked,&0004125C
+               SWIDEF  CD_AudioControl,&0004125D
+               SWIDEF  CD_LastError,&0004125E
+               SWIDEF  CD_AudioLevel,&0004125F
+               SWIDEF  CD_Register,&00041260
+               SWIDEF  CD_Unregister,&00041261
+               SWIDEF  CD_ByteCopy,&00041262
+               SWIDEF  CD_Identify,&00041263
+               SWIDEF  CD_ConvertToLBA,&00041264
+               SWIDEF  CD_ConvertToMSF,&00041265
+
+               ; --- Sarah SWIs ---
+
+               SWIDEF  Sarah_Cload,&00057CC0
+               SWIDEF  Sarah_Csave,&00057CC1
+               SWIDEF  Sarah_Eload,&00057CC2
+               SWIDEF  Sarah_Esave,&00057CC3
+               SWIDEF  Sarah_Envelope,&00057CC4
+               SWIDEF  Sarah_Prdump,&00057CC5
+               SWIDEF  Sarah_Zap,&00057CC6
+
+               ; --- DLLManager SWIs ---
+
+               SWIDEF  DLL_Find,&0004A300
+               SWIDEF  DLL_FindFromTable,&0004A301
+               SWIDEF  DLL_Load,&0004A302
+               SWIDEF  DLL_Lose,&0004A303
+               SWIDEF  DLL_AppDying,&0004A304
+               SWIDEF  DLL_GiveCLibData,&0004A305
+               SWIDEF  DLL_FindCLibData,&0004A306
+               SWIDEF  DLL_InstanceVars,&0004A307
+               SWIDEF  DLL_SetInstanceVars,&0004A308
+               SWIDEF  DLL_AppData,&0004A309
+               SWIDEF  DLL_Prologue,&0004A30A
+               SWIDEF  DLL_ReadStackPtr,&0004A30B
+               SWIDEF  DLL_SetStackPtr,&0004A30C
+               SWIDEF  DLL_NameApp,&0004A30D
+               SWIDEF  DLL_Info,&0004A30E
+               SWIDEF  DLL_FindEntry,&0004A30F
+               SWIDEF  DLL_SaveHandle,&0004A310
+               SWIDEF  DLL_RestoreHandle,&0004A311
+               SWIDEF  DLL_FindInstanceVars,&0004A312
+               SWIDEF  DLL_RegisterAppEntryTable,&0004A313
+               SWIDEF  DLL_FindAppEntry,&0004A314
+               SWIDEF  DLL_SetExtensionTable,&0004A315
+
+               ; --- ZapRedraw SWIs ---
+
+               SWIDEF  ZapRedraw_RedrawArea,&00048480
+               SWIDEF  ZapRedraw_GetPaletteEntry,&00048481
+               SWIDEF  ZapRedraw_RedrawRaster,&00048482
+               SWIDEF  ZapRedraw_ConvertBitmap,&00048483
+               SWIDEF  ZapRedraw_PrepareDataLine,&00048484
+               SWIDEF  ZapRedraw_AddCursor,&00048485
+               SWIDEF  ZapRedraw_FindCharacter,&00048486
+               SWIDEF  ZapRedraw_MoveBytes,&00048487
+               SWIDEF  ZapRedraw_CachedCharSize,&00048488
+               SWIDEF  ZapRedraw_ConvBitmapChar,&00048489
+               SWIDEF  ZapRedraw_CreatePalette,&0004848A
+               SWIDEF  ZapRedraw_InsertChar,&0004848B
+               SWIDEF  ZapRedraw_ReadSystemChars,&0004848C
+               SWIDEF  ZapRedraw_ReverseBitmaps,&0004848D
+               SWIDEF  ZapRedraw_ReadVduVars,&0004848E
+               SWIDEF  ZapRedraw_GetRectangle,&0004848F
+               SWIDEF  ZapRedraw_AddVduBitmaps,&00048490
+               SWIDEF  ZapRedraw_CacheFontChars,&00048491
+               SWIDEF  ZapRedraw_SpriteSize,&00048492
+               SWIDEF  ZapRedraw_RedrawWindow,&00048493
+
+               ; --- 310Support SWIs ---
+
+
+               ; --- ABCLibrary SWIs ---
+
+               SWIDEF  ABCLib_Init,&00080B80
+               SWIDEF  ABCLib_Register,&00080B81
+               SWIDEF  ABCLib_Profile,&00080B82
+               SWIDEF  ABCLib_WAC,&00080B83
+
+               ; --- DDEUtils SWIs ---
+
+               SWIDEF  DDEUtils_Prefix,&00042580
+               SWIDEF  DDEUtils_SetCLSize,&00042581
+               SWIDEF  DDEUtils_SetCL,&00042582
+               SWIDEF  DDEUtils_GetCLSize,&00042583
+               SWIDEF  DDEUtils_GetCl,&00042584
+               SWIDEF  DDEUtils_ThrowbackRegister,&00042585
+               SWIDEF  DDEUtils_ThrowbackUnRegister,&00042586
+               SWIDEF  DDEUtils_ThrowbackStart,&00042587
+               SWIDEF  DDEUtils_ThrowbackSend,&00042588
+               SWIDEF  DDEUtils_ThrowbackEnd,&00042589
+
+               ; --- DragAnObject SWIs ---
+
+               SWIDEF  DragAnObject_Start,&00049C40
+               SWIDEF  DragAnObject_Stop,&00049C41
+
+               ; --- TinyStubs SWIs ---
+
+               SWIDEF  TinySupport_Init,&00082C40
+               SWIDEF  TinySupport_Die,&00082C41
+               SWIDEF  TinySupport_Init2,&00082C42
+               SWIDEF  TinySupport_Share,&00082C43
+
+               ; --- ColourDbox SWIs ---
+
+               SWIDEF  ColourDbox_ClassSWI,&000829C0
+               SWIDEF  ColourDbox_PostFilter,&000829C1
+               SWIDEF  ColourDbox_PreFilter,&000829C2
+
+               ; --- ColourMenu SWIs ---
+
+               SWIDEF  ColourMenu_ClassSWI,&00082980
+               SWIDEF  ColourMenu_PostFilter,&00082981
+               SWIDEF  ColourMenu_PreFilter,&00082982
+
+               ; --- DCS SWIs ---
+
+               SWIDEF  DCS_ClassSWI,&00082A80
+               SWIDEF  DCS_PostFilter,&00082A81
+               SWIDEF  DCS_PreFilter,&00082A82
+
+               ; --- DrawFile SWIs ---
+
+               SWIDEF  DrawFile_Render,&00045540
+               SWIDEF  DrawFile_BBox,&00045541
+               SWIDEF  DrawFile_DeclareFonts,&00045542
+
+               ; --- FileInfo SWIs ---
+
+               SWIDEF  FileInfo_ClassSWI,&00082AC0
+               SWIDEF  FileInfo_PostFilter,&00082AC1
+               SWIDEF  FileInfo_PreFilter,&00082AC2
+
+               ; --- FontDbox SWIs ---
+
+               SWIDEF  FontDbox_ClassSWI,&00082A00
+               SWIDEF  FontDbox_PostFilter,&00082A01
+               SWIDEF  FontDbox_PreFilter,&00082A02
+
+               ; --- FontMenu SWIs ---
+
+               SWIDEF  FontMenu_ClassSWI,&00082A40
+               SWIDEF  FontMenu_PostFilter,&00082A41
+               SWIDEF  FontMenu_PreFilter,&00082A42
+
+               ; --- Iconbar SWIs ---
+
+               SWIDEF  Iconbar_ClassSWI,&00082900
+               SWIDEF  Iconbar_PostFilter,&00082901
+               SWIDEF  Iconbar_PreFilter,&00082902
+
+               ; --- Menu SWIs ---
+
+               SWIDEF  Menu_ClassSWI,&000828C0
+               SWIDEF  Menu_PostFilter,&000828C1
+               SWIDEF  Menu_PreFilter,&000828C2
+               SWIDEF  Menu_UpdateTree,&000828C3
+
+               ; --- PrintDbox SWIs ---
+
+               SWIDEF  PrintDbox_ClassSWI,&00082B00
+               SWIDEF  PrintDbox_PostFilter,&00082B01
+               SWIDEF  PrintDbox_PreFilter,&00082B02
+
+               ; --- ProgInfo SWIs ---
+
+               SWIDEF  ProgInfo_ClassSWI,&00082B40
+               SWIDEF  ProgInfo_PostFilter,&00082B41
+               SWIDEF  ProgInfo_PreFilter,&00082B42
+
+               ; --- SaveAs SWIs ---
+
+               SWIDEF  SaveAs_ClassSWI,&00082BC0
+               SWIDEF  SaveAs_PostFilter,&00082BC1
+               SWIDEF  SaveAs_PreFilter,&00082BC2
+
+               ; --- Scale SWIs ---
+
+               SWIDEF  Scale_ClassSWI,&00082C00
+               SWIDEF  Scale_PostFilter,&00082C01
+               SWIDEF  Scale_PreFilter,&00082C02
+
+               ; --- Toolbox SWIs ---
+
+               SWIDEF  Toolbox_CreateObject,&00044EC0
+               SWIDEF  Toolbox_DeleteObject,&00044EC1
+               SWIDEF  Toolbox_CopyObject,&00044EC2
+               SWIDEF  Toolbox_ShowObject,&00044EC3
+               SWIDEF  Toolbox_HideObject,&00044EC4
+               SWIDEF  Toolbox_GetObjectInfo,&00044EC5
+               SWIDEF  Toolbox_ObjectMiscOp,&00044EC6
+               SWIDEF  Toolbox_SetClientHandle,&00044EC7
+               SWIDEF  Toolbox_GetClientHandle,&00044EC8
+               SWIDEF  Toolbox_GetObjectClass,&00044EC9
+               SWIDEF  Toolbox_GetParent,&00044ECA
+               SWIDEF  Toolbox_GetAncestor,&00044ECB
+               SWIDEF  Toolbox_GetTemplateName,&00044ECC
+               SWIDEF  Toolbox_RaiseToolboxEvent,&00044ECD
+               SWIDEF  Toolbox_GetSysInfo,&00044ECE
+               SWIDEF  Toolbox_Initialise,&00044ECF
+               SWIDEF  Toolbox_LoadResources,&00044ED0
+               SWIDEF  Toolbox_TemplateLookUp,&00044EFB
+               SWIDEF  Toolbox_GetInternalHandle,&00044EFC
+               SWIDEF  Toolbox_RegisterPostFilter,&00044EFD
+               SWIDEF  Toolbox_RegisterPreFilter,&00044EFE
+               SWIDEF  Toolbox_RegisterObjectModule,&00044EFF
+
+               ; --- Window SWIs ---
+
+               SWIDEF  Window_ClassSWI,&00082880
+               SWIDEF  Window_PostFilter,&00082881
+               SWIDEF  Window_PreFilter,&00082882
+               SWIDEF  Window_GetPointerInfo,&00082883
+               SWIDEF  Window_WimpToToolbox,&00082884
+               SWIDEF  Window_RegisterExternal,&00082885
+               SWIDEF  Window_DeregisterExternal,&00082886
+               SWIDEF  Window_SupportExternal,&00082887
+
+               ; --- Hyphenator SWIs ---
+
+               SWIDEF  Hyphenator_ResetDictionary,&00081000
+               SWIDEF  Hyphenator_CreateDictionary,&00081001
+               SWIDEF  Hyphenator_CopyDictionary,&00081002
+               SWIDEF  Hyphenator_EnquireDictionary,&00081003
+               SWIDEF  Hyphenator_FindWord,&00081004
+               SWIDEF  Hyphenator_AddWord,&00081005
+               SWIDEF  Hyphenator_RemoveWord,&00081006
+               SWIDEF  Hyphenator_Hyphenate,&00081007
+               SWIDEF  Hyphenator_GetWords,&00081008
+               SWIDEF  Hyphenator_EnumWord,&00081009
+
+               ; --- ImpressionSpell SWIs ---
+
+               SWIDEF  Spell_Typo,&00080080
+               SWIDEF  Spell_Anagram,&00080081
+               SWIDEF  Spell_Fuzzy,&00080082
+               SWIDEF  Spell_CheckWord,&00080083
+               SWIDEF  Spell_AddWord,&00080084
+               SWIDEF  Spell_GetWord,&00080085
+               SWIDEF  Spell_GetNextWord,&00080086
+               SWIDEF  Spell_EnumWord,&00080087
+               SWIDEF  Spell_CreateUser,&00080088
+               SWIDEF  Spell_LoadUser,&00080089
+               SWIDEF  Spell_SaveUser,&0008008A
+               SWIDEF  Spell_UserToFile,&0008008B
+               SWIDEF  Spell_FileToUser,&0008008C
+               SWIDEF  Spell_GetDictionaryName,&0008008D
+               SWIDEF  Spell_RemoveDictionary,&0008008E
+               SWIDEF  Spell_DeleteWord,&0008008F
+               SWIDEF  Spell_ResetIgnore,&00080090
+               SWIDEF  Spell_AddToIgnore,&00080091
+               SWIDEF  Spell_BrowseWindow,&00080092
+               SWIDEF  Spell_SpellOp,&00080093
+               SWIDEF  Spell_FindWord,&00080094
+               SWIDEF  Spell_ImpressionInfo,&00080095
+               SWIDEF  Spell_ImpressionQuickCheck,&00080096
+               SWIDEF  Spell_FileToFile,&00080097
+               SWIDEF  Spell_SaveDictionaryWithPath,&00080098
+
+               ; --- ABI SWIs ---
+
+               SWIDEF  ABI_Initialise,&00043300
+               SWIDEF  ABI_CloseDown,&00043301
+               SWIDEF  ABI_RenderSlab,&00043302
+               SWIDEF  ABI_Reset,&00043303
+               SWIDEF  ABI_Kill,&00043304
+
+               ; --- AudioManager SWIs ---
+
+               SWIDEF  AudioManager_Info,&00047B40
+               SWIDEF  AudioManager_Reset,&00047B41
+               SWIDEF  AudioManager_ListDrivers,&00047B42
+               SWIDEF  AudioManager_Defaults,&00047B43
+               SWIDEF  AudioManager_Driver,&00047B44
+               SWIDEF  AudioManager_SelectSampler,&00047B45
+               SWIDEF  AudioManager_SamplerStatus,&00047B46
+               SWIDEF  AudioManager_StartSampling,&00047B47
+               SWIDEF  AudioManager_StopSampling,&00047B48
+               SWIDEF  AudioManager_DeselectSampler,&00047B49
+               SWIDEF  AudioManager_PlaySample,&00047B4A
+               SWIDEF  AudioManager_FillBuffer,&00047B4B
+               SWIDEF  AudioManager_ReturnCursor,&00047B4C
+               SWIDEF  AudioManager_KillSample,&00047B4D
+               SWIDEF  AudioManager_AdjustPlay,&00047B4E
+               SWIDEF  AudioManager_ConvertPitch,&00047B4F
+               SWIDEF  AudioManager_Stereo,&00047B50
+               SWIDEF  AudioManager_AttachVoice,&00047B51
+               SWIDEF  AudioManager_SoundPacked,&00047B52
+               SWIDEF  AudioManager_Sound,&00047B53
+               SWIDEF  AudioManager_ReadCCB,&00047B54
+               SWIDEF  AudioManager_WriteCCB,&00047B55
+               SWIDEF  AudioManager_PlaySampleFromFile,&00047B56
+               SWIDEF  AudioManager_QueueEvent,&00047B57
+               SWIDEF  AudioManager_AddEvent,&00047B58
+               SWIDEF  AudioManager_RedirectVIDC,&00047B59
+
+               ; --- ArtworksRenderer SWIs ---
+
+               SWIDEF  AWRender_FileInitAddress,&00046080
+               SWIDEF  AWRender_RenderAddress,&00046081
+               SWIDEF  AWRender_DocBounds,&00046082
+               SWIDEF  AWRender_SendDefs,&00046083
+               SWIDEF  AWRender_ClaimVectors,&00046084
+               SWIDEF  AWRender_ReleaseVectors,&00046085
+               SWIDEF  AWRender_FindFirstFont,&00046086
+               SWIDEF  AWRender_FindNextFont,&00046087
+               SWIDEF  AWRender_MemoryNeeded,&00046088
+
+               ; --- StreamSquash SWIs ---
+
+               SWIDEF  StreamSquash_Initialise,&00044D40
+               SWIDEF  StreamSquash_InfoCompress,&00044D41
+               SWIDEF  StreamSquash_OpenCompress,&00044D42
+               SWIDEF  StreamSquash_CompressBlock,&00044D43
+               SWIDEF  StreamSquash_CloseCompress,&00044D44
+               SWIDEF  StreamSquash_InfoDecompress,&00044D45
+               SWIDEF  StreamSquash_OpenDecompress,&00044D46
+               SWIDEF  StreamSquash_DecompressBlock,&00044D47
+               SWIDEF  StreamSquash_CloseDecompress,&00044D48
+               SWIDEF  StreamSquash_Exit,&00044D49
+
+               ; --- ColourExtend SWIs ---
+
+               SWIDEF  ColourExtend_Info,&00040F40
+               SWIDEF  ColourExtend_Control,&00040F41
+               SWIDEF  ColourExtend_InvalidateCache,&00040F42
+
+               ; --- DitherExtend SWIs ---
+
+               SWIDEF  DitherExtend_SelectTable,&00044580
+               SWIDEF  DitherExtend_SelectGCOLTable,&00044581
+               SWIDEF  DitherExtend_ReturnGCOL,&00044582
+               SWIDEF  DitherExtend_SetGCOL,&00044583
+               SWIDEF  DitherExtend_ReturnColourNumber,&00044584
+               SWIDEF  DitherExtend_ReturnGCOLForMode,&00044585
+               SWIDEF  DitherExtend_ReturnColourNumberForMode,&00044586
+               SWIDEF  DitherExtend_ReturnOppGCOL,&00044587
+               SWIDEF  DitherExtend_SetOppGCOL,&00044588
+               SWIDEF  DitherExtend_ReturnOppColourNumber,&00044589
+               SWIDEF  DitherExtend_ReturnOppGCOLForMode,&0004458A
+               SWIDEF  DitherExtend_ReturnOppColourNumberForMode,&0004458B
+               SWIDEF  DitherExtend_GCOLToColourNumber,&0004458C
+               SWIDEF  DitherExtend_ColourNumberToGCOL,&0004458D
+               SWIDEF  DitherExtend_Info,&0004458E
+               SWIDEF  DitherExtend_Control,&0004458F
+               SWIDEF  DitherExtend_ReturnColourPattern,&00044590
+               SWIDEF  DitherExtend_ReturnColourPatternTable,&00044591
+               SWIDEF  DitherExtend_InvalidatePalette,&00044592
+               SWIDEF  DitherExtend_Antialias,&00044593
+               SWIDEF  DitherExtend_ReadPalette,&00044594
+               SWIDEF  DitherExtend_ReturnColourPatternArray,&00044595
+               SWIDEF  DitherExtend_SetHalftone,&00044596
+               SWIDEF  DitherExtend_ReturnHalftone,&00044597
+               SWIDEF  DitherExtend_SetHalftoneOrigin,&00044598
+               SWIDEF  DitherExtend_ReturnHalftoneOrigin,&00044599
+               SWIDEF  DitherExtend_SelectHalftoneTable,&0004459A
+               SWIDEF  DitherExtend_ReturnHalftoneIntensity,&0004459B
+               SWIDEF  DitherExtend_ReturnHalftoneTable,&0004459C
+               SWIDEF  DitherExtend_SetScreen,&0004459D
+               SWIDEF  DitherExtend_CacheScreen,&0004459E
+               SWIDEF  DitherExtend_SelectColourPatternTable,&0004459F
+
+               ; --- DocumentManager SWIs ---
+
+               SWIDEF  DocumentManager_Open,&000430C0
+               SWIDEF  DocumentManager_Close,&000430C1
+               SWIDEF  DocumentManager_File,&000430C2
+               SWIDEF  DocumentManager_Find,&000430C3
+               SWIDEF  DocumentManager_Args,&000430C4
+               SWIDEF  DocumentManager_GBPB,&000430C5
+               SWIDEF  DocumentManager_Compact,&000430C6
+               SWIDEF  DocumentManager_Reset,&000430C7
+               SWIDEF  DocumentManager_Stamp,&000430C8
+
+               ; --- FontInstallSupport SWIs ---
+
+               SWIDEF  FontInstall_GetFonts,&00044FC0
+               SWIDEF  FontInstall_Reset,&00044FC1
+
+               ; --- FontDraw SWIs ---
+
+               SWIDEF  FontDraw_FindFont,&00046040
+               SWIDEF  FontDraw_LoseFont,&00046041
+               SWIDEF  FontDraw_Paint,&00046042
+
+               ; --- GDraw SWIs ---
+
+               SWIDEF  GDraw_ProcessPath,&00044540
+               SWIDEF  GDraw_ProcessPathFP,&00044541
+               SWIDEF  GDraw_Fill,&00044542
+               SWIDEF  GDraw_FillFP,&00044543
+               SWIDEF  GDraw_Stroke,&00044544
+               SWIDEF  GDraw_StrokeFP,&00044545
+               SWIDEF  GDraw_StrokePath,&00044546
+               SWIDEF  GDraw_StrokePathFP,&00044547
+               SWIDEF  GDraw_FlattenPath,&00044548
+               SWIDEF  GDraw_FlattenPathFP,&00044549
+               SWIDEF  GDraw_TransformPath,&0004454A
+               SWIDEF  GDraw_TransformPathFP,&0004454B
+               SWIDEF  GDraw_ProcessClipPath,&0004454C
+               SWIDEF  GDraw_ProcessClipPathFP,&0004454D
+               SWIDEF  GDraw_ClipPath,&0004454E
+               SWIDEF  GDraw_ClipPathFP,&0004454F
+               SWIDEF  GDraw_ClipPathToPath,&00044550
+               SWIDEF  GDraw_ClipPathToPathFP,&00044551
+               SWIDEF  GDraw_ClearClipRegion,&00044552
+               SWIDEF  GDraw_SetClipRegion,&00044553
+               SWIDEF  GDraw_SetFillStyle,&00044554
+               SWIDEF  GDraw_FillRegion,&00044555
+               SWIDEF  GDraw_SetPrintFlag,&00044556
+               SWIDEF  GDraw_ReadFillStyle,&00044557
+               SWIDEF  GDraw_GetClipRegion,&00044558
+
+               ; --- ImageExtend SWIs ---
+
+               SWIDEF  ImageExtend_Info,&00080E00
+               SWIDEF  ImageExtend_PutSpriteTransformed,&00080E01
+               SWIDEF  ImageExtend_PutSpriteToBufferTransformed,&00080E02
+               SWIDEF  ImageExtend_PutStringTransformed,&00080E03
+               SWIDEF  ImageExtend_GetBBox,&00080E04
+               SWIDEF  ImageExtend_GetImageBBox,&00080E05
+               SWIDEF  ImageExtend_MakeMatrix,&00080E06
+               SWIDEF  ImageExtend_MakeHalftoneTile,&00080E07
+               SWIDEF  ImageExtend_AddKernelToMatrix,&00080E08
+               SWIDEF  ImageExtend_MakeSimpleScreenTile,&00080E09
+
+               ; --- Impulse SWIs ---
+
+               SWIDEF  Impulse_Initialise,&000428C0
+               SWIDEF  Impulse_Decode,&000428C1
+               SWIDEF  Impulse_SendMessage,&000428C2
+               SWIDEF  Impulse_TransmitData,&000428C3
+               SWIDEF  Impulse_FetchData,&000428C4
+               SWIDEF  Impulse_CloseDown,&000428C5
+               SWIDEF  Impulse_DeferReply,&000428C6
+
+               ; --- OLESupport SWIs ---
+
+               SWIDEF  OLE_Version,&00047B00
+               SWIDEF  OLE_LinkFile,&00047B01
+               SWIDEF  OLE_DeLinkFile,&00047B02
+               SWIDEF  OLE_FileStatus,&00047B03
+               SWIDEF  OLE_Invalidate,&00047B04
+               SWIDEF  OLE_SimulateSession,&00047B05
+
+               ; --- GSpriteExtend SWIs ---
+
+               SWIDEF  GSpriteExtend_PlotSprite,&00041480
+               SWIDEF  GSpriteExtend_SwitchOutputToSprite,&00041481
+               SWIDEF  GSpriteExtend_ReadVariable,&00041482
+
+               ; --- Constrain SWIs ---
+
+               SWIDEF  Constrain_Finish,&0004A340
+               SWIDEF  Constrain_MousePos,&0004A341
+               SWIDEF  Constrain_Circle,&0004A342
+               SWIDEF  Constrain_Disc,&0004A343
+
+               ; --- Sledgehammer SWIs ---
+
+               SWIDEF  Sledgehammer_SetDissOptions,&0004A380
+               SWIDEF  Sledgehammer_DissAddress,&0004A381
+               SWIDEF  Sledgehammer_Disassemble,&0004A382
+               SWIDEF  Sledgehammer_Assemble,&0004A383
+               SWIDEF  Sledgehammer_Step,&0004A384
+               SWIDEF  Sledgehammer_StepAddr,&0004A385
+               SWIDEF  Sledgehammer_SetBP,&0004A386
+               SWIDEF  Sledgehammer_RemoveBP,&0004A387
+               SWIDEF  Sledgehammer_Translate,&0004A388
+               SWIDEF  Sledgehammer_BreakPoint,&0004A389
+
+               ; --- DDT SWIs ---
+
+               SWIDEF  Debugger_DebugAIF,&00041D40
+               SWIDEF  Debugger_BeingDebugged,&00041D41
+               SWIDEF  Debugger_StartDebug,&00041D42
+               SWIDEF  Debugger_EndDebug,&00041D43
+
+               ; --- VDUStream SWIs ---
+
+               SWIDEF  Stream_Enable,&00081940
+               SWIDEF  Stream_Disable,&00081941
+               SWIDEF  Stream_Kill,&00081942
+               SWIDEF  Stream_UnKill,&00081943
+               SWIDEF  Stream_Intercept,&00081944
+               SWIDEF  Stream_NoIntercept,&00081945
+               SWIDEF  Stream_ShowCodes,&00081946
+               SWIDEF  Stream_NoCodes,&00081947
+               SWIDEF  Stream_Reset,&00081948
+               SWIDEF  Stream_FlushText,&00081949
+               SWIDEF  Stream_WriteC,&0008194A
+               SWIDEF  Stream_WriteS,&0008194B
+               SWIDEF  Stream_Write0,&0008194C
+               SWIDEF  Stream_WriteN,&0008194D
+               SWIDEF  Stream_NewLine,&0008194E
+               SWIDEF  Stream_WriteT32,&0008194F
+               SWIDEF  Stream_WriteT24,&00081950
+               SWIDEF  Stream_WriteT16,&00081951
+               SWIDEF  Stream_WriteT8,&00081952
+               SWIDEF  Stream_WriteH32,&00081953
+               SWIDEF  Stream_WriteH24,&00081954
+               SWIDEF  Stream_WriteH16,&00081955
+               SWIDEF  Stream_WriteH8,&00081956
+               SWIDEF  Stream_WriteD32,&00081957
+               SWIDEF  Stream_WriteD24,&00081958
+               SWIDEF  Stream_WriteD16,&00081959
+               SWIDEF  Stream_WriteD8,&0008195A
+               SWIDEF  Stream_WriteB32,&0008195B
+               SWIDEF  Stream_WriteB24,&0008195C
+               SWIDEF  Stream_WriteB16,&0008195D
+               SWIDEF  Stream_WriteB8,&0008195E
+               SWIDEF  Stream_WriteRegs,&0008195F
+
+               ; --- WimpExtension SWIs ---
+
+               SWIDEF  WimpExt_Initialise,&00045780
+               SWIDEF  WimpExt_CloseDown,&00045781
+               SWIDEF  WimpExt_SlabIcon,&00045782
+               SWIDEF  WimpExt_Redraw,&00045783
+               SWIDEF  WimpExt_Action,&00045784
+               SWIDEF  WimpExt_IconBarSprite,&00045785
+               SWIDEF  WimpExt_IconBarText,&00045786
+               SWIDEF  WimpExt_LinkWindows,&00045787
+               SWIDEF  WimpExt_OpenLinked,&00045788
+               SWIDEF  WimpExt_CloseLinked,&00045789
+               SWIDEF  WimpExt_UnLinkWindows,&0004578A
+               SWIDEF  WimpExt_CurrentTask,&0004578B
+               SWIDEF  WimpExt_LoadTemplates,&0004578C
+               SWIDEF  WimpExt_SetIconString,&0004578D
+               SWIDEF  WimpExt_OpenWindowTop,&0004578E
+               SWIDEF  WimpExt_SetIcon,&0004578F
+               SWIDEF  WimpExt_GetIcon,&00045790
+               SWIDEF  WimpExt_GetNumberIcon,&00045791
+               SWIDEF  WimpExt_SetNumberIcon,&00045792
+               SWIDEF  WimpExt_IncNumberIcon,&00045793
+               SWIDEF  WimpExt_DecNumberIcon,&00045794
+               SWIDEF  WimpExt_SetPointer,&00045795
+               SWIDEF  WimpExt_Divide,&00045796
+               SWIDEF  WimpExt_ColoursMenu,&00045797
+               SWIDEF  WimpExt_AutoRedraw,&00045798
+               SWIDEF  WimpExt_CentreWindow,&00045799
+               SWIDEF  WimpExt_DragIcon,&0004579A
+               SWIDEF  WimpExt_PutCaretIcon,&0004579B
+               SWIDEF  WimpExt_OpenDialogue,&0004579C
+               SWIDEF  WimpExt_CheckWindowOpen,&0004579D
+               SWIDEF  WimpExt_CopyString,&0004579E
+               SWIDEF  WimpExt_SetWindowTitle,&0004579F
+               SWIDEF  WimpExt_SetIconStringN,&000457A0
+               SWIDEF  WimpExt_FindLeaf,&000457A1
+               SWIDEF  WimpExt_LimitPointer,&000457A2
+               SWIDEF  WimpExt_ReleasePointer,&000457A3
+               SWIDEF  WimpExt_OpenFullSize,&000457A4
+               SWIDEF  WimpExt_LoadRAMTemplate,&000457A5
+               SWIDEF  WimpExt_OpenRequester,&000457A6
+               SWIDEF  WimpExt_CloseRequester,&000457A7
+               SWIDEF  WimpExt_HideLink,&000457A8
+               SWIDEF  WimpExt_UnHideLink,&000457A9
+               SWIDEF  WimpExt_SendHelp,&000457AA
+               SWIDEF  WimpExt_SendWimpHelp,&000457AB
+               SWIDEF  WimpExt_CreateMenu,&000457AC
+               SWIDEF  WimpExt_ReCreateMenu,&000457AD
+               SWIDEF  WimpExt_ShadeEntry,&000457AE
+               SWIDEF  WimpExt_TickEntry,&000457AF
+               SWIDEF  WimpExt_SetIconColour,&000457B0
+               SWIDEF  WimpExt_ShadeIcon,&000457B1
+               SWIDEF  WimpExt_PlotSprite,&000457B2
+               SWIDEF  WimpExt_RedrawDraw,&000457B3
+               SWIDEF  WimpExt_PrePoll,&000457B4
+               SWIDEF  WimpExt_SetExtent,&000457B5
+               SWIDEF  WimpExt_MoveCaret,&000457B6
+               SWIDEF  WimpExt_GetFontMenu,&000457B7
+               SWIDEF  WimpExt_DecodeFontMenu,&000457B8
+               SWIDEF  WimpExt_ControlImmediate,&000457B9
+               SWIDEF  WimpExt_Heap,&000457BA
+               SWIDEF  WimpExt_MemCopy,&000457BB
+               SWIDEF  WimpExt_DataSave,&000457BC
+               SWIDEF  WimpExt_PlotBorder,&000457BD
+               SWIDEF  WimpExt_CentreWindowV,&000457BE
+
+               ; --- WimpExtShadow SWIs ---
+
+               SWIDEF  WimpExt_Sort,&00046380
+               SWIDEF  WimpExt_MemMove,&00046381
+               SWIDEF  WimpExt_MenuWidth,&00046382
+               SWIDEF  WimpExt_DataLoad,&00046383
+               SWIDEF  WimpExt_MoveCaretIcon,&00046384
+               SWIDEF  WimpExt_DrawOp,&00046385
+               SWIDEF  WimpExt_SpriteOp,&00046386
+               SWIDEF  WimpExt_Intersect,&00046387
+               SWIDEF  WimpExt_BorderOp,&00046388
+               SWIDEF  WimpExt_ManualLink,&00046389
+               SWIDEF  WimpExt_MiscOp,&0004638A
+               SWIDEF  WimpExt_ViewIcon,&0004638B
+               SWIDEF  WimpExt_SubstituteArgs,&0004638C
+               SWIDEF  WimpExt_RedirectSprites,&0004638D
+               SWIDEF  WimpExt_LibraryOp,&0004638E
+               SWIDEF  WimpExt_CallLibrary,&0004638F
+               SWIDEF  WimpExt_BackgroundTask,&00046390
+               SWIDEF  WimpExt_ServiceCall,&00046391
+               SWIDEF  WimpExt_CDA,&00046392
+               SWIDEF  WimpExt_Slider,&00046393
+               SWIDEF  WimpExt_DeleteLinked,&00046394
+               SWIDEF  WimpExt_OpenWindowTopC,&00046395
+
+               ; --- PDriver SWIs ---
+
+               SWIDEF  PDriver_Info,&00080140
+               SWIDEF  PDriver_SetInfo,&00080141
+               SWIDEF  PDriver_CheckFeatures,&00080142
+               SWIDEF  PDriver_PageSize,&00080143
+               SWIDEF  PDriver_SetPageSize,&00080144
+               SWIDEF  PDriver_SelectJob,&00080145
+               SWIDEF  PDriver_CurrentJob,&00080146
+               SWIDEF  PDriver_FontSWI,&00080147
+               SWIDEF  PDriver_EndJob,&00080148
+               SWIDEF  PDriver_AbortJob,&00080149
+               SWIDEF  PDriver_Reset,&0008014A
+               SWIDEF  PDriver_GiveRectangle,&0008014B
+               SWIDEF  PDriver_DrawPage,&0008014C
+               SWIDEF  PDriver_GetRectangle,&0008014D
+               SWIDEF  PDriver_CancelJob,&0008014E
+               SWIDEF  PDriver_ScreenDump,&0008014F
+               SWIDEF  PDriver_EnumerateJobs,&00080150
+               SWIDEF  PDriver_SetPrinter,&00080151
+               SWIDEF  PDriver_CancelJobWithError,&00080152
+               SWIDEF  PDriver_SelectIllustration,&00080153
+               SWIDEF  PDriver_InsertIllustration,&00080154
+               SWIDEF  PDriver_DeclareFont,&00080155
+               SWIDEF  PDriver_DeclareDriver,&00080156
+               SWIDEF  PDriver_RemoveDriver,&00080157
+               SWIDEF  PDriver_SelectDriver,&00080158
+               SWIDEF  PDriver_EnumerateDrivers,&00080159
+               SWIDEF  PDriver_MiscOp,&0008015A
+               SWIDEF  PDriver_MiscOpForDriver,&0008015B
+               SWIDEF  PDriver_SetDriver,&0008015C
+
+               ; --- PDumperSupport SWIs ---
+
+               SWIDEF  PDumper_Info,&00041B00
+               SWIDEF  PDumper_Claim,&00041B01
+               SWIDEF  PDumper_Free,&00041B02
+               SWIDEF  PDumper_Find,&00041B03
+               SWIDEF  PDumper_StartJob,&00041B04
+               SWIDEF  PDumper_TidyJob,&00041B05
+               SWIDEF  PDumper_SetColour,&00041B06
+               SWIDEF  PDumper_PrepareStrip,&00041B07
+               SWIDEF  PDumper_LookupError,&00041B08
+               SWIDEF  PDumper_CopyFilename,&00041B09
+
+               ; --- RemotePrinterSupport SWIs ---
+
+               SWIDEF  RemotePrinterSupport_ReadPollwordLocation,&00047980
+               SWIDEF  RemotePrinterSupport_GetNextEvent,&00047981
+               SWIDEF  RemotePrinterSupport_ReadUniqueAddress,&00047982
+               SWIDEF  RemotePrinterSupport_Enable,&00047983
+               SWIDEF  RemotePrinterSupport_Disable,&00047984
+               SWIDEF  RemotePrinterSupport_EnableUpcalls,&00047985
+               SWIDEF  RemotePrinterSupport_DisableUpcalls,&00047986
+
+               ; --- Dynamite SWIs ---
+
+               SWIDEF  Dynamite_Alloc,&0004A3C0
+               SWIDEF  Dynamite_Free,&0004A3C1
+               SWIDEF  Dynamite_FreeWithID,&0004A3C2
+               SWIDEF  Dynamite_BlockInfo,&0004A3C3
+               SWIDEF  Dynamite_ChangeID,&0004A3C4
+               SWIDEF  Dynamite_Resize,&0004A3C5
+               SWIDEF  Dynamite_MidExtend,&0004A3C6
+               SWIDEF  Dynamite_Save,&0004A3C7
+               SWIDEF  Dynamite_Load,&0004A3C8
+               SWIDEF  Dynamite_Reduce,&0004A3C9
+               SWIDEF  Dynamite_Compact,&0004A3CA
+               SWIDEF  Dynamite_Lock,&0004A3CB
+               SWIDEF  Dynamite_Unlock,&0004A3CC
+               SWIDEF  Dynamite_ClaimAnchor,&0004A3CD
+               SWIDEF  Dynamite_ReleaseAnchor,&0004A3CE
+               SWIDEF  Dynamite_ReadSpriteSize,&0004A3CF
+               SWIDEF  Dynamite_Describe,&0004A3D0
+               SWIDEF  Dynamite_IntegrityCheck,&0004A3D1
+               SWIDEF  Dynamite_ChangeAnchor,&0004A3D2
+
+               ; --- GS_Support SWIs ---
+
+               SWIDEF  GS_Support_PaintText,&00042F40
+               SWIDEF  GS_Support_StringIdx,&00042F41
+               SWIDEF  GS_Support_SetCaret,&00042F42
+               SWIDEF  GS_Support_FindLines,&00042F43
+               SWIDEF  GS_Support_wac,&00042F44
+               SWIDEF  GS_Support_formtext,&00042F45
+               SWIDEF  GS_Support_PlaySample,&00042F46
+               SWIDEF  GS_Support_OverLap,&00042F47
+               SWIDEF  GS_Support_OverLap2,&00042F48
+               SWIDEF  GS_Support_NamedObject,&00042F49
+               SWIDEF  GS_Support_NumberedObject,&00042F4A
+               SWIDEF  GS_Support_MenuObject,&00042F4B
+               SWIDEF  GS_Support_FindResource,&00042F4C
+               SWIDEF  GS_Support_IsLinkDrag,&00042F4D
+               SWIDEF  GS_Support_LinkDrag,&00042F4E
+               SWIDEF  GS_Support_GetSample,&00042F4F
+               SWIDEF  GS_Support_FFTData,&00042F50
+               SWIDEF  GS_Support_FFTSample,&00042F51
+               SWIDEF  GS_Support_SampleCtrl,&00042F52
+
+               ; --- InterfaceManager SWIs ---
+
+               SWIDEF  Interface_SlabButton,&00081680
+               SWIDEF  Interface_Render3dWindow,&00081681
+               SWIDEF  Interface_Initialise,&00081682
+               SWIDEF  Interface_CloseDown,&00081683
+               SWIDEF  Interface_SetWorkareaPointer,&00081684
+               SWIDEF  Interface_RemoveWorkareaPointer,&00081685
+               SWIDEF  Interface_Poll,&00081686
+               SWIDEF  Interface_SendHelp,&00081687
+               SWIDEF  Interface_PreProcessKey,&00081688
+               SWIDEF  Interface_Plot3dIcon,&00081689
+               SWIDEF  Interface_BoundingBox,&0008168A
+
+               ; --- Sculptrix SWIs ---
+
+               SWIDEF  Sculptrix_RedrawWindow,&0004A2C0
+               SWIDEF  Sculptrix_DoSlab,&0004A2C1
+               SWIDEF  Sculptrix_SlabIcon,&0004A2C2
+               SWIDEF  Sculptrix_UnslabIcon,&0004A2C3
+               SWIDEF  Sculptrix_BoundingBox,&0004A2C4
+               SWIDEF  Sculptrix_PlotIcon,&0004A2C5
+               SWIDEF  Sculptrix_PlotGroupBox,&0004A2C6
+               SWIDEF  Sculptrix_SetSpriteArea,&0004A2C7
+               SWIDEF  Sculptrix_UpdateIcon,&0004A2C8
+               SWIDEF  Sculptrix_SlabColour,&0004A2C9
+               SWIDEF  Sculptrix_SetConfig,&0004A2CA
+               SWIDEF  Sculptrix_ReadConfig,&0004A2CB
+
+               ; --- TermiteIP SWIs ---
+
+               SWIDEF  TermiteIP_Initialise,&0004AE40
+               SWIDEF  TermiteIP_Finalise,&0004AE41
+               SWIDEF  TermiteIP_Register,&0004AE42
+               SWIDEF  TermiteIP_DeRegister,&0004AE43
+               SWIDEF  TermiteIP_Bindings,&0004AE44
+               SWIDEF  TermiteIP_SendIPPacket,&0004AE45
+               SWIDEF  TermiteIP_AllocatePort,&0004AE46
+               SWIDEF  TermiteIP_CreateSocket,&0004AE47
+               SWIDEF  TermiteIP_ClosePort,&0004AE48
+               SWIDEF  TermiteIP_SendTCPData,&0004AE49
+               SWIDEF  TermiteIP_SendUDPData,&0004AE4A
+               SWIDEF  TermiteIP_IPProtocolNumberToName,&0004AE4B
+               SWIDEF  TermiteIP_ReadIPProtocolEnable,&0004AE4C
+               SWIDEF  TermiteIP_ReadLinkStatus,&0004AE4D
+               SWIDEF  TermiteIP_ChecksumData,&0004AE4E
+               SWIDEF  TermiteIP_ReadPacket,&0004AE4F
+               SWIDEF  TermiteIP_ReadInformation,&0004AE50
+               SWIDEF  TermiteIP_ReadTCPData,&0004AE51
+               SWIDEF  TermiteIP_SendICMPMessage,&0004AE52
+               SWIDEF  TermiteIP_ChecksumDataAndHeader,&0004AE53
+               SWIDEF  TermiteIP_IPAddressToNumber,&0004AE54
+               SWIDEF  TermiteIP_NumberToIPAddress,&0004AE55
+               SWIDEF  TermiteIP_ReadNextEvent,&0004AE56
+               SWIDEF  TermiteIP_NetToArcTime,&0004AE57
+               SWIDEF  TermiteIP_PortInformation,&0004AE58
+               SWIDEF  TermiteIP_DeleteSocket,&0004AE59
+               SWIDEF  TermiteIP_TCPStateToText,&0004AE5A
+               SWIDEF  TermiteIP_DecodeICMPErrorMessage,&0004AE5B
+               SWIDEF  TermiteIP_StartTCPConnection,&0004AE5C
+               SWIDEF  TermiteIP_ReadTCPStatus,&0004AE5D
+               SWIDEF  TermiteIP_ConfigureTCP,&0004AE5E
+               SWIDEF  TermiteIP_ConvertPortNumber,&0004AE5F
+               SWIDEF  TermiteIP_ResolveAddToCache,&0004AE60
+               SWIDEF  TermiteIP_ResolveReadCacheEntry,&0004AE61
+               SWIDEF  TermiteIP_ResolveFindEntryInCache,&0004AE62
+               SWIDEF  TermiteIP_RemoveTCPData,&0004AE63
+               SWIDEF  TermiteIP_ExamineTCPData,&0004AE64
+               SWIDEF  TermiteIP_SetTCPSocketWindow,&0004AE65
+               SWIDEF  TermiteIP_KickTCPSocket,&0004AE66
+               SWIDEF  TermiteIP_CheckSocket,&0004AE67
+               SWIDEF  TermiteIP_TelnetOp,&0004AE68
+               SWIDEF  TermiteIP_ResolveOp,&0004AE69
+               SWIDEF  TermiteIP_CloseTCPConnection,&0004AE6A
+               SWIDEF  TermiteIP_ReadTCPPointers,&0004AE6B
+               SWIDEF  TermiteIP_SetTCPSocketToListen,&0004AE6C
+               SWIDEF  TermiteIP_ResolveChangeCacheEntry,&0004AE6D
+               SWIDEF  TermiteIP_ResolveDeleteCacheEntry,&0004AE6E
+               SWIDEF  TermiteIP_EnumerateOp,&0004AE6F
+               SWIDEF  TermiteIP_ClientInformation,&0004AE70
+               SWIDEF  TermiteIP_SocketInformation,&0004AE71
+               SWIDEF  TermiteIP_ResolveFindIPAddressForName,&0004AE72
+               SWIDEF  TermiteIP_ReadDomainName,&0004AE73
+               SWIDEF  TermiteIP_ClosePortSockets,&0004AE74
+               SWIDEF  TermiteIP_DropTCPConnection,&0004AE75
+               SWIDEF  TermiteIP_ProtocolOp,&0004AE76
+               SWIDEF  TermiteIP_ChangePortFlags,&0004AE77
+               SWIDEF  TermiteIP_MiscOp,&0004AE78
+               SWIDEF  TermiteIP_SendEvent,&0004AE79
+               SWIDEF  TermiteIP_TCPBufferInfo,&0004AE7A
+               SWIDEF  TermiteIP_SocketOp,&0004AE7B
+               SWIDEF  TermiteIP_InterfaceOp,&0004AE7C
+               SWIDEF  TermiteIP_RoutingOp,&0004AE7D
+               SWIDEF  TermiteIP_CDA,&0004AE7E
+
+               ; --- FreeNet SWIs ---
+
+               SWIDEF  Socket_Creat,&00041200
+               SWIDEF  Socket_Bind,&00041201
+               SWIDEF  Socket_Listen,&00041202
+               SWIDEF  Socket_Accept,&00041203
+               SWIDEF  Socket_Connect,&00041204
+               SWIDEF  Socket_Recv,&00041205
+               SWIDEF  Socket_Recvfrom,&00041206
+               SWIDEF  Socket_Recvmsg,&00041207
+               SWIDEF  Socket_Send,&00041208
+               SWIDEF  Socket_Sendto,&00041209
+               SWIDEF  Socket_Sendmsg,&0004120A
+               SWIDEF  Socket_Shutdown,&0004120B
+               SWIDEF  Socket_Setsockopt,&0004120C
+               SWIDEF  Socket_Getsockopt,&0004120D
+               SWIDEF  Socket_Getpeername,&0004120E
+               SWIDEF  Socket_Getsockname,&0004120F
+               SWIDEF  Socket_Close,&00041210
+               SWIDEF  Socket_Select,&00041211
+               SWIDEF  Socket_Ioctl,&00041212
+               SWIDEF  Socket_Read,&00041213
+               SWIDEF  Socket_Write,&00041214
+               SWIDEF  Socket_Stat,&00041215
+               SWIDEF  Socket_Readv,&00041216
+               SWIDEF  Socket_Writev,&00041217
+               SWIDEF  Socket_Gettsize,&00041218
+               SWIDEF  Socket_Sendtosm,&00041219
+
+               ; --- INetDB SWIs ---
+
+               SWIDEF  Internet_GetHostByName,&00046000
+               SWIDEF  Internet_GetHostByAddr,&00046001
+
+               ; --- ColourTrans SWIs ---
+
+               SWIDEF  ColourTrans_SelectTable,&00040740
+               SWIDEF  ColourTrans_SelectGCOLTable,&00040741
+               SWIDEF  ColourTrans_ReturnGCOL,&00040742
+               SWIDEF  ColourTrans_SetGCOL,&00040743
+               SWIDEF  ColourTrans_ReturnColourNumber,&00040744
+               SWIDEF  ColourTrans_ReturnGCOLForMode,&00040745
+               SWIDEF  ColourTrans_ReturnColourNumberForMode,&00040746
+               SWIDEF  ColourTrans_ReturnOppGCOL,&00040747
+               SWIDEF  ColourTrans_SetOppGCOL,&00040748
+               SWIDEF  ColourTrans_ReturnOppColourNumber,&00040749
+               SWIDEF  ColourTrans_ReturnOppGCOLForMode,&0004074A
+               SWIDEF  ColourTrans_ReturnOppColourNumberForMode,&0004074B
+               SWIDEF  ColourTrans_GCOLToColourNumber,&0004074C
+               SWIDEF  ColourTrans_ColourNumberToGCOL,&0004074D
+               SWIDEF  ColourTrans_ReturnFontColours,&0004074E
+               SWIDEF  ColourTrans_SetFontColours,&0004074F
+               SWIDEF  ColourTrans_InvalidateCache,&00040750
+               SWIDEF  ColourTrans_SetCalibration,&00040751
+               SWIDEF  ColourTrans_ReadCalibration,&00040752
+               SWIDEF  ColourTrans_ConvertDeviceColour,&00040753
+               SWIDEF  ColourTrans_ConvertDevicePalette,&00040754
+               SWIDEF  ColourTrans_ConvertRGBToCIE,&00040755
+               SWIDEF  ColourTrans_ConvertCIEToRGB,&00040756
+               SWIDEF  ColourTrans_WriteCalibrationToFile,&00040757
+               SWIDEF  ColourTrans_ConvertRGBToHSV,&00040758
+               SWIDEF  ColourTrans_ConvertHSVToRGB,&00040759
+               SWIDEF  ColourTrans_ConvertRGBToCMYK,&0004075A
+               SWIDEF  ColourTrans_ConvertCMYKToRGB,&0004075B
+               SWIDEF  ColourTrans_ReadPalette,&0004075C
+               SWIDEF  ColourTrans_WritePalette,&0004075D
+               SWIDEF  ColourTrans_SetColour,&0004075E
+               SWIDEF  ColourTrans_MiscOp,&0004075F
+               SWIDEF  ColourTrans_WriteLoadingsToFile,&00040760
+               SWIDEF  ColourTrans_SetTextColour,&00040761
+               SWIDEF  ColourTrans_SetOppTextColour,&00040762
+               SWIDEF  ColourTrans_GenerateTable,&00040763
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/Makefile,fe1 b/StraySrc/Libraries/DLLLib/Makefile,fe1
new file mode 100644 (file)
index 0000000..2e5b4fd
--- /dev/null
@@ -0,0 +1,139 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+OBJS = \
+       o.appEntry o.extEntry o.wSpace o.clib o.findAll \
+       o.loadLocal \
+       o.dsetjmp o.dpoll o.oscli \
+       o.iface
+
+#----- Compiling things -----------------------------------------------------
+
+all: o.dlllib
+
+o.dlllib: $(OBJS)
+       $(AR) -c o.dlllib $(OBJS)
+
+install:
+
+clean:
+       -$(RM) o.*
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.appEntry: s.appEntry
+o.appEntry: libs:header
+o.appEntry: libs:swis
+o.extEntry: s.extEntry
+o.extEntry: libs:header
+o.extEntry: libs:swis
+o.wSpace: s.wSpace
+o.wSpace: libs:header
+o.wSpace: libs:swis
+o.clib: s.clib
+o.clib: libs:header
+o.clib: libs:swis
+o.findAll: s.findAll
+o.findAll: libs:header
+o.findAll: libs:swis
+o.loadLocal: s.loadLocal
+o.loadLocal: libs:header
+o.loadLocal: libs:swis
+o.dsetjmp: s.dsetjmp
+o.dsetjmp: libs:header
+o.dsetjmp: libs:swis
+o.dpoll: s.dpoll
+o.dpoll: libs:header
+o.dpoll: libs:swis
+o.oscli: s.oscli
+o.oscli: libs:swis
+o.oscli: libs:header
+o.iface: s.iface
+o.iface: libs:header
+o.iface: libs:swis
diff --git a/StraySrc/Libraries/DLLLib/h/ctype b/StraySrc/Libraries/DLLLib/h/ctype
new file mode 100644 (file)
index 0000000..62da1c0
--- /dev/null
@@ -0,0 +1,112 @@
+#pragma force_top_level
+#pragma include_only_once
+
+/* ctype.h: ANSI 'C' (X3J11 Oct 88) library header, section 4.3 */
+/* Copyright (C) Codemist Ltd. */
+/* Copyright (C) Acorn Computers Ltd. 1991, 1992 */
+/* version 2.00 */
+
+/*
+ * ctype.h declares several functions useful for testing and mapping
+ * characters. In all cases the argument is an int, the value of which shall
+ * be representable as an unsigned char or shall equal the value of the
+ * macro EOF. If the argument has any other value, the behaviour is undefined.
+ */
+
+#ifndef __ctype_h
+#define __ctype_h
+
+/* N.B. - keep in step with <ctype.c> */
+
+#define __S 1            /* whitespace           */
+#define __P 2            /* punctuation          */
+#define __B 4            /* blank                */
+#define __L 8            /* lower case letter    */
+#define __U 16           /* upper case letter    */
+#define __N 32           /* (decimal) digit      */
+#define __C 64           /* control chars        */
+#define __X 128          /* A-F and a-f          */
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+#ifdef SYSTEM_STATICS
+  extern unsigned *__ctype;
+#elif defined(_DLL)
+  extern unsigned char *_dll_ctype(void);
+  #define __ctype (_dll_ctype())
+#else
+  extern unsigned char __ctype[];
+#endif
+
+#ifdef __cplusplus
+  }
+#endif
+
+#define isalnum(c) (__ctype[c] & (__U+__L+__N))
+    /* non-0 iff c is alphabetic or numeric */
+
+#define isalpha(c) (__ctype[c] & (__U+__L))
+    /* non-0 iff c is alphabetic */
+
+#define iscntrl(c) (__ctype[c] & __C)
+    /* non-0 iff c is a control character - in the ASCII locale */
+    /*       this means (c < ' ') || (c > '~')                  */
+
+#define isdigit(c) (__ctype[c] & __N)
+    /* non-0 iff c is a decimal digit */
+
+#define isgraph(c) (__ctype[c] & (__L+__U+__N+__P))
+    /* non-0 iff c is any printing character other than ' ' */
+
+#define islower(c) (__ctype[c] & __L)
+    /* non-0 iff c is a lower-case letter */
+
+#define isprint(c) (__ctype[c] & (__L+__U+__N+__P+__B))
+    /* non-0 iff c is a printing character - in the ASCII locale */
+    /*       this means 0x20 (space) -> 0x7E (tilde) */
+
+#define ispunct(c) (__ctype[c] & __P)
+    /* non-0 iff c is a non-space, non-alpha-numeric, printing character */
+
+#define isspace(c) (__ctype[c] & __S)
+    /* non-0 iff c is a white-space char: ' ', '\f', '\n', '\r', '\t', '\v'. */
+
+#define isupper(c) (__ctype[c] & __U)
+    /* non-0 iff c is an upper-case letter */
+
+#define isxdigit(c) (__ctype[c] & (__N+__X))
+    /* non-0 iff c is a digit, in 'a'..'f', or in 'A'..'F' */
+
+#ifndef __cplusplus
+extern int (isalnum)(int c);
+extern int (isalpha)(int c);
+extern int (iscntrl)(int c);
+extern int (isdigit)(int c);
+extern int (isgraph)(int c);
+extern int (islower)(int c);
+extern int (isprint)(int c);
+extern int (ispunct)(int c);
+extern int (isspace)(int c);
+extern int (isupper)(int c);
+extern int (isxdigit)(int c);
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern int tolower(int c);
+    /* if c is an upper-case letter then return the corresponding */
+    /* lower-case letter, otherwise return c.                     */
+
+extern int toupper(int c);
+    /* if c is an lower-case letter then return the corresponding */
+    /* upper-case letter, otherwise return c.                     */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* end of ctype.h */
diff --git a/StraySrc/Libraries/DLLLib/h/dll b/StraySrc/Libraries/DLLLib/h/dll
new file mode 100644 (file)
index 0000000..f9c6e59
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * dll.h
+ *
+ * Definitions for DLLLib
+ *
+ * © 1994 Straylight
+ */
+
+#ifndef __dll_h
+#define __dll_h
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- External dependencies ---------------------------------------------*/
+
+#ifndef __os_h
+  #include "os.h"
+#endif
+
+#ifndef __kernel_h
+  #include "kernel.h"
+#endif
+
+#ifndef __wimp_h
+  #include "wimp.h"
+#endif
+
+/*----- Type definitions for DLLs -----------------------------------------*/
+
+typedef void *dll;                      /* What a DLL handle looks like    */
+
+typedef struct                          /* An external DLL table           */
+{
+  char *name;                           /* Name of DLL to load             */
+  int version;                          /* Minimum acceptable version      */
+  char *entryNames;                     /* Pointer to entry name table     */
+  void *branchTable;                    /* Pointer to branch table to fill */
+}
+dll_table;
+
+typedef struct                          /* A DLL information structure     */
+{
+  dll d;                                /* The handle of the DLL           */
+  char *name;                           /* The DLL's textual name          */
+  int version;                          /* The DLL's version number        */
+  char *author;                         /* The name of the DLL's author    */
+  unsigned instSize;                    /* Size of the DLL's instance vars */
+}
+dll_infostr;
+
+/*----- Interface to DLLManager SWIs --------------------------------------*
+ *
+ * The sharper eyed amongst you may have noticed that DLL_Prologue doesn't
+ * have an entry point here.  This is for several reasons:
+ *
+ * 1. It's not a very safe call to make if you don't know what you're doing.
+ *    Then again, nor are any of the others.
+ *
+ * 2. It's not all that useful unless you're writing in assembler, in which
+ *    case you can call the SWI directly.
+ *
+ * 3. Hopefully, the cdll program can generate all the code you'll ever need
+ *    which calls DLL_Prologue, and you'll never need to mess about with it.
+ *
+ * Several of the calls listed here suffer badly from lack of usefulness.
+ * The only ones that you're really likely to want to use are dll_nameApp,
+ * dll_info and dll_findEntry.
+ */
+
+os_error *dll_find(const char */*name*/, int /*version*/, dll */*d*/);
+os_error *dll_findFromTable(const dll_table */*table*/, int /*entries*/);
+os_error *dll_load(void */*buffer*/, const char */*name*/);
+os_error *dll_lose(dll /*d*/);
+os_error *dll_appDying(void);
+os_error *dll_giveCLibData(void */*data*/);
+os_error *dll_findCLibData(void **/*p*/);
+os_error *dll_instanceVars(void */*buffer*/, int */*size*/, int */*magic*/);
+os_error *dll_setInstanceVars(dll /*d*/, void */*workspace*/);
+os_error *dll_appData(void);
+os_error *dll_readStackPtr(int */*sp*/);
+os_error *dll_setStackPtr(int /*sp*/);
+os_error *dll_nameApp(const char */*name*/);
+os_error *dll_info(dll /*d*/, dll_infostr */*i*/);
+os_error *dll_findEntry(dll /*d*/, const char */*name*/,
+                        void (**/*entry*/)());
+os_error *dll_saveHandle(int */*handle*/);
+os_error *dll_restoreHandle(int */*handle*/);
+os_error *dll_findInstanceVars(dll /*d*/, void **/*addr*/);
+os_error *dll_registerAppEntryTable(void (**/*btable*/)(), char */*names*/);
+os_error *dll_findAppEntry(char */*name*/, void (**/*func*/)());
+os_error *dll_setExtensionTable(void (**/*btable*/)(), char */*names*/);
+
+/*----- Doing nothing at all, but without warnings! -----------------------*/
+
+#define _dll_nothing ((void)(0))
+
+/*----- Registration with DLLManager --------------------------------------*/
+
+#ifndef _dll_NODLL
+
+void _dll_appspace(void);
+void _dll_clibdata(void);
+#define _dll_setname(name) (void)dll_nameApp(name)
+
+#else
+
+#define _dll_appspace(x) _dll_nothing
+#define _dll_clibdata(x) _dll_nothing
+#define _dll_setname(name) _dll_nothing
+
+#endif
+
+/*----- Handling *commands ------------------------------------------------*/
+
+#ifndef _dll_NODLL
+
+int _dll_system(const char */*command*/);
+int _dll_ksystem(const char */*command*/, int /*chain*/);
+os_error *_dll_oscli(const char */*command*/);
+os_error *_dll_starttask(const char */*command*/);
+
+#else
+
+#define _dll_system(x) system(x)
+#define _dll_ksystem(x) _kernel_system(x)
+#define _dll_oscli(x) os_cli(x)
+#define _dll_starttask(x) wimp_starttask(x)
+
+#endif
+
+/*----- Handling of extension DLLs ----------------------------------------*/
+
+dll _dll_loadExtension(const char */*name*/);
+void _dll_freeExtension(dll /*d*/);
+
+/*----- setjmp and longjmp support ----------------------------------------*/
+
+#ifndef _dll_NODLL
+
+int _dll_setjmp(void);
+void _dll_longjmped(int /*sp*/);
+
+#else
+
+#define _dll_setjmp(x) (0)
+#define _dll_longjmped(x) ((x)=(x))
+
+#endif
+
+/*----- Other miscellaneous calls -----------------------------------------*/
+
+#ifndef _dll_NODLL
+
+void _dll_giveMemory(void);
+
+#else
+
+#define _dll_giveMemory(x) _dll_nothing
+
+#endif
+
+/*----- External names for extentry functions -----------------------------*/
+
+#ifdef _DLL
+
+#define _dllEntry(name) _dllEntry_ ## name
+
+#else
+
+#define _dllEntry(name) name
+
+#endif
+
+#ifndef _dll_NODLL
+
+#define _extEntry(name) _extEntry_ ## name
+#define _dll_static
+
+#else
+
+#define _extEntry(name) name
+#define _dll_static static
+
+#endif
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/StraySrc/Libraries/DLLLib/h/errno b/StraySrc/Libraries/DLLLib/h/errno
new file mode 100644 (file)
index 0000000..b73eaad
--- /dev/null
@@ -0,0 +1,72 @@
+#pragma force_top_level
+#pragma include_only_once
+
+/* errno.h: ANSI 'C' (X3J11 Oct 88) library header, section 4.1.3 */
+/* Copyright (C) Codemist Ltd. */
+/* Copyright (C) Acorn Computers Ltd. 1991, 1992 */
+/* version 2.00 */
+
+#ifndef __errno_h
+#define __errno_h
+
+#ifndef errno
+  #ifdef __cplusplus
+    extern "C" {
+    #define _VOLATILE
+  #else
+    #define _VOLATILE volatile
+  #endif
+
+  #ifdef SYSTEM_STATICS
+    extern _VOLATILE int *__errno;
+    #define errno *__errno
+  #elif defined(_DLL)
+    extern int *_dll_errno(void);
+    #define errno (*_dll_errno())
+  #else
+    extern _VOLATILE int __errno;
+    #define errno __errno
+  #endif
+
+  #ifdef __cplusplus
+    }
+  #endif
+
+  #undef _VOLATILE
+
+#endif
+
+   /*
+    * expands to a modifiable lvalue that has type volatile int, the value of
+    * which is set to a positive error code by several library functions. It is
+    * initialised to zero at program startup, but is never set to zero by any
+    * library function. The value of errno may be set to nonzero by a library
+    * function call whether or not there is an error, provided the use of errno
+    * is not documented in the description of the function in the Standard.
+    */
+
+#define EDOM    1
+   /*
+    * if a domain error occurs (an input argument is outside the domain over
+    * which the mathematical function is defined) the integer expression errno
+    * acquires the value of the macro EDOM and HUGE_VAL is returned. EDOM may
+    * be used by non-mathematical functions.
+    */
+#define ERANGE 2
+   /*
+    * a range error occurs if the result of a function can not be represented
+    * as a double value. If the result overflows (the magnitude of the result
+    * is so large that it cannot be represented in an object of the specified
+    * type), the function returns the value of the macro HUGE_VAL, with the
+    * same sign as the correct value of the function; the integer expression
+    * errno acquires the value of the macro ERANGE. If the result underflows
+    * (the magnitude of the result is so small that it cannot be represented
+    * in an object of the specified type), the function returns zero; the
+    * integer expression errno acquires the value of the macro ERANGE. ERANGE
+    * may be used by non-mathematical functions.
+    */
+#define ESIGNUM 3
+
+#endif
+
+/* end of errno.h */
diff --git a/StraySrc/Libraries/DLLLib/h/math b/StraySrc/Libraries/DLLLib/h/math
new file mode 100644 (file)
index 0000000..01b4cc1
--- /dev/null
@@ -0,0 +1,167 @@
+#pragma force_top_level
+#pragma include_only_once
+
+/* math.h: ANSI 'C' (X3J11 Oct 88) library header, section 4.5 */
+/* Copyright (C) Codemist Ltd. */
+/* Copyright (C) Acorn Computers Ltd. 1991 */
+/* version 0.02 */
+
+#ifndef __math_h
+#define __math_h
+
+#ifndef HUGE_VAL
+  #define HUGE_VAL __huge_val
+
+  #ifdef __cplusplus
+    #define HUGE __huge_val
+    extern "C" {
+  #endif
+
+  #ifdef _DLL
+    extern const double *_dll_huge_val(void);
+    #define __huge_val (*_dll_huge_val())
+  #else
+    extern const double __huge_val;
+  #endif
+
+  #ifdef __cplusplus
+    }
+  #endif
+
+#endif
+
+#pragma no_side_effects
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern double acos(double /*x*/);
+   /* computes the principal value of the arc cosine of x */
+   /* a domain error occurs for arguments not in the range -1 to 1 */
+   /* Returns: the arc cosine in the range 0 to Pi. */
+extern double asin(double /*x*/);
+   /* computes the principal value of the arc sine of x */
+   /* a domain error occurs for arguments not in the range -1 to 1 */
+   /* and -HUGE_VAL is returned. */
+   /* Returns: the arc sine in the range -Pi/2 to Pi/2. */
+extern double atan(double /*x*/);
+   /* computes the principal value of the arc tangent of x */
+   /* Returns: the arc tangent in the range -Pi/2 to Pi/2. */
+extern double atan2(double /*x*/, double /*y*/);
+   /* computes the principal value of the arc tangent of y/x, using the */
+   /* signs of both arguments to determine the quadrant of the return value */
+   /* a domain error occurs if both args are zero, and -HUGE_VAL returned. */
+   /* Returns: the arc tangent of y/x, in the range -Pi to Pi. */
+
+extern double __d_atan(double);
+#define atan(x) __d_atan(x)
+
+extern double cos(double /*x*/);
+   /* computes the cosine of x (measured in radians). A large magnitude */
+   /* argument may yield a result with little or no significance */
+   /* Returns: the cosine value. */
+extern double sin(double /*x*/);
+   /* computes the sine of x (measured in radians). A large magnitude */
+   /* argument may yield a result with little or no significance */
+   /* Returns: the sine value. */
+
+extern double __d_sin(double);
+extern double __d_cos(double);
+#define sin(x) __d_sin(x)
+#define cos(x) __d_cos(x)
+
+extern double tan(double /*x*/);
+   /* computes the tangent of x (measured in radians). A large magnitude */
+   /* argument may yield a result with little or no significance */
+   /* Returns: the tangent value. */
+   /*          if range error; returns HUGE_VAL. */
+
+extern double cosh(double /*x*/);
+   /* computes the hyperbolic cosine of x. A range error occurs if the */
+   /* magnitude of x is too large. */
+   /* Returns: the hyperbolic cosine value. */
+   /*          if range error; returns HUGE_VAL. */
+extern double sinh(double /*x*/);
+   /* computes the hyperbolic sine of x. A range error occurs if the */
+   /* magnitude of x is too large. */
+   /* Returns: the hyperbolic sine value. */
+   /*          if range error; returns -HUGE_VAL or HUGE_VAL depending */
+   /*          on the sign of the argument */
+extern double tanh(double /*x*/);
+   /* computes the hyperbolic tangent of x. */
+   /* Returns: the hyperbolic tangent value. */
+
+extern double exp(double /*x*/);
+   /* computes the exponential function of x. A range error occurs if the */
+   /* magnitude of x is too large. */
+   /* Returns: the exponential value. */
+   /*          if underflow range error; 0 is returned. */
+   /*          if overflow range error; HUGE_VAL is returned. */
+extern double frexp(double /*value*/, int * /*exp*/);
+   /* breaks a floating-point number into a normalised fraction and an */
+   /* integral power of 2. It stores the integer in the int object pointed */
+   /* to by exp. */
+   /* Returns: the value x, such that x is a double with magnitude in the */
+   /* interval 0.5 to 1.0 or zero, and value equals x times 2 raised to the */
+   /* power *exp. If value is zero, both parts of the result are zero. */
+extern double ldexp(double /*x*/, int /*exp*/);
+   /* multiplies a floating-point number by an integral power of 2. */
+   /* A range error may occur. */
+   /* Returns: the value of x times 2 raised to the power of exp. */
+   /*          if range error; HUGE_VAL is returned. */
+extern double log(double /*x*/);
+   /* computes the natural logarithm of x. A domain error occurs if the */
+   /* argument is negative, and -HUGE_VAL is returned. A range error occurs */
+   /* if the argument is zero. */
+   /* Returns: the natural logarithm. */
+   /*          if range error; -HUGE_VAL is returned. */
+extern double log10(double /*x*/);
+   /* computes the base-ten logarithm of x. A domain error occurs if the */
+   /* argument is negative. A range error occurs if the argument is zero. */
+   /* Returns: the base-ten logarithm. */
+extern double modf(double /*value*/, double * /*iptr*/);
+   /* breaks the argument value into integral and fraction parts, each of */
+   /* which has the same sign as the argument. It stores the integral part */
+   /* as a double in the object pointed to by iptr. */
+   /* Returns: the signed fractional part of value. */
+
+extern double pow(double /*x*/, double /*y*/);
+   /* computes x raised to the power of y. A domain error occurs if x is */
+   /* zero and y is less than or equal to zero, or if x is negative and y */
+   /* is not an integer, and -HUGE_VAL returned. A range error may occur. */
+   /* Returns: the value of x raised to the power of y. */
+   /*          if underflow range error; 0 is returned. */
+   /*          if overflow range error; HUGE_VAL is returned. */
+extern double sqrt(double /*x*/);
+   /* computes the non-negative square root of x. A domain error occurs */
+   /* if the argument is negative, and -HUGE_VAL returned. */
+   /* Returns: the value of the square root. */
+
+extern double ceil(double /*x*/);
+   /* computes the smallest integer not less than x. */
+   /* Returns: the smallest integer not less than x, expressed as a double. */
+extern double fabs(double /*x*/);
+   /* computes the absolute value of the floating-point number x. */
+   /* Returns: the absolute value of x. */
+extern double floor(double /*d*/);
+   /* computes the largest integer not greater than x. */
+   /* Returns: the largest integer not greater than x, expressed as a double */
+extern double fmod(double /*x*/, double /*y*/);
+   /* computes the floating-point remainder of x/y. */
+   /* Returns: the value x - i * y, for some integer i such that, if y is */
+   /*          nonzero, the result has the same sign as x and magnitude */
+   /*          less than the magnitude of y. If y is zero, a domain error */
+   /*          occurs and -HUGE_VAL is returned. */
+
+extern double __d_abs(double);
+#define fabs(x) __d_abs(x)
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma side_effects
+
+#endif
+
+/* end of math.h */
diff --git a/StraySrc/Libraries/DLLLib/h/stdio b/StraySrc/Libraries/DLLLib/h/stdio
new file mode 100644 (file)
index 0000000..e62ca15
--- /dev/null
@@ -0,0 +1,695 @@
+#pragma force_top_level
+#pragma include_only_once
+
+/* stdio.h: ANSI 'C' (X3J11 Oct 88) library header, section 4.9 */
+/* Copyright (C) Codemist Ltd. */
+/* Copyright (C) Acorn Computers Ltd., 1990, 1992 */
+/* version 2.00 */
+
+/* AM July-88 changes to all prototypes so that                         */
+/*      #define mode 3; #include <stdio.h> can work as ANSI require.    */
+
+/*
+ * stdio.h declares two types, several macros, and many functions for
+ * performing input and output. For a discussion on Streams and Files
+ * refer to sections 4.9.2 and 4.9.3 in the above ANSI draft, or to a
+ * modern textbook on C.
+ */
+
+#ifndef __stdio_h
+#define __stdio_h
+
+#define __LIB_VERSION 310       /* 3.10, but int for PP inequality test */
+
+#ifndef __size_t
+#define __size_t 1
+typedef unsigned int size_t;   /* from <stddef.h> */
+#endif
+
+/* ANSI forbids va_list to be defined here */
+typedef char *__va_list[1];       /* keep in step with <stdarg.h> */
+
+#ifndef NULL
+#  define NULL 0                /* see <stddef.h> */
+#endif
+
+typedef struct __fpos_t_struct
+{ unsigned long __lo;             /* add hi one day */
+} fpos_t;
+   /*
+    * fpos_t is an object capable of recording all information needed to
+    * specify uniquely every position within a file.
+    */
+
+typedef struct __FILE_struct
+{ unsigned char *__ptr;
+  int __icnt;      /* two separate _cnt fields so we can police ...        */
+  int __ocnt;      /* ... restrictions that read/write are fseek separated */
+  int __flag;
+  /* AM: the following things do NOT need __ prefixes as they are          */
+  /* are invisible in an ANSI-conforming program.                          */
+  unsigned char *__base; /* buffer base */
+  int __file;            /* RISCOS/Arthur/Brazil file handle */
+  long __pos;            /* position in file */
+  int __bufsiz;          /* maximum buffer size */
+  int __signature;       /* used with temporary files */
+  struct __extradata *__extrap; /* pointer to information about stream */
+} FILE;
+   /*
+    * FILE is an object capable of recording all information needed to control
+    * a stream, such as its file position indicator, a pointer to its
+    * associated buffer, an error indicator that records whether a read/write
+    * error has occurred and an end-of-file indicator that records whether the
+    * end-of-file has been reached.
+    * N.B. the objects contained in the #ifdef __system_io clause are for
+    * system use only.
+    */
+
+# define _IOREAD      0x01 /* system use - open for input */
+# define _IOWRITE     0x02 /* system use - open for output */
+# define _IOBIN       0x04 /* system use - binary stream */
+# define _IOSTRG      0x08 /* system use - string stream */
+# define _IOSEEK      0x10 /* system use - physical seek required before IO */
+# define _IOLAZY      0x20 /* system use - possible seek pending */
+# define _IOSBF      0x800 /* system use - system allocated buffer */
+# define _IOAPPEND 0x08000 /* system use - must seek to eof before write */
+#define _IOEOF     0x40 /* end-of-file reached */
+#define _IOERR     0x80 /* error occurred on stream */
+#define _IOFBF    0x100 /* fully buffered IO */
+#define _IOLBF    0x200 /* line buffered IO */
+#define _IONBF    0x400 /* unbuffered IO */
+
+#define BUFSIZ   (4096) /* system buffer size (as used by setbuf) */
+#define EOF      (-1)
+   /*
+    * negative integral constant, indicates end-of-file, that is, no more input
+    * from a stream.
+    */
+/* It is not clear to me what value FOPEN_MAX should have, so I will
+   err in the cautious direction - ANSI requires it to be at least 8 */
+#define FOPEN_MAX 8           /* check re arthur/unix/mvs */
+   /*
+    * an integral constant expression that is the minimum number of files that
+    * this implementation guarantees can be open simultaneously.
+    */
+/* _SYS_OPEN defines a limit on the number of open files that is imposed
+   by this C library */
+#define _SYS_OPEN 16
+#define FILENAME_MAX 80
+   /*
+    * an integral constant expression that is the size of an array of char
+    * large enough to hold the longest filename string
+    */
+#define L_tmpnam FILENAME_MAX
+   /*
+    * an integral constant expression that is the size of an array of char
+    * large enough to hold a temporary file name string generated by the
+    * tmpnam function.
+    */
+
+#ifndef SEEK_SET
+#define SEEK_SET 0 /* start of stream (see fseek) */
+#define SEEK_CUR 1 /* current position in stream (see fseek) */
+#define SEEK_END 2 /* end of stream (see fseek) */
+#endif
+
+#define TMP_MAX 1000000000
+   /*
+    * an integral constant expression that is the minimum number of unique
+    * file names that shall be generated by the tmpnam function.
+    */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _DLL
+  extern FILE *_dll_iob(void);
+  #define __iob (_dll_iob())
+#else
+  extern FILE __iob[];
+     /* an array of file objects for use by the system. */
+#endif
+
+#ifdef SYSTEM_STATICS
+  extern FILE *stdin;
+  extern FILE *stdout;
+  extern FILE *stderr;
+#else
+  #define stdin  (&__iob[0])
+     /* pointer to a FILE object associated with standard input stream */
+  #define stdout (&__iob[1])
+     /* pointer to a FILE object associated with standard output stream */
+  #define stderr (&__iob[2])
+     /* pointer to a FILE object associated with standard error stream */
+#endif
+
+extern int remove(const char * /*filename*/);
+   /*
+    * causes the file whose name is the string pointed to by filename to be
+    * removed. Subsequent attempts to open the file will fail, unless it is
+    * created anew. If the file is open, the behaviour of the remove function
+    * is implementation-defined (under RISCOS/Arthur/Brazil the operation
+    * fails).
+    * Returns: zero if the operation succeeds, nonzero if it fails.
+    */
+extern int rename(const char * /*old*/, const char * /*new*/);
+   /*
+    * causes the file whose name is the string pointed to by old to be
+    * henceforth known by the name given by the string pointed to by new. The
+    * file named old is effectively removed. If a file named by the string
+    * pointed to by new exists prior to the call of the rename function, the
+    * behaviour is implementation-defined (under RISCOS/Arthur/Brazil, the
+    * operation fails).
+    * Returns: zero if the operation succeeds, nonzero if it fails, in which
+    *          case if the file existed previously it is still known by its
+    *          original name.
+    */
+extern FILE *tmpfile(void);
+   /*
+    * creates a temporary binary file that will be automatically removed when
+    * it is closed or at program termination. The file is opened for update.
+    * Returns: a pointer to the stream of the file that it created. If the file
+    *          cannot be created, a null pointer is returned.
+    */
+extern char *tmpnam(char * /*s*/);
+   /*
+    * generates a string that is not the same as the name of an existing file.
+    * The tmpnam function generates a different string each time it is called,
+    * up to TMP_MAX times. If it is called more than TMP_MAX times, the
+    * behaviour is implementation-defined (under RISCOS/Arthur/Brazil the
+    * algorithm for the name generation works just as well after tmpnam has
+    * been called more than TMP_MAX times as before; a name clash is impossible
+    * in any single half year period).
+    * Returns: If the argument is a null pointer, the tmpnam function leaves
+    *          its result in an internal static object and returns a pointer to
+    *          that object. Subsequent calls to the tmpnam function may modify
+    *          the same object. if the argument is not a null pointer, it is
+    *          assumed to point to an array of at least L_tmpnam characters;
+    *          the tmpnam function writes its result in that array and returns
+    *          the argument as its value.
+    */
+
+extern int fclose(FILE * /*stream*/);
+   /*
+    * causes the stream pointed to by stream to be flushed and the associated
+    * file to be closed. Any unwritten buffered data for the stream are
+    * delivered to the host environment to be written to the file; any unread
+    * buffered data are discarded. The stream is disassociated from the file.
+    * If the associated buffer was automatically allocated, it is deallocated.
+    * Returns: zero if the stream was succesfully closed, or nonzero if any
+    *          errors were detected or if the stream was already closed.
+    */
+extern int fflush(FILE * /*stream*/);
+   /*
+    * If the stream points to an output or update stream in which the most
+    * recent operation was output, the fflush function causes any unwritten
+    * data for that stream to be delivered to the host environment to be
+    * written to the file. If the stream points to an input or update stream,
+    * the fflush function undoes the effect of any preceding ungetc operation
+    * on the stream.
+    * Returns: nonzero if a write error occurs.
+    */
+extern FILE *fopen(const char * /*filename*/, const char * /*mode*/);
+   /*
+    * opens the file whose name is the string pointed to by filename, and
+    * associates a stream with it.
+    * The argument mode points to a string beginning with one of the following
+    * sequences:
+    * "r"         open text file for reading
+    * "w"         create text file for writing, or truncate to zero length
+    * "a"         append; open text file or create for writing at eof
+    * "rb"        open binary file for reading
+    * "wb"        create binary file for writing, or truncate to zero length
+    * "ab"        append; open binary file or create for writing at eof
+    * "r+"        open text file for update (reading and writing)
+    * "w+"        create text file for update, or truncate to zero length
+    * "a+"        append; open text file or create for update, writing at eof
+    * "r+b"/"rb+" open binary file for update (reading and writing)
+    * "w+b"/"wb+" create binary file for update, or truncate to zero length
+    * "a+b"/"ab+" append; open binary file or create for update, writing at eof
+    *
+    * Opening a file with read mode ('r' as the first character in the mode
+    * argument) fails if the file does not exist or cannot be read.
+    * Opening a file with append mode ('a' as the first character in the mode
+    * argument) causes all subsequent writes to be forced to the current end of
+    * file, regardless of intervening calls to the fseek function. In some
+    * implementations, opening a binary file with append mode ('b' as the
+    * second or third character in the mode argument) may initially position
+    * the file position indicator beyond the last data written, because of the
+    * NUL padding (but not under RISCOS/Arthur/Brazil).
+    * When a file is opened with update mode ('+' as the second or third
+    * character in the mode argument), both input and output may be performed
+    * on the associated stream. However, output may not be directly followed by
+    * input without an intervening call to the fflush fuction or to a file
+    * positioning function (fseek, fsetpos, or rewind), and input be not be
+    * directly followed by output without an intervening call to the fflush
+    * fuction or to a file positioning function, unless the input operation
+    * encounters end-of-file. Opening a file with update mode may open or
+    * create a binary stream in some implementations (but not under RISCOS/
+    * Arthur/Brazil). When opened, a stream is fully buffered if and only if
+    * it does not refer to an interactive device. The error and end-of-file
+    * indicators for the stream are cleared.
+    * Returns: a pointer to the object controlling the stream. If the open
+    *          operation fails, fopen returns a null pointer.
+    */
+extern FILE *freopen(const char * /*filename*/, const char * /*mode*/,
+                     FILE * /*stream*/);
+   /*
+    * opens the file whose name is the string pointed to by filename and
+    * associates the stream pointed to by stream with it. The mode argument is
+    * used just as in the fopen function.
+    * The freopen function first attempts to close any file that is associated
+    * with the specified stream. Failure to close the file successfully is
+    * ignored. The error and end-of-file indicators for the stream are cleared.
+    * Returns: a null pointer if the operation fails. Otherwise, freopen
+    *          returns the value of the stream.
+    */
+extern void setbuf(FILE * /*stream*/, char * /*buf*/);
+   /*
+    * Except that it returns no value, the setbuf function is equivalent to the
+    * setvbuf function invoked with the values _IOFBF for mode and BUFSIZ for
+    * size, or (if buf is a null pointer), with the value _IONBF for mode.
+    * Returns: no value.
+    */
+extern int setvbuf(FILE * /*stream*/, char * /*buf*/,
+                   int /*mode*/, size_t /*size*/);
+   /*
+    * may be used after the stream pointed to by stream has been associated
+    * with an open file but before it is read or written. The argument mode
+    * determines how stream will be buffered, as follows: _IOFBF causes
+    * input/output to be fully buffered; _IOLBF causes output to be line
+    * buffered (the buffer will be flushed when a new-line character is
+    * written, when the buffer is full, or when input is requested); _IONBF
+    * causes input/output to be completely unbuffered. If buf is not the null
+    * pointer, the array it points to may be used instead of an automatically
+    * allocated buffer (the buffer must have a lifetime at least as great as
+    * the open stream, so the stream should be closed before a buffer that has
+    * automatic storage duration is deallocated upon block exit). The argument
+    * size specifies the size of the array. The contents of the array at any
+    * time are indeterminate.
+    * Returns: zero on success, or nonzero if an invalid value is given for
+    *          mode or size, or if the request cannot be honoured.
+    */
+
+#pragma -v1   /* hint to the compiler to check f/s/printf format */
+extern int fprintf(FILE * /*stream*/, const char * /*format*/, ...);
+   /*
+    * writes output to the stream pointed to by stream, under control of the
+    * string pointed to by format that specifies how subsequent arguments are
+    * converted for output. If there are insufficient arguments for the format,
+    * the behaviour is undefined. If the format is exhausted while arguments
+    * remain, the excess arguments are evaluated but otherwise ignored. The
+    * fprintf function returns when the end of the format string is reached.
+    * The format shall be a multibyte character sequence, beginning and ending
+    * in its initial shift state. The format is composed of zero or more
+    * directives: ordinary multibyte characters (not %), which are copied
+    * unchanged to the output stream; and conversion specifiers, each of which
+    * results in fetching zero or more subsequent arguments. Each conversion
+    * specification is introduced by the character %. For a description of the
+    * available conversion specifiers refer to section 4.9.6.1 in the ANSI
+    * draft mentioned at the start of this file or to any modern textbook on C.
+    * The minimum value for the maximum number of characters producable by any
+    * single conversion is at least 509.
+    * Returns: the number of characters transmitted, or a negative value if an
+    *          output error occurred.
+    */
+extern int printf(const char * /*format*/, ...);
+   /*
+    * is equivalent to fprintf with the argument stdout interposed before the
+    * arguments to printf.
+    * Returns: the number of characters transmitted, or a negative value if an
+    *          output error occurred.
+    */
+extern int sprintf(char * /*s*/, const char * /*format*/, ...);
+   /*
+    * is equivalent to fprintf, except that the argument s specifies an array
+    * into which the generated output is to be written, rather than to a
+    * stream. A null character is written at the end of the characters written;
+    * it is not counted as part of the returned sum.
+    * Returns: the number of characters written to the array, not counting the
+    *          terminating null character.
+    */
+#pragma -v2   /* hint to the compiler to check f/s/scanf format */
+extern int fscanf(FILE * /*stream*/, const char * /*format*/, ...);
+   /*
+    * reads input from the stream pointed to by stream, under control of the
+    * string pointed to by format that specifies the admissible input sequences
+    * and how thay are to be converted for assignment, using subsequent
+    * arguments as pointers to the objects to receive the converted input. If
+    * there are insufficient arguments for the format, the behaviour is
+    * undefined. If the format is exhausted while arguments remain, the excess
+    * arguments are evaluated but otherwise ignored.
+    * The format is composed of zero or more directives: one or more
+    * white-space characters; an ordinary character (not %); or a conversion
+    * specification. Each conversion specification is introduced by the
+    * character %. For a description of the available conversion specifiers
+    * refer to section 4.9.6.2 in the ANSI draft mentioned at the start of this
+    * file, or to any modern textbook on C.
+    * If end-of-file is encountered during input, conversion is terminated. If
+    * end-of-file occurs before any characters matching the current directive
+    * have been read (other than leading white space, where permitted),
+    * execution of the current directive terminates with an input failure;
+    * otherwise, unless execution of the current directive is terminated with a
+    * matching failure, execution of the following directive (if any) is
+    * terminated with an input failure.
+    * If conversions terminates on a conflicting input character, the offending
+    * input character is left unread in the input strem. Trailing white space
+    * (including new-line characters) is left unread unless matched by a
+    * directive. The success of literal matches and suppressed asignments is
+    * not directly determinable other than via the %n directive.
+    * Returns: the value of the macro EOF if an input failure occurs before any
+    *          conversion. Otherwise, the fscanf function returns the number of
+    *          input items assigned, which can be fewer than provided for, or
+    *          even zero, in the event of an early conflict between an input
+    *          character and the format.
+    */
+extern int scanf(const char * /*format*/, ...);
+   /*
+    * is equivalent to fscanf with the argument stdin interposed before the
+    * arguments to scanf.
+    * Returns: the value of the macro EOF if an input failure occurs before any
+    *          conversion. Otherwise, the scanf function returns the number of
+    *          input items assigned, which can be fewer than provided for, or
+    *          even zero, in the event of an early matching failure.
+    */
+extern int sscanf(const char * /*s*/, const char * /*format*/, ...);
+   /*
+    * is equivalent to fscanf except that the argument s specifies a string
+    * from which the input is to be obtained, rather than from a stream.
+    * Reaching the end of the string is equivalent to encountering end-of-file
+    * for the fscanf function.
+    * Returns: the value of the macro EOF if an input failure occurs before any
+    *          conversion. Otherwise, the scanf function returns the number of
+    *          input items assigned, which can be fewer than provided for, or
+    *          even zero, in the event of an early matching failure.
+    */
+#pragma -v0   /* back to default */
+extern int vprintf(const char * /*format*/, __va_list /*arg*/);
+   /*
+    * is equivalent to printf, with the variable argument list replaced by arg,
+    * which has been initialised by the va_start macro (and possibly subsequent
+    * va_arg calls). The vprintf function does not invoke the va_end function.
+    * Returns: the number of characters transmitted, or a negative value if an
+    *          output error occurred.
+    */
+extern int vfprintf(FILE * /*stream*/,
+                   const char * /*format*/, __va_list /*arg*/);
+   /*
+    * is equivalent to fprintf, with the variable argument list replaced by
+    * arg, which has been initialised by the va_start macro (and possibly
+    * subsequent va_arg calls). The vfprintf function does not invoke the
+    * va_end function.
+    * Returns: the number of characters transmitted, or a negative value if an
+    *          output error occurred.
+    */
+extern int vsprintf(char * /*s*/, const char * /*format*/, __va_list /*arg*/);
+   /*
+    * is equivalent to sprintf, with the variable argument list replaced by
+    * arg, which has been initialised by the va_start macro (and possibly
+    * subsequent va_arg calls). The vsprintf function does not invoke the
+    * va_end function.
+    * Returns: the number of characters written in the array, not counting the
+    *          terminating null character.
+    */
+
+extern int fgetc(FILE * /*stream*/);
+   /*
+    * obtains the next character (if present) as an unsigned char converted to
+    * an int, from the input stream pointed to by stream, and advances the
+    * associated file position indicator (if defined).
+    * Returns: the next character from the input stream pointed to by stream.
+    *          If the stream is at end-of-file, the end-of-file indicator is
+    *          set and fgetc returns EOF. If a read error occurs, the error
+    *          indicator is set and fgetc returns EOF.
+    */
+extern char *fgets(char * /*s*/, int /*n*/, FILE * /*stream*/);
+   /*
+    * reads at most one less than the number of characters specified by n from
+    * the stream pointed to by stream into the array pointed to by s. No
+    * additional characters are read after a new-line character (which is
+    * retained) or after end-of-file. A null character is written immediately
+    * after the last character read into the array.
+    * Returns: s if successful. If end-of-file is encountered and no characters
+    *          have been read into the array, the contents of the array remain
+    *          unchanged and a null pointer is returned. If a read error occurs
+    *          during the operation, the array contents are indeterminate and a
+    *          null pointer is returned.
+    */
+extern int fputc(int /*c*/, FILE * /*stream*/);
+   /*
+    * writes the character specified by c (converted to an unsigned char) to
+    * the output stream pointed to by stream, at the position indicated by the
+    * asociated file position indicator (if defined), and advances the
+    * indicator appropriately. If the file position indicator is not defined,
+    * the character is appended to the output stream.
+    * Returns: the character written. If a write error occurs, the error
+    *          indicator is set and fputc returns EOF.
+    */
+extern int fputs(const char * /*s*/, FILE * /*stream*/);
+   /*
+    * writes the string pointed to by s to the stream pointed to by stream.
+    * The terminating null character is not written.
+    * Returns: EOF if a write error occurs; otherwise it returns a nonnegative
+    *          value.
+    */
+extern int __filbuf(FILE * /*stream*/);
+   /*
+    * SYSTEM USE ONLY, called by getc to refill buffer and or sort out flags.
+    * Returns: first character put into buffer or EOF on error.
+    */
+#define getc(p) \
+    (--((p)->__icnt) >= 0 ? *((p)->__ptr)++ : __filbuf(p))
+#ifndef __cplusplus
+extern int (getc)(FILE * /*stream*/);
+#endif
+   /*
+    * is equivalent to fgetc except that it may be (and is under
+    * RISCOS/Arthur/Brazil) implemented as a macro. stream may be evaluated
+    * more than once, so the argument should never be an expression with side
+    * effects.
+    * Returns: the next character from the input stream pointed to by stream.
+    *          If the stream is at end-of-file, the end-of-file indicator is
+    *          set and getc returns EOF. If a read error occurs, the error
+    *          indicator is set and getc returns EOF.
+    */
+#define getchar() getc(stdin)
+#ifndef __cplusplus
+extern int (getchar)(void);
+#endif
+   /*
+    * is equivalent to getc with the argument stdin.
+    * Returns: the next character from the input stream pointed to by stdin.
+    *          If the stream is at end-of-file, the end-of-file indicator is
+    *          set and getchar returns EOF. If a read error occurs, the error
+    *          indicator is set and getchar returns EOF.
+    */
+extern char *gets(char * /*s*/);
+   /*
+    * reads characters from the input stream pointed to by stdin into the array
+    * pointed to by s, until end-of-file is encountered or a new-line character
+    * is read. Any new-line character is discarded, and a null character is
+    * written immediately after the last character read into the array.
+    * Returns: s if successful. If end-of-file is encountered and no characters
+    *          have been read into the array, the contents of the array remain
+    *          unchanged and a null pointer is returned. If a read error occurs
+    *          during the operation, the array contents are indeterminate and a
+    *          null pointer is returned.
+    */
+extern int __flsbuf(int /*c*/, FILE * /*stream*/);
+   /*
+    * SYSTEM USE ONLY, called by putc to flush buffer and or sort out flags.
+    * Returns: character put into buffer or EOF on error.
+    */
+#define putc(ch, p) \
+    (--((p)->__ocnt) >= 0 ? (*((p)->__ptr)++ = (ch)) : __flsbuf(ch,p))
+#ifndef __cplusplus
+extern int (putc)(int /*c*/, FILE * /*stream*/);
+#endif
+   /*
+    * is equivalent to fputc except that it may be (and is under
+    * RISCOS/Arthur/Brazil) implemented as a macro. stream may be evaluated
+    * more than once, so the argument should never be an expression with side
+    * effects.
+    * Returns: the character written. If a write error occurs, the error
+    *          indicator is set and putc returns EOF.
+    */
+#define putchar(ch) putc(ch, stdout)
+#ifndef __cplusplus
+extern int (putchar)(int /*c*/);
+#endif
+   /*
+    * is equivalent to putc with the second argument stdout.
+    * Returns: the character written. If a write error occurs, the error
+    *          indicator is set and putc returns EOF.
+    */
+extern int puts(const char * /*s*/);
+   /*
+    * writes the string pointed to by s to the stream pointed to by stdout, and
+    * appends a new-line character to the output. The terminating null
+    * character is not written.
+    * Returns: EOF if a write error occurs; otherwise it returns a nonnegative
+    *          value.
+    */
+extern int ungetc(int /*c*/, FILE * /*stream*/);
+   /*
+    * pushes the character specified by c (converted to an unsigned char) back
+    * onto the input stream pointed to by stream. The character will be
+    * returned by the next read on that stream. An intervening call to the
+    * fflush function or to a file positioning function (fseek, fsetpos,
+    * rewind) discards any pushed-back characters. The external storage
+    * corresponding to the stream is unchanged.
+    * One character pushback is guaranteed. If the unget function is called too
+    * many times on the same stream without an intervening read or file
+    * positioning operation on that stream, the operation may fail.
+    * If the value of c equals that of the macro EOF, the operation fails and
+    * the input stream is unchanged.
+    * A successful call to the ungetc function clears the end-of-file
+    * indicator. The value of the file position indicator after reading or
+    * discarding all pushed-back characters shall be the same as it was before
+    * the characters were pushed back. For a text stream, the value of the file
+    * position indicator after a successful call to the ungetc function is
+    * unspecified until all pushed-back characters are read or discarded. For a
+    * binary stream, the file position indicator is decremented by each
+    * successful call to the ungetc function; if its value was zero before a
+    * call, it is indeterminate after the call.
+    * Returns: the character pushed back after conversion, or EOF if the
+    *          operation fails.
+    */
+
+extern size_t fread(void * /*ptr*/,
+                    size_t /*size*/, size_t /*nmemb*/, FILE * /*stream*/);
+   /*
+    * reads into the array pointed to by ptr, up to nmemb members whose size is
+    * specified by size, from the stream pointed to by stream. The file
+    * position indicator (if defined) is advanced by the number of characters
+    * successfully read. If an error occurs, the resulting value of the file
+    * position indicator is indeterminate. If a partial member is read, its
+    * value is indeterminate. The ferror or feof function shall be used to
+    * distinguish between a read error and end-of-file.
+    * Returns: the number of members successfully read, which may be less than
+    *          nmemb if a read error or end-of-file is encountered. If size or
+    *          nmemb is zero, fread returns zero and the contents of the array
+    *          and the state of the stream remain unchanged.
+    */
+extern size_t fwrite(const void * /*ptr*/,
+                    size_t /*size*/, size_t /*nmemb*/, FILE * /*stream*/);
+   /*
+    * writes, from the array pointed to by ptr up to nmemb members whose size
+    * is specified by size, to the stream pointed to by stream. The file
+    * position indicator (if defined) is advanced by the number of characters
+    * successfully written. If an error occurs, the resulting value of the file
+    * position indicator is indeterminate.
+    * Returns: the number of members successfully written, which will be less
+    *          than nmemb only if a write error is encountered.
+    */
+
+extern int fgetpos(FILE * /*stream*/, fpos_t * /*pos*/);
+   /*
+    * stores the current value of the file position indicator for the stream
+    * pointed to by stream in the object pointed to by pos. The value stored
+    * contains unspecified information usable by the fsetpos function for
+    * repositioning the stream to its position at the time  of the call to the
+    * fgetpos function.
+    * Returns: zero, if successful. Otherwise nonzero is returned and the
+    *          integer expression errno is set to an implementation-defined
+    *          nonzero value (under RISCOS/Arthur/Brazil fgetpos cannot fail).
+    */
+extern int fseek(FILE * /*stream*/, long int /*offset*/, int /*whence*/);
+   /*
+    * sets the file position indicator for the stream pointed to by stream.
+    * For a binary stream, the new position is at the signed number of
+    * characters specified by offset away from the point specified by whence.
+    * The specified point is the beginning of the file for SEEK_SET, the
+    * current position in the file for SEEK_CUR, or end-of-file for SEEK_END.
+    * A binary stream need not meaningfully support fseek calls with a whence
+    * value of SEEK_END.
+    * For a text stream, either offset shall be zero, or offset shall be a
+    * value returned by an earlier call to the ftell function on the same
+    * stream and whence shall be SEEK_SET.
+    * The fseek function clears the end-of-file indicator and undoes any
+    * effects of the ungetc function on the same stream. After an fseek call,
+    * the next operation on an update stream may be either input or output.
+    * Returns: nonzero only for a request that cannot be satisfied.
+    */
+extern int fsetpos(FILE * /*stream*/, const fpos_t * /*pos*/);
+   /*
+    * sets  the file position indicator for the stream pointed to by stream
+    * according to the value of the object pointed to by pos, which shall be a
+    * value returned by an earlier call to the fgetpos function on the same
+    * stream.
+    * The fsetpos function clears the end-of-file indicator and undoes any
+    * effects of the ungetc function on the same stream. After an fsetpos call,
+    * the next operation on an update stream may be either input or output.
+    * Returns: zero, if successful. Otherwise nonzero is returned and the
+    *          integer expression errno is set to an implementation-defined
+    *          nonzero value (under RISCOS/Arthur/Brazil the value that of EDOM
+    *          in math.h).
+    */
+extern long int ftell(FILE * /*stream*/);
+   /*
+    * obtains the current value of the file position indicator for the stream
+    * pointed to by stream. For a binary stream, the value is the number of
+    * characters from the beginning of the file. For a text stream, the file
+    * position indicator contains unspecified information, usable by the fseek
+    * function for returning the file position indicator to its position at the
+    * time of the ftell call; the difference between two such return values is
+    * not necessarily a meaningful measure of the number of characters written
+    * or read.
+    * Returns: if successful, the current value of the file position indicator.
+    *          On failure, the ftell function returns -1L and sets the integer
+    *          expression errno to an implementation-defined nonzero value
+    *          (under RISCOS/Arthur/Brazil ftell cannot fail).
+    */
+extern void rewind(FILE * /*stream*/);
+   /*
+    * sets the file position indicator for the stream pointed to by stream to
+    * the beginning of the file. It is equivalent to
+    *          (void)fseek(stream, 0L, SEEK_SET)
+    * except that the error indicator for the stream is also cleared.
+    * Returns: no value.
+    */
+
+extern void clearerr(FILE * /*stream*/);
+   /*
+    * clears the end-of-file and error indicators for the stream pointed to by
+    * stream. These indicators are cleared only when the file is opened or by
+    * an explicit call to the clearerr function or to the rewind function.
+    * Returns: no value.
+    */
+
+#define feof(stream) ((stream)->__flag & _IOEOF)
+#ifndef __cplusplus
+extern int (feof)(FILE * /*stream*/);
+#endif
+   /*
+    * tests the end-of-file indicator for the stream pointed to by stream.
+    * Returns: nonzero iff the end-of-file indicator is set for stream.
+    */
+#define ferror(stream) ((stream)->__flag & _IOERR)
+#ifndef __cplusplus
+extern int (ferror)(FILE * /*stream*/);
+#endif
+   /*
+    * tests the error indicator for the stream pointed to by stream.
+    * Returns: nonzero iff the error indicator is set for stream.
+    */
+extern void perror(const char * /*s*/);
+   /*
+    * maps the error number  in the integer expression errno to an error
+    * message. It writes a sequence of characters to the standard error stream
+    * thus: first (if s is not a null pointer and the character pointed to by
+    * s is not the null character), the string pointed to by s followed by a
+    * colon and a space; then an appropriate error message string followed by
+    * a new-line character. The contents of the error message strings are the
+    * same as those returned by the strerror function with argument errno,
+    * which are implementation-defined.
+    * Returns: no value.
+    */
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+/* end of stdio.h */
diff --git a/StraySrc/Libraries/DLLLib/h/swiv b/StraySrc/Libraries/DLLLib/h/swiv
new file mode 100644 (file)
index 0000000..b51ba0c
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * swiv.h
+ *
+ * Interface to SWI veneer
+ *
+ * © 1997 Straylight
+ */
+
+#ifndef ___swis_h
+#define ___swis_h
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+#ifndef __kernel_h
+  #include "kernel.h"
+#endif
+
+/* --- SWI veneer functions --- *
+ *
+ * Arguments:  int swi == the SWI to call
+ *             unsigned flags == a definition of the SWIs registers
+ *
+ * Returns:    _swi returns the value of the `return' register in the flags
+ *             _swix returns 0, or a pointer to an error block
+ *
+ * Use:                Calls a SWI, passing it a collection of registers, and
+ *             filling in the registers as given in the function call.
+ *
+ *             Order of arguments is as follows:
+ *
+ *             Input registers:        One word for each input register
+ *             Output registers:       Address to store each reg value
+ *             Flags address:          Address to store PC+flags value
+ *             Block contents:         Build contents of local block at end
+ */
+
+extern int _swi(int /*swi*/, unsigned /*flags*/,...);
+extern _kernel_oserror *_swix(int /*swi*/, unsigned /*flags*/,...);
+
+/* --- Various flags settings --- *
+ *
+ * _in(n) -- declare Rn as an input register
+ * _inr(m, n) -- declare Rm--Rn as input registers
+ * _out(n) -- declare Rn as an output register
+ * _outr(m, n) -- declare Rm--Rn as output registers
+ * _return(n) -- return Rn from _swi
+ * _block(n) -- point Rn at block containing remaining arguments
+ */
+
+#ifndef _FLAGS
+
+  /* --- _flags -- return or output processor flags --- */
+
+  #define _flags       (0x10)
+
+  /* --- _in and _inr -- input a register, or a range of registers --- */
+
+  #define _in(r)       (1u << (r))
+  #define _inr(ra,rb)  (((~0) << (ra)) ^ ((~0) << ((rb)+1)))
+
+  /* --- _out and _outr -- output a register, or a range of registers --- */
+
+  #define _out(r)      (1u << (31-((r) == _flags ? 10 : (r))))
+  #define _outr(ra,rb) (((~0) << (31-(rb))) ^ ((~0) << (32-(ra))))
+
+  /* --- _block -- point a register at block built from arguments --- */
+
+  #define _block(r)    (((r) << 12) | 0x800)
+
+  /* --- _return -- return register from _swi (not _swix) --- */
+
+  #define _return(r)   ((r) == _flags ? 0xF0000 : (r) << 16)
+
+  /* --- Constants for ARM processor flags --- */
+
+  #define _n           (0x80000000u)
+  #define _z           (0x40000000u)
+  #define _c           (0x20000000u)
+  #define _v           (0x10000000u)
+
+  /* --- Acorn style capital-letter macros --- */
+
+  #define _FLAGS       _flags
+  #define _IN(x)       _in(x)
+  #define _INR(x,y)    _inr(x,y)
+  #define _OUT(x)      _out(x)
+  #define _OUTR(x,y)   _outr(x,y)
+  #define _BLOCK(x)    _block(x)
+  #define _RETURN(x)   _return(x)
+  #define _N           _n
+  #define _Z           _z
+  #define _C           _c
+  #define _V           _v
+
+#endif
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/StraySrc/Libraries/DLLLib/s/appEntry b/StraySrc/Libraries/DLLLib/s/appEntry
new file mode 100644 (file)
index 0000000..584023c
--- /dev/null
@@ -0,0 +1,35 @@
+;
+; appEntry.s
+;
+; Registering application entry points
+;
+; © 1994 Straylight
+;
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLL$$Code|,CODE,READONLY
+
+; --- _dll_regAppEntry ---
+;
+; On entry:    a1 == pointer to stubs table
+;              a2 == pointer to name table
+; On exit:     --
+
+               EXPORT  |_dll_regAppEntry|
+|_dll_regAppEntry| ROUT
+
+               MOV     ip,lr
+               SWI     DLL_RegisterAppEntryTable
+               MOVS    pc,ip
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/s/clib b/StraySrc/Libraries/DLLLib/s/clib
new file mode 100644 (file)
index 0000000..7a5968c
--- /dev/null
@@ -0,0 +1,51 @@
+;
+; clib.s
+;
+; Finding CLibrary data
+;
+; © 1994 Straylight
+;
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLL$$Code|,CODE,READONLY
+
+; FILE *_dll_iob(void)
+
+               EXPORT  |_dll_iob|
+|_dll_iob|     MOV     ip,lr
+               SWI     XDLL_FindCLibData
+               ADD     a1,a1,#4
+               MOVS    pc,ip
+
+; int *_dll_errno(void)
+
+               EXPORT  |_dll_errno|
+|_dll_errno|   MOV     ip,lr
+               SWI     XDLL_FindCLibData
+               MOVS    pc,ip
+
+; char *_dll_ctype(void)
+
+               EXPORT  |_dll_ctype|
+|_dll_ctype|   MOV     ip,lr
+               SWI     XDLL_FindCLibData
+               ADD     a1,a1,#&290
+               MOVS    pc,ip
+
+; double *_dll_huge_val(void)
+
+               EXPORT  |_dll_huge_val|
+|_dll_huge_val|        MOV     ip,lr
+               SWI     XDLL_FindCLibData
+               ADD     a1,a1,#&390
+               MOVS    pc,ip
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/s/dpoll b/StraySrc/Libraries/DLLLib/s/dpoll
new file mode 100644 (file)
index 0000000..26e63f8
--- /dev/null
@@ -0,0 +1,145 @@
+;
+; dpoll
+;
+; Wimp_Poll support for DLLs and applications that use them
+;
+; © 1994 Straylight
+;
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLL$$Code|,CODE,READONLY
+
+; --- _dll_wimpPoll ---
+;
+; On entry:    a1 == event mask
+;              a2 == pointer to wimp poll block
+;              a4 == pointer to poll word if bit 22 of a1 is set
+; On exit:     a1 == reason code returned by Wimp_Poll
+;              Other registers preserved
+;
+; Floating point status is preserved if a1 on entry has bit 24 set and the
+; floating point emulator or hardware is present.  The floating point
+; registers preserved are f4-f7 and the FPSR.
+
+               EXPORT  |_dll_wimpPoll|
+|_dll_wimpPoll|        ROUT
+
+               STMFD   sp!,{v1-v3,lr}
+
+               MOV     v2,#0                   ;Don't restore FP state
+               TST     a1,#1<<24               ;Does caller want FP saved?
+               BIC     v3,a1,#1<<24            ;We're doing it, not the WIMP
+               BEQ     %00                     ;No -- skip this bit
+               SWI     XFPEmulator_Version     ;Is the FPE/FPA there?
+               MOVVC   v2,#1                   ;Yes -- set flag to restore
+               BLVC    save_fp                 ;Save the FP state
+
+00             SWI     XDLL_SaveHandle         ;Get my application handle
+               MOV     v1,a1                   ;Look after it
+               MOV     a1,v3                   ;Restore event mask
+               SWI     XWimp_Poll              ;Do the SWI call
+               ORRVS   v2,v2,#2                ;Set bit 1 of v2 if error
+               MOV     v3,a1                   ;Save the reason code/error
+               MOV     a1,v1                   ;Restore application handle
+               SWI     XDLL_RestoreHandle      ;Put the handle back again
+               MOV     a1,v3                   ;Restore event code/error
+
+               TST     v2,#1                   ;Is bit 0 set?
+               BLNE    restore_fp              ;Yes -- restore FP state
+               TST     v2,#2                   ;Was there an error?
+               LDMFD   sp!,{v1-v3,lr}          ;Restore all registers anyhow
+               BICEQS  pc,lr,#V_flag           ;No -- clear V flag
+               ORRS    pc,lr,#V_flag           ;Yes -- set V flag
+
+               LTORG
+
+; --- _dll_wimpPollIdle ---
+;
+; On entry:    a1 == event mask
+;              a2 == pointer to wimp poll block
+;              a3 == earliest time to return with an idle event
+;              a4 == pointer to poll word if bit 22 of a1 is set
+; On exit:     a1 == reason code returned by Wimp_Poll
+;              Other registers preserved
+;
+; Floating point status is preserved if a1 on entry has bit 24 set and the
+; floating point emulator or hardware is present.  The floating point
+; registers preserved are f4-f7 and the FPSR.
+
+               EXPORT  |_dll_wimpPollIdle|
+|_dll_wimpPollIdle| ROUT
+
+               STMFD   sp!,{v1-v3,lr}
+
+               MOV     v2,#0                   ;Don't restore FP state
+               TST     a1,#1<<24               ;Does caller want FP saved?
+               BIC     v3,a1,#1<<24            ;We're doing it, not the WIMP
+               BEQ     %00                     ;No -- skip this bit
+               SWI     XFPEmulator_Version     ;Is the FPE/FPA there?
+               MOVVC   v2,#1                   ;Yes -- set flag to restore
+               BLVC    save_fp                 ;Save the FP state
+
+00             SWI     XDLL_SaveHandle         ;Get my application handle
+               MOV     v1,a1                   ;Look after it
+               MOV     a1,v3                   ;Restore event mask
+               SWI     XWimp_PollIdle          ;Do the SWI call
+               ORRVS   v2,v2,#2                ;Set bit 1 of v2 if error
+               MOV     v3,a1                   ;Save the reason code/error
+               MOV     a1,v1                   ;Restore application handle
+               SWI     XDLL_RestoreHandle      ;Put the handle back again
+               MOV     a1,v3                   ;Restore event code/error
+
+               TST     v2,#1                   ;Is bit 0 set?
+               BLNE    restore_fp              ;Yes -- restore FP state
+               TST     v2,#2                   ;Was there an error?
+               LDMFD   sp!,{v1-v3,lr}          ;Restore all registers anyhow
+               BICEQS  pc,lr,#V_flag           ;No -- clear V flag
+               ORRS    pc,lr,#V_flag           ;Yes -- set V flag
+
+               LTORG
+
+; --- save_fp ---
+;
+; On entry:    --
+; On exit:     v1 corrupted
+
+save_fp                ROUT
+
+               RFS     v1                      ;Read the FP status word
+               STMFD   sp!,{v1}                ;Stack it
+               MOV     v1,#0                   ;We will zero the FPSR
+               WFS     v1                      ;Zero it
+               SUB     sp,sp,#4*12             ;Leave space for 4 FP regs
+               STFE    f4,[sp,#0*12]           ;Stack F4
+               STFE    f5,[sp,#1*12]           ;Stack F5
+               STFE    f6,[sp,#2*12]           ;Stack F6
+               STFE    f7,[sp,#3*12]           ;Stack F7
+               MOVS    pc,lr                   ;Return to caller
+
+; --- restore_fp ---
+;
+; On entry:    --
+; On exit:     v1 corrupted
+
+restore_fp     ROUT
+
+               MOV     v1,#0                   ;We will zero the FPSR
+               WFS     v1                      ;Zero it
+               LDFE    f4,[sp,#0*12]           ;Unstack F4
+               LDFE    f5,[sp,#1*12]           ;Unstack F5
+               LDFE    f6,[sp,#2*12]           ;Unstack F6
+               LDFE    f7,[sp,#3*12]           ;Unstack F7
+               ADD     sp,sp,#4*12             ;Move stack ptr up past FP
+               LDMFD   sp!,{v1}                ;Restore FPSR
+               WFS     v1                      ;Write it to the FPSR
+               MOVS    pc,lr                   ;Return to caller
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/s/dsetjmp b/StraySrc/Libraries/DLLLib/s/dsetjmp
new file mode 100644 (file)
index 0000000..2306d22
--- /dev/null
@@ -0,0 +1,43 @@
+;
+; dsetjmp.s
+;
+; Support for exceptional comtrol flow
+;
+; © 1994 Straylight
+;
+
+;----- Standard stuff -----------------------------------------------------*/
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLL$$Code|,CODE,READONLY
+
+; int _dll_setjmp(void)
+
+               EXPORT  |_dll_setjmp|
+|_dll_setjmp|  ROUT
+
+               MOV     ip,lr
+               SWI     XDLL_ReadStackPtr
+               MOVS    pc,ip
+
+               LTORG
+
+; void _dll_longjmped(int sp)
+
+               EXPORT  |_dll_longjmped|
+|_dll_longjmped| ROUT
+
+               MOV     ip,lr
+               MOV     a2,sl
+               SWI     XDLL_SetStackPtr
+               MOVS    pc,ip
+
+               LTORG
+
+;----- That's all, folks --------------------------------------------------*/
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/s/extEntry b/StraySrc/Libraries/DLLLib/s/extEntry
new file mode 100644 (file)
index 0000000..86f2013
--- /dev/null
@@ -0,0 +1,35 @@
+;
+; extentry.s
+;
+; External entry veneer
+;
+; © 1994 Straylight
+;
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLL$$Code|,CODE,READONLY
+
+; --- _dll_extentry ---
+
+               EXPORT  |_dll_extentry|
+|_dll_extentry|        ROUT
+
+               MOV     a1,lr                   ;Pass current return address
+               MOV     a2,sl                   ;Pass stack limit pointer
+               MOV     a3,#0                   ;Indicate we want app space
+               SWI     DLL_Prologue            ;Execute the DLL prologue
+               MOV     lr,a1                   ;Insert dummy return address
+               LDMFD   sp!,{a1-a3}             ;Restore corrupted registers
+               MOV     pc,ip                   ;Call actual routine
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/s/findAll b/StraySrc/Libraries/DLLLib/s/findAll
new file mode 100644 (file)
index 0000000..36fa3f6
--- /dev/null
@@ -0,0 +1,71 @@
+;
+; findall.s
+;
+; Load an application's DLLs from the stub table
+;
+; © 1994 Straylight
+;
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Other external dependencies ------------------------------------------
+
+               IMPORT  |x$stack_overflow|
+               IMPORT  atexit
+               IMPORT  malloc
+               IMPORT  |_dll_giveMemory|
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLL$$Code|,CODE,READONLY
+
+; --- _dll_findall ---
+;
+; On entry:    a1 == DLL$$ExternalTable$$Base
+;              a2 == DLL$$ExternalTable$$Limit
+; On exit:     --
+
+               EXPORT  |_dll_findall|
+|_dll_findall|
+               ROUT
+
+               ; --- APCS procedure entry ---
+
+               MOV     ip,sp
+               STMFD   sp!,{fp,ip,lr,pc}
+               SUB     fp,ip,#4
+               CMP     sp,sl
+               BLLT    |x$stack_overflow|
+
+               ; --- Find the DLLs in the table ---
+
+               SWI     DLL_FindFromTable       ;Load DLLs in the app's table
+
+               ; --- Make sure the DLLs are freed at exit time ---
+
+               LDR     a1,=|_dll_dying|        ;Point to tidy up routine
+               BL      atexit                  ;Add tidy-up routine to list
+
+               ; --- Give the DLLs some application space ---
+
+               LDMDB   fp,{fp,sp,lr}           ;Find registers again
+               B       |_dll_giveMemory|       ;Tail-call optimisation :-)
+
+               LTORG
+
+; --- _dll_dying ---
+
+|_dll_dying|   ROUT
+
+               MOV     ip,lr                   ;Keep link register safely
+               SWI     DLL_AppDying            ;Close down the application
+               MOVS    pc,ip                   ;Return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/s/iface b/StraySrc/Libraries/DLLLib/s/iface
new file mode 100644 (file)
index 0000000..217e1a0
--- /dev/null
@@ -0,0 +1,230 @@
+;
+; iface.s
+;
+; Interface to DLLManager SWIs
+;
+; © 1994 Straylight
+;
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLL$$Code|,CODE,READONLY
+
+; os_error *dll_find(char *name,int version,dll *d)
+
+               EXPORT  dll_find
+dll_find
+               MOV     ip,lr
+               SWI     XDLL_Find
+               STRVC   a1,[a3]
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_findFromTable(dll_table *table,int entries)
+
+               EXPORT  dll_findFromTable
+dll_findFromTable
+               MOV     ip,lr
+               ADD     a2,a1,a2,LSL #2
+               SWI     XDLL_FindFromTable
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_load(void *buffer,char *name)
+
+               EXPORT  dll_load
+dll_load
+               MOV     ip,lr
+               SWI     XDLL_Load
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_lose(dll d)
+
+               EXPORT  dll_lose
+dll_lose
+               MOV     ip,lr
+               SWI     XDLL_Lose
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_appDying(void)
+
+               EXPORT  dll_appDying
+dll_appDying
+               MOV     ip,lr
+               SWI     XDLL_AppDying
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_giveCLibData(void *data)
+
+               EXPORT  dll_giveCLibData
+dll_giveCLibData
+               MOV     ip,lr
+               SWI     XDLL_GiveCLibData
+               MOVVC   a1,#0
+               MOVS    pc,ip
+               LTORG
+
+; os_error *dll_findCLibData(void **p)
+
+               EXPORT  dll_findCLibData
+dll_findCLibData
+               MOV     ip,lr
+               MOV     a2,a1
+               SWI     XDLL_FindCLibData
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_instanceVars(void *buffer,int *size,int *magic)
+
+               EXPORT  dll_instanceVars
+dll_instanceVars
+               MOV     ip,lr
+               MOV     a4,v1
+               LDR     v1,[a3]
+               SWI     XDLL_InstanceVars
+               STRVC   v1,[a3]
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOV     v1,a4
+               MOVS    pc,ip
+
+; os_error *dll_setInstanceVars(dll d,void *workspace)
+
+               EXPORT  dll_setInstanceVars
+dll_setInstanceVars
+               MOV     ip,lr
+               SWI     XDLL_SetInstanceVars
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_appData(void)
+
+               EXPORT  dll_appData
+dll_appData
+               MOV     ip,lr
+               MOV     a1,sl
+               SWI     XDLL_AppData
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_readStackPtr(int *sp)
+
+               EXPORT  dll_readStackPtr
+dll_readStackPtr
+               MOV     ip,lr
+               MOV     a2,a1
+               SWI     XDLL_ReadStackPtr
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_setStackPtr(int sp)
+
+               EXPORT  dll_setStackPtr
+dll_setStackPtr
+               MOV     ip,lr
+               MOV     a2,sl
+               SWI     XDLL_SetStackPtr
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_nameApp(char *name)
+
+               EXPORT  dll_nameApp
+dll_nameApp
+               MOV     ip,lr
+               SWI     XDLL_NameApp
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_info(dll d,dll_info *i)
+
+               EXPORT  dll_info
+dll_info       STMFD   sp!,{v1,lr}
+               MOV     ip,a2
+               SWI     XDLL_Info
+               STMVCIA ip,{a1-a4,v1}
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,pc}^
+
+; os_error *dll_findEntry(dll d,char *name,void (**entry)())
+
+               EXPORT  dll_findEntry
+dll_findEntry
+               MOV     ip,lr
+               SWI     XDLL_FindEntry
+               STRVC   a1,[a3]
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_saveHandle(int *handle)
+
+               EXPORT  dll_saveHandle
+dll_saveHandle
+               MOV     ip,lr
+               MOV     a2,a1
+               SWI     XDLL_SaveHandle
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_restoreHandle(int *handle)
+
+               EXPORT  dll_restoreHandle
+dll_restoreHandle
+               MOV     ip,lr
+               LDR     a1,[a1]
+               SWI     XDLL_RestoreHandle
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_findInstanceVars(dll d,void **addr)
+
+               EXPORT  dll_findInstanceVars
+dll_findInstanceVars
+               MOV     ip,lr
+               SWI     XDLL_FindInstanceVars
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_registerAppEntryTable(void (**btable)(),char *names)
+
+               EXPORT  dll_registerAppEntryTable
+dll_registerAppEntryTable
+               MOV     ip,lr
+               SWI     XDLL_RegisterAppEntryTable
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_findAppEntry(char *name,void (**func)())
+
+               EXPORT  dll_findAppEntry
+dll_findAppEntry
+               MOV     ip,lr
+               SWI     XDLL_FindAppEntry
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+; os_error *dll_setExtensionTable(void (**btable)(),char *names)
+
+               EXPORT  dll_setExtensionTable
+dll_setExtensionTable
+               MOV     ip,lr
+               SWI     XDLL_SetExtensionTable
+               MOVVC   a1,#0
+               MOVS    pc,ip
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/s/loadLocal b/StraySrc/Libraries/DLLLib/s/loadLocal
new file mode 100644 (file)
index 0000000..ec0def5
--- /dev/null
@@ -0,0 +1,118 @@
+;
+; loadlocal.s
+;
+; Loading and initialising extension DLLs
+;
+; © 1994 Straylight
+;
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Other external dependencies ------------------------------------------
+
+               IMPORT  |x$stack_overflow|
+               IMPORT  malloc
+               IMPORT  free
+               IMPORT  |_dll_giveMemory|
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLL$$Code|,CODE,READONLY
+
+; dll _dll_loadExtension(char *name)
+
+               EXPORT  |_dll_loadExtension|
+|_dll_loadExtension|
+dle            ROUT
+
+               ; --- APCS header ---
+
+               MOV     ip,sp
+               STMFD   sp!,{v1-v3,fp,ip,lr,pc}
+               SUB     fp,ip,#4
+               CMP     sp,sl
+               BLLT    |x$stack_overflow|
+
+               ; --- Find the size of the DLL file ---
+
+               MOV     v3,a1                   ;Look after the name pointer
+               MOV     a2,a1                   ;Pass filename to OS_File
+               MOV     a1,#17                  ;Load, no path variable
+               SWI     XOS_File                ;Find information about DLL
+               BVS     %10dle                  ;If it failed, return 0
+               CMP     a1,#1                   ;Check that it's a file
+               BNE     %10dle                  ;If not, return failure
+
+               ; --- Allocate a block for the DLL ---
+
+               ADD     a1,v1,#20               ;Allocate an extra 20 bytes
+               BL      malloc                  ;Allocate the workspace
+               CMP     a1,#0                   ;Did it work?
+               BEQ     %10dle                  ;No -- return failure
+               MOV     v2,a1                   ;Look after this pointer
+
+               ; --- Load the DLL into the block ---
+
+               MOV     a2,v3                   ;Point to DLL name
+               SWI     XDLL_Load               ;Load the DLL into memory
+               BVS     %11dle                  ;If it failed, free the block
+
+               ; --- Allocate workspace for the DLL ---
+
+               MOV     a1,v2                   ;Point to the DLL
+               SWI     XDLL_Info               ;Find information about it
+               MOV     a1,v1                   ;Allocate the right amount
+               BL      malloc                  ;Allocate some workspace
+               CMP     a1,#0                   ;Ensure that it worked
+               BEQ     %11dle                  ;Kill everything if it failed
+               MOV     a2,a1                   ;Set up workspace pointer
+               MOV     a1,v2                   ;Point to DLL
+               SWI     XDLL_SetInstanceVars    ;Give it the memory
+
+               ; --- Allocate space for any other DLLs loaded ---
+
+               BL      |_dll_giveMemory|       ;Allocate space for new DLLs
+
+               ; --- Return the DLL handle to the caller
+
+               MOV     a1,v2                   ;Put the handle away nicely
+               LDMDB   fp,{v1-v3,fp,sp,pc}^    ;Return to caller
+
+               ; --- Free DLL block and return to caller ---
+
+11dle          MOV     a1,v2                   ;Point to DLL block
+               BL      free                    ;Free the memory it used
+
+               ; --- Return to caller with tail between legs ---
+
+10dle          MOV     a1,#0                   ;Return a NULL pointer
+               LDMDB   fp,{v1-v3,fp,sp,pc}^    ;Return to caller
+
+               LTORG
+
+; void _dll_freeExtension(dll d)
+
+               EXPORT  |_dll_freeExtension|
+|_dll_freeExtension|
+
+               MOV     ip,sp
+               STMFD   sp!,{v1,fp,ip,lr,pc}
+               SUB     fp,ip,#4
+               CMP     sp,sl
+               BLLT    |x$stack_overflow|
+
+               MOV     v1,a1
+               SWI     DLL_FindInstanceVars
+               BL      free
+               MOV     a1,v1
+               LDMDB   fp,{v1,fp,sp,lr}
+               B       free
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/s/oscli b/StraySrc/Libraries/DLLLib/s/oscli
new file mode 100644 (file)
index 0000000..652d90e
--- /dev/null
@@ -0,0 +1,147 @@
+;
+; oscli.s
+;
+; OSCLI and system support for DLLs and clients
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  system
+               IMPORT  |_kernel_system|
+               IMPORT  |x$stack_overflow|
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLL$$Code|,CODE,READONLY
+
+; --- _dll_system ---
+;
+; On entry:    a1 == pointer to command line string (passed to system)
+; On exit:     a1 == return code, as for system()
+
+               EXPORT  |_dll_system|
+|_dll_system|  ROUT
+
+               ; --- Standard APCS bit on the top ---
+
+               MOV     ip,sp                   ;Keep current stack pointer
+               STMFD   sp!,{v1,v2,fp,ip,lr,pc} ;Create new stack frame
+               SUB     fp,ip,#4                ;Point fp at new stack frame
+               CMP     sp,sl                   ;Is there enough stack?
+               BLLT    |x$stack_overflow|      ;No -- create some more
+
+               ; --- Preserve the old application handle ---
+
+               MOV     v2,a1                   ;Preserve string pointer
+               SWI     DLL_SaveHandle          ;Get the current handle
+               MOV     v1,a1                   ;Preserve its value
+
+               ; --- Call the actual command ---
+
+               MOV     a1,v2                   ;Restore string pointer
+               BL      system                  ;Do whatever it is we do
+
+               ; --- Restore the handle and exit ---
+
+               MOV     v2,a1                   ;Keep hold of return value
+               MOV     a1,v1                   ;Transfer old handle
+               SWI     DLL_RestoreHandle       ;Set up the handle again
+               MOV     a1,v2                   ;Reinstate the return value
+               LDMDB   fp,{v1,v2,fp,sp,pc}^    ;Return to caller
+
+               LTORG
+
+; --- _dll_ksystem ---
+;
+; On entry:    R0 == pointer to command to execute
+;              R1 == 0 to run as a subprocess, nonzero to replace
+; On exit:     >=0 for success, <0 for failure
+
+               EXPORT  |_dll_ksystem|
+|_dll_ksystem| ROUT
+
+               ; --- Standard APCS bit on the top ---
+
+               MOV     ip,sp                   ;Keep current stack pointer
+               STMFD   sp!,{v1,v2,fp,ip,lr,pc} ;Create new stack frame
+               SUB     fp,ip,#4                ;Point fp at new stack frame
+               CMP     sp,sl                   ;Is there enough stack?
+               BLLT    |x$stack_overflow|      ;No -- create some more
+
+               ; --- Preserve the old application handle ---
+
+               MOV     v2,a1                   ;Preserve string pointer
+               SWI     DLL_SaveHandle          ;Get the current handle
+               MOV     v1,a1                   ;Preserve its value
+
+               ; --- Call the actual command ---
+
+               MOV     a1,v2                   ;Restore string pointer
+               BL      |_kernel_system|        ;Do whatever it is we do
+
+               ; --- Restore the handle and exit ---
+
+               MOV     v2,a1                   ;Keep hold of return value
+               MOV     a1,v1                   ;Transfer old handle
+               SWI     DLL_RestoreHandle       ;Set up the handle again
+               MOV     a1,v2                   ;Reinstate the return value
+               LDMDB   fp,{v1,v2,fp,sp,pc}^    ;Return to caller
+
+               LTORG
+
+; --- _dll_oscli ---
+;
+; On entry:    R0 == pointer to command string for OS_CLI
+; On exit:     R0 == pointer to error, or 0
+
+               EXPORT  |_dll_oscli|
+|_dll_oscli|   ROUT
+
+               MOV     ip,lr                   ;Keep link register
+               MOV     a2,a1                   ;Keep pointer to string
+               SWI     DLL_SaveHandle          ;Get our current handle
+               MOV     a3,a1                   ;Save it away
+               MOV     a1,a2                   ;Restore pointer to command
+               SWI     XOS_CLI                 ;Do the actual command
+               MOVVS   a2,a1                   ;Save error ptr if it failed
+               MOVVC   a2,#0                   ;Otherwise remember it worked
+               MOV     a1,a3                   ;Restore the old handle
+               SWI     DLL_RestoreHandle       ;Resinstate the handle
+               MOV     a1,a2                   ;Point at error block
+               MOVS    pc,ip                   ;And return to caller
+
+               LTORG
+
+; --- _dll_starttask ---
+;
+; On entry:    R0 == pointer to command to run as a separate task
+; On exit:     R0 == pointer to error, or 0
+
+               EXPORT  |_dll_starttask|
+|_dll_starttask| ROUT
+
+               MOV     ip,lr                   ;Keep link register
+               MOV     a2,a1                   ;Keep pointer to string
+               SWI     DLL_SaveHandle          ;Get our current handle
+               MOV     a3,a1                   ;Save it away
+               MOV     a1,a2                   ;Restore pointer to command
+               SWI     XWimp_StartTask         ;Do the actual command
+               MOVVS   a2,a1                   ;Save error ptr if it failed
+               MOVVC   a2,#0                   ;Otherwise remember it worked
+               MOV     a1,a3                   ;Restore the old handle
+               SWI     DLL_RestoreHandle       ;Resinstate the handle
+               MOV     a1,a2                   ;Point at error block
+               MOVS    pc,ip                   ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/s/wSpace b/StraySrc/Libraries/DLLLib/s/wSpace
new file mode 100644 (file)
index 0000000..04c1d8f
--- /dev/null
@@ -0,0 +1,71 @@
+;
+; wspace.s
+;
+; Handling of DLL workspace and similar things
+;
+; © 1994 Straylight
+;
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Other external dependencies ------------------------------------------
+
+               IMPORT  |x$stack_overflow|
+               IMPORT  malloc
+
+               IMPORT  |__errno|,WEAK          ;Vile hack :-(
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLL$$Code|,CODE,READONLY
+
+; --- _dll_giveMemory ---
+
+               EXPORT  |_dll_giveMemory|
+|_dll_giveMemory| ROUT
+
+               MOV     ip,sp
+               STMFD   sp!,{v1,fp,ip,lr,pc}
+               SUB     fp,ip,#4
+               CMP     sp,sl
+               BLLT    |x$stack_overflow|
+
+               MOV     v1,#0                   ;Start with magic number at 0
+00             SWI     DLL_InstanceVars        ;Give DLL some variables
+               CMP     v1,#0                   ;Is this the end yet?
+               LDMEQDB fp,{v1,fp,sp,pc}^       ;Yes -- return to caller
+               BL      malloc                  ;Allocate variables as reqd.
+               B       %b00                    ;And give to the DLL
+
+               LTORG
+
+; --- _dll_appspace ---
+
+               EXPORT  |_dll_appspace|
+|_dll_appspace|        ROUT
+
+               MOV     ip,lr                   ;Keep hold of link register
+               MOV     a1,sl                   ;Point to stack limit thingy
+               SWI     DLL_AppData             ;Tell DLLManager about this
+               MOVS    pc,ip                   ;Return to caller
+
+               LTORG
+
+; --- _dll_clibdata ---
+
+               EXPORT  |_dll_clibdata|
+|_dll_clibdata|        ROUT
+
+               MOV     ip,lr                   ;Keep link register safe
+               LDR     a1,=|__errno|           ;Find the C Library's space
+               SWI     DLL_GiveCLibData        ;Pass on the CLib data
+               MOVS    pc,ip                   ;Return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/DLLLib/sh/dllswis b/StraySrc/Libraries/DLLLib/sh/dllswis
new file mode 100644 (file)
index 0000000..ccea7ca
--- /dev/null
@@ -0,0 +1,51 @@
+;
+; DLLswis.sh
+;
+; SWI name-number translation for DLLLib
+;
+; © 1994 Straylight
+;
+
+               ^       &CC000
+
+DLL_Find               #       1
+DLL_FindFromTable      #       1
+DLL_Load               #       1
+DLL_Lose               #       1
+DLL_AppDying           #       1
+DLL_GiveCLibData       #       1
+DLL_FindCLibData       #       1
+DLL_InstanceVars       #       1
+DLL_SetInstanceVars    #       1
+DLL_AppData            #       1
+DLL_Prologue           #       1
+DLL_ReadStackPtr       #       1
+DLL_SetStackPtr                #       1
+DLL_NameApp            #       1
+DLL_Info               #       1
+DLL_FindEntry          #       1
+DLL_SaveHandle         #       1
+DLL_RestoreHandle      #       1
+
+               ^       &EC000
+
+XDLL_Find              #       1
+XDLL_FindFromTable     #       1
+XDLL_Load              #       1
+XDLL_Lose              #       1
+XDLL_AppDying          #       1
+XDLL_GiveCLibData      #       1
+XDLL_FindCLibData      #       1
+XDLL_InstanceVars      #       1
+XDLL_SetInstanceVars   #       1
+XDLL_AppData           #       1
+XDLL_Prologue          #       1
+XDLL_ReadStackPtr      #       1
+XDLL_SetStackPtr       #       1
+XDLL_NameApp           #       1
+XDLL_Info              #       1
+XDLL_FindEntry         #       1
+XDLL_SaveHandle                #       1
+XDLL_RestoreHandle     #       1
+
+               END
diff --git a/StraySrc/Libraries/Makefile,fe1 b/StraySrc/Libraries/Makefile,fe1
new file mode 100644 (file)
index 0000000..e362d22
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all:
+       submake *.Makefile
+
+install:
+       submake *.Makefile -- install
+
+clean:
+       submake *.Makefile -- clean
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/Libraries/Quartz/Makefile,fe1 b/StraySrc/Libraries/Quartz/Makefile,fe1
new file mode 100644 (file)
index 0000000..8dae398
--- /dev/null
@@ -0,0 +1,123 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+OBJS = \
+       o.kernel \
+       o.fastMove o.string o.screen
+
+#----- Compiling things -----------------------------------------------------
+
+all: o.quartz
+
+o.quartz: $(OBJS)
+       $(AR) -c o.quartz $(OBJS)
+
+install:
+
+clean:
+       -$(RM) o.*
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.kernel: s.kernel
+o.kernel: libs:swis
+o.kernel: libs:header
+o.kernel: s.kernel
+o.kernel: libs:swis
+o.kernel: libs:header
+o.fastMove: s.fastMove
+o.fastMove: libs:s.fastMove
+o.fastMove: libs:header
+o.fastMove: libs:swis
+o.string: s.string
+o.string: libs:swis
+o.string: libs:header
+o.screen: s.screen
+o.screen: libs:header
+o.screen: libs:swis
diff --git a/StraySrc/Libraries/Quartz/s/fastMove b/StraySrc/Libraries/Quartz/s/fastMove
new file mode 100644 (file)
index 0000000..6e9b1f0
--- /dev/null
@@ -0,0 +1 @@
+               LNK     libs:s.fastMove
diff --git a/StraySrc/Libraries/Quartz/s/kernel b/StraySrc/Libraries/Quartz/s/kernel
new file mode 100644 (file)
index 0000000..a2fda54
--- /dev/null
@@ -0,0 +1,262 @@
+;
+; kernel.s
+;
+; Quartz module support library kernel (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Quartz library.
+;
+; Quartz is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Quartz is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Quartz.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+
+               ; --- User supplied symbols ---
+
+               IMPORT  quartz_name             ;The module's name string
+               IMPORT  quartz_help             ;The help and version string
+
+               IMPORT  quartz_swiChunk,WEAK    ;SWI chunk number
+               IMPORT  quartz_swiNames,WEAK    ;SWI name table
+               IMPORT  quartz_swiTrans,WEAK    ;SWI name/number convert code
+               IMPORT  quartz_swiCode,WEAK     ;Main SWI handling code
+
+               IMPORT  quartz_appCode,WEAK     ;Any application code
+
+               IMPORT  |Quartz$$Commands$$Base|,WEAK
+
+               ; --- Other important objects ---
+
+               IMPORT  |Quartz$$Table$$Base|,WEAK
+               IMPORT  |Quartz$$Table$$Limit|,WEAK
+
+               IMPORT  |Quartz$$Service$$Base|,WEAK
+               IMPORT  |Quartz$$Service$$Limit|,WEAK
+
+;----- The actual module header ---------------------------------------------
+
+               AREA    |!!!Module$$Header|,CODE,READONLY
+
+quartz__base   DCD     quartz_appCode          ;The start entry point
+               DCD     quartz__init            ;Main initialisation
+               DCD     quartz__closeDown       ;Close down code
+               DCD     quartz__service         ;Service call handling
+               DCD     quartz_name             ;The module name string
+               DCD     quartz_help             ;Help/version (use setdate!)
+               DCD     |Quartz$$Commands$$Base| ;The command table
+               DCD     quartz_swiChunk         ;The SWI chunk number
+               DCD     quartz_swiCode          ;The SWI entry point code
+               DCD     quartz_swiNames         ;The SWI name table
+               DCD     quartz_swiTrans         ;SWI name/number translation
+
+;----- Initialisation and finalisation code ---------------------------------
+
+; --- quartz_base ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to module base
+;
+; Use:         Returns a pointer to the module's base
+
+               EXPORT  quartz_base
+quartz_base    ROUT
+
+               ADR     R0,quartz__base         ;Point to the module base
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- quartz__init ---
+;
+; On entry:    R12 == pointer too where to store private word
+;
+; On exit:     --
+;
+; Use:         Initialises Quartz library and any client modules which feel
+;              they want to use this mechanism.
+
+quartz__init   ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Save some registers
+
+               MOV     R5,R12                  ;Keep private word address
+
+               ; --- Find the amount of workspace we need ---
+
+               ADR     R9,quartz__base         ;Find the module base address
+               LDR     R7,=|Quartz$$Table$$Base|
+               LDR     R8,=|Quartz$$Table$$Limit|
+               ADD     R7,R9,R7                ;Convert to actual addresses
+               ADD     R8,R9,R8
+
+               MOV     R0,R7                   ;Point at the table start
+               MOV     R3,#quartz__wSize       ;Get my workspace size
+
+00quartz__init CMP     R0,R8                   ;Have we finished yet?
+               BGE     %05quartz__init         ;Yes -- exit this loop
+               LDMIA   R0!,{R1,R2,R4,R6}       ;Get initialisation stuff
+               ADD     R3,R3,R1                ;Add on the workspace size
+               B       %00quartz__init         ;And loop round again
+
+               ; --- Allocate the workspace nicely ---
+
+05quartz__init CMP     R3,#0                   ;Do we want any workspace?
+               BEQ     %09quartz__init         ;No -- don't allocate any
+
+               MOV     R0,#6                   ;Allocate memory from RMA
+               SWI     XOS_Module              ;Get the memory nicely
+               BVS     %99quartz__init         ;If it failed, skip to end
+               STR     R2,[R12,#0]             ;Store the workspace address
+               MOV     R12,R2                  ;Remember this address
+               STR     R12,quartz__wSpace      ;Save this address for later
+
+               ; --- Now initialise the first words ---
+
+09quartz__init MOV     R0,R7                   ;Point to the table base
+               MOV     R6,R12                  ;Keep the workspace address
+               MOV     R14,#0                  ;For zeroing things
+
+10quartz__init CMP     R0,R8                   ;Have we finished yet?
+               BGE     %19quartz__init         ;Yes -- exit the loop then
+               LDMIA   R0!,{R1-R4}             ;Load the table entries
+               CMP     R1,#0                   ;Does he have any workspace?
+               STRNE   R6,[R9,R2]              ;Yes -- store workspace addr
+               STRNE   R14,[R6,#0]             ;And initialise first word
+               ADD     R6,R6,R1                ;Move the workspace addr on
+               B       %10quartz__init         ;Now go round for the rest
+
+               ; --- Finally initialise all the other sections ---
+
+19quartz__init MOV     R6,R7                   ;Get the start pointer nicely
+20quartz__init CMP     R6,R8                   ;Have we finished yet?
+               BGE     %30quartz__init         ;Yes -- wrap it all up
+               LDMIA   R6!,{R1-R4}             ;Load the initialisation info
+               CMP     R3,#0                   ;Does he want initialising?
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               ADDNE   PC,R9,R3                ;And call his routine
+               BVS     %95quartz__init         ;Tidy up if it failed
+               ADD     R12,R12,R1              ;Move on the workspace addr
+               B       %20quartz__init         ;Go round for the rest
+30quartz__init LDMFD   R13!,{R0-R9,PC}^        ;I declare this module open
+
+               ; --- Tidy up -- it all failed ---
+
+95quartz__init MOV     R12,R5                  ;Point at private word
+               BL      quartz__closeDown       ;Close down other sections
+
+99quartz__init ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R9,R14}        ;Unstack all the registers
+               ORRS    PC,R14,#V_flag          ;Return the error to system
+
+quartz__wSpace DCD     0
+
+               LTORG
+
+; --- quartz__closeDown ---
+;
+; On entry:    R12 == pointer to private word
+;
+; On exit:     --
+;
+; Use:         Closes down a module.
+
+quartz__closeDown ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Save some registers
+               MOV     R5,R12                  ;Keep private word pointer
+               LDR     R12,[R12,#0]            ;Load workspace base address
+
+               ADR     R9,quartz__base         ;Find the module base address
+               LDR     R7,=|Quartz$$Table$$Base|
+               LDR     R8,=|Quartz$$Table$$Limit|
+               ADD     R7,R9,R7                ;Convert to actual addresses
+               ADD     R8,R9,R8
+
+               MOV     R6,R7                   ;Get the start pointer again
+               LDR     R12,quartz__wSpace      ;Find the workspace base
+
+10             CMP     R6,R8                   ;Have we finished yet?
+               BGE     %40quartz__closeDown    ;Yes -- deallocate memory
+               LDMIA   R6!,{R1-R4}             ;Load the initialisation info
+               CMP     R4,#0                   ;Does he want closing down?
+               BEQ     %30quartz__closeDown    ;No -- ignore it then
+               CMP     R1,#0                   ;Did he want workspace?
+               BEQ     %20quartz__closeDown    ;No -- close him down anyway
+               LDR     R14,[R12,#0]            ;Yes -- load first word
+               CMP     R14,#0                  ;Has he started up yet?
+20             MOVNE   R14,PC                  ;Yes -- set up return address
+               ADDNE   PC,R9,R4                ;And call the routine nicely
+30             ADD     R12,R12,R1              ;Move on the workspace addr
+               B       %10quartz__closeDown    ;Go round and do some more
+
+40             MOV     R0,#7                   ;Deallocate workspace
+               LDR     R2,[R5,#0]              ;Load workspace base address
+               SWI     XOS_Module              ;Free all my workspace
+               MOV     R14,#0                  ;Don't have workspace no more
+               STR     R14,[R5,#0]             ;So zero my private word
+
+               LDMFD   R13!,{R0-R9,PC}^        ;Return to caller
+
+               LTORG
+
+; --- quartz__service ---
+;
+; On entry:    R1 == service call number
+;
+; On exit:     As returned by service call handlers
+;
+; Use:         Handles service calls
+
+quartz__service        ROUT
+
+               STMFD   R13!,{R9-R11,R14}       ;Save far too few registers
+               ADR     R9,quartz__base         ;Find module base
+               LDR     R10,=|Quartz$$Service$$Base|
+               LDR     R11,=|Quartz$$Service$$Limit|
+               ADD     R10,R9,R10              ;Convert to actual addresses
+               ADD     R11,R9,R11
+
+10             CMP     R10,R11                 ;Have we finished yet?
+               LDMEQFD R13!,{R9-R11,PC}^       ;Yes -- return (whew)
+               LDMIA   R10!,{R12,R14}          ;Get the service handler
+               CMP     R1,R14                  ;Does he want this service?
+               MOVEQ   R14,PC                  ;Yes -- set up return addr
+               ADDEQ   PC,R9,R12               ;And call his handler
+               B       %10quartz__service      ;And go round again
+
+               LTORG
+
+               AREA    |Quartz$$Commands_|,CODE,READONLY
+
+               DCD     0                       ;Terminate command table
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+quartz__wStart #       0
+quartz__wSize  EQU     {VAR}-quartz__wStart
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Quartz/s/screen b/StraySrc/Libraries/Quartz/s/screen
new file mode 100644 (file)
index 0000000..8a23d38
--- /dev/null
@@ -0,0 +1,177 @@
+;
+; screen.s
+;
+; Screen mode information caching (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Quartz library.
+;
+; Quartz is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Quartz is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Quartz.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+;
+; None.
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Quartz$$Code|,CODE,READONLY
+
+; --- screen_getInfo ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to screen information block
+;
+; Use:         This call returns a pointer to a block of information
+;              about the current screen modes. The offset for different
+;              bits of data are defined in screen.sh
+
+               EXPORT  screen_getInfo
+screen_getInfo ROUT
+
+               LDR     R0,screen__wSpace       ;Get my workspace
+               ADD     R0,R0,#4                ;Point to the data block
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- screen__cache ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Caches screen information for the current mode
+
+screen__cache  ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Stack some registers
+               LDR     R12,screen__wSpace      ;Locate my workspace
+
+               ; --- Now read relevent mode variables ---
+
+               MOV     R3,#1                   ;A useful value
+               MOV     R0,#-1                  ;Get info on current mode
+
+               MOV     R1,#4                   ;XEigFactor
+               SWI     OS_ReadModeVariable     ;Read its value
+               MOV     R4,R2                   ;Look after xEig
+               MOV     R9,R3,LSL R4            ;Get dx correctly
+
+               MOV     R1,#5                   ;YEigFactor
+               SWI     OS_ReadModeVariable     ;Read its value
+               MOV     R5,R2                   ;Look after yEig
+               MOV     R10,R3,LSL R5           ;Get dy correctly
+
+               MOV     R1,#9                   ;Log2BPP
+               SWI     OS_ReadModeVariable     ;Read its value
+               MOV     R6,R3,LSL R2            ;Calculate bpp
+
+               MOV     R1,#11                  ;XWindLimit
+               SWI     OS_ReadModeVariable     ;Read its value
+               ADD     R2,R2,#1                ;Calculate screen width
+               MOV     R7,R2,LSL R4            ;width=(XwindLimit+1)<<xEig
+
+               MOV     R1,#12                  ;XWindLimit
+               SWI     OS_ReadModeVariable     ;Read its value
+               ADD     R2,R2,#1                ;Calculate screen width
+               MOV     R8,R2,LSL R5            ;height=(YwindLimit+1)<<yEig
+
+               ; --- Now store the cached information ---
+
+               STMIB   R12,{R4-R10}            ;Store in my workspace
+
+               ; --- And return to caller ---
+
+               LDMFD   R13!,{R0-R10,PC}^       ;Return
+
+               LTORG
+
+; --- screen_init ---
+;
+; On entry:    R12 == pointer to private workspace
+;
+; On exit:     --
+;
+; Use:         Initialises the ptr system
+
+               EXPORT  screen_init
+screen_init    ROUT
+
+               STMFD   R13!,{R0,R14}           ;Stack some registers
+
+               ; --- Are we already initialised? ---
+
+               LDR     R0,screen__flags        ;Get my flags
+               TST     R0,#sFlag__inited       ;Are we initialised?
+               LDMNEFD R13!,{R0,PC}^           ;Yes -- return
+
+               ORR     R0,R0,#sFlag__inited    ;Set flags
+               STR     R0,screen__flags        ;And store them back
+
+               ; --- Now cache the current mode info ---
+
+               BL      screen__cache           ;Cache screen information
+
+               ; --- That's it now ---
+
+               LDMFD   R13!,{R0,PC}^           ;Return
+
+               LTORG
+
+screen__wSpace DCD     0                       ;My workspace pointer
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+screen__wStart #       0
+
+screen__flags  #       4                       ;Flags
+
+screen__xEig   #       4                       ;X Eig Factor
+screen__yEig   #       4                       ;Y Eig Factor
+screen__bpp    #       4                       ;Bits per pixel
+screen__width  #       4                       ;Current screen width
+screen__height #       4                       ;Current screen height
+screen__dx     #       4                       ;x pixel size
+screen__dy     #       4                       ;y pixel size
+
+screen__wSize  EQU     {VAR}-screen__wStart
+
+sFlag__inited  EQU     (1<<0)                  ;I've been initialised
+
+               AREA    |Quartz$$Service|,CODE,READONLY
+
+               DCD     screen__cache,&46
+
+               AREA    |Quartz$$Table|,CODE,READONLY
+
+               DCD     screen__wSize           ;Workspace size
+               DCD     screen__wSpace          ;Workspace pointer
+               DCD     screen_init             ;Initialisation code
+               DCD     0                       ;Finalisation
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Quartz/s/string b/StraySrc/Libraries/Quartz/s/string
new file mode 100644 (file)
index 0000000..93a459f
--- /dev/null
@@ -0,0 +1,473 @@
+;
+; string.s
+;
+; String handling routines (control terminated) (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Quartz library.
+;
+; Quartz is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Quartz is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Quartz.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+;
+; None.
+
+;----- Main code ------------------------------------------------------------
+;
+; No string routine corrupts the scratchpad.
+
+               AREA    |Quartz$$Code|,CODE,READONLY
+
+; --- str_cpy ---
+;
+; On entry:    R0 == destination string
+;              R1 == source string
+;
+; On exit:     R0 == pointer to terminator of destination
+;
+; Use:         Copies a string from one block to another.  It leaves the
+;              destination pointer at the end of the string so that any
+;              subsequent copies concatenate other bits on the same string.
+;              Single characters can of course be appended with
+;
+;                      MOV     Rx,#&cc
+;                      STRB    Rx,[R0],#1
+
+               EXPORT  str_cpy
+str_cpy                ROUT
+
+               STMFD   R13!,{R1,R14}           ;Keep return address safe
+00str_cpy      LDRB    R14,[R1],#1             ;Get a byte from source
+               CMP     R14,#' '                ;Is it a control character
+               MOVLT   R14,#0                  ;Yes -- translate to a 0
+               STRB    R14,[R0],#1             ;Store in destination
+               BGE     %00str_cpy              ;No -- copy another byte
+               SUB     R0,R0,#1                ;Point back at terminator
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- str_qcpy ---
+;
+; On entry:    R0 == destination pointer
+;              R1 == source pointer
+;
+; On exit:     R0 == pointer to terminator of destination
+;
+; Use:         This copies the source string to the destination. It is
+;              much faster than str_cpy if boths the string are word
+;              aligned. Note that it only works with NULL terminated
+;              strings.
+
+               EXPORT  str_qcpy
+str_qcpy       ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Stack some registers
+
+               ; --- Are both strings word aligned? ---
+
+               ORR     R2,R0,R1                ;OR them together
+               ANDS    R2,R2,#3                ;Is bit 0 or 1 set?
+               BNE     %10str_qcpy             ;Yes, do non-word aligned cpy
+
+               ; --- Set up bit structures ---
+
+               MOV     R3,#&01                 ;Set bit 0
+               ADD     R3,R3,#&100             ;Set bits 0 and 8
+               ADD     R3,R3,R3,ROR #16        ;Set LSB of each byte in word
+
+               MOV     R4,#&80                 ;Set bit 7
+               ADD     R4,R4,#&8000            ;Set bit 15
+               ADD     R4,R4,R4,ROR #16        ;Set MSB of each byte in word
+
+               ; --- Branch to word loading routine ---
+
+               B       %02str_qcpy             ;Branch ahead
+
+               ; --- Copy the loaded word ---
+
+01str_qcpy     STR     R2,[R0],#4              ;Store word
+
+               ; --- Load a word, and check if any byte in it is 0 ---
+               ;
+               ; The algorithm is actually quite simple. By looking at
+               ; each byte in the word being loaded individually,
+               ; if we subtract 1 from it, the MSB of that byte is set
+               ; if the byte was 0 to start with (ie. it becomes -1).
+               ; However, the MSB may also be set if it was set to
+               ; start with. If this is the case then we clear it
+               ; after the subtract operation.
+               ;
+               ; This is why R3 is set up as it is. R4 can then be used
+               ; to see if any of MSB is set -- if so, then at least
+               ; one of the bytes was initially 0 :-)
+
+02str_qcpy     LDR     R2,[R1],#4              ;Load a word
+               SUB     R5,R2,R3                ;Subtract 1 from each byte
+               BIC     R5,R5,R2                ;Clear MSB(s) if set in R2
+               ANDS    R5,R5,R4                ;Are any MSBs set
+               BEQ     %02str_qcpy             ;No, try another 4 bytes
+
+               ; --- Now do the remaining bytes ---
+
+03str_qcpy     STRB    R2,[R0],#1              ;Store a byte
+               ANDS    R2,R2,#&FF              ;Clear the first byte
+               SUBEQ   R0,R0,#1                ;Point to NULL byte if finshd
+               LDMEQIA R13!,{R1-R5,PC}^        ;And return to caller
+               MOV     R2,R2,ASR #8            ;Prepare next byte
+               B       %03str_qcpy             ;Copy what's left
+
+               ; --- Do a non-word aligned copy ---
+
+10str_qcpy     LDRB    R2,[R1],#1              ;Get a byte
+               STRB    R2,[R0],#1              ;Store it in destination
+               CMP     R2,#0                   ;Is it a terminator
+               BNE     %10str_qcpy             ;No -- keep copying
+               SUB     R0,R0,#1                ;Point to NULL
+               LDMFD   R13!,{R1-R5,PC}^
+
+               LTORG
+
+; --- str_len ---
+;
+; On entry:    R0 == pointer to string
+;
+; On exit:     R0 == length of the string
+;
+; Use:         Calculates the length of a string.
+
+               EXPORT  str_len
+str_len                ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               MOV     R14,R0                  ;Point to the string
+               MOV     R0,#0                   ;Current length is 0
+00str_len      LDRB    R1,[R14],#1             ;Get a byte from the string
+               CMP     R1,#' '                 ;Is it the end yet?
+               LDMLTFD R13!,{R1,PC}^           ;Yes -- return
+               ADD     R0,R0,#1                ;Bump the length counter
+               B       %00str_len              ;And go back for more
+
+               LTORG
+
+; --- str_cmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         Case-sensitively compares two strings.  You can use the
+;              normal ARM condition codes after the compare, so you can
+;              treat this as a normal CMP type thing (except the arguments
+;              must be in R0 and R1, and it mangles R14).
+
+               EXPORT  str_cmp
+str_cmp                ROUT
+
+               STMFD   R13!,{R0,R1,R3-R5,R14}
+00str_cmp      LDRB    R3,[R0],#1              ;Get a character from A
+               LDRB    R4,[R1],#1              ;And one from B
+               CMP     R3,#&20                 ;Is that the end of A?
+               MOVLT   R3,#0                   ;Yes -- pretend it's null
+               CMP     R4,#&20                 ;Is that the end of B?
+               MOVLT   R4,#0                   ;Yes -- pretend it's null
+               CMP     R3,R4                   ;How do they match up?
+               LDMNEFD R13!,{R0,R1,R3-R5,PC}   ;If NE, return condition
+               CMP     R3,#0                   ;Is this the end?
+               BNE     %00str_cmp              ;No -- loop again
+               LDMFD   R13!,{R0,R1,R3-R5,PC}   ;Return to caller
+
+; --- str_icmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         As for str_cmp above, but case-insensitive.
+
+               EXPORT  str_icmp
+str_icmp       ROUT
+
+               STMFD   R13!,{R0,R1,R3-R5,R14}
+               ADR     R5,str__caseTable       ;Point to upper-case table
+00str_icmp     LDRB    R3,[R0],#1              ;Get a character from A
+               LDRB    R4,[R1],#1              ;And one from B
+               LDRB    R3,[R5,R3]              ;If so, convert using table
+               LDRB    R4,[R5,R4]              ;(both characters)
+               CMP     R3,R4                   ;How do they match up?
+               LDMNEFD R13!,{R0,R1,R3-R5,PC}   ;If NE, return condition
+               CMP     R3,#0                   ;Is this the end?
+               BNE     %00str_icmp             ;No -- loop again
+               LDMFD   R13!,{R0,R1,R3-R5,PC}   ;Return to caller
+
+str__caseTable DCB     &00,&00,&00,&00,&00,&00,&00,&00
+               DCB     &00,&00,&00,&00,&00,&00,&00,&00
+               DCB     &00,&00,&00,&00,&00,&00,&00,&00
+               DCB     &00,&00,&00,&00,&00,&00,&00,&00
+               DCB     &20,&21,&22,&23,&24,&25,&26,&27
+               DCB     &28,&29,&2A,&2B,&2C,&2D,&2E,&2F
+               DCB     &30,&31,&32,&33,&34,&35,&36,&37
+               DCB     &38,&39,&3A,&3B,&3C,&3D,&3E,&3F
+               DCB     &40,&41,&42,&43,&44,&45,&46,&47
+               DCB     &48,&49,&4A,&4B,&4C,&4D,&4E,&4F
+               DCB     &50,&51,&52,&53,&54,&55,&56,&57
+               DCB     &58,&59,&5A,&5B,&5C,&5D,&5E,&5F
+               DCB     &60,&41,&42,&43,&44,&45,&46,&47
+               DCB     &48,&49,&4A,&4B,&4C,&4D,&4E,&4F
+               DCB     &50,&51,&52,&53,&54,&55,&56,&57
+               DCB     &58,&59,&5A,&7B,&7C,&7D,&7E,&7F
+               DCB     &80,&81,&82,&83,&84,&85,&86,&87
+               DCB     &88,&89,&8A,&8B,&8C,&8D,&8E,&8F
+               DCB     &90,&91,&92,&93,&94,&95,&96,&97
+               DCB     &98,&99,&9A,&9B,&9C,&9D,&9E,&9F
+               DCB     &A0,&A1,&A2,&A3,&A4,&A5,&A6,&A7
+               DCB     &A8,&A9,&AA,&AB,&AC,&AD,&AE,&AF
+               DCB     &B0,&B1,&B2,&B3,&B4,&B5,&B6,&B7
+               DCB     &B8,&B9,&BA,&BB,&BC,&BD,&BE,&BF
+               DCB     &C0,&C1,&C2,&C3,&C4,&C5,&C6,&C7
+               DCB     &C8,&C9,&CA,&CB,&CC,&CD,&CE,&CF
+               DCB     &D0,&D1,&D2,&D3,&D4,&D5,&D6,&D7
+               DCB     &D8,&D9,&DA,&DB,&DC,&DD,&DE,&DF
+               DCB     &E0,&E1,&E2,&E3,&E4,&E5,&E6,&E7
+               DCB     &E8,&E9,&EA,&EB,&EC,&ED,&EE,&EF
+               DCB     &F0,&F1,&F2,&F3,&F4,&F5,&F6,&F7
+               DCB     &F8,&F9,&FA,&FB,&FC,&FD,&FE,&FF
+
+               LTORG
+
+; --- str_subst ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R1 == Pointer to output buffer
+;              R2-R11 == Pointer to filler strings (optional)
+;
+; On exit:     R0 == Pointer to start of buffer
+;              R1 == Pointer to terminating null
+;
+; Use:         Performs string substitution, filling in a skeleton string
+;              containing placeholders with `filler' strings.  The
+;              placeholders are actually rather powerful.  The syntax of
+;              these is as follows:
+;
+;                      `%' [<type>] <digit>
+;
+;              (spaces are for clarity -- in fact you must not include
+;              spaces in the format string.)
+;
+;              <digit> is any charater between `0' and `9'.  It refers to
+;              registers R2-R11 (so `0' means R2, `5' is R7 etc.)  How the
+;              value is interpreted is determined by <type>.
+;
+;              <type> is one of:
+;
+;              s       String.  This is the default.  The register is
+;                      considered to be a pointer to an ASCII string
+;                      (control terminated).
+;
+;              i       Integer.  The (signed) decimal representation is
+;                      inserted.  Leading zeros are suppressed.
+;
+;              x       Hex fullword.  The hexadecimal representation of the
+;                      register is inserted.  Leading zeros are included.
+;
+;              b       Hex byte.  The hexadecimal representation of the
+;                      least significant byte is inserted.  Leading zeros
+;                      are included.
+;
+;              c       Character.  The ASCII character corresponding to the
+;                      least significant byte is inserted.
+
+               EXPORT  str_subst
+str_subst      ROUT
+
+               STMFD   R13!,{R1-R11,R14}
+
+               ; --- Move arguments into more amenable registers ---
+
+               MOV     R11,R0                  ;Pointer to skeleton string
+
+               ; --- Main `get a character' loop ---
+
+00str_subst    LDRB    R14,[R11],#1            ;Get an input character
+               CMP     R14,#'%'                ;Is it a `%' sign?
+               BEQ     %01str_subst            ;Yes -- deal with it
+02str_subst    CMP     R14,#&20                ;Is it the end of input?
+               MOVLT   R14,#0                  ;Yes -- null terminate it
+               STRB    R14,[R1],#1             ;Not special, so store it
+               BGE     %00str_subst            ;No -- get another one
+               SUB     R1,R1,#1                ;Point to null terminator
+               LDMFD   R13!,{R0,R2-R11,PC}^    ;And return to caller
+
+               ; --- Found a `%' sign, so find out what to substitute ---
+
+01str_subst    LDRB    R14,[R11],#1            ;Get the next character
+
+               ; --- Now find out what we're substituting ---
+
+               ORR     R9,R14,#&20             ;Convert it to lowercase
+               CMP     R9,#'s'                 ;Is it a string?
+               CMPNE   R9,#'i'                 ;Or an integer?
+               CMPNE   R9,#'x'                 ;Or a fullword hex number?
+               CMPNE   R9,#'b'                 ;Or a single byte in hex?
+               CMPNE   R9,#'c'                 ;Or an ASCII character?
+               LDREQB  R14,[R11],#1            ;And get another character
+
+               ; --- Now find which filler it is ---
+
+               CMP     R14,#'0'                ;Is it a digit?
+               BLT     %02str_subst            ;No -- just ignore the `%'
+               CMP     R14,#'9'                ;Make sure it's small enough
+               BGT     %02str_subst            ;No -- just ignore the `%'
+               SUB     R14,R14,#'0'-1          ;Convert to binary (1..10)
+               LDR     R0,[R13,R14,LSL #2]     ;Load appropriate register
+
+               ; --- Now find out how to substitute this argument ---
+
+               MOV     R2,#256                 ;Buffer size -- saves space
+
+               CMP     R9,#'s'                 ;Is it meant to be a string?
+               BEQ     %03str_subst            ;Yes -- a quick copy loop
+               CMP     R9,#'i'                 ;A decimal integer?
+               BEQ     %04str_subst            ;Yes -- go ahead to convert
+               CMP     R9,#'x'                 ;A hex fullword?
+               BEQ     %05str_subst            ;Yes -- convert that
+               CMP     R9,#'b'                 ;A hex byte?
+               BEQ     %06str_subst            ;Yes -- convert that
+               CMP     R9,#'c'                 ;A character?
+               BEQ     %07str_subst            ;Yes -- convert that
+
+               ; --- String substitution copy-loop ---
+
+03str_subst    LDRB    R14,[R0],#1             ;Get an input byte
+               CMP     R14,#&20                ;Is it the end of the string?
+               BLT     %00str_subst            ;Yes -- read main string
+               STRB    R14,[R1],#1             ;No -- store it in output
+               B       %03str_subst            ;... and get another one
+
+               ; --- Decimal integer conversion ---
+
+04str_subst    SWI     OS_ConvertInteger4      ;Convert and update nicely
+               B       %00str_subst            ;And rejoin the main loop
+
+               ; --- Hexadecimal fullword conversion ---
+
+05str_subst    SWI     OS_ConvertHex8          ;Convert and update nicely
+               B       %00str_subst            ;And rejoin the main loop
+
+               ; --- Hexadecimal byte conversion ---
+
+06str_subst    SWI     OS_ConvertHex2          ;Convert and update nicely
+               B       %00str_subst            ;And rejoin the main loop
+
+               ; --- ASCII character conversion ---
+
+07str_subst    STRB    R0,[R1],#1              ;Store the byte in
+               B       %00str_subst            ;And rejoin the main loop
+
+               LTORG
+
+; --- str_error ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R2-R11 == Pointers to fillin strings
+;
+; On exit:     R0 == Pointer to error in buffer
+;              R1 == Pointer to terminator
+;
+; Use:         Fills in an error skeleton (like a substitution skeleton in
+;              str_subst above with an error number on the front) and
+;              returns a pointer to it.  The buffer used is found by calling
+;              str_buffer (see below), so you can safely use the result of
+;              one call as a filler string for the next.
+;
+;              Filler strings may be held in the scratchpad.
+
+               EXPORT  str_error
+str_error      ROUT
+
+               STMFD   R13!,{R14}              ;Store the link register
+               BL      str_buffer              ;Find a spare buffer
+               LDR     R14,[R0],#4             ;Get the error number
+               STR     R14,[R1],#4             ;Output it too
+               BL      str_subst               ;Do the string substitution
+               SUB     R0,R0,#4                ;Point to the error start
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+str__wSpace    DCD     0                       ;Pointer to error buffer
+
+; ---- str_buffer ---
+;
+; On entry:    --
+;
+; On exit:     R1 == pointer to the next free buffer
+;
+; Use:         Returns a pointer to a 256-byte buffer.  There are at present
+;              2 buffers, which are returned alternately.
+
+               EXPORT  str_buffer
+str_buffer     ROUT
+
+               STMFD   R13!,{R14}              ;Save a work register
+
+               ; --- Work out which buffer to use ---
+               ;
+               ; This uses some vaguely clever tricks, so watch out  [mdw]
+               ; In fact, the C compiler used exactly the same tricks when
+               ; tried `return (buffer+256*(count^=1))'.
+
+               LDR     R14,str__wSpace         ;Find the workspace
+               LDR     R1,[R14,#0]             ;Get the current buffer
+               EOR     R1,R1,#1                ;Toggle the buffer number
+               STR     R1,[R14],#4             ;Store the new one back
+               ADD     R1,R14,R1,LSL #8        ;Point to correct buffer
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+str__buffers   EQU     2                       ;Use two buffers for now
+
+               ^       0                       ;Don't tie it to R12
+str__wStart    #       0
+
+str__buffNum   #       4
+str__buffer    #       256*str__buffers        ;The number of buffers I want
+
+str__wSize     EQU     {VAR}-str__wStart
+
+               AREA    |Quartz$$Table|,CODE,READONLY
+
+               DCD     str__wSize              ;For the error buffer
+               DCD     str__wSpace             ;Pointer to the pointer
+               DCD     0                       ;No initialisation
+               DCD     0                       ;No finalisation
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Quartz/sh/!FilerConf,050 b/StraySrc/Libraries/Quartz/sh/!FilerConf,050
new file mode 100644 (file)
index 0000000..3f1695f
--- /dev/null
@@ -0,0 +1 @@
+\11
\ No newline at end of file
diff --git a/StraySrc/Libraries/Quartz/sh/fastMove b/StraySrc/Libraries/Quartz/sh/fastMove
new file mode 100644 (file)
index 0000000..3488218
--- /dev/null
@@ -0,0 +1,49 @@
+;
+; fastMove.sh
+;
+; Fast memory manipulation
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Quartz library.
+;
+; Quartz is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Quartz is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Quartz.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   fastMove
+
+; --- fastMove ---
+;
+; On entry:    R0 == destination pointer
+;              R1 == source pointer
+;              R2 == number of bytes to move
+;
+; On exit:     --
+;
+; Use:         A very fast block moving routine.  Word aligning is not
+;              necessary, and the blocks may overlap.  This is basically
+;              the routine from PRM 2, hacked to cope with overlapping.
+
+               IMPORT  fastMove
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Quartz/sh/quartz b/StraySrc/Libraries/Quartz/sh/quartz
new file mode 100644 (file)
index 0000000..bf28a51
--- /dev/null
@@ -0,0 +1,45 @@
+;
+; quartz.sh
+;
+; Quartz module support library kernel
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Quartz library.
+;
+; Quartz is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Quartz is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Quartz.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   quartz_base
+
+; --- quartz_base ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to module base
+;
+; Use:         Returns a pointer to the module's base
+
+               IMPORT  quartz_base
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Quartz/sh/screen b/StraySrc/Libraries/Quartz/sh/screen
new file mode 100644 (file)
index 0000000..004a24d
--- /dev/null
@@ -0,0 +1,71 @@
+;
+; screen.s
+;
+; Screen mode information caching
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Quartz library.
+;
+; Quartz is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Quartz is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Quartz.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   screen_getInfo
+;   screen_init
+
+;----- Data offsets ---------------------------------------------------------
+
+               ^       0
+screen_xEig    #       4
+screen_yEig    #       4
+screen_bpp     #       4
+screen_width   #       4
+screen_height  #       4
+screen_dx      #       4
+screen_dy      #       4
+
+;----- Functions provided ---------------------------------------------------
+
+; --- screen_getInfo ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to screen information block
+;
+; Use:         This call returns a pointer to a block of information
+;              about the current screen modes. The offset for different
+;              bits of data are defined in screen.sh
+
+               IMPORT  screen_getInfo
+
+; --- screen_init ---
+;
+; On entry:    R12 == pointer to screen workspace
+;
+; On exit:     --
+;
+; Use:         Initialises the screen information caching system
+
+               IMPORT  screen_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Quartz/sh/string b/StraySrc/Libraries/Quartz/sh/string
new file mode 100644 (file)
index 0000000..082123b
--- /dev/null
@@ -0,0 +1,170 @@
+;
+; string.sh
+;
+; String handling routines (control terminated)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Quartz library.
+;
+; Quartz is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Quartz is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Quartz.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   str_cpy
+;   str_len
+;   str_cmp
+;   str_icmp
+;   str_subst
+;   str_error
+;
+; Notes:
+;
+;   All strings written by these routines are output as NULL-terminated,
+;   regardless of the original terminator.
+
+; --- str_cpy ---
+;
+; On entry:    R0 == destination string
+;              R1 == source string
+;
+; On exit:     R0 == pointer to terminator of destination
+;
+; Use:         Copies a string from one block to another.  It leaves the
+;              destination pointer at the end of the string so that any
+;              subsequent copies concatenate other bits on the same string.
+;              Single characters can of course be appended with
+;
+;                      MOV     Rx,#&cc
+;                      STRB    Rx,[R0],#1
+
+               IMPORT  str_cpy
+
+; --- str_len ---
+;
+; On entry:    R0 == pointer to string
+;
+; On exit:     R0 == length of the string
+;
+; Use:         Calculates the length of a string.
+
+               IMPORT  str_len
+
+; --- str_cmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         Case-sensitively compares two strings.  You can use the
+;              normal ARM conditio codes after the compare, so you can treat
+;              this as a normal CMP type thing (except the arguments must
+;              be in R0 and R1, and it mangles R14).
+
+               IMPORT  str_cmp
+
+; --- str_icmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         As for str_cmp above, but case-insensitive.
+
+               IMPORT  str_icmp
+
+; --- str_subst ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R1 == Pointer to output buffer
+;              R2-R11 == Pointer to filler strings (optional)
+;
+; On exit:     R0 == Pointer to start of buffer
+;              R1 == Pointer to terminating null
+;
+; Use:         Performs string substitution, filling in a skeleton string
+;              containing placeholders with `filler' strings.  The
+;              placeholders are actually rather powerful.  The syntax of
+;              these is as follows:
+;
+;                      `%' [<type>] <digit>
+;
+;              (spaces are for clarity -- in fact you must not include
+;              spaces in the format string.)
+;
+;              <digit> is any charater between `0' and `9'.  It refers to
+;              registers R2-R11 (so `0' means R2, `5' is R7 etc.)  How the
+;              value is interpreted is determined by <type>.
+;
+;              <type> is one of:
+;
+;              s       String.  This is the default.  The register is
+;                      considered to be a pointer to an ASCII string
+;                      (control terminated).
+;
+;              i       Integer.  The (signed) decimal representation is
+;                      inserted.  Leading zeros are suppressed.
+;
+;              x       Hex fullword.  The hexadecimal representation of the
+;                      register is inserted.  Leading zeros are included.
+;
+;              b       Hex byte.  The hexadecimal representation of the
+;                      least significant byte is inserted.  Leading zeros
+;                      are included.
+;
+;              c       Character.  The ASCII character corresponding to the
+;                      least significant byte is inserted.
+
+               IMPORT  str_subst
+
+; --- str_error ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R2-R11 == Pointers to fillin strings
+;
+; On exit:     R0 == Pointer to error in buffer
+;              R1 == Pointer to terminator
+;
+; Use:         Fills in an error skeleton (like a substitution skeleton in
+;              str_subst above with an error number on the front) and
+;              returns a pointer to it.  The buffer used is found by calling
+;              str_buffer (see below), so you can safely use the result of
+;              one call as a filler string for the next.
+;
+;              Filler strings may be held in the scratchpad.
+
+               IMPORT  str_error
+
+; ---- str_buffer ---
+;
+; On entry:    --
+;
+; On exit:     R1 == pointer to the next free buffer
+;
+; Use:         Returns a pointer to a 256-byte buffer.  There are at present
+;              2 buffers, which are returned alternately.
+
+               IMPORT  str_buffer
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/Makefile,fe1 b/StraySrc/Libraries/Sapphire/Makefile,fe1
new file mode 100644 (file)
index 0000000..42ac6ed
--- /dev/null
@@ -0,0 +1,1041 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+# --- Components of the DLL stub library ---
+
+DLLSTUBS = \
+       stub.core stub.resources \
+       stub.list stub.tearoff \
+       stub.csapph stub.thread \
+       o.bnrStub o.stub o.llistStub
+
+# --- Dynamic libraries to build ---
+
+DLLS = dll.core dll.resources dll.list dll.tearoff dll.csapph dll.thread
+
+# --- Core library components ---
+
+COREOBJ = \
+       o.divide o.coRoutine o.except o.fastMove o.fixedPt o.libOpts o.mem \
+                o.rand o.seh o.sqrt o.string \
+       o.alloc o.flex o.heap o.subAlloc \
+       o.cmdLine o.msgs o.res o.resources o.resspr o.template \
+       o.roVersion o.hour o.ptr o.screen o.wimp o.winUtils \
+       o.defHandler o.drag o.event o.help o.idle o.menu o.transWin o.win \
+       o.akbd o.keyString o.repeater \
+       o.dynPtr o.draw o.fontMenu o.ibicon o.pane o.sprite o.tspr \
+       o.dbox dbx.o.dbx dbx.o.arrow dbx.o.colourPot dbx.o.fileIcon \
+               dbx.o.numWrite dbx.o.slider dbx.o.stringSet \
+       o.colourBox o.mbox o.progInfo xfer.o.saveAs o.writable \
+       o.buttons o.errorBox o.nopoll o.note o.report o.saveWarn o.warning \
+       o.chunk choices.o.choices choices.o.options choices.o.prefs \
+       xfer.o.load xfer.o.save xfer.o.xload xfer.o.xsave
+
+COREDLLOBJ = $(COREOBJ) o.dKernel o.dBanner
+CORESTATOBJ = $(COREOBJ) o.kernel o.banner
+
+# --- Resources library components ---
+
+RSCOBJ = o.sapphRes o.rsc
+RESOURCES = rsc.messages rsc.sprites rsc.templates
+
+# --- List library components ---
+
+LISTOBJ = o.gallery o.llistman o.listbox o.viewer
+
+# --- Tearoff library components ---
+
+TMSOBJ = \
+       tms.o.tmsCreate tms.o.tmsGlue tms.o.tmsMain \
+       libs:tearSupt.o.tearSupt
+
+# --- Sapphire C support library components ---
+
+CSAPPHOBJ = \
+       csapph.o.cmath csapph.o.crout csapph.o.crts csapph.o.csapph \
+       csapph.o.csetjmp csapph.o.ctype
+
+# --- Thread library components ---
+
+THREADOBJ = o.thread
+
+# --- Extension library offsets ---
+
+TMSOFF = 24
+LISTOFF = 28
+THREADOFF = 32
+CSAPPHOFF = 36
+
+# --- Static library components ---
+
+STATOBJ = $(CORESTATOBJ) $(LISTOBJ) $(TMSOBJ) $(CSAPPHOBJ) $(THREADOBJ)
+
+#----- Interface targets ----------------------------------------------------
+
+# --- Main target ---
+
+all: $(DLLS) lib.sapphire lib.sapphdll lib.csapph
+       submake Modules.Makefile
+
+# --- Installing the libraries ---
+
+install: $(DLLS)
+       cdir <SSR$DLLDir>.Straylight
+       cdir <SSR$DLLDir>.Straylight.Sapphire
+       $(INSTALL) $(DLLS) <SSR$DLLDir>.Straylight.Sapphire
+       submake Modules.Makefile -- install
+
+# --- Cleansing the build tree ---
+
+clean:
+       -$(RM) ..o.* lib.* dll.* dc.* dh.* dl.* ds.* $(DLLS)
+       submake Modules.Makefile -- clean
+
+#----- Building the static libraries ----------------------------------------
+
+lib.sapphdll: $(DLLSTUBS)
+       $(AR) -c lib.sapphdll $(DLLSTUBS)
+
+lib.csapph: csapph.o.cstart
+       $(INSTALL) csapph.o.cstart lib.csapph
+
+lib.sapphire: $(STATOBJ)
+       test -file lib.sapphire -exists -else "$(AR) -c lib.sapphire"
+       $(AR) -i lib.sapphire $?
+
+#----- Building dynamic libraries -------------------------------------------
+
+# --- There are lots of little generated files lying around ---
+#
+# For creating DLLs, I need a collection of small AOF files.  For a DLL
+# `foo' I may need:
+#
+# dh.foo       cdll-generated library header
+# ds.foo       cdll-generated client stub
+# dc.foo       buildstub-generated client stub
+# dl.foo       buildstub-generated library stub
+
+# --- Core library ---
+
+stub.core: ds.core
+       $(LD_AOF) ds.core
+
+ds.core dh.core: def.core lib.sapphire
+       $(CDLL) def.core ds.core dh.core
+
+dll.core: dh.core $(COREDLLOBJ)
+       $(LD_DLL) dh.core $(COREDLLOBJ)
+       $(SET_DLL) dll.core
+
+# --- Resources library ---
+
+stub.resources: ds.resources
+       $(LD_AOF) ds.resources
+
+ds.resources dh.resources: def.resources $(RSCOBJ)
+       $(CDLL) def.resources ds.resources dh.resources
+
+o.rsc: $(RESOURCES)
+       resgen rsc o.rsc
+
+dll.resources: dh.resources $(RSCOBJ)
+       $(LD_DLL) dh.resources $(RSCOBJ)
+       $(SET_DLL) dll.resources
+
+# --- List library ---
+
+stub.list: ds.list dc.list
+       $(LD_AOF) ds.list dc.list
+
+dc.list dl.list:
+       buildstub dl.list dc.list __list_stub $(LISTOFF)
+
+ds.list dh.list: def.list lib.sapphire dl.list
+       $(CDLL) def.list ds.list dh.list
+
+dll.list: dh.list dl.list ds.core $(LISTOBJ)
+       $(LD_DLL) dh.list dl.list ds.core $(LISTOBJ)
+       $(SET_DLL) dll.list
+
+# --- Thread library ---
+
+stub.thread: ds.thread dc.thread
+       $(LD_AOF) ds.thread dc.thread
+
+dc.thread dl.thread:
+       buildstub dl.thread dc.thread __thread_stub $(THREADOFF)
+
+ds.thread dh.thread: def.thread lib.sapphire dl.thread
+       $(CDLL) def.thread ds.thread dh.thread
+
+dll.thread: dh.thread dl.thread ds.core $(THREADOBJ)
+       $(LD_DLL) dh.thread dl.thread ds.core $(THREADOBJ)
+       $(SET_DLL) dll.thread
+
+# --- Sapphire C support library ---
+
+stub.csapph: ds.csapph dc.csapph
+       $(LD_AOF) ds.csapph dc.csapph
+
+dc.csapph dl.csapph:
+       buildstub dl.csapph dc.csapph __csapph_stub $(CSAPPHOFF)
+
+ds.csapph dh.csapph: def.csapph lib.sapphire dl.csapph
+       $(CDLL) def.csapph ds.csapph dh.csapph
+
+dll.csapph: dh.csapph dl.csapph ds.core $(CSAPPHOBJ)
+       $(LD_DLL) dh.csapph dl.csapph ds.core $(CSAPPHOBJ)
+       $(SET_DLL) dll.csapph
+
+# --- Tearoff library ---
+
+stub.tearoff: ds.tearoff dc.tearoff
+       $(LD_AOF) ds.tearoff dc.tearoff
+
+dc.tearoff dl.tearoff:
+       buildstub dl.tearoff dc.tearoff __tearoff_stub $(TMSOFF)
+
+ds.tearoff dh.tearoff: def.tearoff lib.sapphire dl.tearoff
+       $(CDLL) def.tearoff ds.tearoff dh.tearoff
+
+dll.tearoff: dh.tearoff dl.tearoff ds.core $(TMSOBJ)
+       $(LD_DLL) dh.tearoff dl.tearoff ds.core $(TMSOBJ)
+       $(SET_DLL) dll.tearoff
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+csapph.o.crts: csapph.s.crts
+csapph.o.crts: libs:header
+csapph.o.crts: libs:stream
+csapph.o.crts: sapphire:divide
+csapph.o.csapph: csapph.s.csapph
+csapph.o.csapph: libs:header
+csapph.o.csapph: libs:swis
+csapph.o.csapph: libs:stream
+csapph.o.csapph: libs:s.xswi
+csapph.o.csapph: libs:s.swihack
+csapph.o.csetjmp: csapph.s.csetjmp
+csapph.o.csetjmp: libs:header
+csapph.o.csetjmp: libs:swis
+csapph.o.csetjmp: libs:stream
+csapph.o.ctype: csapph.s.ctype
+csapph.o.ctype: libs:header
+csapph.o.ctype: libs:swis
+csapph.o.ctype: libs:stream
+o.thread: s.thread
+o.thread: libs:header
+o.thread: libs:swis
+o.thread: sapphire:alloc
+o.thread: sapphire:suballoc
+o.thread: sapphire:idle
+o.thread: sapphire:msgs
+o.thread: sapphire:sapphire
+o.bnrStub: s.bnrStub
+o.bnrStub: libs:header
+o.bnrStub: libs:swis
+o.bnrStub: libs:stream
+o.stub: s.stub
+o.stub: libs:header
+o.stub: libs:swis
+o.stub: libs:stream
+o.llistStub: s.llistStub
+csapph.o.cstart: csapph.s.cstart
+csapph.o.cstart: libs:header
+csapph.o.cstart: libs:stream
+csapph.o.cstart: sapphire:sapphire
+o.subAlloc: s.subAlloc
+o.subAlloc: libs:swis
+o.subAlloc: libs:header
+o.subAlloc: sapphire:alloc
+o.subAlloc: sapphire:mem
+o.subAlloc: sapphire:sapphire
+o.cmdLine: s.cmdLine
+o.cmdLine: libs:header
+o.cmdLine: libs:swis
+o.msgs: s.msgs
+o.msgs: libs:header
+o.msgs: libs:swis
+o.msgs: sapphire:alloc
+o.msgs: sapphire:sapphire
+o.msgs: sapphire:string
+o.msgs: sapphire:res
+o.msgs: sapphire:resources
+o.res: s.res
+o.res: libs:header
+o.res: libs:swis
+o.res: sapphire:string
+o.res: sapphire:sapphire
+o.resources: s.resources
+o.resources: libs:header
+o.resources: libs:swis
+o.resources: libs:stream
+o.resources: sapphire:except
+o.resources: sapphire:sapphire
+o.resspr: s.resspr
+o.resspr: libs:header
+o.resspr: libs:swis
+o.resspr: sapphire:alloc
+o.resspr: sapphire:msgs
+o.resspr: sapphire:res
+o.resspr: sapphire:resources
+o.resspr: sapphire:sapphire
+o.resspr: sapphire:string
+o.template: s.template
+o.template: libs:header
+o.template: libs:swis
+o.template: sapphire:alloc
+o.template: sapphire:fastMove
+o.template: sapphire:except
+o.template: sapphire:mem
+o.template: sapphire:msgs
+o.template: sapphire:res
+o.template: sapphire:resources
+o.template: sapphire:resspr
+o.template: sapphire:sapphire
+o.template: sapphire:string
+o.roVersion: s.roVersion
+o.roVersion: libs:swis
+o.roVersion: libs:header
+o.roVersion: sapphire:sapphire
+o.hour: s.hour
+o.hour: libs:header
+o.hour: libs:swis
+o.hour: sapphire:except
+o.hour: sapphire:sapphire
+o.ptr: s.ptr
+o.ptr: libs:header
+o.ptr: libs:swis
+o.ptr: sapphire:event
+o.ptr: sapphire:except
+o.ptr: sapphire:idle
+o.ptr: sapphire:resspr
+o.ptr: sapphire:sapphire
+o.ptr: sapphire:screen
+o.ptr: sapphire:sprite
+o.ptr: sapphire:string
+o.ptr: sapphire:wimp
+o.screen: s.screen
+o.screen: libs:header
+o.screen: libs:swis
+o.screen: sapphire:sapphire
+o.screen: sapphire:event
+o.wimp: s.wimp
+o.wimp: libs:header
+o.wimp: libs:swis
+o.wimp: sapphire:except
+o.wimp: sapphire:libOpts
+o.wimp: sapphire:roVersion
+o.wimp: sapphire:sapphire
+o.winUtils: s.winUtils
+o.winUtils: libs:header
+o.winUtils: libs:swis
+o.winUtils: sapphire:screen
+o.defHandler: s.defHandler
+o.defHandler: libs:header
+o.defHandler: libs:swis
+o.defHandler: sapphire:resspr
+o.drag: s.drag
+o.drag: libs:header
+o.drag: libs:swis
+o.drag: libs:stream
+o.drag: sapphire:akbd
+o.drag: sapphire:idle
+o.drag: sapphire:intKeys
+o.drag: sapphire:sapphire
+o.drag: sapphire:screen
+o.drag: sapphire:win
+o.event: s.event
+o.event: libs:header
+o.event: libs:swis
+o.event: sapphire:sapphire
+o.event: sapphire:suballoc
+o.event: sapphire:hour
+o.help: s.help
+o.help: libs:header
+o.help: libs:swis
+o.help: sapphire:event
+o.help: sapphire:idle
+o.help: sapphire:msgs
+o.help: sapphire:sapphire
+o.help: sapphire:string
+o.idle: s.idle
+o.idle: libs:header
+o.idle: libs:swis
+o.idle: sapphire:sapphire
+o.idle: sapphire:suballoc
+o.idle: sapphire:event
+o.menu: s.menu
+o.menu: libs:header
+o.menu: libs:swis
+o.menu: sapphire:event
+o.menu: sapphire:libOpts
+o.menu: sapphire:sapphire
+o.menu: sapphire:string
+o.menu: sapphire:fastMove
+o.menu: sapphire:msgs
+o.menu: sapphire:help
+o.transWin: s.transWin
+o.transWin: libs:header
+o.transWin: libs:swis
+o.transWin: libs:stream
+o.transWin: sapphire:event
+o.transWin: sapphire:sapphire
+o.win: s.win
+o.win: libs:header
+o.win: libs:swis
+o.win: sapphire:sapphire
+o.win: sapphire:suballoc
+o.win: sapphire:event
+o.akbd: s.akbd
+o.akbd: libs:header
+o.akbd: libs:swis
+o.akbd: sapphire:keyMap
+o.akbd: sapphire:intKeys
+o.keyString: s.keyString
+o.keyString: libs:header
+o.keyString: libs:swis
+o.keyString: sapphire:msgs
+o.keyString: sapphire:keyMap
+o.keyString: sapphire:string
+o.repeater: s.repeater
+o.repeater: libs:header
+o.repeater: libs:swis
+o.repeater: libs:stream
+o.repeater: sapphire:divide
+o.repeater: sapphire:idle
+o.repeater: sapphire:sapphire
+o.repeater: sapphire:win
+o.dynPtr: s.dynPtr
+o.dynPtr: libs:header
+o.dynPtr: libs:swis
+o.dynPtr: sapphire:ptr
+o.dynPtr: sapphire:resspr
+o.draw: s.draw
+o.draw: libs:header
+o.draw: libs:swis
+o.draw: sapphire:divide
+o.draw: sapphire:mem
+o.draw: sapphire:msgs
+o.draw: sapphire:roVersion
+o.draw: sapphire:sapphire
+o.draw: sapphire:screen
+o.draw: sapphire:sprite
+o.fontMenu: s.fontMenu
+o.fontMenu: libs:header
+o.fontMenu: libs:swis
+o.fontMenu: libs:stream
+o.fontMenu: sapphire:alloc
+o.fontMenu: sapphire:event
+o.fontMenu: sapphire:flex
+o.fontMenu: sapphire:menu
+o.fontMenu: sapphire:menuDefs
+o.fontMenu: sapphire:msgs
+o.fontMenu: sapphire:sapphire
+o.fontMenu: sapphire:string
+o.ibicon: s.ibicon
+o.ibicon: libs:header
+o.ibicon: libs:swis
+o.ibicon: sapphire:msgs
+o.ibicon: sapphire:suballoc
+o.ibicon: sapphire:sapphire
+o.ibicon: sapphire:string
+o.ibicon: sapphire:resspr
+o.ibicon: sapphire:wimp
+o.ibicon: sapphire:win
+o.pane: s.pane
+o.pane: libs:header
+o.pane: libs:swis
+o.pane: sapphire:alloc
+o.pane: sapphire:event
+o.pane: sapphire:screen
+o.pane: sapphire:sapphire
+o.pane: sapphire:suballoc
+o.pane: sapphire:tspr
+o.sprite: s.sprite
+o.sprite: libs:header
+o.sprite: libs:swis
+o.sprite: sapphire:resspr
+o.sprite: sapphire:screen
+o.tspr: s.tspr
+o.tspr: libs:header
+o.tspr: libs:swis
+o.tspr: sapphire:screen
+o.tspr: sapphire:wimp
+o.nopoll: s.nopoll
+o.nopoll: libs:header
+o.nopoll: libs:swis
+o.nopoll: sapphire:defHandler
+o.nopoll: sapphire:event
+o.nopoll: sapphire:hour
+o.nopoll: sapphire:sapphire
+o.nopoll: sapphire:screen
+o.report: s.report
+o.report: libs:header
+o.report: libs:swis
+o.report: sapphire:buttons
+o.report: sapphire:errorBox
+o.report: sapphire:except
+o.report: sapphire:msgs
+o.report: sapphire:sapphire
+o.report: sapphire:seh
+o.report: sapphire:string
+o.saveWarn: s.saveWarn
+o.saveWarn: libs:header
+o.saveWarn: libs:swis
+o.saveWarn: libs:stream
+o.saveWarn: sapphire:buttons
+o.saveWarn: sapphire:errorBox
+o.saveWarn: sapphire:msgs
+o.saveWarn: sapphire:sapphire
+o.saveWarn: sapphire:string
+o.saveWarn: sapphire:warning
+o.saveWarn: sapphire:xfer.saveAs
+o.chunk: s.chunk
+o.chunk: libs:header
+o.chunk: libs:swis
+o.chunk: libs:stream
+o.chunk: sapphire:alloc
+o.chunk: sapphire:fastMove
+o.chunk: sapphire:flex
+o.chunk: sapphire:string
+o.chunk: sapphire:xfer.xsave
+choices.o.choices: choices.s.choices
+choices.o.choices: libs:header
+choices.o.choices: libs:swis
+choices.o.choices: libs:stream
+choices.o.choices: sapphire:res
+choices.o.choices: sapphire:sapphire
+choices.o.choices: sapphire:string
+xfer.o.save: xfer.s.save
+xfer.o.save: libs:header
+xfer.o.save: libs:swis
+xfer.o.save: sapphire:fastMove
+xfer.o.save: sapphire:msgs
+xfer.o.save: sapphire:sapphire
+xfer.o.save: sapphire:string
+xfer.o.save: sapphire:wimp
+xfer.o.save: sapphire:win
+xfer.o.xload: xfer.s.xload
+xfer.o.xload: libs:header
+xfer.o.xload: libs:swis
+xfer.o.xload: sapphire:alloc
+xfer.o.xload: sapphire:coRoutine
+xfer.o.xload: sapphire:fastMove
+xfer.o.xload: sapphire:sapphire
+xfer.o.xsave: xfer.s.xsave
+xfer.o.xsave: libs:header
+xfer.o.xsave: libs:swis
+xfer.o.xsave: sapphire:alloc
+xfer.o.xsave: sapphire:coRoutine
+xfer.o.xsave: sapphire:fastMove
+xfer.o.xsave: sapphire:sapphire
+o.kernel: s.kernel
+o.kernel: libs:header
+o.kernel: libs:swis
+o.kernel: libs:stream
+o.gallery: s.gallery
+o.gallery: libs:header
+o.gallery: libs:swis
+o.gallery: libs:stream
+o.gallery: sapphire:idle
+o.gallery: sapphire:screen
+o.gallery: sapphire:viewer
+o.llistman: s.llistman
+o.llistman: libs:header
+o.llistman: libs:swis
+o.llistman: sapphire:alloc
+o.llistman: sapphire:fastMove
+o.llistman: sapphire:sapphire
+o.listbox: s.listbox
+o.listbox: libs:header
+o.listbox: libs:swis
+o.listbox: sapphire:alloc
+o.listbox: sapphire:fastMove
+o.listbox: sapphire:idle
+o.listbox: sapphire:divide
+o.listbox: sapphire:pane
+o.listbox: sapphire:resspr
+o.listbox: sapphire:sapphire
+o.listbox: sapphire:screen
+o.listbox: sapphire:tspr
+o.listbox: sapphire:win
+o.viewer: s.viewer
+o.viewer: libs:header
+o.viewer: libs:swis
+o.viewer: libs:stream
+o.viewer: sapphire:akbd
+o.viewer: sapphire:alloc
+o.viewer: sapphire:divide
+o.viewer: sapphire:drag
+o.viewer: sapphire:fastMove
+o.viewer: sapphire:msgs
+o.viewer: sapphire:sapphire
+o.viewer: sapphire:screen
+o.viewer: sapphire:wimp
+o.viewer: sapphire:win
+o.viewer: sapphire:winUtils
+tms.o.tmsCreate: tms.s.tmsCreate
+tms.o.tmsCreate: libs:header
+tms.o.tmsCreate: libs:swis
+tms.o.tmsCreate: libs:stream
+tms.o.tmsCreate: sapphire:alloc
+tms.o.tmsCreate: sapphire:heap
+tms.o.tmsCreate: sapphire:keyString
+tms.o.tmsCreate: sapphire:msgs
+tms.o.tmsCreate: sapphire:resspr
+tms.o.tmsCreate: sapphire:sapphire
+tms.o.tmsCreate: sapphire:string
+tms.o.tmsCreate: sapphire:wimp
+tms.o.tmsCreate: sapphire:win
+tms.o.tmsCreate: sapphire:winUtils
+tms.o.tmsCreate: sapphire:_tms.tmsGlobal
+tms.o.tmsCreate: sapphire:_tms.tmsMain
+tms.o.tmsGlue: tms.s.tmsGlue
+tms.o.tmsGlue: libs:header
+tms.o.tmsGlue: libs:swis
+tms.o.tmsGlue: libs:stream
+tms.o.tmsGlue: libs:tearSupt.sh.tearSupt
+tms.o.tmsGlue: sapphire:event
+tms.o.tmsGlue: sapphire:errorBox
+tms.o.tmsGlue: sapphire:heap
+tms.o.tmsGlue: sapphire:mem
+tms.o.tmsGlue: sapphire:sapphire
+tms.o.tmsGlue: sapphire:screen
+tms.o.tmsGlue: sapphire:wimp
+tms.o.tmsGlue: sapphire:win
+tms.o.tmsGlue: sapphire:_tms.tmsGlobal
+tms.o.tmsGlue: sapphire:_tms.tmsMain
+tms.o.tmsMain: tms.s.tmsMain
+tms.o.tmsMain: libs:header
+tms.o.tmsMain: libs:swis
+tms.o.tmsMain: libs:tearSupt.sh.tearsupt
+tms.o.tmsMain: sapphire:errorBox
+tms.o.tmsMain: sapphire:help
+tms.o.tmsMain: sapphire:idle
+tms.o.tmsMain: sapphire:keyString
+tms.o.tmsMain: sapphire:msgs
+tms.o.tmsMain: sapphire:resspr
+tms.o.tmsMain: sapphire:sapphire
+tms.o.tmsMain: sapphire:screen
+tms.o.tmsMain: sapphire:string
+tms.o.tmsMain: sapphire:tspr
+tms.o.tmsMain: sapphire:wimp
+tms.o.tmsMain: sapphire:win
+tms.o.tmsMain: sapphire:_tms.tmsCreate
+tms.o.tmsMain: sapphire:_tms.tmsGlobal
+tms.o.tmsMain: sapphire:_tms.tmsGlue
+csapph.o.cmath: csapph.s.cmath
+csapph.o.cmath: libs:header
+csapph.o.cmath: libs:stream
+csapph.o.crout: csapph.s.crout
+csapph.o.crout: libs:header
+csapph.o.crout: libs:stream
+csapph.o.crout: sapphire:alloc
+csapph.o.crout: sapphire:flex
+csapph.o.crout: sapphire:msgs
+csapph.o.crout: sapphire:sapphire
+csapph.o.crout: sapphire:string
+o.divide: s.divide
+o.divide: libs:header
+o.divide: libs:swis
+o.coRoutine: s.coRoutine
+o.coRoutine: libs:header
+o.coRoutine: libs:swis
+o.coRoutine: sapphire:alloc
+o.coRoutine: sapphire:sapphire
+o.coRoutine: sapphire:seh
+o.coRoutine: sapphire:suballoc
+o.except: s.except
+o.except: libs:header
+o.except: libs:swis
+o.except: sapphire:sapphire
+o.except: sapphire:suballoc
+o.fastMove: s.fastMove
+o.fastMove: libs:s.fastMove
+o.fastMove: libs:header
+o.fastMove: libs:swis
+o.libOpts: s.libOpts
+o.libOpts: libs:header
+o.libOpts: libs:swis
+o.libOpts: libs:stream
+o.libOpts: sapphire:sapphire
+o.libOpts: sapphire:suballoc
+o.mem: s.mem
+o.mem: libs:swis
+o.mem: libs:header
+o.rand: s.rand
+o.rand: libs:header
+o.rand: libs:swis
+o.rand: sapphire:divide
+o.rand: sapphire:sapphire
+o.seh: s.seh
+o.seh: libs:header
+o.seh: libs:swis
+o.seh: libs:stream
+o.seh: sapphire:except
+o.seh: sapphire:msgs
+o.seh: sapphire:sapphire
+o.sqrt: s.sqrt
+o.sqrt: libs:header
+o.sqrt: libs:swis
+o.sqrt: libs:stream
+o.string: s.string
+o.string: libs:swis
+o.string: libs:header
+o.string: sapphire:sapphire
+o.alloc: s.alloc
+o.alloc: libs:header
+o.alloc: libs:swis
+o.alloc: sapphire:msgs
+o.alloc: sapphire:sapphire
+o.alloc: sapphire:subAlloc
+o.sapphRes: s.sapphRes
+o.sapphRes: libs:header
+o.sapphRes: libs:swis
+o.sapphRes: libs:stream
+o.dKernel: s.dKernel
+o.dKernel: s.kernel
+o.dKernel: libs:header
+o.dKernel: libs:swis
+o.dKernel: libs:stream
+choices.o.options: choices.s.options
+choices.o.options: libs:header
+choices.o.options: libs:swis
+choices.o.options: libs:stream
+choices.o.options: sapphire:chunk
+choices.o.options: sapphire:divide
+choices.o.options: sapphire:flex
+choices.o.options: sapphire:string
+choices.o.options: sapphire:xfer.xsave
+choices.o.prefs: choices.s.prefs
+choices.o.prefs: libs:header
+choices.o.prefs: libs:swis
+choices.o.prefs: libs:stream
+choices.o.prefs: sapphire:alloc
+choices.o.prefs: sapphire:chunk
+choices.o.prefs: sapphire:flex
+choices.o.prefs: sapphire:heap
+choices.o.prefs: sapphire:res
+choices.o.prefs: sapphire:sapphire
+choices.o.prefs: sapphire:xfer.load
+choices.o.prefs: sapphire:choices.choices
+xfer.o.load: xfer.s.load
+xfer.o.load: libs:swis
+xfer.o.load: libs:header
+xfer.o.load: sapphire:alloc
+xfer.o.load: sapphire:event
+xfer.o.load: sapphire:fastMove
+xfer.o.load: sapphire:flex
+xfer.o.load: sapphire:msgs
+xfer.o.load: sapphire:sapphire
+xfer.o.load: sapphire:string
+xfer.o.load: sapphire:wimp
+xfer.o.load: sapphire:win
+o.flex: s.flex
+o.flex: libs:s.flex
+o.flex: libs:header
+o.flex: libs:swis
+o.flex: sapphire:fastMove
+o.flex: sapphire:event
+o.flex: sapphire:except
+o.flex: sapphire:libOpts
+o.flex: sapphire:roVersion
+o.flex: sapphire:sapphire
+o.flex: libs:sh.flexws
+o.heap: s.heap
+o.heap: libs:s.heap
+o.heap: libs:header
+o.heap: libs:swis
+o.heap: sapphire:alloc
+o.heap: sapphire:flex
+o.heap: sapphire:msgs
+o.heap: sapphire:fastMove
+o.heap: sapphire:sapphire
+o.heap: libs:sh.heapws
+o.dBanner: s.dBanner
+o.dBanner: s.banner
+o.dBanner: libs:header
+o.dBanner: libs:swis
+o.dBanner: libs:stream
+o.dBanner: sapphire:alloc
+o.dBanner: sapphire:dbox
+o.dBanner: sapphire:divide
+o.dBanner: sapphire:event
+o.dBanner: sapphire:flex
+o.dBanner: sapphire:heap
+o.dBanner: sapphire:hour
+o.dBanner: sapphire:nopoll
+o.dBanner: sapphire:res
+o.dBanner: sapphire:sapphire
+o.dBanner: sapphire:screen
+o.dBanner: sapphire:wimp
+o.dBanner: sapphire:dbx.dbx
+o.dBanner: sapphire:dbx.slider
+o.dBanner: sapphire:dbx.dbx
+dbx.o.arrow: dbx.s.arrow
+dbx.o.arrow: libs:header
+dbx.o.arrow: libs:swis
+dbx.o.arrow: sapphire:dbox
+dbx.o.arrow: sapphire:repeater
+dbx.o.arrow: sapphire:dbx.dbx
+dbx.o.arrow: sapphire:dbx._dbxMacs
+dbx.o.colourPot: dbx.s.colourPot
+dbx.o.colourPot: libs:header
+dbx.o.colourPot: libs:swis
+dbx.o.colourPot: libs:stream
+dbx.o.colourPot: sapphire:colourBox
+dbx.o.colourPot: sapphire:dbox
+dbx.o.colourPot: sapphire:errorBox
+dbx.o.colourPot: sapphire:screen
+dbx.o.colourPot: sapphire:winUtils
+dbx.o.colourPot: sapphire:dbx.dbx
+dbx.o.colourPot: sapphire:dbx._dbxMacs
+dbx.o.fileIcon: dbx.s.fileIcon
+dbx.o.fileIcon: libs:header
+dbx.o.fileIcon: libs:swis
+dbx.o.fileIcon: sapphire:dbox
+dbx.o.fileIcon: sapphire:sapphire
+dbx.o.fileIcon: sapphire:screen
+dbx.o.fileIcon: sapphire:string
+dbx.o.fileIcon: sapphire:win
+dbx.o.fileIcon: sapphire:dbx.dbx
+dbx.o.fileIcon: sapphire:dbx._dbxMacs
+dbx.o.numWrite: dbx.s.numWrite
+dbx.o.numWrite: libs:header
+dbx.o.numWrite: libs:swis
+dbx.o.numWrite: sapphire:dbox
+dbx.o.numWrite: sapphire:keyMap
+dbx.o.numWrite: sapphire:string
+dbx.o.numWrite: sapphire:dbx.dbx
+dbx.o.numWrite: sapphire:dbx._dbxMacs
+dbx.o.slider: dbx.s.slider
+dbx.o.slider: libs:header
+dbx.o.slider: libs:swis
+dbx.o.slider: sapphire:dbox
+dbx.o.slider: sapphire:divide
+dbx.o.slider: sapphire:idle
+dbx.o.slider: sapphire:win
+dbx.o.slider: sapphire:msgs
+dbx.o.slider: sapphire:screen
+dbx.o.slider: sapphire:winUtils
+dbx.o.slider: sapphire:dbx.dbx
+dbx.o.slider: sapphire:dbx._dbxMacs
+dbx.o.stringSet: dbx.s.stringSet
+dbx.o.stringSet: libs:header
+dbx.o.stringSet: libs:swis
+dbx.o.stringSet: libs:stream
+dbx.o.stringSet: sapphire:dbox
+dbx.o.stringSet: sapphire:menu
+dbx.o.stringSet: sapphire:menuDefs
+dbx.o.stringSet: sapphire:msgs
+dbx.o.stringSet: sapphire:string
+dbx.o.stringSet: sapphire:dbx.dbx
+dbx.o.stringSet: sapphire:dbx._dbxMacs
+o.colourBox: s.colourBox
+o.colourBox: libs:header
+o.colourBox: libs:swis
+o.colourBox: libs:stream
+o.colourBox: sapphire:dbox
+o.colourBox: sapphire:msgs
+o.colourBox: sapphire:sapphire
+o.colourBox: sapphire:keyMap
+o.mbox: s.mbox
+o.mbox: libs:header
+o.mbox: libs:swis
+o.mbox: sapphire:dbox
+o.mbox: sapphire:help
+o.mbox: sapphire:msgs
+o.progInfo: s.progInfo
+o.progInfo: libs:header
+o.progInfo: libs:swis
+o.progInfo: sapphire:dbox
+o.progInfo: sapphire:mbox
+o.progInfo: sapphire:sapphire
+xfer.o.saveAs: xfer.s.saveAs
+xfer.o.saveAs: libs:header
+xfer.o.saveAs: libs:swis
+xfer.o.saveAs: sapphire:dbox
+xfer.o.saveAs: sapphire:help
+xfer.o.saveAs: sapphire:msgs
+xfer.o.saveAs: sapphire:note
+xfer.o.saveAs: sapphire:sapphire
+xfer.o.saveAs: sapphire:dbx.dbx
+xfer.o.saveAs: sapphire:dbx.fileIcon
+xfer.o.saveAs: sapphire:dbx.dbx
+xfer.o.saveAs: sapphire:xfer.save
+o.writable: s.writable
+o.writable: libs:header
+o.writable: libs:swis
+o.writable: sapphire:dbox
+o.writable: sapphire:fastMove
+o.writable: sapphire:msgs
+o.writable: sapphire:sapphire
+o.writable: sapphire:string
+o.buttons: s.buttons
+o.buttons: libs:header
+o.buttons: libs:swis
+o.buttons: libs:stream
+o.buttons: sapphire:dbox
+o.buttons: sapphire:msgs
+o.errorBox: s.errorBox
+o.errorBox: libs:header
+o.errorBox: libs:swis
+o.errorBox: libs:stream
+o.errorBox: sapphire:buttons
+o.errorBox: sapphire:dbox
+o.errorBox: sapphire:msgs
+o.errorBox: sapphire:nopoll
+o.errorBox: sapphire:sapphire
+o.errorBox: sapphire:string
+o.errorBox: sapphire:template
+o.errorBox: sapphire:wimp
+o.note: s.note
+o.note: libs:header
+o.note: libs:swis
+o.note: sapphire:dbox
+o.note: sapphire:errorBox
+o.note: sapphire:msgs
+o.note: sapphire:nopoll
+o.note: sapphire:sapphire
+o.note: sapphire:string
+o.warning: s.warning
+o.warning: libs:header
+o.warning: libs:swis
+o.warning: libs:stream
+o.warning: sapphire:buttons
+o.warning: sapphire:dbox
+o.warning: sapphire:errorBox
+o.warning: sapphire:msgs
+o.warning: sapphire:nopoll
+o.warning: sapphire:sapphire
+o.warning: sapphire:string
+o.warning: sapphire:template
+o.warning: sapphire:wimp
+o.banner: s.banner
+o.banner: libs:header
+o.banner: libs:swis
+o.banner: libs:stream
+o.banner: sapphire:alloc
+o.banner: sapphire:dbox
+o.banner: sapphire:divide
+o.banner: sapphire:event
+o.banner: sapphire:flex
+o.banner: sapphire:heap
+o.banner: sapphire:hour
+o.banner: sapphire:nopoll
+o.banner: sapphire:res
+o.banner: sapphire:sapphire
+o.banner: sapphire:screen
+o.banner: sapphire:wimp
+o.banner: sapphire:dbx.dbx
+o.banner: sapphire:dbx.slider
+o.banner: sapphire:dbx.dbx
+o.dbox: s.dbox
+o.dbox: libs:header
+o.dbox: libs:swis
+o.dbox: sapphire:akbd
+o.dbox: sapphire:alloc
+o.dbox: sapphire:event
+o.dbox: sapphire:keyMap
+o.dbox: sapphire:help
+o.dbox: sapphire:hour
+o.dbox: sapphire:msgs
+o.dbox: sapphire:sapphire
+o.dbox: sapphire:string
+o.dbox: sapphire:subAlloc
+o.dbox: sapphire:template
+o.dbox: sapphire:transWin
+o.dbox: sapphire:win
+o.dbox: sapphire:winUtils
+dbx.o.dbx: dbx.s.dbx
+dbx.o.dbx: libs:header
+dbx.o.dbx: libs:swis
+dbx.o.dbx: sapphire:dbox
+dbx.o.dbx: sapphire:msgs
+dbx.o.dbx: sapphire:screen
diff --git a/StraySrc/Libraries/Sapphire/Modules/Docs/Sprinkle b/StraySrc/Libraries/Sapphire/Modules/Docs/Sprinkle
new file mode 100644 (file)
index 0000000..0b3f544
--- /dev/null
@@ -0,0 +1,138 @@
+
+     /####\  ######\  ######\   ####   ###\   ##  ##  /#/  ##      ######
+     ##/     ##   )#  ##   )#    ##    ##\#\  ##  ## /#/   ##      ##
+     \####\  ######/  ######/    ##    ## \#\ ##  ##<#<    ##      #####
+        \##  ##       ##  \#\    ##    ##  \#\##  ## \#\   ##      ##
+     \####/  ##       ##   \#\  ####   ##   \###  ##  \#\  ######  ######
+
+                      ©   1 9 9 5   S t r a y l i g h t
+
+_____________________________________________________________________________
+
+
+                                About Sprinkle
+
+       Sprite areas are just big blocks of memory with lots of sprites in,
+       and this is all well and good.  Until you want to add some more
+       without making the whole area move.
+
+       The problem becomes particularly awkward when you start writing
+       extendable applications (e.g., using Straylight's Dynamic Linking
+       System) and you want to allow each extension DLL to have its own
+       sprites file which are joined to the main one.
+
+       There are traditionally three possible solutions to the problem:
+
+        1. Forget it.  Force the sprites to be in the main application's
+           sprites file.  Extensions can't have their own sprites, or
+           they have to merge them with the main file at installation
+           time
+
+        2. Make the block bigger and then merge the files.  This will cause
+           your heap to fragment, and the sprite area to move, so you
+           mustn't have any windows created which use the sprite area.
+           Alternatively, you could put the sprite area at the bottom of a
+           shifting heap, and extend it there, so that the area itself
+           doesn't move.  This prevents you from having a non-shifting heap
+           there, though.  I think this is the approach which ArtWorks uses.
+
+        3. Make each extension have its own sprite area, which it has to
+           manage itself.  This makes it awkward to use shared sprites
+           from the kernel's sprite file, and can be wasteful of space.
+
+       Sprinkle is `Option 4 -- make the Operating System nicer.'
+
+_____________________________________________________________________________
+
+
+                              The basic concept
+
+       The whole problem outlined above is caused by the sprite areas being
+       in big contiguous blocks.  It would all go away if you could instead
+       put sprites into linked lists, which you could extend at run-time
+       without any of the heartache normally caused by this.  Sprinkle is
+       a small patch which allows you to link sprite areas together, so
+       you can access a sprite in any of the linked areas just by pointing
+       at the first one.
+
+_____________________________________________________________________________
+
+
+                          Linking your sprite areas
+
+       Sprinkle simply extends the functionality of OS_SpriteOp.  It doesn't
+       have any SWIs of its own.  It makes use of a special part of the
+       sprite area definition called the `extension area', which as far as
+       I can make out is not defined anywhere.
+
+       You identify a sprite area as being linked by putting the following
+       data into the extension area:
+
+               Offset  Size    Value
+               0       4       &4B4C5053 (`SPLK')
+               4       4       Address of next sprite area, or 0
+
+       The list is terminated either by a sprite area which doesn't
+       have this data in its extension area, or by a 0 pointer in its
+       link word.
+
+       Loading a sprite file into an area and allowing it to be linked is
+       fairly simple:
+
+       [In basic]
+
+       SYS "OS_File",17,name$ TO ,,,,sz%
+       DIM blk% sz%+16
+       blk%!0=sz%
+       SYS "OS_File",16,name$,blk%+4+8,0
+       blk%!4=blk%!12
+       blk%!8=24
+       blk%!12=blk%!20+8
+       $(blk%+16)="SPLK"
+       blk%!20=0
+
+       [In assembler]
+
+       ; On entry:     R0 == pointer to filename
+
+                       MOV     R1,R0
+                       MOV     R0,#17
+                       SWI     OS_File
+                       ADD     R0,R4,#16
+                       BL      alloc    ;allocate r0 bytes, return in r0
+                       STMFD   R13!,{R0}
+                       ADD     R2,R0,#12
+                       MOV     R3,#0
+                       MOV     R0,#16
+                       SWI     OS_File
+                       LDMFD   R13!,{R0}
+                       ADD     R14,R0,#12
+                       LDMIA   R14,{R1-R3}
+                       MOV     R2,#24
+                       ADD     R3,R3,#8
+                       LDR     R4,=&4B4C5053
+                       MOV     R5,#0
+                       ADD     R14,R0,#4
+                       STMIA   R14,{R1-R5}
+
+       ; On exit:      R0 == pointer to area
+       ;               R1-R5, R14 corrupted
+
+       (Obviously you need to do some more error checking than this code
+       has done.)
+
+_____________________________________________________________________________
+
+
+                                 Restrictions
+
+       Sprinkle isn't intended for really heavy use -- ensuring that all
+       the OS_SpriteOp calls worked exactly as expected on linked areas
+       would be fairly prohibitive in terms of effort.  Instead, it does
+       a `reasonable' job on the read-only SpriteOp calls.  It provides
+       enough support to allow you to use sprites from linked areas in
+       your dialogue boxes, and that's about it.  If you do try writing-
+       type operations which don't have enough memory, they will probably
+       fail with strange errors (like `Sprite not found').
+
+_____________________________________________________________________________
diff --git a/StraySrc/Libraries/Sapphire/Modules/Makefile,fe1 b/StraySrc/Libraries/Sapphire/Modules/Makefile,fe1
new file mode 100644 (file)
index 0000000..e5a4773
--- /dev/null
@@ -0,0 +1,124 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Various macros -------------------------------------------------------
+
+MODULES = Constrain Sprinkle
+
+#----- Compiling things -----------------------------------------------------
+
+all: $(MODULES)
+
+install: $(MODULES)
+       $(INSTALL) $(MODULES) <SSR$ModDir>
+
+clean:
+       -$(RM) o.* $(MODULES)
+
+#----- Modules --------------------------------------------------------------
+
+Constrain: o.constrain
+       $(SETDATE) o.conVersion \
+               version="Constrain\t1.00 $(MODDATE) $(CRIGHT)"
+       $(LD_MOD) o.constrain o.conVersion
+       $(SET_MOD)
+
+Sprinkle: o.sprinkle
+       $(SETDATE) o.sprVersion \
+               version="Sprinkle\t1.00 $(MODDATE) $(CRIGHT)"
+       $(LD_MOD) o.sprinkle o.sprVersion
+       $(SET_MOD)
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.sprinkle: s.sprinkle
+o.sprinkle: libs:header
+o.sprinkle: libs:swis
+o.sprinkle: libs:stream
+o.constrain: s.constrain
+o.constrain: libs:header
+o.constrain: libs:swis
diff --git a/StraySrc/Libraries/Sapphire/Modules/s/constrain b/StraySrc/Libraries/Sapphire/Modules/s/constrain
new file mode 100644 (file)
index 0000000..ed24078
--- /dev/null
@@ -0,0 +1,654 @@
+;
+; constrain.s
+;
+; Mouse movement constraining
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; Constrain is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Constrain is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Constrain.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               IMPORT  version
+
+;----- Module header --------------------------------------------------------
+
+               AREA    |!!!Module$$Header|,CODE,READONLY
+
+               DCD     0                       ;Start code
+               DCD     initialise              ;Initialisation routine
+               DCD     finalise                ;Finalisation code
+               DCD     0                       ;Service call handler
+               DCD     title                   ;Title pointer
+               DCD     version                 ;The help string
+               DCD     0                       ;No keyword table
+               DCD     &4A340                  ;SWI chunk number
+               DCD     swi_handler             ;SWI handler code
+               DCD     swi_decode              ;SWI decode table
+               DCD     0                       ;No decoding code needed
+
+title          DCB     "Constrain",0
+
+;----- Initialisation and finalisation --------------------------------------
+
+initialise     ROUT
+
+               STMFD   R13!,{R14}              ;Stack link register nicely
+
+               ; --- Get some workspace ---
+
+               MOV     R0,#6                   ;Allocate workspace
+               MOV     R3,#ws__wSize           ;Make it *this* big
+               SWI     XOS_Module              ;Get me memory
+               LDMVSFD R13!,{PC}               ;Return if it barfed
+               STR     R2,[R12]                ;Stash the workspace pointer
+               MOV     R12,R2                  ;Move the pointer across
+
+               ; --- Do some initialising ---
+
+               MOV     R14,#0                  ;No current constraint
+               STR     R14,ws__routine         ;Store that away
+
+               ; --- Done ---
+
+               LDMFD   R13!,{PC}^              ;Return to caller happy
+
+               LTORG
+
+finalise       ROUT
+
+               STMFD   R13!,{R11,R14}
+               MOV     R11,R12                 ;Keep the private word ptr
+               LDR     R12,[R12]               ;Find my workspace
+
+               BL      constrain_finish        ;Close any constraint
+
+               ; --- Free my workspace ---
+
+               MOV     R0,#7                   ;Free RMA space
+               MOV     R2,R12                  ;Point to workspace
+               SWI     XOS_Module              ;Try to free the memory
+               MOV     R0,#0                   ;Gonna zero the private word
+               STR     R0,[R11]                ;Then zero it
+               LDMFD   R13!,{R11,PC}^          ;A happy bunny
+
+               LTORG
+
+;----- SWI dispatching ------------------------------------------------------
+
+swi_decode     DCB     "Constrain",0
+               DCB     "Finish",0
+               DCB     "MousePos",0
+               DCB     "Circle",0
+               DCB     "Disc",0
+               DCB     0
+
+swi_handler    LDR     R12,[R12]               ;Get my workspace
+               CMP     R11,#(%01-%00)/4        ;Within range?
+               ADDLO   PC,PC,R11,LSL#2         ;Yes -- dispatch
+               B       %01                     ;No -- complain
+
+00             B       constrain_finish
+               B       constrain_mousePos
+               B       constrain_circ
+               B       constrain_disc
+
+01             ADR     R0,noSuchSWI            ;Point to the error
+               ORRS    PC,R14,#V_flag          ;And return with error
+
+noSuchSWI      DCD     &1E6
+               DCB     "Unknown Constrain operation",0
+
+;----- Main code ------------------------------------------------------------
+
+; --- divide ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         A standard divide routine.  Fairly speedy, hopefully.
+;              The results are always such that
+;
+;                      |quotient| <= |(divisor/dividend)|,
+;
+;                      |remainder| < |divisor|
+;
+;              and
+;
+;                      quotient * divisor + remainder == dividend
+
+divide         ROUT
+
+               STMFD   R13!,{R2,R3,R14}        ;Save some registers
+
+               ; --- A note about the method ---
+               ;
+               ; We use traditional long division, but unroll the loop a
+               ; lot to keep the thing ticking over at a good rate.
+
+               ; --- First, mess about with the signs ---
+
+               ANDS    R14,R0,#&80000000       ;Get the dividend's sign bit
+               ORR     R14,R14,R14,LSR #1      ;Copy -- this is sign of mod
+               RSBNE   R0,R0,#0                ;Take absolute value of R0
+               ANDS    R3,R1,#&80000000        ;Get the divisor's sign too
+               RSBNE   R1,R1,#0                ;Take absolute value of R1
+               EOR     R14,R14,R3              ;Calculate sign of quotient
+               MOV     R3,R1                   ;Look after the divisor
+
+               ; --- Shift divisor up for long division ---
+               ;
+               ; We keep shifting the divisor up until it's greater than
+               ; the dividend, and then we skip ahead to the divide section
+
+               MOV     R2,#0                   ;Quotient starts off at 0
+00divide       CMP     R0,R3,LSL #0
+               BLS     %10divide
+               CMP     R0,R3,LSL #1
+               BLS     %11divide
+               CMP     R0,R3,LSL #2
+               BLS     %12divide
+               CMP     R0,R3,LSL #3
+               BLS     %13divide
+               CMP     R0,R3,LSL #4
+               BLS     %14divide
+               CMP     R0,R3,LSL #5
+               BLS     %15divide
+               CMP     R0,R3,LSL #6
+               BLS     %16divide
+               CMP     R0,R3,LSL #7
+               MOVHI   R3,R3,LSL #8
+               BHI     %00divide
+
+               ; --- Now we have the shift-down loop ---
+               ;
+               ; This is where the actual job of dividing is performed.
+               ; We shift the divisor back down until it's back where we
+               ; started again.
+
+17divide       CMP     R0,R3,LSL #7
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R3,LSL #7
+16divide       CMP     R0,R3,LSL #6
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R3,LSL #6
+15divide       CMP     R0,R3,LSL #5
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R3,LSL #5
+14divide       CMP     R0,R3,LSL #4
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R3,LSL #4
+13divide       CMP     R0,R3,LSL #3
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R3,LSL #3
+12divide       CMP     R0,R3,LSL #2
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R3,LSL #2
+11divide       CMP     R0,R3,LSL #1
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R3,LSL #1
+10divide       CMP     R0,R3,LSL #0
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R3,LSL #0
+
+               CMP     R3,R1                   ;Have we finished dividing?
+               MOVHI   R3,R3,LSR #8            ;No -- shift down a byte
+               BHI     %17divide               ;And loop round again
+
+               ; --- Now tidy everything up ---
+
+               TST     R14,#&40000000          ;Is remainder to be negative?
+               RSBNE   R1,R0,#0                ;Yes -- negate it
+               MOVEQ   R1,R0                   ;No -- just copy it nicely
+               TST     R14,#&80000000          ;Is quotient to be negative?
+               RSBNE   R0,R2,#0                ;Yes -- negate it
+               MOVEQ   R0,R2                   ;No -- just copy it nicely
+
+               LDMFD   R13!,{R2,R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- divRound ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient, rounded to nearest integer
+;              R1 == remainder
+;
+; Use:         Calculates a rounded-to-nearest quotient, rather than one
+;              rounded towards zero, which is what divide returns you.
+;
+;              The remainder is fiddled during this process, so that the
+;              properties
+;
+;                      quotient * divisor + remainder == dividend
+;
+;              and
+;
+;                      |remainder| < |divisor|
+;
+;              still hold (so the remainder's sign may well change).
+
+divRound       ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,R0                   ;Keep a copy of the dividend
+               CMP     R1,#0                   ;Is the divisor positive?
+               MOVGE   R14,R1                  ;Yes -- just copy it
+               RSBLT   R14,R1,#0               ;No -- negate it on the way
+               CMP     R0,#0                   ;Is the dividend positive?
+               ADDGE   R0,R0,R14,ASR #1        ;Yes -- add half the divisor
+               SUBLT   R0,R0,R14,ASR #1        ;No -- subtract it
+               SUB     R2,R2,R0                ;Remember this difference
+               BL      divide                  ;Do the division
+               ADD     R1,R1,R2                ;Modify remainder suitably
+               LDMFD   R13!,{R2,PC}^           ;Return to caller
+
+               LTORG
+
+; --- sqrt ---
+;
+; On entry:    R0 == value to square-root
+;
+; On exit:     R0 == the result
+;
+; Use:         Evaluates the square root of the number given.  This routine
+;              is constructed from the information supplied by David Seal,
+;              and is *extremely* fast.
+
+               EXPORT  sqrt
+sqrt           ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack registers
+               MOV     R1,#0                   ;Result so far
+               MOV     R2,#0                   ;Current remainder
+               MOV     R3,#1                   ;A '01' pair
+               MOV     R4,#3                   ;A nice mask
+
+               GBLA    count
+count          SETA    0                       ;Start the count at 30
+
+               WHILE   count<=28               ;Set up the loop condition
+
+               AND     R14,R4,R0,LSR #30-count
+               ORR     R2,R14,R2,LSL #2
+               ORR     R14,R3,R1,LSL #2
+               CMP     R2,R14
+               ADC     R1,R1,R1
+               SUBCS   R2,R2,R14
+
+count          SETA    count+2
+
+               WEND
+
+               AND     R14,R4,R0
+               ORR     R2,R14,R2,LSL #2
+               ORR     R14,R3,R1,LSL #2
+               CMP     R2,R14
+               ADC     R1,R1,R1
+               SUBCS   R2,R2,R14
+
+c              MOV     R0,R1                   ;Put the result in R0
+               LDMFD   R13!,{R1-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- constrain_circ ---
+;
+; On entry:    R0 == x position of circle centre
+;              R1 == y position of circle centre
+;              R2 == radius of circle
+;              R3 == maximum distance below centre allowed
+;
+; On exit:     --
+;
+; Use:         Constrains the mouse to the given circle outline
+
+constrain_circ ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack some registers
+               BL      constrain_finish        ;Clear a current constraint
+               MUL     R14,R2,R2               ;Get the radius squared
+               MOV     R2,R14                  ;Put in back in R2
+               STMIA   R12,{R0-R3}             ;Store parameter in RMA ws
+               MOV     R0,#1                   ;Call this often
+               ADR     R1,constrain__circ      ;Routine to call
+               STR     R1,ws__routine          ;Remember this pointer
+               MOV     R2,R12                  ;Pass this R12 value
+               SWI     XOS_CallEvery           ;Call every 50cs
+               MOV     R0,#106                 ;Define mouse parameters
+               MOV     R1,#&81                 ;Pointer 1 -- de-linked
+               SWI     XOS_Byte                ;Do the OS_Byte call
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+; --- constrain_disc ---
+;
+; On entry:    R0 == x position of circle centre
+;              R1 == y position of circle centre
+;              R2 == radius of circle
+;
+; On exit:     --
+;
+; Use:         Constrains the mouse to the given circle outline
+
+constrain_disc ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack some registers
+               BL      constrain_finish        ;Clear a current constraint
+               MUL     R14,R2,R2               ;Get the radius squared
+               MOV     R2,R14                  ;Put in back in R2
+               STMIA   R12,{R0-R2}             ;Store parameter in RMA ws
+               MOV     R0,#1                   ;Call this often
+               ADR     R1,constrain__disc      ;Routine to call
+               STR     R1,ws__routine          ;Remember this pointer
+               MOV     R2,R12                  ;Pass this R12 value
+               SWI     XOS_CallEvery           ;Call every 50cs
+               MOV     R0,#106                 ;Define mouse parameters
+               MOV     R1,#&81                 ;Pointer 1 -- de-linked
+               SWI     XOS_Byte                ;Do the OS_Byte call
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+; --- constrain__circ ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Called on interrupts to constrin the mouse
+
+constrain__circ        ROUT
+               STMFD   R13!,{R0-R11,R14}       ;Stack some registers
+
+               SWI     XOS_Mouse               ;Get the current mouse pos
+10             LDMIA   R12,{R4-R6,R9}          ;Load interesting values
+               MOV     R10,#0                  ;Temporary flags word
+
+               ; --- Set R7 == horizontal distance from centre squared ---
+
+               SUB     R14,R0,R4               ;Get distance in R14
+               MUL     R7,R14,R14              ;Square it and copy
+               CMP     R7,#&10000              ;Is it too big?
+               MOVGT   R7,#&10000              ;Yes -- reduce (stop oflow)
+               LDR     R8,ws__oldX             ;Get the old x position
+               SUB     R8,R8,R4                ;Get the relative position
+               EOR     R8,R8,R14               ;See if top bit is changed
+               TST     R8,#(1<<31)             ;Test the top bit
+               ORRNE   R10,R10,#(1<<0)         ;Set the 'side changed' bit
+
+               ; --- Set R8 == vertical distance from centre squared ---
+
+               SUB     R11,R5,R9               ;Get actual maximum height
+               MUL     R8,R9,R9                ;Get the y distance squared
+               CMP     R1,R11                  ;Is it high enough?
+               MOVLE   R1,R11                  ;No -- then raise it
+               SUBLE   R7,R6,R8                ;Calculate the corner x pos
+               ORRLE   R10,R10,#2              ;Remember we made this bodge
+               SUBS    R14,R1,R5               ;Get distance in R14
+               BGE     %00constrain__circ      ;If in upper quadrants, skip
+               CMP     R8,R6                   ;Is there a sensible distance
+               BGT     %00constrain__circ      ;No -- skip this magic bit
+               TST     R10,#1                  ;Have we changed sides?
+               BEQ     %00constrain__circ      ;Nope -- skip ahead
+               LDR     R0,ws__oldX             ;Make sure were on correct sd
+               SUB     R7,R6,R8                ;Calculate the corner x pos
+               ORR     R10,R10,#2              ;Remember we made this bodge
+               B       %01constrain__circ      ;Skip next instruction
+
+00             MUL     R8,R14,R14              ;Square it and copy
+               CMP     R8,#&10000              ;Is it too big?
+               MOVGT   R8,#&10000              ;Yes -- reduce (stop oflow)
+
+01             ADDS    R9,R7,R8                ;Dist from centre squared
+               BEQ     %90constrain__circ      ;If 0, return
+
+               ; --- Don't allow a diagonal skip ---
+
+               TST     R10,#1                  ;Has x changed sides?
+               BEQ     %02constrain__circ      ;No -- forget this check
+               LDR     R14,ws__oldY            ;Get the old Y value
+               SUB     R3,R14,R5               ;Get distance from centre
+               MOV     R2,R1                   ;Get the new Y value
+               SUB     R2,R2,R5                ;Get the new distance
+               EOR     R3,R3,R2                ;Has sign bit changed?
+               TST     R3,#(1<<31)             ;Test it
+               BEQ     %02constrain__circ      ;No -- skip ahead
+               MOV     R1,R14                  ;Use this Y value
+               LDR     R0,ws__oldX             ;And this X value
+               SUB     R14,R0,R4               ;Get the hz distance
+               MUL     R7,R14,R14              ;And put the square in R7
+               SUB     R14,R1,R5               ;Get the vt distance
+               MUL     R8,R14,R14              ;And put the square in R8
+               ORR     R10,R10,#2              ;Force a *mouse* update
+               ADDS    R9,R7,R8                ;Dist from centre squared
+               BEQ     %90constrain__circ      ;If 0, return
+
+               ; --- Calculate corrected relative positions ---
+
+02             MOV     R2,R0                   ;Look after the original...
+               MOV     R3,R1                   ;... mouse position
+
+               MOV     R1,R9                   ;We'll need to divide by this
+               MUL     R0,R7,R6                ;Multiply up to give thing
+               BL      divRound                ;Do the main division
+               BL      sqrt                    ;And take the square root
+               CMP     R2,R4                   ;Which side of the centre?
+               ADDGE   R2,R4,R0                ;This is the x position
+               SUBLT   R2,R4,R0                ;This is the x position
+
+               MOV     R1,R9                   ;We'll need to divide by this
+               MUL     R0,R8,R6                ;Multiply up to give thing
+               BL      divRound                ;Do the main division
+               BL      sqrt                    ;And take the square root
+               CMP     R3,R5                   ;Which side of the centre?
+               ADDGE   R3,R5,R0                ;This is the y position
+               SUBLT   R3,R5,R0                ;This is the y position
+
+               ; --- Make sure y isn't too low now ---
+
+               CMP     R3,R11                  ;Is the y value too low?
+               MOVLT   R0,R2                   ;Yes -- get the new x and...
+               MOVLT   R1,R3                   ;... y coordinates
+               BLT     %10constrain__circ      ;And skip back round (yeuch)
+
+               ; --- Store the newly modified mouse positions ---
+
+               STR     R2,ws__oldX             ;Store the new pointer...
+               STR     R3,ws__oldY             ;...positions away
+
+               ; --- Now move the mouse pointer position ---
+
+               MOV     R0,#5                   ;OS_Word subreason code
+               ORR     R0,R0,R2,LSL #8         ;Move in the x position
+               ORR     R0,R0,R3,LSL #24        ;And the bottom of the y
+               MOV     R1,R3,LSR #8            ;Get the top of the y
+               STMFD   R13!,{R0,R1}            ;Save the block on the stack
+               MOV     R0,#21                  ;OS_Word main reason code
+               MOV     R1,R13                  ;Point to the new block thing
+               SWI     XOS_Word                ;Position the mouse pointer
+
+               ; --- Constrain the *mouse* to the circular band ---
+
+               SUBS    R14,R9,R6               ;f(distance from circumf.)
+               RSBLT   R14,R14,#0              ;Make sure it's positive
+               CMP     R14,#256                ;Is this within the band?
+               CMPLE   R10,#1                  ;Make sure we didn't bodge
+               MOVGT   R14,#3                  ;No -- move mouse position
+               STRGTB  R14,[R13,#0]            ;Store new subreason code
+               SWIGT   XOS_Word                ;And move the position
+
+               ADD     R13,R13,#8              ;Reclaim the OS_Word block
+90             LDMFD   R13!,{R0-R11,PC}^       ;Return to caller
+
+               LTORG
+
+; --- constrain__disc ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Called on interrupts to constrin the mouse
+
+constrain__disc        ROUT
+               STMFD   R13!,{R0-R11,R14}       ;Stack some registers
+               SWI     XOS_Mouse               ;Get the current mouse pos
+10             LDMIA   R12,{R4-R6}             ;Load interesting values
+               MOV     R10,#0                  ;Temporary flags word
+
+               ; --- Set R7 == horizontal distance from centre squared ---
+
+               SUB     R14,R0,R4               ;Get distance in R14
+               MUL     R7,R14,R14              ;Square it and copy
+               CMP     R7,#&10000              ;Is it too big?
+               MOVGT   R7,#&10000              ;Yes -- reduce (stop oflow)
+
+               ; --- Set R8 == vertical distance from centre squared ---
+
+               SUBS    R14,R1,R5               ;Get distance in R14
+00             MUL     R8,R14,R14              ;Square it and copy
+               CMP     R8,#&10000              ;Is it too big?
+               MOVGT   R8,#&10000              ;Yes -- reduce (stop oflow)
+
+01             ADDS    R9,R7,R8                ;Dist from centre squared
+               BEQ     %90constrain__disc      ;If 0, return
+
+               ; --- Calculate corrected relative positions ---
+
+
+02             MOV     R2,R0                   ;Look after the original...
+               MOV     R3,R1                   ;... mouse position
+
+               CMP     R6,R9                   ;Are we in the circle?
+               BGE     %03constrain__disc      ;Yes -- just move it then
+
+               MOV     R1,R9                   ;We'll need to divide by this
+               MUL     R0,R7,R6                ;Multiply up to give thing
+               BL      divRound                ;Do the main division
+               BL      sqrt                    ;And take the square root
+               CMP     R2,R4                   ;Which side of the centre?
+               ADDGE   R2,R4,R0                ;This is the x position
+               SUBLT   R2,R4,R0                ;This is the x position
+
+               MOV     R1,R9                   ;We'll need to divide by this
+               MUL     R0,R8,R6                ;Multiply up to give thing
+               BL      divRound                ;Do the main division
+               BL      sqrt                    ;And take the square root
+               CMP     R3,R5                   ;Which side of the centre?
+               ADDGE   R3,R5,R0                ;This is the y position
+               SUBLT   R3,R5,R0                ;This is the y position
+
+               ; --- Store the newly modified mouse positions ---
+
+03             STR     R2,ws__oldX             ;Store the new pointer...
+               STR     R3,ws__oldY             ;...positions away
+
+               ; --- Now move the mouse pointer position ---
+
+               MOV     R0,#5                   ;OS_Word subreason code
+               ORR     R0,R0,R2,LSL #8         ;Move in the x position
+               ORR     R0,R0,R3,LSL #24        ;And the bottom of the y
+               MOV     R1,R3,LSR #8            ;Get the top of the y
+               STMFD   R13!,{R0,R1}            ;Save the block on the stack
+               MOV     R0,#21                  ;OS_Word main reason code
+               MOV     R1,R13                  ;Point to the new block thing
+               SWI     XOS_Word                ;Position the mouse pointer
+
+               ; --- Constrain the *mouse* to the circular band ---
+
+               CMP     R6,R9
+               MOVLT   R14,#3                  ;No -- move mouse position
+               STRLTB  R14,[R13,#0]            ;Store new subreason code
+               SWILT   XOS_Word                ;And move the position
+
+               ADD     R13,R13,#8              ;Reclaim the OS_Word block
+90             LDMFD   R13!,{R0-R11,PC}^       ;Return to caller
+
+               LTORG
+
+; --- constrain_finish ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Finishes a constraining operation
+
+constrain_finish ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack some registers
+
+               ; --- Check whether there's a constrain on ---
+
+               LDR     R0,ws__routine          ;Check the routine
+               CMP     R0,#0                   ;Is there one going?
+               LDMEQFD R13!,{R0-R2,PC}^        ;No -- do nothing then
+
+               ; --- Remove the routine ---
+
+               MOV     R1,R12                  ;Pass this R12 value
+               SWI     XOS_RemoveTickerEvent   ;Call every 50cs
+               MOV     R0,#106                 ;Change mouse parameters
+               MOV     R1,#&1                  ;Pointer 1, linked
+               SWI     XOS_Byte                ;Do the thing
+
+               ; --- Clear the routine ---
+
+               MOV     R14,#0                  ;Clear the pointer
+               STR     R14,ws__routine         ;Store that away
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+; --- constrain_mousePos ---
+;
+; On entry:    --
+;
+; On exit:     R0 == x coordinate of pointer
+;              R1 == y coordinate of pointer
+;
+; Use:         Returns the current mouse position during a constrain
+;              operation.
+
+constrain_mousePos ROUT
+
+               ADR     R0,ws__oldX             ;Point to the coordinates
+               LDMIA   R0,{R0,R1}              ;And read them out
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+;----- Workspace layout -----------------------------------------------------
+
+               ^       0,R12
+
+ws__wStart     #       0                       ;The start of the workspace
+ws__parameters #       16                      ;Parameters for the constrain
+ws__routine    #       4                       ;The routine to call
+ws__oldX       #       4                       ;The old X coordinate
+ws__oldY       #       4                       ;The old Y coordinate
+
+ws__wSize      EQU     {VAR}-ws__wStart        ;The workspace size
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/Modules/s/sprinkle b/StraySrc/Libraries/Sapphire/Modules/s/sprinkle
new file mode 100644 (file)
index 0000000..e37b184
--- /dev/null
@@ -0,0 +1,157 @@
+;
+; sprinkle.s
+;
+; Handling of linked sprite areas (MDW)
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; Sprinkle is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sprinkle is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sprinkle.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  version
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |!!!Module$$Header|,CODE,READONLY
+
+               DCD     0
+               DCD     sl__init
+               DCD     sl__final
+               DCD     0
+               DCD     sl__name
+               DCD     version
+               DCD     0
+
+sl__name       DCB     "Sprinkle",0
+
+;----- Module header --------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- sl__init ---
+;
+; On entry:    --
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Initialises our module.
+
+sl__init       ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+               MOV     R0,#&1F                 ;SpriteV's vector number
+               ADR     R1,sl__spriteV          ;Point to my handler routine
+               MOV     R2,#0                   ;No workspace required
+               SWI     XOS_Claim               ;Try to claim the vector
+               LDMFD   R13!,{PC}               ;Return with that status
+
+               LTORG
+
+; --- sl__final ---
+;
+; On entry:    --
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Finalises our module when it's not needed any more.
+
+sl__final      ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+               MOV     R0,#&1F                 ;SpriteV's vector number
+               ADR     R1,sl__spriteV          ;Point to the handler routine
+               MOV     R2,#0                   ;No workspace passed
+               SWI     XOS_Release             ;Release the vector
+               LDMFD   R13!,{PC}^              ;Return without hassle
+
+               LTORG
+
+; --- sl__spriteV ---
+;
+; On entry:    R0 == reason code
+;              R1 == pointer to sprite area, normally
+;
+; On exit:     As for OS_SpriteOp
+;
+; Use:         Catches calls to OS_SpriteOp, to allow linked sprite areas.
+
+sl__spriteV    ROUT
+
+               TST     R0,#&100                ;Is it named/user area?
+               MOVEQS  PC,R14                  ;No -- pass on the call then
+
+               STMFD   R13!,{R10,R14}          ;Save some registers
+
+               ; --- See if this call needs a sprite area in R1 ---
+
+               AND     R14,R0,#&300            ;Get the magic extra bits
+               CMP     R14,#&100               ;Using a user area?
+               LDMNEFD R13!,{R10,PC}^          ;No -- then do nothing
+
+               BIC     R14,R0,#&300            ;Clear the magic bits
+               CMP     R14,#8                  ;Does call need area in R1?
+               LDMCCFD R13!,{R10,PC}^          ;No -- do nothing then
+
+               ; --- See if the sprite area is linked ---
+
+10sl__spriteV  LDR     R14,[R1,#8]             ;Load offset to first sprite
+               CMP     R14,#24                 ;Enough space for link?
+               LDMCCFD R13!,{R10,PC}^          ;No -- do nothing then
+
+               LDR     R10,[R1,#16]            ;Load first word of link
+               LDR     R14,sl__magic           ;Load the magic word
+               CMP     R10,R14                 ;Do these match?
+               LDMNEFD R13!,{R10,PC}^          ;No -- do nothing then
+
+               ; --- Now worked it out then ---
+
+               LDR     R10,[R1,#20]            ;Load the link pointer
+               CMP     R10,#0                  ;End of the list?
+               LDMEQFD R13!,{R10,PC}^          ;Yes -- do nothing then
+
+               ; --- Now call OS_SpriteOp and post-process ---
+
+               STMFD   R13!,{R0,R10}           ;Save reason code and link
+               MOV     R14,PC                  ;Get PC and flags in R14
+               ADD     R14,R14,#12             ;Point to postprocess code
+               STMFD   R13!,{R14}              ;Save those registers away
+               ADD     R14,R13,#12             ;Skip over stacked registers
+               LDMIA   R14,{R10,PC}^           ;And call OS_SpriteOp
+
+               ; --- Returned from OS_SpriteOp ---
+
+               LDMVSFD R13!,{R0,R1}            ;If failed, load link pointer
+               BVS     %10sl__spriteV          ;And loop backwards to next
+               ADD     R13,R13,#8              ;Point to old stack frame
+               LDMFD   R13!,{R10,R14,PC}^      ;And claim the call
+
+sl__magic      DCB     "SPLK"
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/README b/StraySrc/Libraries/Sapphire/README
new file mode 100644 (file)
index 0000000..c6a3f33
--- /dev/null
@@ -0,0 +1,1039 @@
+A very brief overview of Sapphire
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+_____________________________________________________________________________
+
+IS THIS ALL THERE IS?
+
+
+The Grand Plan was to write a really good library, sell some spiffy
+applications which used it, and then sell the library.  This
+spectacularly failed to work, mainly because we had no ideas for killer
+applications.  The result is Sapphire.
+
+Since we'd planned to write some big applications before releasing
+Sapphire to anyone else, we took a rather relaxed attitude to
+documentation.  There is some LaTeX documentation lying around, but
+mostly it's initial versions of things, with big gaps where less
+interesting text should be filled in later.  In short, it's no use to
+anyone.
+
+On the other hand, we realised that a library of this complexity with no
+documentation at all would be a total disaster, so all the header files
+are profusely commented, mostly to the standard of a final-copy
+reference manual.
+
+This text file is intended as a brief hacker's eye view of how to write
+Sapphire applications, and how some of the more complicated and/or
+interesting bits work.
+
+_____________________________________________________________________________
+
+ABOUT THE AUTHORS
+
+
+Sapphire was designed and written, over the course of a couple of years,
+by Mark Wooding and Tim `Tycho' Armes.  Each source file usually bears
+the initials (`MDW' or `TMA') of the person mainly responsible for
+writing it.  In some cases, this is misleading.  For example, although
+the `msgs' code for translating message tokens into strings is labelled
+`MDW', the first two versions of this file were written by Tim: I took
+over later because I rewrote it to kill the bugs.  Similarly, the fact
+that one of us wrote a source file doesn't tell you who designed it. For
+example, the `menu' code was entirely written by Tim, although we both
+worked on the design for several days beforehand.
+
+_____________________________________________________________________________
+
+A HISTORY LESSON
+
+
+Sapphire is an attempt to learn from the experience we both had with
+STEEL.  STEEL (Straylight's Extensive Event-driven Library) is a
+more-or-less complete re-write of RISC_OSLib, and although it had given
+up being call-compatible, and had diverged quite considerably by the
+release of Desktop C, it suffered because of the limitations of its
+structure.  All the original non-RISC_OSLib code had been written by me,
+in a rather ragged way.
+
+The name Sapphire comes from the old ITV sci-fi series `Sapphire and
+Steel', obviously.  It's a rotten joke, but that's what you get when you
+think up names for libraries in a pub.  The idea was that two of us
+could do much better than either acting alone, by bouncing ideas between
+each other until we sorted out the problems.  We threw out any thought
+of compatibility with any existing software, and any hope of interfacing
+a high-level language.  Then we started coding.
+
+_____________________________________________________________________________
+
+INFLUENCES
+
+
+The design of Sapphire has been influenced by looking at lots of other
+pieces of software.  A lot of structure is based on RISC_OSLib: STEEL
+was derived from RISC_OSLib, and it did a lot of things right.  Another
+particularly strong influence is Computer Concepts' Advanced Box
+Interface (ABI) as used in Impression and ArtWorks.  (I even went as far
+as buying the ArtWorks SDK more-or-less to get my hands on some ABI
+documentation.)  There was an influence from what I perceived to be `the
+way OS/2's Presentation Manager does it', although this wasn't always
+positive.
+
+_____________________________________________________________________________
+
+SUPPORTED LANGUAGES
+
+
+Sapphire supports ARM assembler.  That's about it.  One of the last
+Sapphire-related projects was interfacing C to Sapphire; this is still
+mostly incomplete.  The basic job of making C code call Sapphire code
+and vice-versa is finished and reliable.  The hard bit, handling
+Sapphire-style definition tables, isn't even begun yet.
+
+One of the projects I set myself over a year ago was a language, then
+called `cdata', which would act as a pre-processor for C and allow
+definition tables to be created without the amount of pain currently
+required.  (If you don't believe me, see the definition of the icon bar
+menu in the `csapph' test program.)
+
+_____________________________________________________________________________
+
+THE SAPPHIRE ENVIRONMENT
+
+
+Sapphire doesn't use APCS.  Let's get that clear right away.  You try to
+use APCS, and Sapphire will hate you for the rest of your life.
+
+Because the target language is assembler, Sapphire itself sometimes
+plays fast and loose with the rules, but the basic ideas, such as they
+are, are presented here.
+
+Registers R10-R15 are assigned special purposes.
+
+For architectural reasons, R15 is the program counter, and R14 is the
+subroutine link register.  Because R14 is modified by subroutine calls,
+it is often used as a temorary register in computations.
+
+R13 points to a full descending stack.  Sapphire doesn't allocate a very
+big stack unless you ask it to, so be careful with recursion.  There's
+no stack limit checking either.
+
+R10 and R12 provide the program's current state.  R12 is the `workspace'
+pointer, and R10 is the `object' pointer.  The idea is that R12 points
+to a statically allocated data block, and R10 points to a `currently
+interesting object'.  For example, in a multi-document editor, R10 would
+point to an information block describing the document currently being
+processed.  Because it's important to hide information between
+components of a program, different components have different workspace
+areas.  Similarly, different parts of a program see the world at
+different levels: the part of a drawing program which is concerned with
+file-level operations keeps R10 as a pointer to the document anchor; the
+part concerned with manipulating individual objects within a document
+might keep R10 referring to an object.  Note that R10 and R12 rarely
+take part in inter-component interfaces.  Object handles are passed
+between components in low-numbered registers, as normal arguments, and
+then copied into R10 later.
+
+R11 is Sapphire's `application context' pointer.  It's also known as the
+`scratchpad' pointer.  From R11 upwards is the `scratchpad': a block of
+memory available for any purpose.  Any procedure may corrupt the
+scratchpad, so it's never safe to assume that it is preserved over
+inter-component calls.  Immediately below R11 are workspace offsets.
+These allow Sapphire and its client applications to find statically
+allocated workspace.  If R11 is pointing to the wrong place, Sapphire
+will crash!
+
+On a procedure call, this is what usually happens:
+
+  R0--R9 == arguments
+  R10, R12 == variables owned by caller
+  R13 == pointer to full descending stack
+  R11 == application context pointer (Scratchpad)
+
+On return:
+
+  R0--R9 == return values, or usually preserved
+  R10, R12 preserved
+  R13 == preserved
+  R11 == application context pointer
+  Flags either preserved or set as a return value
+
+Sapphire's fond of returning information in the flags.  For example, if
+you ask for memory and there isn't any, allocation functions return with
+carry set.  Sometimes, errors are returned in the normal way, by setting
+overflow and pointing R0 at an error block.  If you don't return
+something useful in a flag, preserve it.
+
+Sapphire behaves slightly different when it's calling its client back.
+When you register a handler function, you supply a pointer to the code,
+and R10 and R12 values to pass it.  It will ensure that these values are
+in those registers at call time.
+
+_____________________________________________________________________________
+
+SAPPHIRE'S MEMORY MAP
+
+
+Sapphire has strong ideas about how an application's memory is laid out.
+Here's a poor attempt at a diagram:
+
+
+                   _____________  <--- Top of current wimpslot
+                  |             |
+                  :    Flex     :
+                  :    heap     :
+                  |             |
+                  |-------------|
+                  |  Resizing   |
+                  |    heap     |
+                  |-------------| <--- Top of initial wimpslot
+              R13 |    Stack    |
+                  |-------------|
+              R11 | Scratchpad  |
+                  | App context |
+                  |-------------|
+                  |             |
+                  |Default heap |
+                  |             |
+                  |-------------|
+              R12 |  Workspace  |
+                  |-------------|
+                  | Application |
+                  |    code     |
+            &8000 |_____________| <--- Base of application memory
+
+
+Hmmm.  Not too shabby.
+
+Now, in words:
+
+During initialisation, Sapphire's kernel finds the top of available
+memory and puts the stack there, growing downwards.  Below the stack, it
+allocates the scratchpad area, so that there's a small amount of `slop'
+between the the stack growing down and the scratchpad growing up.  The
+kernel then examines the available library components, and allocates
+workspace for them, starting just above the application's read-write
+area.  (A Sapphire application shouldn't actually have any read-write
+data -- R12-space is a much better way of doing the same job.)  Once
+that's done, it initialises an OS_Heap heap between the top of workspace
+and the bottom of the application context area just below the
+scratchpad.  This is the `default heap'.
+
+Above the initial wimpslot is Flex space.  Flex is Sapphire's shifting
+heap manager.  It's named after RISC_OSLib's shifting heap, although
+it's completely rewritten, and much extended.  Flex has complete control
+over the area above the initial wimpslot.  The first Flex block is taken
+by a resizing heap manager, which creates a nonshifting heap there. This
+is registered automatically with Sapphire's allocation manager, so you
+can forget about it completely.
+
+This brings me on to...
+
+_____________________________________________________________________________
+
+MEMORY MANAGEMENT
+
+
+Sapphire sees three sorts of memory:
+
+  * Static memory.  This is allocated at initialisation time by the
+    kernel, and put into the workspace area.  R12 points here.
+
+  * Fixed-size blocks representing objects.  These are allocated and
+    freed at run-time by the program, using Sapphire's allocation
+    manager.  R10 points to one of these, usually.
+
+  * Large or variable-size blocks representing data.  These are
+    allocated and freed by the program using Flex.
+
+Typically each large block in Flex-space has an accompanying `anchor'
+block in heap-space.
+
+The allocation manager attempts to paper over the mess involved with
+having more than one nonshifting heap.  STEEL actually does this job
+better, putting the client in control of where blocks get allocated.
+Sapphire's approach, to fill up one heap and move on to the next, is
+simpler, but can lead to fragmentation.
+
+_____________________________________________________________________________
+
+INITIALISATION
+
+
+RISC_OSLib (and STEEL) programs start off with a huge chunk of
+initialisation code, most of which is really boring:
+
+       wimpt_init("progname");
+       dbox_init();
+       win_init();
+       /* ... */
+
+Sapphire gets rid of all that by using a neat feature of AOF.  Each
+library component, or `unit' as we called them, contains a four-word
+table entry.  The linker collects the entries together, and the kernel
+can examine them all to see which units are linked in.  Each entry
+contains:
+
+  * The address to store the unit's workspace offset.
+  * The size of workspace required.
+  * Minimum acceptable Scratchpad size (if more than 256 bytes).
+  * Address of initialisation procedure.
+
+By convention, the first word of a unit's workspace contains flags, bit
+zero of which indicates that the unit has been initialised.  A unit's
+initialisation procedure performs the following actions:
+
+  * It checks it's not already initialised.
+  * It initialises anything it depends on (this causes the required
+    units to be linked too).
+  * It initialises itself.
+  * It sets its initialised flag and returns.
+
+Library initialisation is a two-step process.  The first step,
+`sapphire_init', initialises the kernel and the basic memory map.  The
+second step, `sapphire_libInit', initialises the library units.
+
+_____________________________________________________________________________
+
+DYNAMIC LINKING
+
+
+The original idea was that Sapphire would be really small.  Well, take a
+look at its feature set and tell me that it's big.  So we paid no
+attention to making Sapphire dynamically linkable.  When it became
+obvious that this wasn't working properly, I started investigating
+methods for making Sapphire into a DLL.
+
+I was saved by two features of Sapphire code:
+
+  * Sapphire programs preserve R11 everywhere.
+  * Sapphire's kernel allocates workspace for the units at run-time.
+
+The first fact gives me re-entrancy automatically.  R11 becomes the one
+thing that the dynamically-linked Sapphire library can use to decide
+where its workspace is.
+
+Finding workspace is rather grubby in Sapphire, so it's hidden beneath a
+macro.  For the curious, this is what happens:
+
+               LDR     R12,workoff_addr
+               LDR     R14,[R11,#-magic_offset]
+               ADD     R12,R14,R12
+
+The trick works because the allocation of workspace /offsets/ depends
+only on the order of units within the library, so they can be shared;
+the value loaded from R11-space is worked out by the kernel and put in
+application memory on startup.
+
+Most of the kernel ends up in the DLL.  The application is linked
+against a really small stub, which basically contains front ends for a
+few kernel functions to (maybe) find the Sapphire DLLs, point to a
+collection of tables, and call the corresponding function in the core.
+
+The exact mechanism is complicated.  Interested readers are referred to
+the source code.
+
+The upshot of all of this is that, although SDLS was designed
+specifically to solve the problem of APCS shared libraries, Sapphire's
+style of shared library requires much less code to be linked into the
+client, much thinner veneering (because the kernel handles re-entrancy),
+and the result is both more robust and cleaner.
+
+_____________________________________________________________________________
+
+ERROR HANDLING
+
+
+Sapphire programs know about two sorts of errors:
+
+  * Program errors, which should never occur.
+  * Environmental errors, which must be anticipated.
+
+Environmental errors are reported by setting the V flag on exit from a
+function.  Sapphire routines are documented according to whether they
+can return errors: it is safe to ignore the V flag on exit from a
+routine whose documentation does not state that it returns errors. An
+environmental error typically requires some sort of user intervention,
+and suggests a friendly explanation that some sort of fault has
+occurred.
+
+Program errors are raised by OS_GenerateError and caught by Sapphire's
+error handler.  There's a rule of thumb which states: `Never test for an
+error you can't handle.'  Sapphire follows this advice.  Most calls to
+the operating system have the X bit clear, causing errors to be sent to
+the error handler.  Program error messages are intentionally technical.
+The idea is to encourage naive users to write them down, so that they
+remember them and report them accurately.
+
+Part of the initial design was that a Sapphire application should
+/never/ exit as a result of program fault.  A user should always be able
+to try to get to a save box and save data.  (Too much experience of
+Paint falling over with type 5s prompted this decision.)  The
+application pops up an error report giving the user a choice between
+killing the program or trying to soldier on.  Soldiering on seemed
+remarkably successful in general.
+
+A later addition to Sapphire was `Structured Exception Handling', which
+is a lower-level version of C++'s try/throw/catch exception handling.
+This builds upon the existing base, and allows programs to tidy up in
+the event of errors before propagating them back down to the bottom
+level `Continue/Quit' handler.
+
+
+This concludes the tour of Sapphire's run-time support functionality.
+The rest describes plain ol' library features.
+
+_____________________________________________________________________________
+
+EVENT HANDLING
+
+
+Sapphire has a fairly simple but highly effective strategy for dealing
+with events, inspired in part by the FilterManager module in RISC OS 3.
+
+The `event' unit is responsible for low-level event handling.
+Applications call `event_poll' instead of calling the SWI Wimp_PollIdle
+directly; the calling sequences are almost the same for both routines.
+`event_poll' returns C set if it handled the event itself, and C clear
+if it failed to handle it.  A defalt handler procedure is provided to
+perform any required actions for a particular event.  A Sapphire
+application's poll loop typically looks like this:
+
+loop           BL      event_poll
+               BLCC    handle_unknowns
+               BLCC    defHandler
+               B       loop
+
+and that's it.
+
+Most of the hard work is done by filters.  Sapphire knows about three
+types of filters:
+
+  * Pre-filters are shown arguments to Wimp_Poll before it's called, and
+    can modify them in controlled ways, e.g., clearing event mask bits,
+    or changing the `time-to-return' argument.  A pre-filter can
+    `claim' a call to Wimp_Poll by storing a `fake' event in the buffer
+    and returning carry set.  Other pre-filters are skipped, and the
+    fake event is passed to the post-filters.
+
+  * Post-filters are shown the result from a call to Wimp_Poll.  They
+    can perform any action they like, except for modifying the event.  A
+    post-filter can claim an event by returning C set; other
+    post-filters are not called, and `event_poll' returns C set.
+
+  * Fake-event filters are a novel idea introduced to handle transient
+    dialogue boxes.  Immediately after a return from Wimp_Poll, Sapphire
+    scans the list of fake-event handlers.  Each one is entitled to
+    `steal' this event and replace it with another by returning carry
+    set.  Once an event has been stolen, it is passed through the
+    post-filters.  When `event_poll' is called again, Sapphire
+    restores the previous genuine event and continues calling fake-event
+    filters from the point at which it left off.  Thus, Sapphire
+    provides a general mechanism for inserting events.
+
+Everything else is based off this mechanism.
+
+The `win' unit dispatches window-specific events to window handlers by
+registering a post-filter.  The `menu' unit also establishes a
+post-filter, and passes events to the owner of the current menu.
+
+The main use for fake-event handlers is to handle transient windows.  A
+separate Sapphire unit, `transWin', remembers the handle of the current
+transient window.  When an event arrives, its fake-event handler checks
+whether the transient window is open.  If it has been closed, it steals
+the event, whatever it was, and substitutes a fake `window close' event
+to be picked up by the owner of the transient window.
+
+[Actually, `transWin' is careful to allow redraw events through
+unmolested.  Bad window flicker results if redraw requests are tampered
+with.]
+
+_____________________________________________________________________________
+
+MENUS IN SAPPHIRE
+
+
+Sapphire knows about two types of menus, and its interface to
+applications reflects this.  Standard RISC OS transient menus will be
+familiar to most readers.  Straylight tearoff menus will be less well
+known -- see Glass for a real-life example of tearoff menus in action.
+
+Sapphire's interface to handling menus is inspired by Computer Concepts'
+Advanced Box Interface system.  Menus are always constructed
+dynamically, as needed.  The procedure `menu_create' is given four
+arguments:
+
+  * The address of a menu definition.
+  * The address of a menu event handler.
+  * R10 and R12 values to pass to the handler.
+
+The `menu_create' procedure may be called any number of times before the
+next Wimp_Poll: the menu definitions are concatenated.  This allows
+applications to create dynamic and context-sensitive menus easily.
+
+The first `menu_create' call is different from the others: the menu
+definition must contain a menu title.  (It need not contain any menu
+items, though.)  Both the menu title and the items are /variable size/
+objects -- the more odd features a menu item has, the more space its
+definition occupies.  Menu definitions are also /read-only/.  Dynamic
+features like ticking and shading must be handled separately.
+
+Each menu item (and title) is begun with a `feature mask' -- a word
+containing a flag bit for each feature.  The feature mask is followed by
+data appropriate to the various features selected.  For example, the
+`has a submenu' feature requires a pointer to the submenu definition and
+a pointer to the procedure which will handle events for the submenu.
+
+Menu features which require dynamic information (e.g., context-sensitive
+message strings, or ticking and shading) have, as part of their feature
+data, offsets from the menu handler's R10 containing the required
+information.  The `shade item' feature requires an offset from R10 and a
+bit position -- it will shade the item when the appropriate bit in the
+word at [R10, #offset] is set.  Sapphire's menu system understands the
+concept of `radio items' -- groups of items of which only one may be
+ticked at a time.  The feature data for a radio item consists of an R10
+offset and a value to match -- the application then sets [R10, #offset]
+to be (for example) 0 for the first item in the group, 1 for the second,
+and so on.
+
+It's important to get the hang of the concepts here, because lots of
+other bits of Sapphire use this same idea.
+
+The `menuDefs.sh' header file contains a large number of macros which
+hide most of the mess of this.
+
+_____________________________________________________________________________
+
+DIALOGUE BOXES
+
+
+Sapphire's dialogue box handling is extremely powerful.  There's also a
+lot of code in `dbox.s' which does jobs that the WindowManager ought to
+do, or does wrong.
+
+Dialogue boxes are `resources'.  Sapphire tries to keep the
+interface to handling resources consistent.  When you want one, you
+`create' it, and when you don't need it any more, you `destroy' it.
+A successful `create' of a dialogue box yields a `dbox' -- a handle
+which represents the dialogue box.
+
+Sapphire is carefully constructed so that dialogue boxes don't need to
+exist unless they're actually in use.  Most programs create dialogue
+boxes only when they need to appear on-screen, and destroy them again
+once they're closed.  To this end, Sapphire generates fake close events
+for transient windows.
+
+Dialogue boxes can be created from several different sources of
+information, and to handle this, there are actually three different
+`create' routines:
+
+  * `dbox_create' is the standard call.  A client passes a string naming
+    the template from which to create the dialogue, and the dialogue box
+    manager returns a handle.  The window definition is copied, along
+    with all the indirected data, so that you can create multiple
+    instances of a template without tripping over aliasing problems.
+
+  * `dbox_fromEmbedded' creates a dialogue from an `embedded template'
+    -- a compact and easily expanded representation of a window template
+    which is statically linked into the client program.  Again, the data
+    is copied from the template, so aliasing problems don't exist.
+
+  * `dbox_fromDefn' is the most powerful call (and the others are
+    implemented in terms of it).  The client passes a pointer to a
+    complete window definition, which the Sapphire uses `as is',
+    without copying it.
+
+Embedded templates were introduced for very small programs (e.g.,
+DLLMerge).  Sapphire makes use of them because common dialogue boxes
+have been stored in a shared `Sapphire.Resources' DLL as embedded
+templates.  This makes programs easier to upgrade for new versions of
+Sapphire (just copy the new DLLs in and you get the new dialogues free)
+and reduces resource requirements since there's only one copy in memory
+at any given time.
+
+Displaying dialogue boxes introduces more flexibility.  The procedure
+`dbox_open' is given a dbox and an `open style', and a collection of
+arguments appropriate to the style.  Styles permitted are:
+
+  * In its current position (or in the position it was in the template
+    file).
+
+  * In the middle of the screen.
+
+  * Centred over the mouse pointer.
+
+  * At a given Y coordinate (but the current X coordinate).
+
+  * At a given X and Y position.
+
+The open style also contains a `transient or persistent' flag, which is
+useful for dialogue boxes hanging off of menu items.  If a menu is open
+currently, Sapphire will automatically open the dbox as a submenu, in
+the correct place, unless you explicitly instruct it not to do this
+using another open style bit.
+
+Sapphire doesn't pass Wimp events directly on to client event handlers.
+Instead, it pre-processes them, putting the important information from
+the event into registers, and sending a `dbox event' to the handler.
+The handler can then either `claim' the event for itself (by saying that
+it's handled it) or pass it on.  Unclaimed events are acted upon by
+Sapphire.
+
+As an example of the sort of preprocessing Sapphire does for dialogue
+box events, it breaks a redraw request into an individual event for each
+rectangle.  If its redraw events are unclaimed (as they ought to be), it
+will call Sculptrix to fill in the 3D borders around the icons.
+
+Sapphire handles radio buttons itself, if click events on them are
+unclaimed.  Using type-11 buttons and a non-zero ESG means that the user
+can deselect all buttons in a set by clicking the selected one with
+`adjust'.  An application can deal with this by selecting the icon
+explicitly, but (a) this causes flicker, and (b) if the application is
+going to the trouble of having explicit code to deal with the situation,
+it may as well do the job properly.  Sapphire considers an icon with
+button type 3 and non-zero ESG to be a `Sapphire radio button' and does
+the right thing with it.
+
+Shaded icons are also handled by Sapphire rather than the Wimp, because
+the standard behaviour is highly inconsistent.  For example, sometimes
+icon backgrounds are shaded in addition to foregrounds.  In text-and-
+sprite icons, the text is /not/ shaded when it ought to be (for
+consistency with text-only icons).  It's basically a mess.  Sapphire
+uses a complicated shading algorithm which seems fairly close to the
+behaviour of ABI.
+
+Sapphire also handles caret blinking and cursor changing over writable
+icons automatically.
+
+Keypresses also receive default handling from Sapphire.  Unclaimed
+cursor keys cause the caret to move between writable icons, scrolling
+the window where necessary (both horizontally and vertically) to ensure
+that the new focus icon is visible.
+
+The procedure to set a string in an indirected icon is probably
+excessive.  It ensures that the string really needs changing before
+flickering the icon.  It truncates the string rather than overflowing
+the icon's buffer, discarding either the start or the end depending on
+the icon's `right align' flag, optionally putting a `...' to indicate
+that a truncation was performed.
+
+Sapphire inherited a curious feature called `embedded titles' from
+STEEL, which in turn was inspired by RISC OS version of the game
+`Elite'.  A client nominates an icon within a window which has no title
+bar as being an `embedded title'.  Sapphire will thereafter
+automatically draw a Sculptrix group box around this icon, using the
+window's real title text as the group title.  This is used in `Info'
+windows, as well as the warning, note and error windows.
+
+Sapphire can handle `nonpolling' windows.  In some cases it's desirable
+to arrest the user's attention by requiring acknowledgement of a message
+or the taking of a decision, and sometimes continuing to poll would be
+dangerous or undesirable for other reasons.  For example, a serious
+error report mustn't multitask, because the error might recur.  The `To
+save...' message caused by attempting to save a file without a full
+pathname shouldn't multitask, because the click on the OK button will
+close the menu tree (which is extremely irritating).  The only way to
+handle a prequit message under RISC OS 2 is to ask the user whether
+quitting is permitted in a nonpolling way, so the decision to cancel a
+shutdown sequence can be made before an acknowledgement is returned to
+the task manager.  The handling for nonpolling windows is split into two
+parts.  The `nopoll' unit displays dialogue boxes and reports mouse
+clicks and keypresses as fake events through Sapphire's pre-handler
+mechanism (so nonpolling dialogues present an identical programmer
+interface to normal ones).  The `buttons' unit displays a given
+dialogue, permitting a collection of action buttons to be given
+appropriate pieces of text.
+
+The real richness of Sapphire's dialogue box handling comes from custom
+controls.  A whole subsystem, `dbx' is provided for dealing with custom
+controls.
+
+The client registers a table defining the required controls for a
+particular dialogue box.  The table contains variable size entries, each
+one beginning with a standard header:
+
+  * Number of the icon which hosts the control.
+  * Pointer to the control definition.
+  * Various flags (control specific).
+  * The offset of the control's writable data within the dialogue
+    handler's R10-space.
+
+This is followed by whatever constant data the control handler requires.
+Sapphire dbx controls are always hosted by icons.  This makes them easy
+to lay out in template editors.
+
+Custom controls generate their own events which are sent to the client's
+handler procedure.  They are also given dialogue box events (after the
+client has had a chance to claim them for itself) as `dbx events'.  For
+example, Sapphire will only ask a control to draw itself if (a) the
+control requests redraw events and (b) the current rectangle intersects
+the control's host icon.
+
+Sapphire takes redrawing of controls very seriously.  It ensures that
+the graphics clipping area is set to the intersection of the control's
+host icon and the redraw rectangle, to prevent any `accidents' from
+messing up the rest of the display.  It passes this amended rectangle to
+the control to allow it to perform source-level clipping.  The custom
+RGB-coloursquare and HSV-colourcircle controls in the (unfinished)
+colour selector use the provided rectangle to plot the new graphics by
+direct screen access.
+
+Predefined custom controls are:
+
+  * A slider.  This is written very carefully to avoid any flicker while
+    the bar is being dragged or updated.
+
+  * A `bump' arrow button, which presses its icon in while it's being
+    held down, and autorepeats.  The arrow control keeps a count of how
+    many `ticks' have been missed, and sends them to the dialogue box as
+    large packets, rather than individually.  This makes programs which
+    spend a long time processing bump requests feel responsive even when
+    they're really being slow.
+
+  * A file icon, which represents a filetype in a window.  File icons
+    can optionally be draggable (for save operations).  When solid drags
+    are requested by the user (and the DragASprite module is available),
+    the control will make the icon disappear while the icon is being
+    dragged, to produce the illusion of the icon being `lifted off' the
+    dialogue box.
+
+  * A `string set' control, which drops down a menu of strings and
+    allows the user to choose one, which it displays.
+
+  * A simple `colour pot' which allows a user to choose one of the
+    sixteen standard Wimp colours.  This control pops open a small
+    dialogue box of its own when requsted.
+
+Custom controls provide a great deal of functionality at very little
+programmer effort.  Why no other library for RISC OS handles them
+properly is a mystery to me.  The Toolbox has a go, but fails miserably;
+compared to the power of Sapphire's `dbx' subsystem, it might as well
+not bother.
+
+(Sapphire was mature when the Toolbox betas were available.  The idea
+for proper custom controls came from OS/2, but the implementation is
+very much in Sapphire's own style.)
+
+_____________________________________________________________________________
+
+DATA TRANSFER
+
+
+It used to be the case that data transfer was one of the really hard
+bits of an application.  I remember trying to put it off as long as
+possible whenever I wrote a STEEL application.  Sapphire tries very hard
+to make data transfer as painless as possible.
+
+Both loading and saving have two layers to them.  Underneath, there's a
+low-level interface which exposes the nature of the transfer (whether
+it's to a file, or in-memory).  Above that, there's an abstract
+interface which presents both transfer types as a (non-seekable) stream
+of data, providing buffering and a simple programming interface.  This
+high-level interface works perfectly well on files even without a data
+transfer context, and occasionally gets (ab)used as a general stream
+interface to file data, for example, when saving preferences files.
+
+The lower-level code was designed to be useful both in conjunction with
+the high-level interfaces and on its own.  Often, the low-level
+interface is the better choice.
+
+Oddly, the low-level interface is higher-level than RISC_OSLib's.
+
+A low-level data save operation is initiated by the `save' call.  It
+requires a large number of arguments, detailing the recipient's window
+handle, the filename, filetype, and a block of handling routines.  The
+handling routines are:
+
+  * Save: write your data to a file, given its name.  Return an error if
+    saving failed.
+
+  * Send: return (giving a base pointer and size) a block to send to the
+    recipient.  Return CS if this is the last block, or CC if there's
+    more to come.  The first time this handler is called, it's given the
+    value 0 in R2; after that, the return value of R2 is passed back in
+    the next call, to provide some sort of context.  It's called over
+    and over until either the recipient complains or the handler returns
+    end-of-data.
+
+  * Success: the data was transferred successfully (and may or may not
+    be permanently safe).
+
+  * Failed: the data transfer failed, either because of a local error,
+    or because the receiver failed.
+
+Note that the `send' handler can return a block of any size.  It's
+Sapphire's responsibility to handle the recipient's buffer size.  In the
+case where all the data is in one big flex block, the send routine
+becomes trivial.  Sapphire makes RAM transfer /easier/ than writing to a
+file!
+
+Loading data in similar in spirit.  There's a single routine, `load',
+which is given a block of handlers:
+
+  * InitBuf: create a buffer in which to receive data, and perform any
+    other setting up necessary to start a RAM transfer.  The handler is
+    given an estimated file size, and the proposed leafname.
+
+  * KillBuf: RAM transfer has failed, so destroy the buffer (if it was
+    only temporary).  This is called when RAM transfer was unsuccessful
+    for some reason.
+
+  * Extend: the current buffer was filled: I need a new one.  (It's
+    called `extend' because the normal reaction is to extend a flex
+    block and return the new area.)
+
+  * DoneBuf: RAM transfer has succeeded, so do whatever's necessary.
+    (Typically, an application might free some `slop space' at the end
+    of the buffer.)
+
+  * File: load the data from a given file.
+
+  * Done: data transfer succeeded.
+
+  * Failed: data transfer failed, either because of something we did
+    wrong or because the sender had problems.
+
+Sapphire provides routines to do most of the work of the InitBuf,
+KillBuf, Extend, DoneBuf and File handlers in the case where we're just
+loading directly into a flex block, and in many cases, the
+supplied KillBuf, Extend and DoneBuf routines can be used directly.
+
+The higher-level interfaces `xsave' and `xload' are designed to link
+onto the low-level interfaces, and provide handlers which can (in many
+cases) be given directly to the low-level calls.  They take as an
+argument a tranfer routine, which is called to do the actual save or
+load operation.  It is called just like a normal subroutine.  When it
+returns, the transfer is ended.  It calls `xsave' or `xload' routines
+to read and write bytes, words, strings or whole blocks of memory;
+Sapphire buffers data where this would be useful.  Sapphire provides a
+separate stack for the transfer routine, so that the read or write
+routines can pause for a Wimp_Poll to send or receive more data by RAM
+transfer, although this is invisible to the transfer routine, which just
+sees a simple interface to a stream of data.  Errors from the transfer
+are carefully propagated back to the transfer routine, which sees error
+returns from read or write operations.
+
+Sapphire includes a standard `saveAs' box, whose interface is slightly
+simpler than the `save' routine.
+
+_____________________________________________________________________________
+
+THE SAPPHIRE CHUNK FORMAT, AND PREFERENCES HANDLING
+
+
+A Sapphire `chunk' file is very simply a file representation of a list
+of named chunks of data.  Sapphire provides functions to read chunk
+files, claim chunks, and write chunk files back again.
+
+When a chunk file is loaded, each chunk is placed in a Flex block.  A
+client can `claim' a chunk.  Once this is done, the client can either
+modify the data in-place, or free the block and provide a pointer to a
+procedure to write equivalent data to the chunk file when it's saved.
+
+The original idea was to support preferences files in a modular way --
+each component could find its own preferences chunk without needing to
+know about anything other than the chunk system.  We noticed that this
+could easily be extended to handle binary data, and we could base a
+general file format on the idea.  A typical Straylight document would
+look something like this:
+
+       ;
+       ; Generated by Straylight Frobnitz
+       ;
+
+       [Header]
+       Format = Frobnitz data
+       FormatVersion = 3.15
+       Author = J. R. Hacker
+
+       [FrobData]
+       Bin[00]....[binary rubbish]
+
+       [FrobOptions]
+       AutoDelay = 300
+       AutoMods = 50
+       ...
+
+You get the idea.  The text chunks can be modified by anyone with a text
+editor -- the binary areas are self-contained and don't care where they
+are in a file.
+
+Some user preferences are best stored as raw chunks.  For example, the
+`FontDir' program keeps a chunk containing the list of font directories
+known to it.  Most are better expressed through the sort of key/value
+syntax shown in the above example.  Sapphire provides a separate
+mechanism for handling these which interwork with the chunk file system.
+
+The `options' unit will, when requested, claim a chunk from a chunk
+file, and translate its textual contents into an easily digestable
+binary format.  When the chunk file is saved, Sapphire will
+automatically read the binary data, and translate whatever's there back
+into text.  Using text as an external representation insulates the
+client program from version changes -- default values can be provided
+for keys which aren't defined, for example.
+
+Each key/value pair in the chunk has the general format:
+
+  <key> [=] <string> [;<comment>]
+
+A <string> is either a sequence of unquoted characters, or quoted by one
+of the pairs `', '', or "".  A quote character can be duplicated to
+insert a literal quote in the string.  Any of the characters `#', `|' or
+`;' begins a comment (although `;' is preferred because we're assembler
+programmers).
+
+The set of permissable options is provided to Sapphire as a table, each
+entry of which states the name of the key, the offset within the options
+block to store the (binary) value, the type of the value, and any data
+the type handler needs for its own purposes.  It's another
+variable-size-entry table, like a menu definition or a dbx control list.
+More types can easily be written by client programs.  Standard handlers
+are provided:
+
+  * The string type reads quoted or unquoted strings.  It always writes
+    quoted strings.
+
+  * The integer type reads signed or unsigned integers in any base (up
+    to 36).  It usually writes decimal numbers although it can be
+    persuaded to use a different base.
+
+  * The literal type never reads anything.  It writes out a string
+    (maybe some kind of comment) when requested.
+
+  * The enum type reads a string, looks it up in a table, and stores the
+    index.  The match is case-insensitive.  Abbreviations are
+    accepted; ambiguous abbreviations match the first string found in
+    the table.  It writes out the full correct-case string.
+
+  * The bool type is a special case of the enum type -- it reads either
+    one of `true', `on' or 'yes' for a true value, or `false', `off' or
+    `no' for false, and sets a single bit for its answer (for space
+    efficiency).  On output, it writes one of `true' or `false', unless
+    requested to use `on' or `off', in which case it also suppresses the
+    optional `=' sign on output.
+
+  * The version type reads version numbers of the form `xxx.yz' and
+    stores them as integers, multiplied by 100.  It writes them out
+    in the same form, with trailing zeros if necessary.
+
+The preferences system DoggySoft added into WimpExtension is the nearest
+thing which comes close, but Sapphire does the job in a much more
+powerful way.  This is actually quite surprising, since the unit isn't
+particularly large.  (This is partly due to an interesting coding trick
+I came up with to reduce typing, which I've entirely failed to make use
+of in any high-level language.  See `choices/options.s' for details.)
+
+_____________________________________________________________________________
+
+HIGH LEVEL LANGUAGE INTERFACE
+
+
+This is stil very sketchy, but a discussion may interest some readers.
+The C interface has to deal with several problems:
+
+  * Sapphire's procedure calls aren't even a little bit compatible with
+    APCS.  Sapphire gains a lot of its power and elegance from its lax
+    calling conventions.
+
+  * C programmers tend to use different names for commonly used
+    functions.
+
+  * Sapphire's variable-size-entry tables aren't easy to represent in C.
+
+The last problem hasn't been addressed.  The trivial `Hello, world'
+example program contains a horrible block of hex where the menu
+definition is meant to be.  To be fair, we envisaged the user-interface
+parts of Sapphire applications to be in assembler, to keep the
+user-facing parts of a program light and responsive, while the back-end
+bits were in C.
+
+The second problem just involves writing a lot of veneers and playing
+with macros.  I didn't bother trying to make the functions ANSI
+compliant.  Only the bare bones of a standard library is provided.
+
+The first is the only technically interesting problem.  Making C call
+Sapphire is a fairly simple task of inserting a veneer in the right
+place.  I wrote a `_call' function which works rather like `_swi', to
+allow C to call any Sapphire function.  There's a small problem to do
+with R11 which needs dealing with, though.  My solution was simple --
+since Sapphire doesn't have any stack checking anyway, compile code with
+stack limit checking turned off and move R11 into R10 (APCS's stack
+limit pointer) and back to R11 on inter-language borders.
+
+The really interesting problem, then, is making Sapphire understand how
+to call C functions.  Again, some hacking is performed.  Any C function
+which is intended to be called by Sapphire is declared as follows:
+
+__sapph(funcname)(regset *r [, type *r10 [, type *r12 [, char *scratch]]])
+
+(APCS's way of passing arguments in registers allows the flexibility of
+arguments -- if a function doesn't need R10 or R12 it doesn't need to
+declare them.  More arguments can be read by putting them after
+`scratch' -- they just get pulled off the stack.)
+
+The macro constructs a function with the given name, just before the
+actual compiled function, whose name is changed to `__sapph__funcname'.
+
+The actual code generated by the compiler for this atrocity is:
+
+funcname       STMFD   R13!,{R14}
+               MOV     R14,PC
+               B       __sapph_veneer
+
+__sapph__funcname
+               <APCS entry sequence>
+               ...
+
+The `__sapph_veneer' routine knows that the function it's meant to call
+is pointed to by R14.  It stores all the registers on the stack, points
+R0 at them (to make the regset variable), sets up the other arguments,
+puts R11 into R10, and calls the C routine.  On exit, it pulls the
+registers off the stack, puts R11 back in its proper place, sets
+flags appropriately, and returns.
+
+The C function can set return values by modifying the `regset' argument
+it's passed.  It can also modify the flags by returning an appropriate
+value as its result.  For example
+
+       return (C_set | V_clear);
+
+returns with C set, V clear and the other flags unaltered.
+
+This is a very hamfisted way of dealing with the problem.  But Sapphire
+was never designed to work with C.  In fact, it's almost true to say
+that Sapphire was designed never to work with C -- the fact that it's
+possible after all is more a credit to humen ingenuity than Sapphire's
+design.
+
+_____________________________________________________________________________
+
+CONCLUSION
+
+
+Your tour through the interesting bits of Sapphire is complete.  There
+are plenty of other `neat toys' in there, waiting for you to find them.
+Most source files contain some sort of interesting twist on an old idea,
+or a neat programming trick.
+
+The sources are commented to excess.  Almost every line contains a
+comment.  Obscure tricks and other bits of non-obvious code are usually
+tagged `Horrid hack' or `Neat trick', at least the first time we used
+that particular construction.  Searching for `hack' should produce lots
+of interesting code to read.
+
+Anything else you want to know: just read the header file documentation
+and/or the source code.  Or you can ask me.  Just bear in mind that it's
+been a long time since I wrote anything which used Sapphire and I'll
+probably have to read the headers and/or the source code anyway.
+
+Sapphire, for Tim and myself, has been a labour of love.  I'm extremely
+proud of it: of its small size, its speed, its elegant design, its power
+and versatility.  Please, treat it with respect.
+
+I'm almost in tears as I type this, so I'd better stop.  Thanks for
+reading,
+
+
+
+  Mark Wooding, mdw@excessus.demon.co.uk
+  17 December 1997
diff --git a/StraySrc/Libraries/Sapphire/bs/fixedPt,ffb b/StraySrc/Libraries/Sapphire/bs/fixedPt,ffb
new file mode 100644 (file)
index 0000000..bf0dfe4
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/bs/fixedPt,ffb differ
diff --git a/StraySrc/Libraries/Sapphire/bsh/banner,ffb b/StraySrc/Libraries/Sapphire/bsh/banner,ffb
new file mode 100644 (file)
index 0000000..14caf03
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/bsh/banner,ffb differ
diff --git a/StraySrc/Libraries/Sapphire/bsh/dbx,ffb b/StraySrc/Libraries/Sapphire/bsh/dbx,ffb
new file mode 100644 (file)
index 0000000..ec13f02
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/bsh/dbx,ffb differ
diff --git a/StraySrc/Libraries/Sapphire/bsh/flex,ffb b/StraySrc/Libraries/Sapphire/bsh/flex,ffb
new file mode 100644 (file)
index 0000000..40b61d0
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/bsh/flex,ffb differ
diff --git a/StraySrc/Libraries/Sapphire/bsh/libOpts,ffb b/StraySrc/Libraries/Sapphire/bsh/libOpts,ffb
new file mode 100644 (file)
index 0000000..6365c3e
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/bsh/libOpts,ffb differ
diff --git a/StraySrc/Libraries/Sapphire/bsh/menuDefs,ffb b/StraySrc/Libraries/Sapphire/bsh/menuDefs,ffb
new file mode 100644 (file)
index 0000000..9e29c5e
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/bsh/menuDefs,ffb differ
diff --git a/StraySrc/Libraries/Sapphire/bsh/options,ffb b/StraySrc/Libraries/Sapphire/bsh/options,ffb
new file mode 100644 (file)
index 0000000..7c80277
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/bsh/options,ffb differ
diff --git a/StraySrc/Libraries/Sapphire/bsh/stdDbox,ffb b/StraySrc/Libraries/Sapphire/bsh/stdDbox,ffb
new file mode 100644 (file)
index 0000000..7f43afb
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/bsh/stdDbox,ffb differ
diff --git a/StraySrc/Libraries/Sapphire/choices/s/choices b/StraySrc/Libraries/Sapphire/choices/s/choices
new file mode 100644 (file)
index 0000000..79ae5da
--- /dev/null
@@ -0,0 +1,215 @@
+;
+; choices.choices.s
+;
+; Locate user-configurable resource files
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:res
+               GET     sapphire:sapphire
+               GET     sapphire:string
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- choices_useChoices ---
+;
+; On entry:    R0 == 0 to disable use of `Choices', >0 to enable, or <0 to
+;                      read
+;
+; On exit:     R0 == previous setting
+;
+; Use:         This call allows an application to determine whether its
+;              user-configurable resources are looked for in Acorn's
+;              `Choices' directory, or only in the application's directory.
+;
+;              An application would typically make this call after parsing
+;              its command-line options, to allow a Network Manager to
+;              enable the `Choices' support.
+
+               EXPORT  choices_useChoices
+choices_useChoices ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  chs__wSpace             ;Find my workspace
+               MOVS    R14,R0                  ;Copy arg, and set Z and N
+               LDR     R0,chs__flags           ;Load the flags word
+               ORRPL   R14,R0,#chFlag__useChs  ;If N clear, set the flag
+               BICEQ   R14,R14,#chFlag__useChs ;But if Z set, clear it
+               STRPL   R14,chs__flags          ;If changed, save flag back
+               AND     R0,R0,#chFlag__useChs   ;Set up return value
+               LDMFD   R13!,{R12,PC}^          ;And return to caller
+
+               LTORG
+
+; --- choices_find ---
+;
+; On entry:    R0 == pointer to resource filename
+;              R1 == pointer to buffer to build filename in
+;              R2 == flags:
+;                      bit 0 == file will be written to (use Choices$Write)
+;
+; On exit:     R0 == pointer to filename
+;              R1 == pointer to terminating NULL
+;              CS if the file was found, else CC
+;
+; Use:         Locates a user-configurable resource file.  The search order
+;              depends on (a) whether the file will be written (bit 0 of R2)
+;              and (b) whether the use of Acorn's `Choices' system is
+;              enabled.
+;
+;              The search order is as follows:
+;
+;              * Choices:appName.leaf / <Choices$Write>.appName.leaf
+;              * res_find(leaf)
+;
+;              (i.e. it looks in the `Choices' structure first, and if that
+;              fails, it will use res_find).
+
+               EXPORT  choices_find
+choices_find   ROUT
+
+               STMFD   R13!,{R2-R6,R12,R14}    ;Save some registers
+               WSPACE  chs__wSpace             ;Locate my workspace
+               MOV     R5,R0                   ;Get the leafname safely
+               MOV     R6,R1                   ;And the buffer pointer
+               LDR     R14,chs__flags          ;Load the flags
+               TST     R14,#chFlag__useChs     ;Are we using Acorn's thing?
+               BEQ     %50choices_find         ;No -- just use res then
+
+               ; --- Now sort out what we're doing ---
+
+               TST     R2,#1                   ;Are we writing the file?
+               BNE     %20choices_find         ;Yes -- that's special
+
+               ; --- We're trying to read ---
+
+               ADR     R0,chs__path            ;Point to the variable name
+               MOV     R1,R11                  ;Build value in scratchpad
+               MOV     R2,#256                 ;Say this is very big
+               MOV     R3,#0                   ;This is the first call
+               MOV     R4,#3                   ;Please convert to a string
+               SWI     XOS_ReadVarVal          ;Try to read the value
+               BVS     %50choices_find         ;If it failed, try res_find
+
+               MOV     R0,R6                   ;Point to his buffer
+               ADR     R1,chs__prefix          ;Point to path prefix
+               BL      str_cpy                 ;Copy that over
+               ADD     R2,R0,#10               ;Allow 10 chars for appname
+               LDR     R1,sapph_appName        ;Find application's name
+               BL      str_cpy                 ;Copy that over
+               CMP     R0,R2                   ;Have we gone too far?
+               MOVCS   R0,R2                   ;Yes -- backpedal a bit
+               MOV     R14,#'.'                ;Store directory separator
+               STRB    R14,[R0],#1             ;Save that out
+               MOV     R1,R5                   ;Point to his leafname
+               BL      str_cpy                 ;Add that to the end too
+               MOV     R1,R0                   ;Get the end of the buffer
+               MOV     R0,R6                   ;Point to buffer start
+               BL      res_exists              ;Is the file there?
+               BCS     %90choices_find         ;Yes -- return then
+               B       %50choices_find         ;No luck -- use res_find
+
+               ; --- We're trying to write ---
+
+20choices_find ADR     R0,chs__write           ;Point to the variable name
+               MOV     R1,R11                  ;Build value in scratchpad
+               MOV     R2,#256                 ;Say this is very big
+               MOV     R3,#0                   ;This is the first call
+               MOV     R4,#3                   ;Please convert to a string
+               SWI     XOS_ReadVarVal          ;Try to read the value
+               BVS     %50choices_find         ;If it failed, try res_find
+
+               MOV     R0,R6                   ;Point to his buffer
+               MOV     R14,#'<'                ;Wrap name in `<>'s
+               STRB    R14,[R0],#1             ;Save that in the buffer
+               ADR     R1,chs__write           ;Point to write prefix
+               BL      str_cpy                 ;Copy that over
+               MOV     R14,#'>'                ;Close odd brackets
+               STRB    R14,[R0],#1             ;Save that in the buffer
+               MOV     R14,#'.'                ;Add a directory separator
+               STRB    R14,[R0],#1             ;Save that in the buffer
+               ADD     R2,R0,#10               ;Allow 10 chars for appname
+               LDR     R1,sapph_appName        ;Find application's name
+               BL      str_cpy                 ;Copy that over
+               CMP     R0,R2                   ;Have we gone too far?
+               MOVCS   R0,R2                   ;Yes -- backpedal a bit
+               MOV     R2,R0                   ;Remember where we are
+               MOV     R14,#0                  ;Terminate name here
+               STRB    R14,[R0],#1             ;Save that out
+
+               ; --- Create <Choices$Write>.appName ---
+
+               MOV     R4,#0                   ;Default number of entries
+               MOV     R1,R6                   ;Point to the buffer
+               MOV     R0,#8                   ;Create a directory
+               SWI     XOS_File                ;Try to create it at least
+               BVS     %50choices_find         ;If no luck, use res_find
+
+               ; --- Now attach the leafname ---
+
+               MOV     R0,R2                   ;Find the end of the name
+               MOV     R14,#'.'                ;Add a directory separator
+               STRB    R14,[R0],#1             ;Store that
+               MOV     R1,R5                   ;Point to the leafname
+               BL      str_cpy                 ;Copy that on the end
+               MOV     R0,R6                   ;Point to the buffer
+               MOV     R1,R0                   ;Get the end of the buffer
+               BL      res_exists              ;Does that exist?
+               B       %90choices_find         ;Return that anyway
+
+               ; --- We had no luck ourselves -- try res_find ---
+
+50choices_find MOV     R0,R5                   ;Point to the leafname
+               MOV     R1,R6                   ;And to the buffer
+               BL      res_find                ;Try to find the file
+
+               ; --- Return finally ---
+               ;
+               ; The correct file-exists state is already in C, as is the
+               ; end pointer.
+
+90choices_find LDMFD   R13!,{R2-R6,R12,R14}    ;Restore registers
+               ORRCSS  PC,R14,#C_flag          ;If C set, set C on exit
+               BICCCS  PC,R14,#C_flag          ;Else clear C
+
+chs__path      DCB     "Choices$Path",0
+chs__prefix    DCB     "Choices:",0
+chs__write     DCB     "Choices$Write",0
+
+               LTORG
+
+chs__wSpace    DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+chs__wStart    #       0
+
+chs__flags     #       4                       ;Various interesting flags
+
+chs__wSize     EQU     {VAR}-chs__wStart
+
+chFlag__useChs EQU     (1<<0)                  ;Use Acorn's `Choices' system
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     chs__wSize
+               DCD     chs__wSpace
+               DCD     256
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/choices/s/options b/StraySrc/Libraries/Sapphire/choices/s/options
new file mode 100644 (file)
index 0000000..a4679d8
--- /dev/null
@@ -0,0 +1,883 @@
+;
+; choices.options.s
+;
+; Read options from an options chunk (MDW)
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:chunk
+               GET     sapphire:divide
+               GET     sapphire:flex
+               GET     sapphire:string
+
+
+               GET     sapphire:xfer.xsave
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- options_read ---
+;
+; On entry:    R0 == chunk file handle
+;              R1 == pointer to a chunk name
+;              R2 == pointer to options definition
+;              R3,R4 specify address of output block
+;
+; On exit:     --
+;
+; Use:         Claims the specified options chunk, and reads the data in
+;              it into a binary block.  Because the output data might be
+;              in a flex block, the two registers R3,R4 which define its
+;              address work as follows:
+;
+;              R3 == address or offset of data
+;              R4 == -1 if R3 is address, else flex anchor address
+
+               EXPORT  options_read
+options_read   ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Save some registers
+               MOV     R5,R3                   ;Move output block address
+               MOV     R6,R4                   ;Somewhere safe
+               MOV     R3,R2                   ;Put definition in R10
+               MOV     R4,#0                   ;I have no workspace
+               ADR     R2,options__saver       ;Point to options saver
+               BL      chunk_claim             ;Claim this chunk
+               BVS     %90options_read         ;If it failed, return
+
+               STMIB   R1,{R3,R5,R6}           ;Save def and output block
+               STMFD   R13!,{R1}               ;Look after this address
+
+               ; --- Start work on parsing the block ---
+
+               CMP     R6,#-1                  ;Is this a flex block?
+               LDRNE   R6,[R6]                 ;Yes -- load the anchor
+               ADDNE   R5,R6,R5                ;And find the output address
+               MOV     R6,R5                   ;Copy address over to R6
+
+               MOV     R0,R1                   ;Point to flex anchor
+               BL      flex_size               ;Find the block size
+               LDR     R4,[R1]                 ;Load the block base
+               ADD     R5,R4,R0                ;Find limit of anchor
+
+               ; --- State 0: Newline ---
+
+opt__newline   ADR     R7,%f00                 ;Where to go on newline
+               ADR     R8,opt__end             ;Where to go on EOF
+               ADR     R9,opt__comment         ;Where to go on comment
+               ADR     R10,%f00                ;Where to go on whitespace
+00             BL      opt__nextChar           ;Get another character
+               ADR     R7,opt__newline         ;Start all over on newline
+
+               ; --- State 1: Read an option name ---
+
+opt__optName   MOV     R1,R11                  ;Find start of name buffer
+               ADR     R10,opt__equals         ;On whitespace, find equals
+00             STRB    R0,[R1],#1              ;Save this first byte
+               BL      opt__nextChar           ;Get the next byte ready
+               CMP     R0,#'='                 ;Is this an equals
+               BNE     %b00                    ;Otherwise branch back
+               B       opt__wsArg              ;Yes -- skip ws and get arg
+
+               ; --- State 2: Skip optional `=' sign ---
+
+opt__equals    BL      opt__nextChar           ;Get another character
+               CMP     R0,#'='                 ;Is this an equals
+               BNE     opt__arg                ;No -- start on the argument
+
+               ; --- State 3: Skip leading whitespace on argument ---
+
+opt__wsArg     ADR     R10,%f00                ;On whitespace, loop
+00             BL      opt__nextChar           ;Get another character
+
+               ; --- State 4: Read the argument ---
+               ;
+               ; Here we just sort out what to do next; we don't actually
+               ; read anything.
+
+opt__arg       MOV     R14,#0                  ;Null terminate the name
+               STRB    R14,[R1],#1             ;Stuff that on the end
+
+               BL      str_buffer              ;Get a string buffer
+               MOV     R2,R1                   ;Look after its address
+
+               ADR     R7,opt__readArg         ;Stop reading at newline
+               ADR     R8,opt__readArg         ;Or at end of file
+
+               CMP     R0,#'`'                 ;A leading backquote is...
+               MOVEQ   R0,#'''                 ;... the same as a quote
+               CMPNE   R0,#'''                 ;Is string in single quotes?
+               CMPNE   R0,#'"'                 ;Is string in double quotes?
+               BEQ     opt__quote              ;Yes -- handle that
+
+               ; --- State 5: Read undelimited argument ---
+
+opt__undelim   ADR     R9,opt__readArg         ;Stop at comment chars too
+               ADR     R10,%f00                ;But whitespace is important
+00             STRB    R0,[R1],#1              ;Store byte in buffer
+               BL      opt__nextChar           ;Get another character
+               B       %b00                    ;And keep on going
+
+               ; --- State 6: Read quote delimited argument ---
+               ;
+               ; Here we don't use the normal nextChar system, because (a)
+               ; we'd need to turn most of it off, and (b) I need a
+               ; register!
+
+opt__quote     MOV     R14,R0                  ;Look after delimiter
+
+00             CMP     R4,R5                   ;Finished yet?
+               LDRCCB  R0,[R4],#1              ;Load a byte from the block
+               MOVCS   R0,#-1                  ;Otherwise say it's -1
+
+               CMP     R0,#&0A                 ;Found a newline here?
+               CMPNE   R0,#-1                  ;Or the end of file?
+               BEQ     opt__readArg            ;Yes -- stop going then
+
+               CMP     R0,R14                  ;Is this a quote character?
+               STRNEB  R0,[R1],#1              ;No -- stuff it in the buffer
+               BNE     %b00                    ;And leap backwards
+
+               CMP     R4,R5                   ;Finished yet?
+               LDRCCB  R0,[R4],#1              ;Load a byte from the block
+               MOVCS   R0,#-1                  ;Otherwise say it's -1
+               CMP     R0,R14                  ;Is the quote doubled?
+               STREQB  R0,[R1],#1              ;Yes -- stuff in the buffer
+               BEQ     %b00                    ;And leap backwards
+
+               ; --- State 7: Skip the rest of the line ---
+               ;
+               ; We must have (a) reached the end of the line/file, (b)
+               ; found a comment start, or (c) finished a delimited string.
+               ; In all these cases we should skip on until the start of
+               ; a line (unless we're already there, of course).
+
+opt__readArg   CMP     R0,#&0A                 ;Was that a line end?
+               CMPNE   R0,#-1                  ;Or the end of it all?
+               CMPNE   R4,R5                   ;Finished yet?
+               LDRNEB  R0,[R4],#1              ;Load a byte from the block
+               BNE     opt__readArg            ;And see if we skip that too
+
+               ; --- State 8: Finally we can get on with the search ---
+
+opt__search    MOV     R14,#0                  ;Terminate the string
+               STRB    R14,[R1],#1             ;Store that on the end
+
+               MOV     R10,R3                  ;Find the option block base
+00             ADD     R0,R10,#opt_name        ;Find the option name
+               MOV     R1,R11                  ;Point to our option name
+               BL      str_icmp                ;Compare the strings
+               BEQ     opt__read               ;Match -- handle that
+               LDMIA   R10,{R7,R8}             ;Load flags and size
+               TST     R7,#optFlag_last        ;Is this the last entry?
+               ADDEQ   R10,R10,R8              ;No -- move on to next one
+               BEQ     %b00                    ;And loop back again
+               B       opt__newline            ;No joy -- try the next line
+
+               ; --- Found a matching block -- call parser ---
+
+opt__read      LDMIA   R10,{R0,R1,R7,R8}       ;Load all the data out
+               TST     R7,#optFlag_ignore      ;Are we meant to read this?
+               BNE     opt__newline            ;No -- ignore it then
+               MOV     R1,R2                   ;Point to argument string
+               MOV     R2,R8                   ;Look after the type addr
+               ADD     R8,R10,#opt_name        ;Point to official name
+               ADD     R10,R6,R7               ;Find binary rep buffer
+               MOV     R9,R8                   ;Point to name start
+               MOV     R7,R0                   ;And get the flags word
+
+00             LDRB    R14,[R9],#1             ;Load byte from name
+               CMP     R14,#&20                ;Is this the end yet?
+               BCS     %b00                    ;No -- keep looking then
+               ADD     R9,R9,#3                ;Now word align pointer
+               BIC     R9,R9,#3                ;This is type-specific ptr
+
+               MOV     R0,#optReason_read      ;Tell routine to read
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R2                   ;And call the routine
+               B       opt__newline            ;And try the next line
+
+               ; --- Read a comment ---
+
+opt__comment   CMP     R4,R5                   ;Finished yet?
+               LDRNEB  R0,[R4],#1              ;Load a byte from the block
+               CMPNE   R0,#&0A                 ;Was that a line end?
+               BNE     opt__comment            ;And see if we skip that too
+               B       opt__newline            ;Try the next line now
+
+               ; --- Reached the very end finally ---
+
+opt__end       LDMFD   R13!,{R0}               ;Load the anchor block
+               MOV     R1,#0                   ;Don't free -- just reduce
+               BL      flex_extend             ;No longer need this
+               MOV     R14,#0                  ;Zero the anchor now
+               STR     R14,[R0,#0]             ;To make things happy
+
+90options_read LDMFD   R13!,{R0-R10,PC}^       ;Return to caller at last
+
+               ; --- opt__nextChar ---
+               ;
+               ; In a somewhat strange attempt to keep code size down, we
+               ; do checking for lots of strange characters here.  Addresses
+               ; of bits of code to call on newlines, comments etc. are
+               ; held in registers.  Most of the time, then, you don't
+               ; even need an explicit loop.  For example
+               ;
+               ;   ADR R10,{PC}+4
+               ;   BL opt__nextChar
+               ;
+               ; skips whitespace all by itself.
+
+opt__nextChar  CMP     R4,R5                   ;Finished yet?
+               LDRCCB  R0,[R4],#1              ;Load a byte from the block
+               MOVCS   R0,#-1                  ;Otherwise say it's -1
+
+               CMP     R0,#';'                 ;Maybe this is a comment
+               CMPNE   R0,#'#'                 ;Or maybe a different comment
+               CMPNE   R0,#'|'                 ;Or yet another one
+               MOVEQ   PC,R9                   ;Yes -- handle that then
+               CMP     R0,#&0A                 ;Found a newline here?
+               MOVEQ   PC,R7                   ;Yes -- don't mind that
+               CMP     R0,#-1                  ;Is this end-of-file?
+               MOVEQ   PC,R8                   ;Yes -- tidy up then
+               CMP     R0,#&20                 ;Is this a space
+               CMPNE   R0,#&09                 ;Or maybe a tab
+               MOVEQ   PC,R10                  ;Yes -- handle that
+               MOVS    PC,R14                  ;Otherwise return to caller
+
+               LTORG
+
+; --- options__saver ---
+;
+; On entry:    R0 == address of chunk anchor
+;              R10 == pointer to options definition
+;
+; On exit:     May return an error
+;
+; Use:         Saves a binary block of data as textual options.
+
+options__saver ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Save loads of registers
+               LDMIB   R0,{R4-R6}              ;Load data from the anchor
+               CMP     R6,#-1                  ;Is data in a flex block?
+               LDRNE   R6,[R6,#0]              ;Yes -- load block base
+               ADDNE   R5,R6,R5                ;And add that to the offset
+               MOV     R6,R5                   ;Put base in different reg
+
+               ; --- Start work now ---
+
+10             LDMFD   R4,{R7-R10}             ;Load values from table
+               MOV     R2,R10                  ;Look after call address
+               ADD     R10,R6,R9               ;Find the binary data field
+               ADD     R9,R4,#opt_name         ;Find the option name
+               ADD     R4,R4,R8                ;Move on to next block
+               MOV     R8,R9                   ;Point to the name again
+
+00             LDRB    R14,[R9],#1             ;Load byte from the name
+               CMP     R14,#&20                ;Reached the end yet?
+               BCS     %b00                    ;No -- keep looking
+               ADD     R9,R9,#3                ;Word align to find the
+               BIC     R9,R9,#3                ;Type-specific data
+
+               MOV     R0,#optReason_write     ;Tell parser to write
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R2                   ;And call the routine
+               MOVVC   R0,#&0A                 ;Write final newline
+               BLVC    xsave_byte              ;Write that out
+               BVS     %99options__saver       ;If it failed, stop now
+               TST     R7,#optFlag_last        ;Was that the last block?
+               BEQ     %b10                    ;No -- skip back then
+
+               MOV     R0,#&0A                 ;Terminate with two newlines
+               BL      xsave_byte              ;Write that out
+               LDMVCFD R13!,{R0-R10,R14}       ;Restore registers
+               BICVCS  PC,R14,#V_flag          ;And return with no errors
+
+99             ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R10,R14}       ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return with the error
+
+               LTORG
+
+; --- options_write ---
+;
+; On entry:    R0 == terminator character to write, 0 for none, or -1 for
+;                      quoting with 's
+;              R1 == pointer to name to save
+;
+; On exit:     May return an error
+;
+; Use:         Writes out an option name, terminated with the character
+;              given in R0 (which will normally be a space or an `=' sign).
+
+               EXPORT  options_write
+options_write  ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R2,R0                   ;Look after terminator
+
+               CMP     R2,#-1                  ;Are we quoting strings?
+               MOVEQ   R0,#'''                 ;Yes -- write initial '
+               BLEQ    xsave_byte              ;Write that out
+               BVS     %90options_write        ;If it failed, return error
+
+00             LDRB    R0,[R1],#1              ;Load next byte of string
+               CMP     R0,#&20                 ;Is this the end yet?
+               BCC     %f00                    ;Yes -- deal with that
+               BL      xsave_byte              ;Write that out
+               BVS     %90options_write        ;If it failed, return error
+               CMP     R2,#-1                  ;Are we quoting?
+               CMPEQ   R0,#'''                 ;Writing a quote?
+               BNE     %b00                    ;No -- skip back then
+               BL      xsave_byte              ;Write out a second quote
+               BVC     %b00                    ;And loop back round
+               BVS     %90options_write        ;If it failed, return error
+
+00             CMP     R2,#-1                  ;Are we quoting?
+               MOVEQ   R2,#'''                 ;Yes -- terminate with '
+               MOVS    R0,R2                   ;Get terminator char
+               BLNE    xsave_byte              ;Write that byte out
+               LDMVCFD R13!,{R0-R2,R14}        ;If OK, restore registers
+               BICVCS  PC,R14,#V_flag          ;And return without error
+
+90options_write        ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1,R2,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return
+
+               LTORG
+
+;----- Standard data types --------------------------------------------------
+
+; --- optType_string ---
+;
+; Flags:       --
+;
+; Data:                (word) buffer size of string
+;
+; Use:         Handles string data.  The binary representation is a ctrl
+;              terminated string.  The textual representation is a sequence
+;              of characters, which is always output in single quotes,
+;              although this is not necessary for the input.  The string
+;              will be truncated to fit in the buffer during reading.
+
+               EXPORT  optType_string
+optType_string ROUT
+
+               CMP     R0,#2                   ;Do I understand this?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch then
+               MOVS    PC,R14                  ;Otherwise just return
+
+               B       %50optType_string       ;Read a string
+
+               ; --- Write the string out ---
+
+               STMFD   R13!,{R14}              ;Save some registers
+               MOV     R0,#'='                 ;Write a trailing `=' sign
+               MOV     R1,R8                   ;Point to option name
+               BL      options_write           ;Write the name out
+               MOVVC   R0,#-1                  ;Now quote output string
+               MOVVC   R1,R10                  ;Get string to write
+               BLVC    options_write           ;Write the string out too
+               LDMFD   R13!,{PC}               ;And return to caller
+
+               ; --- Read a string in ---
+
+50             LDR     R2,[R9,#0]              ;Load the buffer size
+00             LDRB    R0,[R1],#1              ;Load next byte from string
+               CMP     R0,#&20                 ;Is this the end yet?
+               SUBCSS  R2,R2,#1                ;No -- decrement size
+               MOVCC   R0,#0                   ;If at end, write a 0
+               STRB    R0,[R10],#1             ;Write that out nicely
+               BCS     %b00                    ;And loop round for more
+               MOVS    PC,R14                  ;Return to caller finally
+
+               LTORG
+
+; --- optType_integer ---
+;
+; Flags:       bit 8 == use given default base
+;
+; Data:                (word) default base, if bit 8 set
+;
+; Use:         Handles integer data.  The binary representation is a 32-
+;              bit integer value.  The textual representation is the normal
+;              RISC OS style of numbers (i.e. the base_value notation is
+;              supported).  Numbers are always output in the default base
+;              given (or in decimal if there is none given).  Numbers
+;              being read may always have a sign; numbers will only be
+;              output with a sign if the default base is decimal.  Uppercase
+;              letters will be used for output, but any case is acceptable
+;              for input.
+;
+;              Special prefixes allowed are `%' for binary and `&' for hex.
+;              Such numbers are always output with these prefixes.
+
+               EXPORT  optType_integer
+optType_integer        ROUT
+
+               CMP     R0,#2                   ;Do I understand this?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch then
+               MOVS    PC,R14                  ;Otherwise just return
+
+               B       %50optType_integer      ;Read an integer
+
+               ; --- Write an integer ---
+
+               STMFD   R13!,{R3-R5,R14}        ;Save some registers
+               MOV     R0,#'='                 ;Write a trailing `=' sign
+               MOV     R1,R8                   ;Point to the option name
+               BL      options_write           ;Write the name out
+               LDMVSFD R13!,{R3-R5,PC}         ;If it failed, die
+
+               ; --- Write out a suitable prefix ---
+
+               TST     R7,#(1<<8)              ;Is there a base given?
+               LDRNE   R5,[R9],#4              ;Yes -- load the base
+               MOVEQ   R5,#10                  ;Otherwise use decimal
+               LDR     R3,[R10,#0]             ;Load the integer
+
+               CMP     R5,#10                  ;Writing in decimal?
+               TSTEQ   R3,#(1<<31)             ;And the number's positive?
+               BEQ     %10optType_integer      ;Yes -- skip onwards
+
+               MOV     R0,#0                   ;Initially, no char to write
+               CMP     R5,#10                  ;Now, is it decimal?
+               EOREQ   R0,R0,#'-' :EOR: '&'    ;Yes -- write a `-'
+               RSBEQ   R3,R3,#0                ;And also negate it
+               CMPNE   R5,#16                  ;Or maybe hex?
+               EOREQ   R0,R0,#'&' :EOR: '%'    ;Yes -- write a `&'
+               CMPNE   R5,#2                   ;Or lastly binary?
+               EOREQ   R0,R0,#'%'              ;Yes -- write a `%'
+               BLEQ    xsave_byte              ;Write that byte out
+               LDMVSFD R13!,{R3-R5,PC}         ;If it failed, die
+               BEQ     %10optType_integer      ;And skip onwards
+
+               MOV     R0,R5                   ;Get the base in decimal
+               MOV     R1,R11                  ;Point into scratchpad
+               MOV     R2,#256                 ;Give typical size for this
+               SWI     OS_ConvertInteger4      ;Convert it to an integer
+               MOV     R1,R11                  ;Point to the buffer
+00             LDRB    R0,[R1],#1              ;Load next byte
+               CMP     R0,#&20                 ;Finished yet?
+               MOVCC   R0,#'_'                 ;Yes -- finish with `_'
+               BL      xsave_byte              ;Write out the byte
+               LDMVSFD R13!,{R3-R5,PC}         ;If it failed, die
+               BCS     %b00                    ;And keep on going
+
+               ; --- Build the string in the scratchpad ---
+
+10             MOV     R4,R11                  ;Start a pointer into R11
+               MOV     R0,R3                   ;Get the number to write
+00             MOV     R1,R5                   ;Get the base too
+               BL      div_unsigned            ;Get next digit in R1
+               ADD     R1,R1,#'0'              ;Turn into a digit
+               CMP     R1,#'9'+1               ;Is it too big for this?
+               ADDCS   R1,R1,#'A'-'9'-1        ;Yes -- turn into letter
+               STRB    R1,[R4],#1              ;Save in next byte of R11
+               CMP     R0,#0                   ;Have we finished yet?
+               BNE     %b00                    ;No -- do another digit then
+
+               ; --- Now write out the digits ---
+               ;
+               ; They're all in the scratchpad in *reverse* order.
+
+00             LDRB    R0,[R4,#-1]!            ;Load next character
+               BL      xsave_byte              ;Write that out nicely
+               LDMVSFD R13!,{R3-R5,PC}         ;If it failed, die
+               CMP     R4,R11                  ;Have we finished yet?
+               BHI     %b00                    ;No -- do the rest then
+
+               LDMFD   R13!,{R3-R5,PC}^        ;Return to caller
+
+               ; --- Read an integer in ---
+
+50             STMFD   R13!,{R3-R5,R14}        ;Save a register
+               MOV     R5,R1                   ;Look after string pointer
+
+               TST     R7,#(1<<8)              ;Is there a base given?
+               LDRNE   R3,[R9],#4              ;Yes -- load the base
+               MOVEQ   R3,#10                  ;Otherwise use decimal
+               MOV     R1,#0                   ;Value starts at 0
+               MOV     R2,#0                   ;Keep decimal check in case
+               MOV     R4,#0                   ;Clear a flags word
+
+00             LDRB    R0,[R5],#1              ;Load next byte
+               CMP     R0,#'&'                 ;Check for base prefix
+               CMPNE   R0,#'%'                 ;Either will do
+               BEQ     %60optType_integer      ;Yes -- handle that then
+               CMP     R0,#'_'                 ;Was that a base spec?
+               BEQ     %65optType_integer      ;Yes -- handle that then
+               CMP     R0,#'-'                 ;Is it a minus sign?
+               CMPNE   R0,#'+'                 ;Might as well allow + too
+               BEQ     %70optType_integer      ;Yes -- deal with it
+
+               SUB     R14,R0,#'A'             ;First check letters
+               CMP     R14,#26                 ;Is this in range?
+               SUBCS   R14,R0,#'a'             ;No -- also do lowercase
+               CMPCS   R14,#26                 ;Check that too
+               ORRCC   R4,R4,#(1<<0)           ;Yes -- can't be a base then
+               ADDCC   R14,R14,#10             ;Put into letter position
+               SUBCS   R14,R0,#'0'             ;Otherwise check digits
+               CMPCS   R14,#10                 ;Make sure of them too
+               BCS     %90optType_integer      ;Got something strange
+
+               CMP     R14,#10                 ;Is it a valid base 10 digit?
+               ADDCC   R2,R2,R2,LSL #2         ;Also accumulate base 10 vsn
+               ADDCC   R2,R14,R2,LSL #1        ;In case of a base
+               ORRCC   R4,R4,#(1<<2)           ;Yup -- got a decimal digit
+               ORRCS   R4,R4,#(1<<4)           ;Otherwise say this is bad
+
+               TST     R4,#(1<<3)              ;Is accumulator OK?
+               BNE     %b00                    ;No -- don't change it
+               CMP     R14,R3                  ;Is it OK in our base?
+               MLACC   R1,R3,R1,R14            ;Accumulate result
+               ORRCC   R4,R4,#(1<<1)           ;Yup -- got a real digit
+               ORRCS   R4,R4,#(1<<3)           ;Otherwise say this is bad
+               B       %b00                    ;If it was a digit, loop
+
+               ; --- Change of base with shorthand base char ---
+
+60             TST     R4,#&3f                 ;Any digits read so far?
+               BNE     %90optType_integer      ;Yes -- this is naughty then
+               CMP     R0,#'&'                 ;Entering hex mode?
+               MOVEQ   R3,#16                  ;Yes -- base 16 then
+               MOVNE   R3,#2                   ;No -- base 2 is the other
+               ORR     R4,R4,#(1<<5)           ;Say we have a firm base
+               B       %b00                    ;Now go back to read digits
+
+               ; --- Change of base with `_' thing ---
+
+65             TST     R4,#(1<<4) + (1<<5)     ;Check base is valid, and...
+               BNE     %90optType_integer      ;we haven't got one already
+               TST     R4,#(1<<2)              ;Make sure we read a digit
+               BEQ     %90optType_integer      ;No -- nothing to do then
+               MOV     R3,R2                   ;Make decimal number the base
+               ORR     R4,R4,#(1<<5)           ;Say we have a firm base
+               BIC     R4,R4,#(1<<1) + (1<<3)  ;Clear accumulator flags
+               MOV     R1,#0                   ;And clear accumulator
+               B       %b00                    ;Now go back to read digits
+
+               ; --- Read a `-' or `+' sign ---
+
+70             TST     R4,#&7f                 ;Any digits read so far?
+               BNE     %90optType_integer      ;Yes -- this is naughty then
+               ORR     R4,R4,#(1<<6)           ;Say we read a sign
+               CMP     R0,#'-'                 ;Is it a minus?
+               ORREQ   R4,R4,#(1<<7)           ;Yes -- set `-' flag then
+               B       %b00                    ;Now go back to read digits
+
+               ; --- We've stopped -- if we read something, store it ---
+
+90             TST     R4,#(1<<7)              ;Must we negate the result?
+               RSBNE   R1,R1,#0                ;Yes -- do this
+               TST     R4,#(1<<1)              ;Did we read anything?
+               STRNE   R1,[R10,#0]             ;Yes -- stuff it away then
+               LDMFD   R13!,{R3-R5,PC}^        ;And return to caller
+
+               LTORG
+
+; --- optType_literal ---
+;
+; Flags:       --
+;
+; Data:                (string) data to write out (*null* terminated)
+;
+; Use:         Reads nothing; leave the name blank.  Writes out the data
+;              literally.  Note that an extra linefeed is added to the
+;              end, so don't overdo it.
+
+               EXPORT  optType_literal
+optType_literal        ROUT
+
+               CMP     R0,#2                   ;Do I understand this?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch then
+               MOVS    PC,R14                  ;Otherwise just return
+
+               MOVS    PC,R14                  ;You can't read a literal
+
+               ; --- Write the literal data ---
+
+               STMFD   R13!,{R14}              ;Save a register
+00             LDRB    R0,[R9],#1              ;Load a byte
+               CMP     R0,#0                   ;Is that the end?
+               BLNE    xsave_byte              ;No -- write out the byte
+               LDMVSFD R13!,{PC}               ;If it failed, return
+               BNE     %b00                    ;If not finished, loop
+               LDMFD   R13!,{PC}^              ;Return when done
+
+               LTORG
+
+; --- optType_enum ---
+;
+; Flags:       bit 8 == quote output string
+;              bit 9 == don't put an `=' sign in output
+;
+; Data:                See below
+;
+; Use:         The data is a collection of ctrl-terminated strings, itself
+;              terminated by a zero-length entry.  The textual
+;              representation is one of these strings, or an abbreviation
+;              of one.  The binary representation is a word containing the
+;              index into the list.
+
+               EXPORT  optType_enum
+optType_enum   ROUT
+
+               CMP     R0,#2                   ;Do I understand this?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch then
+               MOVS    PC,R14                  ;Otherwise just return
+
+               B       %50optType_enum         ;Read one of the strings
+
+               ; --- Write the appropriate string ---
+
+               STMFD   R13!,{R2,R14}           ;Stack a register
+               MOV     R0,R9                   ;Point to the table
+               LDR     R1,[R10,#0]             ;Load the current value
+               BL      str_index               ;Find the correct string
+               LDMCCFD R13!,{R2,PC}^           ;If that failed, do nothing
+               MOV     R2,R0                   ;Look after the index
+
+               TST     R7,#(1<<9)              ;Do we want an equals?
+               MOVEQ   R0,#'='                 ;Write an equals after name
+               MOVNE   R0,#' '                 ;Or maybe a space instead
+               MOV     R1,R8                   ;Point to option name
+               BL      options_write           ;Write that out
+               LDMVSFD R13!,{R2,PC}            ;If it failed, return
+               ANDS    R0,R7,#(1<<8)           ;Are we quoting strings?
+               MOVNE   R0,#-1                  ;Yes -- quote output
+               MOV     R1,R2                   ;Point to the string
+               BL      options_write           ;Write that out
+               LDMFD   R13!,{R2,PC}            ;And return to caller
+
+               ; --- Read one of the strings ---
+
+50optType_enum STMFD   R13!,{R14}              ;Stack a register
+               MOV     R0,R9                   ;Point to the table
+               BL      str_match               ;Look up the string
+               STRCS   R0,[R10,#0]             ;If found, store index
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- optType_bool ---
+;
+; Flags:       bit 8 == make flag active low
+;              bit 9 == use `on'/`off' rather than `true'/`false'; also
+;                      suppresses the `=' sign
+;
+; Data:                (word) bit mask to OR or BIC within word
+;
+; Use:         Handles a boolean option.  It will translate between the
+;              strings `true' or `false' and a bit (or set of bits) within
+;              a word.
+
+               EXPORT  optType_bool
+optType_bool   ROUT
+
+               CMP     R0,#2                   ;Do I understand this?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch then
+               MOVS    PC,R14                  ;Otherwise just return
+
+               B       %50optType_bool         ;Read one of the strings
+
+               ; --- Write a boolean value ---
+
+               STMFD   R13!,{R14}              ;Save a register
+               TST     R7,#(1<<9)              ;Write on/off, not true/false
+               MOVNE   R0,#' '                 ;Yes -- use a space then
+               MOVEQ   R0,#'='                 ;Else terminate with an `='
+               MOV     R1,R8                   ;Point to the option name
+               BL      options_write           ;Write that out
+               LDMVSFD R13!,{PC}               ;If it failed, return
+
+               LDR     R0,[R10,#0]             ;Load the flags word
+               LDR     R14,[R9],#4             ;Load the mask
+               TST     R7,#(1<<8)              ;Is flag active low?
+               EORNE   R0,R0,R14               ;Yes -- toggle it then
+               ANDS    R1,R0,R14               ;Is the option set?
+               MOVNE   R1,#1                   ;Yes -- use true string
+               TST     R7,#(1<<9)              ;Write on/off, not true/false
+               ORRNE   R1,R1,#2                ;Yes -- use second set then
+               ADR     R0,opt__boolTbl         ;Point to boolean table
+               BL      str_index               ;Find correct string
+               MOV     R1,R0                   ;Point to the string it found
+               MOV     R0,#0                   ;Don't terminate string
+               BL      options_write           ;Write that out
+               LDMFD   R13!,{PC}               ;And return
+
+               ; --- Read a boolean value ---
+
+50optType_bool STMFD   R13!,{R14}              ;Save a register
+               ADR     R0,opt__boolTbl         ;Point to the table
+               BL      str_match               ;Match a string
+               LDMCCFD R13!,{PC}^              ;If no match, return
+               TST     R0,#1                   ;Is the value false?
+               LDR     R0,[R10,#0]             ;Load the flags word
+               LDR     R14,[R9],#4             ;Load the mask
+               BICEQ   R0,R0,R14               ;False -- clear flag
+               ORRNE   R0,R0,R14               ;True -- set flag
+               TST     R7,#(1<<8)              ;Is flag active low?
+               EORNE   R0,R0,R14               ;Yes -- toggle it then
+               STR     R0,[R10,#0]             ;Save new flags back
+               LDMFD   R13!,{PC}^              ;And return
+
+opt__boolTbl   DCB     "false",0,      "true",0
+               DCB     "off",0,        "on",0
+               DCB     "no",0,         "yes",0
+               DCB     0
+
+               LTORG
+
+; --- optType_version ---
+;
+; Flags:       --
+;
+; Data:                --
+;
+; Use:         Converts between version number strings (of the form
+;              <int>[.[<digit>[<digit>]]]) and integers.  The version
+;              number is stored multiplied by 100.
+
+               EXPORT  optType_version
+optType_version        ROUT
+
+               CMP     R0,#2                   ;Do I understand this?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch then
+               MOVS    PC,R14                  ;Otherwise just return
+
+               B       %50optType_version      ;Read a version number
+
+               ; --- Write a version number ---
+
+               STMFD   R13!,{R2-R4,R14}        ;Save some registers
+
+               MOV     R0,#'='                 ;Write an equals sign
+               MOV     R1,R8                   ;Point to option name
+               BL      options_write           ;Write that string out
+               LDMVSFD R13!,{R2-R4,PC}         ;If it failed, return
+
+               LDR     R0,[R10,#0]             ;Load the version value
+               BL      div10                   ;Get bottom minor vsn digit
+               MOV     R4,R1                   ;Look after that
+               BL      div10                   ;Get top minor vsn digit
+               MOV     R3,R1                   ;Look after that too
+               MOV     R2,R0                   ;And get major version
+               MOV     R1,R11                  ;Output to scratchpad
+               ADR     R0,opt__vsnSkel         ;Point to skeleton string
+               BL      str_subst               ;Build the output string
+
+               MOV     R1,R0                   ;Point to output string
+               MOV     R0,#0                   ;Don't terminate this
+               BL      options_write           ;Write that out nicely
+               LDMFD   R13!,{R2-R4,PC}         ;And return to caller
+
+opt__vsnSkel   DCB     "%i0.%i1%i2",0
+
+               ; --- Read a version number ---
+
+50             STMFD   R13!,{R2,R14}           ;Save some registers
+
+               ; --- Read major version ---
+
+               MOV     R2,#0                   ;Start an accumulator
+               MOV     R0,#0                   ;Clear some flags
+00             LDRB    R14,[R1],#1             ;Load next byte of input
+               CMP     R14,#'.'                ;Is this the separator?
+               BEQ     %f00                    ;Yes -- sip forwards then
+               SUB     R14,R14,#'0'            ;Turn into an integer
+               CMP     R14,#10                 ;Is it in range?
+               ORRCC   R0,R0,#1                ;Yes -- we have a valid vsn
+               ADDCC   R2,R2,R2,LSL #2         ;So accumulate major vsn
+               ADDCC   R2,R14,R2,LSL #1
+               BCC     %b00                    ;And loop back again
+
+               ; --- Found something unexpected ---
+
+               TST     R0,#1                   ;Do we have a version number?
+               ADDNE   R2,R2,R2,LSL #2         ;Multiply major version by 5
+               ADDNE   R2,R2,R2,LSL #2         ;And again (x25)
+               MOVNE   R2,R2,LSL #2            ;And by 4 (x100)
+               STRNE   R2,[R10,#0]             ;And write out this value
+               LDMFD   R13!,{R2,PC}^           ;Return to caller finally
+
+               ; --- Read minor version number ---
+
+00             LDRB    R14,[R1],#1             ;Load next byte of input
+               SUB     R14,R14,#'0'            ;Turn into an integer
+               CMP     R14,#10                 ;Is it in range?
+               MOVCS   R14,#0                  ;No -- treat it as zero then
+               ADD     R2,R2,R2,LSL #2         ;Accumulate *anyway*; this
+               ADD     R2,R14,R2,LSL #1        ;puts zeroes on the end
+               LDRCCB  R14,[R1],#1             ;Maybe load the next one
+               SUBCC   R14,R14,#'0'            ;Turn into an integer
+               CMPCC   R14,#10                 ;Is it in range?
+               MOVCS   R14,#0                  ;No -- treat it as zero then
+               ADD     R2,R2,R2,LSL #2         ;Accumulate again
+               ADD     R2,R14,R2,LSL #1
+               STR     R2,[R10,#0]             ;And write out this value
+               LDMFD   R13!,{R2,PC}^           ;Return to caller finally
+
+               LTORG
+
+;----- Data structures ------------------------------------------------------
+
+; --- Options definition block ---
+
+               ^       0
+opt_flags      #       4                       ;Flags for this item
+opt_length     #       4                       ;Size of this table entry
+opt_offset     #       4                       ;Offset in block of data
+opt_type       #       4                       ;Address of type handler
+opt_name       #       0                       ;Name of this option
+
+; --- Option block flags ---
+
+optFlag_last   EQU     (1<<0)                  ;This is the last block
+optFlag_ignore EQU     (1<<1)                  ;Don't read this option
+
+; --- Integer type flags ---
+
+intFlag_base   EQU     (1<<8)                  ;Default base specified
+
+; --- Enumeration type flags ---
+
+enumFlag_quote EQU     (1<<8)                  ;Quote the output string
+enumFlag_noEq  EQU     (1<<9)                  ;Don't output an `=' sign
+
+; --- Boolean type flags ---
+
+boolFlag_cpl   EQU     (1<<8)                  ;Flag is complemented
+boolFlag_onOff EQU     (1<<9)                  ;Use `on'/`off' notation
+
+; --- Type handler reason codes ---
+;
+; All enter with:
+;
+;  R0 == reason code
+;  R7 == flags read from table
+;  R8 == address of option name
+;  R9 == address of type-specific data
+; R10 == address of binary option
+
+               ^       0
+optReason_read #       1                       ;Read from option string
+                                               ;R1 == pointer to string
+
+optReason_write        #       1                       ;Write data to xsave file
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/choices/s/prefs b/StraySrc/Libraries/Sapphire/choices/s/prefs
new file mode 100644 (file)
index 0000000..63dbd9c
--- /dev/null
@@ -0,0 +1,130 @@
+;
+; choices.prefs.s
+;
+; Management of application's preferences file
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:chunk
+               GET     sapphire:flex
+               GET     sapphire:heap
+               GET     sapphire:res
+               GET     sapphire:sapphire
+
+               GET     sapphire:xfer.load
+
+               GET     sapphire:choices.choices
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- prefs_find ---
+;
+; On entry:    --
+;
+; On exit:     R0 == chunk handle of loaded preferences file
+;
+; Use:         Returns the chunk handle of the preferences file.  You can
+;              then claim your chunk of options from the preferences file
+;              using options_read.
+
+               EXPORT  prefs_find
+prefs_find     ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               WSPACE  prefs__wSpace,R0        ;Find my workspace
+               LDR     R0,[R0,#:INDEX:prefs__handle]
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- prefs_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Loads the application's preferences file.
+
+               EXPORT  prefs_init
+prefs_init     ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers
+               WSPACE  prefs__wSpace           ;Find my workspace
+               LDR     R14,prefs__handle       ;Get the prefs chunk file
+               CMP     R14,#0                  ;Is it already created?
+               LDMNEFD R13!,{R0-R2,R12,PC}^    ;Yes -- nothing doing
+
+               ; --- Initialise bits of the library ---
+
+               BL      res_init                ;So I can find resources
+               BL      flex_init               ;For memory management
+               BL      alloc_init              ;For memory management too
+               BL      heap_init               ;So that it doesn't get upset
+
+               ; --- Create a chunk file ---
+
+               BL      chunk_create            ;Create the file
+               SWIVS   OS_GenerateError        ;If it failed, take it badly
+               STR     R0,prefs__handle        ;Save that away for later
+
+               ; --- Now load the preferences file ---
+
+               ADR     R0,prefs__file          ;Point to leafname
+               MOV     R1,R11                  ;Find a spare buffer
+               BL      choices_find            ;Get a complete filename
+               LDMCCFD R13!,{R0-R2,R12,PC}^    ;If file not there, stop
+               MOV     R1,R0                   ;Point to this name
+               SUB     R13,R13,#4              ;Make a flex anchor
+               MOV     R2,R13                  ;Point to this anchor
+               BL      load_file               ;And load the file into it
+               BVS     %99prefs_init           ;If it failed, tidy up
+               MOV     R1,R13                  ;Point to the anchor
+               LDR     R0,prefs__handle        ;Load the chunk file anchor
+               BL      chunk_read              ;Read the preferences file
+
+               ; --- Tidy up and return ---
+
+               MOV     R0,R13                  ;Point to the flex anchor
+               BL      flex_free               ;Free the file block
+
+99             ADD     R13,R13,#4              ;Clear up the stack space
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;And return to caller
+
+prefs__file    DCB     "Choices",0
+
+               LTORG
+
+prefs__wSpace  DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+prefs__wStart  #       0
+
+prefs__handle  #       4                       ;Handle of prefs chunk file
+
+prefs__wSize   EQU     {VAR}-prefs__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     prefs__wSize
+               DCD     prefs__wSpace
+               DCD     0
+               DCD     prefs_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/colSelect/s/colSelect b/StraySrc/Libraries/Sapphire/colSelect/s/colSelect
new file mode 100644 (file)
index 0000000..aab199d
--- /dev/null
@@ -0,0 +1,437 @@
+;
+; colSelect.s
+;
+; The Colour Selector kernel
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:dbox
+               GET     sapphire:errorBox
+               GET     sapphire:menu
+               GET     sapphire:menuDefs
+               GET     sapphire:msgs
+               GET     sapphire:pane
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx.stringSet
+
+               GET     sapphire:_cs.vars
+               GET     sapphire:_cs.models
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- colSelect ---
+;
+; On entry:    R0 == address of a colour block
+;              R1 == pointer to routine to call when done
+;              R2 == R10 to call routine with
+;              R3 == R12 to call routine with
+;
+; On exit:     May return error
+;
+; Use:         Displays a colour selector dialogue box.  It allows the user
+;              to edit a colour (understatement....)
+
+               EXPORT  colSelect
+colSelect      ROUT
+
+               BIC     R14,R14,#V_flag         ;Clear the V flag
+               STMFD   R13!,{R0-R4,R10,R14}    ;Save a load of registers
+
+               ; --- Try to create a workspace block ---
+
+               MOV     R0,#cs__dSize           ;Get my data size
+               BL      alloc                   ;Try to allocate the memory
+               BLCS    alloc_error             ;If it failed, get a message
+               BCS     %99colSelect            ;And tidy up as we go
+               MOV     R10,R0                  ;Look after this block
+
+               ; --- Now create a dialogue box ---
+
+               ADR     R0,cs__dbName           ;Point to the dialogue name
+               BL      dbox_create             ;Create the dialogue
+               BVS     %98colSelect            ;Tidy up if it failed
+               STR     R0,cs__frameDb          ;Save the dialogue handle
+               ADR     R1,cs__handler          ;The event handler
+               MOV     R2,R10                  ;Pass this R10 value
+               MOV     R3,R12                  ;And this R12 value
+               BL      dbox_eventHandler       ;Set up the handler
+               ADR     R1,cs__dbxBlock         ;Point to dbx information
+               BL      dbx_declare             ;Declare the block
+
+               ; --- Save the caller's information ---
+
+               LDR     R0,[R13,#0]             ;Load his colour's address
+               LDMIA   R0,{R1-R3}              ;Load the colour arguments
+               ADR     R14,cs__address         ;Point into the data block
+               STMIA   R14,{R0-R3}             ;And save all of that stuff
+
+               ; --- Set up the workspace ---
+
+               MOV     R14,#3                  ;Start on low resolution
+               STR     R14,cs__resolution      ;Save it in the workspace
+
+               ; --- Set up the initial model ---
+
+               BL      cs__initModel           ;Get a model index
+               BVS     %97colSelect            ;Clean up on an error
+               MOV     R4,R2                   ;Keep the model number
+               STR     R0,cs__modelDb          ;Save model's dialogue box
+               BL      dbox_window             ;Get the window handle
+               MOV     R3,R0                   ;Put model's db handle in R3
+               LDR     R0,cs__frameDb          ;Get frame db handle
+               MOV     R1,#dbOpen_persist+dbOpen_current
+               BL      dbox_open               ;Open the dialogue box
+               MOV     R1,#csIcon__rgb         ;The first model icon number
+               ADD     R1,R1,R2                ;Get the correct icon number
+               MOV     R2,#1                   ;Turn the icon on
+               BL      dbox_select             ;Select the icon
+               MOV     R2,R3                   ;Pane window handle
+               BL      dbox_window             ;Get the window handle
+               MOV     R1,#csIcon__models      ;The icon handle
+               BL      pane_add                ;Add the pane
+               BL      pane_open               ;Open the pane
+               BL      cs__setCaret            ;And give it the focus
+95colSelect    LDMFD   R13!,{R0-R4,R10,PC}^    ;Return to caller
+
+97colSelect    MOV     R4,R0                   ;Preserve R0
+               LDR     R0,cs__frameDb          ;Get the dialogue box handle
+               BL      dbox_destroy            ;Destroy the dialogue box
+               MOV     R0,R4                   ;Get R0 back
+98colSelect    MOV     R4,R0                   ;Preserve R0
+               MOV     R0,R10                  ;Point to allocated memory
+               BL      free                    ;Free it nicely
+               MOV     R0,R4                   ;Get R0 back
+99colSelect    ADD     R13,R13,#4              ;Don't load R0
+               LDMFD   R13!,{R1-R4,R10,R14}    ;Load registers
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+cs__dbName     DCB     "colSelect",0
+
+cs__dbxBlock   CONTROL csIcon__colour,colButton,R10,0,:INDEX: cs__colour
+               ECTRL
+               STRSET  csIcon__resDisp,R10,:INDEX: cs__resolution,                                     cs__resMenu,cs__resStrings,csIcon__resDisp
+               STRSET  csIcon__resMenu,R10,:INDEX: cs__resolution,                                     cs__resMenu,cs__resStrings,csIcon__resDisp
+               DBXEND
+
+cs__resMenu    MENU    "csRESMT"
+               ITEM    "csRESVH:Very high"
+               RADIO   0,0
+               ITEM    "csRESH:High"
+               RADIO   0,1
+               ITEM    "csRESM:Medium"
+               RADIO   0,2
+               ITEM    "csRESL:Low"
+               RADIO   0,3
+               MENUEND
+
+cs__resStrings DCB     "csRESVH:Very high",0
+               DCB     "csRESH:High",0
+               DCB     "csRESM:Medium",0
+               DCB     "csRESL:Low",0
+
+; --- cs__initModel ---
+;
+; On entry:    R2 == colour model number, or 0
+;
+; On exit:     R0 == dialogue box created by colour model, or error
+;              R2 == preserved, or index of RGB model
+;
+; Use:         Initialises a colour model dialogue box.
+
+cs__initModel  ROUT
+
+               CMP     R2,#cs__noModels        ;Is the model in range?
+               MOVHS   R2,#cMod_rgb            ;No -- use RGB then
+               ADD     PC,PC,R2,LSL #2         ;Call the function
+               DCB     "MDW!"
+
+00cs__initModel        B       rgb_open
+               B       hsv_open
+10cs__initModel
+
+cs__noModels   EQU     (%10-%00)/4
+
+; --- cs__setCaret ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets the caret in the current colour select pane window.
+
+cs__setCaret   ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               LDR     R0,cs__modelDb          ;Get the model dialogue
+               BL      dbox_window             ;And find its window handle
+               MOV     R1,#-1                  ;In no particular icon
+               MOV     R2,#&ff000000           ;Quite a long way away
+               ORR     R2,R2,#&00ff0000
+               MOV     R3,#0                   ;Doesn't really matter
+               MOV     R4,#&02000000           ;Hide caret, make it small
+               MOV     R5,#-1                  ;No index into icon, please
+               SWI     Wimp_SetCaretPosition   ;Set the caret's position
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+               LTORG
+
+; --- cs__handler ---
+;
+; On entry:    R0 == dialogue box event code
+;              R1-R9 == depend on the event
+;              R10 == colour selector data
+;              R12 == nothing much, actually -- corrupted on exit
+;
+; On exit:     --
+;
+; Use:         Handles events for the main dialogue frame
+
+cs__handler    ROUT
+
+               CMP     R0,#stringSet_event     ;Is this a string set event?
+               BEQ     cs__resMenuClk          ;Yes -- handle that
+
+               CMP     R0,#dbEvent_OK          ;Is it an OK event?
+               CMPNE   R0,#csIcon__ok          ;Or a click on OK?
+               BEQ     cs__ok                  ;Yes -- handle it then
+
+               CMP     R0,#dbEvent_help        ;Does someone want help?
+               BEQ     cs__getHelp             ;Yes -- deal with that too
+
+               SUB     R12,R0,#csIcon__rgb     ;Was it a model icon?
+               CMP     R12,#cs__noModels
+               BLO     cs__changeModel         ;Yes -- deal with it
+
+               MOVS    PC,R14
+
+               ; --- Handle an OK click/keypress ---
+
+cs__ok         ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R5,R1                   ;Remember mouse button state
+               MOV     R0,R9                   ;Get my dialogue handle
+               MOV     R1,#csIcon__ok          ;And the OK button
+               BL      dbox_slab               ;Press it in nicely
+
+               ; --- Find the actual colour he chose ---
+
+               BL      dbox_unslab             ;Unslab the button
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               LTORG
+
+               ; --- Give a help message if required ---
+
+cs__getHelp    B       dbox_help               ;Just let dbox do it all!
+
+               ; --- Handle the resolution menu button ---
+
+cs__resMenuClk ROUT
+
+               CMP     R1,#csIcon__resDisp     ;Is this the resolution one?
+               MOVNES  PC,R14                  ;No -- ignore it then
+
+               STMFD   R13!,{R0,R10,R14}       ;Save some registers
+               LDR     R10,cs__modelDb         ;Get the model's handle too
+               MOV     R0,#csEvent__newRes     ;The resolution's changed
+               BL      dbx_sendEvent           ;Send the event out
+               LDMFD   R13!,{R0,R10,PC}^       ;And return to caller
+
+               LTORG
+
+               ; --- Handle a model selection ---
+
+cs__changeModel        ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+               LDR     R1,cs__colour+col_model ;Load the existing model
+               CMP     R1,R12                  ;Is it the same?
+               LDMEQFD R13!,{R0-R3,PC}^        ;Yes -- return
+
+               ; --- Tell old model to update colour ---
+
+               STMFD   R13!,{R10}              ;Save my instance pointer
+               LDR     R10,cs__modelDb         ;Get the current panel dbox
+               MOV     R0,#csEvent__read       ;Tell it to read its settings
+               BL      dbx_sendEvent           ;Send it the event
+               LDMFD   R13!,{R10}              ;Restore the instance pointer
+
+               ; --- First try to get a new model dialogue ---
+
+               MOV     R2,R12                  ;Get the new colour model
+               BL      cs__initModel           ;Try to initialise it nicely
+               BVS     %90cs__changeModel      ;If it failed, report error
+
+               ; --- Now remove the old one ---
+
+               STMFD   R13!,{R0,R10}           ;Save some important regs
+               LDR     R10,cs__modelDb         ;Get the current panel dbox
+               MOV     R0,R10                  ;Get it in R0
+               BL      dbox_window             ;Find its window handle
+               MOV     R3,R0                   ;Keep this value nicely
+               SUB     R13,R13,#24             ;Space for a caret block
+               MOV     R1,R13                  ;Point to the caret block
+               SWI     Wimp_GetCaretPosition   ;Find the caret nicely
+               LDR     R0,[R13,#0]             ;Load the focus window handle
+               CMP     R0,R3                   ;Is it the panel?
+               MOVNE   R3,#0                   ;No -- clear the value then
+               ADD     R13,R13,#24             ;Restore the stack pointer
+               MOV     R0,#csEvent__close      ;Send a close event
+               BL      dbx_sendEvent           ;Send the event
+               LDMFD   R13!,{R0,R10}           ;Restore the registers again
+
+               ; --- Set up the new panel nicely ---
+
+               STR     R0,cs__modelDb          ;Store the new db handle
+               STR     R2,cs__colour+col_model ;And the new model type
+               BL      dbox_window             ;Get the new window handle
+               MOV     R2,R0                   ;This is the new pane
+               LDR     R0,cs__frameDb          ;Get the main dialogue box
+               BL      dbox_window             ;And get its window handle
+               MOV     R1,#csIcon__models      ;The main icon thingy
+               BL      pane_swap               ;Swap the pane over
+               CMP     R3,#0                   ;Was the caret in the panel
+               BLNE    cs__setCaret            ;Yes -- put it in the new one
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+90             MOV     R1,#1                   ;Only an OK button please
+               BL      errorBox                ;Call error box
+               LDMFD   R13!,{R0-R3,R14}        ;Return to caller
+               ORRS    PC,R14,#C_flag          ;Don't change the radio state
+
+               LTORG
+
+; --- cs_passBack ---
+;
+; On entry:    R0-R7 == dialogue box event information
+;              R10 == pointer to colour selector instance
+;
+; On exit:     --
+;
+; Use:         Passes an event back to the main colour selector frame dbox.
+
+               EXPORT  cs_passBack
+cs_passBack    ROUT
+
+               STMFD   R13!,{R10,R14}          ;Save some registers
+               LDR     R10,cs__frameDb         ;Get the dialogue handle
+               BL      dbx_sendEvent           ;Pass the event on
+               LDMFD   R13!,{R10,PC}^          ;And return to caller
+
+               LTORG
+
+; --- cs_colChange ---
+;
+; On entry:    R10 == currently selected dialogue box
+;
+; On exit:     --
+;
+; Use:         Updates the colour selector's colour display.
+
+               EXPORT  cs_colChange
+cs_colChange   ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R0,cs__frameDb          ;Load the frame handle
+               MOV     R1,#csIcon__colour      ;Get the colour button icon
+               BL      dbx_update              ;Redraw it nicely
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+; --- cs_immediate ---
+;
+; On entry:    R10 == currently selected dialogue box
+;
+; On exit:     CS if immediate operations are enabled, or CC
+;
+; Use:         Informs the caller whether sliders and arrows should cause
+;              immediate update of the dialogue box, or wait until the
+;              operation has completed.
+
+               EXPORT  cs_immediate
+cs_immediate   ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R0,cs__frameDb          ;Load the frame handle
+               MOV     R1,#csIcon__instant     ;Get instant effect switch
+               BL      dbox_isSelected         ;Is it selected?
+               LDMFD   R13!,{R0,R1,PC}         ;Return this state
+
+               LTORG
+
+; --- cs_resolution ---
+;
+; On entry:    R10 == currently selected dialogue box
+;
+; On exit:     R0 == quality value, from 0 (pixel) to 3 (grotty)
+;
+; Use:         Returns the current resolution value.  This is interpreted
+;              in a model-dependent manner.
+
+               EXPORT  cs_resolution
+cs_resolution  ROUT
+
+               LDR     R0,cs__resolution       ;Load the value out
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+;----- Icon numbers ---------------------------------------------------------
+
+csIcon__models EQU     0
+csIcon__rgb    EQU     2
+csIcon__hsv    EQU     3
+csIcon__cmyk   EQU     4
+csIcon__help   EQU     5
+csIcon__cancel EQU     6
+csIcon__ok     EQU     10
+csIcon__colour EQU     9
+csIcon__trans  EQU     7
+csIcon__instant        EQU     12
+csIcon__resDisp        EQU     14
+csIcon__resMenu        EQU     15
+
+;----- dbx controls ---------------------------------------------------------
+
+               EXPORT  colButton
+colButton      DCD     0,0
+               DCD     dbxMask_redraw
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+               LDR     R0,[R8,#0]              ;Get the RGB colour
+               MOV     R3,#&180                ;ColourTrans flags
+               MOV     R4,#0                   ;GCOL type
+               SWI     XColourTrans_SetGCOL    ;Set the colour
+
+               ; --- If error, try without dithering ---
+
+               LDRVS   R0,[R8,#0]              ;Get the RGB colour
+               MOVVS   R3,#&080                ;ColourTrans flags
+               MOVVS   R4,#0                   ;GCOL type
+               SWIVS   ColourTrans_SetGCOL     ;Set the colour
+
+               ; --- Do a CLG... cunning! ----
+
+               SWI     OS_WriteI+16            ;Plot the colour nicley
+
+               LDMFD   R13!,{R0-R4,PC}^        ;Return nicley then
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/colSelect/s/hsv b/StraySrc/Libraries/Sapphire/colSelect/s/hsv
new file mode 100644 (file)
index 0000000..14113d3
--- /dev/null
@@ -0,0 +1,958 @@
+;
+; hsv.s
+;
+; HSV functions (TMA)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:divide
+               GET     sapphire:fixedPt
+               GET     sapphire:screen
+               GET     sapphire:sqrt
+
+               GET     sapphire:dbx.dbx
+
+               GET     sapphire:string
+               GET     sapphire:note
+
+               GET     sapphire:_cs.kernel
+               GET     sapphire:_cs.vars
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- hsv_open ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Called by the colour picker
+
+               EXPORT  hsv_open
+hsv_open       ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Stack the link register
+               ADR     R0,hsv_dbName           ;Point to dialogue box name
+               BL      dbox_create             ;Create the dialogue box
+
+       ; --- TEMPORARY CODE ---
+
+               LDMVSFD R13!,{R1-R3,PC}         ;Return to caller
+               ADR     R1,hsv__dbh
+               MOV     R2,R10
+               MOV     R3,R12
+               BL      dbox_eventHandler
+               LDMVSFD R13!,{R1-R3,PC}         ;Return to caller
+               ADR     R1,hsv__dbxDef          ;Point to the control defn
+               BL      dbx_declare             ;Declare it to dbx nicely
+
+               LDMFD   R13!,{R1-R3,PC}         ;Return to caller
+
+
+hsv_dbName     DCB     "hsv",0
+
+hsv__dbxDef    CONTROL 0,hsvCircle,R10,0,0
+               ECTRL
+               DBXEND
+
+               LTORG
+
+hsv__dbh       ROUT
+
+               CMP     R0,#csEvent__close      ;Is this a close event?
+               MOVNES  PC,R14                  ;No -- return then
+               STMFD   R13!,{R0,R14}           ;Save registers
+               MOV     R0,R9
+               BL      dbox_destroy
+               LDMFD   R13!,{R0,PC}^
+
+               LTORG
+
+; --- hsv_plotCircle ---
+;
+; On entry:    R0 == x coord of centre of circle to plot
+;              R1 == y coord of centre of circle to plot
+;              R2 == x step (in OS units, must be power of 2)
+;              R3 == y step (in OS units, must be power of 2)
+;              R4 == value coordinate (in 16.16 form)
+;              R5 == pointer to graphics rectangle block
+;
+; On exit:     --
+;
+; Use:         Plots an HSV colour circle at the position specified.
+;              This should look really pretty as long as you're not using
+;              RISC OS 2 :-(.
+
+               EXPORT  hsv_plotCircle
+hsv_plotCircle ROUT
+
+               STMFD   R13!,{R0-R10,R12,R14}   ;Save a job lot of regs
+               MOV     R12,R5                  ;Keep pointer to graphics blk
+
+               ; --- Set up the radius value ---
+
+               MOV     R14,R4,LSR #9           ;Calculate the radius value
+               MUL     R10,R14,R14             ;Now square it and keep it
+
+               ; --- Work out the pixel sizes ---
+
+               BL      screen_getInfo          ;Find out about the screen
+               LDMIA   R0,{R6,R7}              ;Load the eign factors
+               MOV     R14,#1                  ;We're going to shift this
+               MOV     R6,R14,LSL R6           ;Calculate the x pixel size
+               MOV     R7,R14,LSL R7           ;And the y pixel size
+               STMFD   R13!,{R6,R7}            ;Save these for later use
+
+               ; --- Start the main loop off ---
+
+               LDR     R9,[R12,#12]            ;Get top of the rectangle
+               SUB     R9,R9,R1                ;Subtract the circle centre
+               CMP     R9,#127                 ;Is the rectangle too high?
+               MOVGT   R9,#127                 ;Yes -- start at circle top
+               SUB     R14,R3,#1               ;Turn ystep into bitmask
+               BIC     R9,R9,R14               ;And align to multiple nicely
+
+               ; --- Get start x position into R1 ---
+
+               LDR     R1,[R12,#0]             ;Get left hand side of area
+               LDR     R14,[R13,#8]            ;Load the centre position
+               SUB     R1,R1,R14               ;Subtract to get offset
+               CMP     R1,#-128                ;Is it too far to the left?
+               MOVLT   R1,#-128                ;Yes -- fix it up
+               SUB     R14,R2,#1               ;Turn xstep into bitmask
+               BIC     R1,R1,R14               ;Align to step value nicely
+
+               ; --- Get finish x position into R4 ---
+
+               LDR     R4,[R12,#8]             ;Get the right hand side pos
+               LDR     R0,[R13,#8]             ;Load the x centre position
+               SUB     R4,R4,R0                ;Convert to offset
+               CMP     R4,#128                 ;Is this off the right side?
+               MOVGT   R4,#128                 ;Yes -- stop being silly then
+
+               ; --- And now get finish y position into R5 ---
+
+               LDR     R5,[R12,#4]             ;Get the bottom pos
+               LDR     R0,[R13,#12]            ;Load the y centre position
+               SUB     R5,R5,R0                ;Convert to offset
+               SUB     R5,R5,R3                ;Get the bottom of the sqr
+               CMP     R5,#-128                ;Is this off the bottom?
+               MOVLT   R5,#-128                ;Yes -- don't be silly then
+
+               ; --- Plot a row ---
+
+00             MOV     R8,R1                   ;Start at beginning of row
+
+               ; --- Plot this rectangle ---
+
+01             LDMIA   R13,{R6,R7}             ;Load pixel widths and things
+               STMFD   R13!,{R1-R5,R8,R9}      ;Save some useful things
+               SUB     R4,R2,R6                ;xstep-dx
+               SUB     R5,R3,R7                ;ystep-dy
+
+               ; --- Calculate minx and maxx for given rectangle ---
+
+               MUL     R14,R9,R9               ;Get y^2
+               SUB     R6,R10,R14              ;Calculate minx
+               ADD     R0,R9,R5                ;y+ystep-dy
+               MUL     R14,R0,R0               ;(y+ystep-dy)^2
+               SUB     R7,R10,R14              ;Calculate maxx
+
+               ; --- Calculate various square values of x ---
+
+               MUL     R0,R8,R8                ;Get x^2
+               ADD     R14,R8,R2               ;Get x+xstep
+               MUL     R1,R14,R14              ;And square that too
+               CMP     R8,#0                   ;Is x negative
+               RSBLT   R0,R0,#0                ;Yes -- make R0 -ve
+               RSBLT   R1,R1,#0                ;...and make R1 -ve
+
+               ; --- Swap minx and maxx if we need to ---
+
+               MOV     R14,#0                  ;Clear our `swap' flag
+               CMP     R8,#0                   ;Is x < 0
+               EORGE   R14,R14,#1              ;No -- toggle swap flag
+               RSBLT   R6,R6,#0                ;Yes -- make it -ve
+               RSBLT   R7,R7,#0                ;...and that too
+               CMP     R9,#0                   ;Is y < 0
+               EORLT   R14,R14,#1              ;Yes -- toggle swap flag
+               TST     R14,#1                  ;Do we need to swap?
+               EORNE   R6,R6,R7                ;Yes -- swap them round
+               EORNE   R7,R6,R7
+               EORNE   R6,R6,R7
+
+               ; --- Is the rectangle outside the circle ---
+
+               CMP     R1,R6                   ;Is (x+xstep)^2<minx?
+               CMPLT   R8,#0                   ;Yes -- ensure x<0
+               BLT     %10hsv_plotCircle       ;It is -- plot a rectangle
+               CMP     R0,R7                   ;Is x^2>=maxx?
+               CMPGE   R8,#0                   ;Yes -- is x>=0
+               BLT     %20hsv_plotCircle       ;No -- Try an edge rectangle
+
+               ; --- Plot a blank square ---
+
+10             MOV     R0,#1                   ;Wimp colour 1
+               SWI     Wimp_SetColour          ;Set the colour
+               BL      hsv__plotRectangle      ;Plot the rectangle
+               B       %70hsv_plotCircle       ;And branch to the end
+
+               ; --- Is the rectangle on the circle edge? ---
+
+20             CMP     R8,#0                   ;Is x < 0?
+               CMPLT   R0,R7                   ;Is x^2<maxx?
+               BLT     %25hsv_plotCircle       ;Yes -- plot the circle
+               CMP     R8,#0                   ;Is x>=0
+               CMPGE   R1,R6                   ;Is (x+xstep)>=minx
+               BLT     %40hsv_plotCircle       ;No -- plot an entire square
+
+               ; --- Plot an edge square then ---
+
+25             MOV     R0,#1                   ;Wimp colour 1
+               SWI     Wimp_SetColour          ;Set the colour
+               BL      hsv__plotRectangle      ;Plot the rectangle
+               BL      hsv__setColour          ;Set the correct colour
+               ADD     R7,R9,R5                ;Our final loop value
+               ADD     R14,R13,#36             ;Point to centre coords
+               LDMIA   R14,{R3,R5}             ;Get the centre coordinates
+
+30             MUL     R14,R9,R9               ;y^2
+               SUBS    R0,R10,R14              ;Get r^2-y^2
+               BLT     %35hsv_plotCircle       ;Yes -- go round loop again
+       ;       BL      sqrt                    ;Calculate the square root
+
+               CMP     R8,#0                   ;Is x<0?
+               RSBLT   R1,R0,#0                ;Yes -- get xstart pos
+               ADDLT   R6,R8,R4                ;...and xend position
+               MOVGE   R1,R8                   ;No -- this xstart
+               LDRGE   R6,[R13,#28]            ;...get dx
+               SUBGE   R6,R0,R6                ;...and calc xend pos
+
+               CMP     R1,R6                   ;Is there anything to plot?
+               BGT     %35hsv_plotCircle       ;No -- skip this line out
+               ADD     R1,R1,R3                ;x0
+               ADD     R2,R9,R5                ;y0
+               MOV     R0,#4                   ;Move absolute
+               SWI     OS_Plot                 ;Do the move
+               MOV     R0,#5                   ;Plot solid line absolute
+               ADD     R1,R3,R6                ;x1
+               ADD     R2,R9,R5                ;y1
+               SWI     OS_Plot                 ;Do the move
+
+35             LDR     R14,[R13,#32]           ;Get dy
+               ADD     R9,R9,R14               ;Increment y value
+               CMP     R9,R7                   ;Are we at the end?
+               BLE     %30hsv_plotCircle       ;And keep ploting lines
+               B       %70                     ;Finished this square
+
+               ; --- Now plot an entire coloured square ---
+
+40             BL      hsv__setColour          ;Set the colour
+               BL      hsv__plotRectangle      ;Plot it then
+
+               ; --- Find which square to do next ---
+
+70             LDMFD   R13!,{R1-R5,R8,R9}      ;Get back registers
+
+               ADD     R8,R8,R2                ;Increment R8 nicely
+               CMP     R8,R4                   ;Have we finished a row?
+               BLT     %01hsv_plotCircle       ;No -- do some more then
+
+               SUB     R9,R9,R3                ;Move down to the next row
+               CMP     R9,R5                   ;Have we finished it yet?
+               BGE     %00hsv_plotCircle       ;No -- do the next row
+
+               ; --- We did it then! ---
+
+               ADD     R13,R13,#8              ;Skip past variable area
+               LDMFD   R13!,{R0-R10,R12,PC}^   ;Jubilations and things
+
+               LTORG
+
+; --- hsv__plotRectangle ---
+;
+; On entry:    R4 == width
+;              R5 == height
+;              R8 == x offset from centre
+;              R9 == y offset from centre
+;              R13+36 centre coordinates
+;
+; On exit:     R0-R2 corrupted
+
+hsv__plotRectangle ROUT
+
+               ADD     R0,R13,#36              ;Point to circle centre
+               LDMIA   R0,{R1,R2}              ;Load the coordinates
+               MOV     R0,#4                   ;Move cursor absolute
+               ADD     R1,R1,R8                ;To this x coord
+               ADD     R2,R2,R9                ;And this y coord
+               SWI     OS_Plot                 ;Do the move
+               MOV     R0,#97                  ;Rectangle fill relative
+               MOV     R1,R4                   ;This wide
+               MOV     R2,R5                   ;This high
+               SWI     OS_Plot                 ;Plot the rectangle
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- hsv__setColour ---
+;
+; On entry:    R0 == x coord
+;              R1 == y coord
+;              R10 == radius^2
+;              R13+52 == value
+;
+; On exit:     --
+
+hsv__setColour ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+               BL      fxp_pol                 ;Calculate hue
+               MOV     R3,R0                   ;Preserve angle
+
+               MUL     R14,R1,R1               ;Get y^2
+               MUL     R0,R2,R2                ;Get x^2
+               ADD     R0,R0,R14               ;Add them
+               MOV     R1,R10                  ;Get radius^2
+               MOV     R0,R0,LSL#16            ;Prepare for division
+               CMP     R1,#0                   ;Will we divide by 0?
+               BLNE    div_round               ;No -- perform the division
+               MOVEQ   R0,#0                   ;Yes -- make it 0 for luck
+               MOV     R1,R0                   ;The saturation
+               MOV     R0,R3                   ;Get hue back
+               LDR     R2,[R13,#76]            ;Get value
+               BL      hsv_HSVToRGB            ;Convert to RGB
+               RSB     R0,R0,R0,LSL#8          ;Multiple by 255
+               RSB     R1,R1,R1,LSL#8          ;Multiple by 255
+               RSB     R2,R2,R2,LSL#8          ;Multiple by 255
+               AND     R0,R0,#&FF0000          ;Ensure it's 0-255
+               AND     R1,R1,#&FF0000          ;Ensure it's 0-255
+               AND     R2,R2,#&FF0000          ;Ensure it's 0-255
+               MOV     R0,R0,LSR#8             ;Set up red component
+               ORR     R0,R0,R1                ;And green component
+               ORR     R0,R0,R2,LSL#8          ;And finally blue
+               MOV     R14,R0                  ;Preserve R0
+               MOV     R3,#&100                ;The colourTrans flags
+               MOV     R4,#0                   ;GCOL action
+               SWI     XColourTrans_SetGCOL    ;Set the colour
+               MOVVS   R3,#0                   ;Try without dither
+               MOVVS   R0,R14                  ;Get colour back
+               SWIVS   ColourTrans_SetGCOL     ;Set the colour
+
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- hsv__plot32k ---
+;
+; On entry:    R0 == left hand side of colour square to plot
+;              R1 == bottom edge of colour square to plot
+;              R2 == pointer to graphics window block
+;              R3 == pointer to screen information block
+;              R7 == unlimited minimum x position to plot
+;              R8 == unlimited minimum y position to plot
+;              R9 == unlimited maximum x position to plot
+;              R10 == unlimited maximum y position to plot
+;              On stack: saved {R0-R12,R14}
+;
+; On exit:     --
+;
+; Use:         Displays an HSV circle on the screen at a given location,
+;              in a 16bpp mode, using direct screen access.
+
+hsv__plot32k   ROUT
+
+               ; --- Limit the relative box positions ---
+
+               ADD     R4,R3,#screen_dx        ;Find the pixel positions
+               LDMIA   R4,{R4,R5}              ;Load them into registers
+
+               CMP     R7,#0                   ;Is min x too small?
+               MOVLT   R7,#0                   ;Yes -- raise it to 0
+               CMP     R8,#0                   ;Is min y too small?
+               MOVLT   R8,#0                   ;Yes --- raise that too
+               CMP     R9,#256                 ;Is the max x too large?
+               MOVGT   R9,#256                 ;Yes -- reduce it then
+               CMP     R10,#256                ;Is the max y too large?
+               MOVGT   R10,#256                ;Yes -- reduce it then
+               SUB     R9,R9,R4                ;Make this inclusive
+               SUB     R10,R10,R5              ;Make this inclusive too
+
+               ; --- Find address of thing on the screen ---
+
+               MOV     R5,R7                   ;Remember left hand offset
+               MOV     R6,R10                  ;And right hand one
+
+               SUB     R9,R9,R7                ;Work out width
+               SUB     R8,R10,R8               ;And height
+               ADD     R7,R7,R0                ;Work out left hand side
+               ADD     R10,R10,R1              ;And maximum y
+
+               SUB     R13,R13,#20             ;Space for our vdu vars
+               ADR     R0,hsv__vduVars         ;Point to the var numbers
+               MOV     R1,R13                  ;Point to our output block
+               SWI     OS_ReadVduVariables     ;Get the values nicely
+
+               ; --- Convert things to pixels sizes ---
+
+               LDMIA   R13!,{R3,R4}            ;Load out eig factors
+               MOV     R7,R7,LSR R3            ;Convert left hand side
+               MOV     R8,R8,LSR R4            ;And height
+               MOV     R9,R9,LSR R3            ;The width too
+               MOV     R10,R10,LSR R4          ;And the top coord
+
+               LDMIA   R13!,{R0,R1,R2}         ;Load other vdu vars
+               SUB     R14,R1,R10              ;Shift origin to top left
+               MLA     R0,R14,R2,R0            ;Work out address of row
+               ADD     R12,R0,R7,LSL #1        ;Work out left address
+               ADD     R11,R12,R9,LSL #1       ;Work out right hand side too
+               MOV     R9,R2                   ;Put scan line width in R9
+               MOV     R10,R8                  ;And height in R10
+
+               SUB     R8,R5,#128              ;Work out x start position
+               SUB     R7,R6,#128              ;And y start position
+
+               MOV     R14,#1                  ;Get a useful value
+               MOV     R6,R14,LSL R3           ;x step
+               MOV     R5,R14,LSL R4           ;y step
+               MOV     R4,R8                   ;Initial x value
+               MOV     R3,#&10000              ;Value
+
+               ; --- Plot the circle then ---
+
+10hsv__plot32k MOV     R0,#0                   ;Clear buffer register
+               MOV     R1,R12                  ;Get the current address
+
+               BL      hsv__getColour32        ;Get the colour then
+
+               TST     R1,#2                   ;Is this address aligned?
+               BEQ     %20hsv__plot32k         ;Yes -- start at main loop
+               LDR     R14,[R1,#-2]            ;No -- load word from here
+               MOV     R14,R14,LSL #16         ;Shift all the way up
+               ORR     R14,R0,R14,LSR #16      ;Build the replacement word
+               STR     R14,[R1,#-2]            ;And store in frame buffer
+               B       %25hsv__plot32k         ;Jump to end of loop
+
+               ; --- Now the main plotting loop ---
+
+20hsv__plot32k TST     R1,#2                   ;Is this an odd address?
+               STRNE   R0,[R1,#-2]             ;Yes -- done both half words
+
+25hsv__plot32k ADD     R1,R1,#2                ;Move onto next pixel
+               ADD     R8,R8,R6                ;Increment x position
+               CMP     R1,R11                  ;Are we at the line end?
+               BLLS    hsv__getColour32        ;No -- get the colour then
+               BLS     %20hsv__plot32k         ;...and go round for more
+
+               ; --- We've finished; do we have a half word left over? ---
+
+30hsv__plot32k TST     R1,#2                   ;Is the address odd?
+               BEQ     %35hsv__plot32k         ;No -- jump ahead
+               LDR     R14,[R1,#-2]            ;Yes -- read old word
+               MOV     R0,R0,LSR #16           ;Put buffer value in low hw
+               MOV     R14,R14,LSR #16         ;Shift down screen value too
+               ORR     R14,R0,R14,LSL #16      ;Build up correct word
+               STR     R14,[R1,#-2]            ;Store this word away
+
+               ; --- Move onto the next row ---
+
+35hsv__plot32k ADD     R12,R12,R9              ;Move left address down
+               ADD     R11,R11,R9              ;And the right address
+               SUB     R7,R7,R5                ;Decrement the y position
+               MOV     R8,R4                   ;Initial start x position
+               SUBS    R10,R10,#1              ;Decrement the line count
+               BCS     %10hsv__plot32k         ;And keep on going
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               LTORG
+
+hsv__vduVars   DCD     4,5                     ;X and Y eigen factors
+               DCD     149                     ;Start of display memory
+               DCD     12                      ;How high is the screen
+               DCD     6                       ;Width of scan line in pixels
+               DCD     -1
+
+; --- hsv__getColour32 ---
+;
+; On entry:    R0 == colour word so far
+;              R1 == current screen address
+;              R3 == value (16.16)
+;              R7 == y position
+;              R8 == x position
+;
+; On exit:     R0 == updated colour word
+;
+;
+; Use:         Determines the colour of the pixel at the given position
+;              for a 32k colour mode
+
+hsv__getColour32 ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Stack some regsiters
+
+               MOV     R5,R0                   ;Look after old colour
+               MUL     R2,R7,R7                ;Get y^2
+               MUL     R14,R8,R8               ;Get x^2
+               ADD     R2,R2,R14               ;Get x^2+y^2
+               CMP     R2,#&4000               ;Is this in range?
+               BCS     %50hsv__getColour32     ;No -- do really clever stuff
+
+               MOV     R0,R8                   ;Put x position in R0
+               MOV     R1,R7                   ;And x position in R1
+               BL      fxp_pol                 ;Calculate hue
+               MOV     R4,R0                   ;Preserve angle
+
+               MOV     R0,R2                   ;x^2 + y^2
+               MOV     R1,#&4000               ;Get radius^2
+               MOV     R0,R0,LSL#16            ;Prepare for division
+               CMP     R1,#0                   ;Will we divide by 0?
+               BLNE    div_round               ;No -- perform the division
+               MOVEQ   R0,#0                   ;Yes -- make it 0 for luck
+
+               MOV     R1,R0                   ;The saturation
+
+               MOV     R0,R4                   ;Get hue back
+               MOV     R2,R3                   ;Put value in R2
+               BL      hsv_HSVToRGB            ;Convert to RGB
+
+               RSB     R0,R0,R0,LSL#5          ;Multiple by 31
+               RSB     R1,R1,R1,LSL#5          ;Multiple by 31
+               RSB     R2,R2,R2,LSL#5          ;Multiple by 31
+               AND     R0,R0,#&1F0000          ;Ensure it's 0-31
+               AND     R1,R1,#&1F0000          ;Ensure it's 0-31
+               AND     R2,R2,#&1F0000          ;Ensure it's 0-31
+
+               ORR     R14,R0,R1,LSL #5        ;Red and green
+               ORR     R14,R14,R2,LSL #10      ;...blue
+
+               ORR     R0,R14,R5,LSR #16       ;Return colour number
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to caller
+
+               ; --- Position is out of range ---
+
+50             LDR     R14,[R1,#0]             ;Load halfword at address
+               MOV     R14,R14,LSL #16         ;Put it into top halfword
+               ORR     R0,R14,R5,LSR #16       ;Build up new colour value
+               LDMFD   R13!,{R1-R5,PC}^        ;And return to caller
+
+               LTORG
+
+; --- hsv__plot16m ---
+;
+; On entry:    R0 == left hand side of colour square to plot
+;              R1 == bottom edge of colour square to plot
+;              R2 == pointer to graphics window block
+;              R3 == pointer to screen information block
+;              R7 == unlimited minimum x position to plot
+;              R8 == unlimited minimum y position to plot
+;              R9 == unlimited maximum x position to plot
+;              R10 == unlimited maximum y position to plot
+;              On stack: saved {R0-R12,R14}
+;
+; On exit:     --
+;
+; Use:         Displays an HSV circle on the screen at a given location,
+;              in a 32bpp mode, using direct screen access.
+
+hsv__plot16m   ROUT
+
+               ; --- Limit the relative box positions ---
+
+               ADD     R4,R3,#screen_dx        ;Find the pixel positions
+               LDMIA   R4,{R4,R5}              ;Load them into registers
+
+               CMP     R7,#0                   ;Is min x too small?
+               MOVLT   R7,#0                   ;Yes -- raise it to 0
+               CMP     R8,#0                   ;Is min y too small?
+               MOVLT   R8,#0                   ;Yes --- raise that too
+               CMP     R9,#256                 ;Is the max x too large?
+               MOVGT   R9,#256                 ;Yes -- reduce it then
+               CMP     R10,#256                ;Is the max y too large?
+               MOVGT   R10,#256                ;Yes -- reduce it then
+               SUB     R9,R9,R4                ;Make this inclusive
+               SUB     R10,R10,R5              ;Make this inclusive too
+
+               ; --- Find address of thing on the screen ---
+
+               MOV     R5,R7                   ;Remember left hand offset
+               MOV     R6,R10                  ;And right hand one
+
+               SUB     R9,R9,R7                ;Work out width
+               SUB     R8,R10,R8               ;And height
+               ADD     R7,R7,R0                ;Work out left hand side
+               ADD     R10,R10,R1              ;And maximum y
+
+               SUB     R13,R13,#20             ;Space for our vdu vars
+               ADR     R0,hsv__vduVars         ;Point to the var numbers
+               MOV     R1,R13                  ;Point to our output block
+               SWI     OS_ReadVduVariables     ;Get the values nicely
+
+               ; --- Convert things to pixels sizes ---
+
+               LDMIA   R13!,{R3,R4}            ;Load out eig factors
+               MOV     R7,R7,LSR R3            ;Convert left hand side
+               MOV     R8,R8,LSR R4            ;And height
+               MOV     R9,R9,LSR R3            ;The width too
+               MOV     R10,R10,LSR R4          ;And the top coord
+
+               LDMIA   R13!,{R0,R1,R2}         ;Load other vdu vars
+               SUB     R14,R1,R10              ;Shift origin to top left
+               MLA     R0,R14,R2,R0            ;Work out address of row
+               ADD     R12,R0,R7,LSL #2        ;Work out left address
+               ADD     R11,R12,R9,LSL #2       ;Work out right hand side too
+               MOV     R9,R2                   ;Put scan line width in R9
+               MOV     R10,R8                  ;And height in R10
+
+               SUB     R8,R5,#128              ;Work out x start position
+               SUB     R7,R6,#128              ;And y start position
+
+               MOV     R14,#1                  ;Get a useful value
+               MOV     R6,R14,LSL R3           ;x step
+               MOV     R5,R14,LSL R4           ;y step
+               MOV     R4,R8                   ;Initial x value
+               MOV     R3,#&10000              ;Value
+
+               ; --- Plot the circle then ---
+
+10hsv__plot16m MOV     R1,R12                  ;Get the current address
+
+               ; --- Now the main plotting loop ---
+
+20hsv__plot16m BL      hsv__getColour16        ;Get the colour then
+               STR     R0,[R1],#4              ;Yes -- done both half words
+
+25hsv__plot16m ADD     R8,R8,R6                ;Increment x position
+               CMP     R1,R11                  ;Are we at the line end?
+               BLS     %20hsv__plot16m         ;...and go round for more
+
+               ; --- Move onto the next row ---
+
+30hsv__plot16m ADD     R12,R12,R9              ;Move left address down
+               ADD     R11,R11,R9              ;And the right address
+               SUB     R7,R7,R5                ;Decrement the y position
+               MOV     R8,R4                   ;Initial start x position
+               SUBS    R10,R10,#1              ;Decrement the line count
+               BCS     %10hsv__plot16m         ;And keep on going
+
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- hsv__getColour16--
+;
+; On entry:    R3 == value (16.16)
+;              R7 == y position
+;              R8 == x position
+;
+; On exit:     R0 == updated colour word
+;
+; Use:         Determines the colour of the pixel at the given position
+;              for a 32m colour mode
+
+hsv__getColour16 ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack some regsiters
+
+               MUL     R2,R7,R7                ;Get y^2
+               MUL     R4,R8,R8                ;Get x^2
+               ADD     R2,R2,R4                ;Get x^2+y^2
+               CMP     R2,#&4000               ;Is this in range?
+               LDRCS   R0,[R1,#0]              ;No -- load previous colour
+               LDMCSFD R13!,{R1-R4,PC}^        ;And return to caller
+
+               MOV     R0,R8                   ;Put x position in R0
+               MOV     R1,R7                   ;And x position in R1
+               BL      fxp_pol                 ;Calculate hue
+               MOV     R4,R0                   ;Preserve angle
+
+               MOV     R0,R2                   ;x^2 + y^2
+               MOV     R1,#&4000               ;Get radius^2
+               MOV     R0,R0,LSL#16            ;Prepare for division
+               CMP     R1,#0                   ;Will we divide by 0?
+               BLNE    div_round               ;No -- perform the division
+               MOVEQ   R0,#0                   ;Yes -- make it 0 for luck
+
+               MOV     R1,R0                   ;The saturation
+               MOV     R0,R4                   ;Get hue back
+               MOV     R2,R3                   ;Put value in R2
+               BL      hsv_HSVToRGB            ;Convert to RGB
+
+               RSB     R0,R0,R0,LSL#8          ;Multiple by 255
+               RSB     R1,R1,R1,LSL#8          ;Multiple by 255
+               RSB     R2,R2,R2,LSL#8          ;Multiple by 255
+               AND     R0,R0,#&FF0000          ;Ensure it's 0-255
+               AND     R1,R1,#&FF0000          ;Ensure it's 0-255
+               AND     R2,R2,#&FF0000          ;Ensure it's 0-255
+
+               ORR     R0,R2,R0,LSR #16        ;Get red & blue components
+               ORR     R0,R0,R1,LSR #8         ;And green
+
+               LDMFD   R13!,{R1-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- hsv__plotCircle ---
+;
+; On entry:    R0 == left hand side of colour square to plot
+;              R1 == bottom edge of colour square to plot
+;              R2 == pointer to graphics window block
+;
+; On exit:     --
+;
+; Use:         Dispatches to the most suitable hsv plotting routine for
+;              the given mode.
+
+hsv__plotCircle        ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save lots of registers
+
+               ; --- Work out the minimum coordinates ---
+
+               LDMIA   R2,{R7,R8,R9,R10}       ;Load the coordinates out
+               SUB     R7,R7,R0                ;Translate min x to relative
+               SUB     R8,R8,R1                ;Translate min y too
+               SUB     R9,R9,R0                ;Translate max x too
+               SUB     R10,R10,R1              ;Translate max y
+
+               ; --- Try to dispatch ---
+
+               MOV     R4,R0                   ;Look after left hand side
+
+               BL      screen_getInfo          ;Get screen info block
+               MOV     R3,R0                   ;Put it in R3
+               MOV     R0,R4                   ;And get left hand side back
+               LDR     R14,[R3,#screen_bpp]    ;Load current bits/pixel
+               CMP     R14,#16                 ;Is this a 32K mode?
+               BEQ     hsv__plot32k            ;Yes -- well, go to it
+               CMP     R14,#32                 ;Is this a 32K mode?
+               BEQ     hsv__plot16m
+
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- The dbx control ---
+
+hsvCircle      ROUT
+
+               DCD     0,0
+               DCD     dbxMask_redraw+dbxMask_click
+
+               CMP     R0,#dbxEvent_click
+               BEQ     %10
+
+               STMFD   R13!,{R0-R2,R10,R14}    ;Stack some registers
+               MOV     R10,R8                  ;Put dbox data in R10
+               MOV     R0,R2                   ;Put bottom left in R0
+               MOV     R1,R3                   ;And bottom right in R1
+               MOV     R2,R6                   ;Put graphics rectangle in R2
+               BL      hsv__plotCircle         ;Plot the circle then
+               LDMFD   R13!,{R0-R2,R10,PC}^    ;Return to caller
+
+10             STMFD   R13!,{R0-R5,R14}
+               MOV     R0,R10
+               BL      dbx_controlBBox
+               SUB     R4,R4,R2
+               SUB     R5,R5,R3
+               ADD     R0,R2,R4,LSR #1
+               ADD     R1,R3,R5,LSR #1
+               MOV     R2,#128
+               SWI     Constrain_Disc
+               LDMFD   R13!,{R0-R5,PC}^
+
+               LTORG
+
+               [ 0=1
+; --- sqrt ---
+;
+; On entry:    R0 == number to find square root of
+;
+; On exit:     R0 == square root of number passed in
+;
+; Use:         Calculates the square root of the number passed to
+;              the nearest integer
+
+sqrt           ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Stack some registers
+               MOV     R4,R0,LSR#2             ;Get an approximation
+               MOV     R3,#-1                  ;The old value
+               MOV     R2,R0                   ;Keep this value
+               MOV     R5,#10                  ;Maximum number of iterations
+
+00sqrt         MOV     R0,R2,ASR #1            ;Divide number to squareroot
+               MOVS    R1,R4                   ;By 2*our approximation
+               BEQ     %01sqrt                 ;Divide by 0 -- leave now
+               BL      div_round               ;Round result to nearest
+               ADD     R4,R0,R4,ASR #1         ;Add this to x/2
+
+               SUBS    R5,R5,#1                ;Decrement iteration count
+               BEQ     %01sqrt                 ;Too low -- skip to end
+
+               CMP     R4,R3                   ;Is solution same as last?
+               MOVNE   R3,R4                   ;No -- remember result
+               BNE     %00sqrt                 ;...and keep trying
+
+01sqrt         MOV     R0,R4                   ;Return root in R0
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to caller
+
+               LTORG
+               ]
+
+; --- HSV -> RGB conversion ---
+
+; --- div60 ---
+;
+; On entry:    R0 == integer to divide
+;
+; On exit:     R0 == quotient after division by 60
+;              R1 == remainder after division by 60
+;
+; Use:         Divides an integer very quickly by 60.
+;
+; [Generated by Straylight divc]
+
+div60          ROUT
+
+               STMFD R13!,{R2,R14}
+               MOVS R2,R0
+               RSBMI R0,R0,#0
+               MOV R1,R0
+
+               ADD R0,R0,R0,LSR#4
+               ADD R0,R0,R0,LSR#8
+               ADD R0,R0,R0,LSR#16
+
+               MOV R0,R0,LSR #6
+
+               RSB R14,R0,R0,LSL#4
+               MOV R14,R14,LSL#2
+
+               SUB R1,R1,R14
+               SUBS R1,R1,#60
+               ADDGE R0,R0,#1
+               ADDLT R1,R1,#60
+
+               CMP R2,#0
+               RSBMI R0,R0,#0
+               RSBMI R1,R1,#0
+               LDMFD R13!,{R2,PC}^
+
+               LTORG
+
+; --- hsv_HSVToRGB ---
+;
+; On entry:    R0 == hue
+;              R1 == saturation
+;              R2 == value
+;
+; On exit:     R0 == red
+;              R1 == green
+;              R2 == blue
+;
+; Use:         Convert a colour in HSV to the equivalent in RGB notation.
+;              All number are taken in 16.16 fixed point form. RGB values
+;              range from 0 to 1 on output.
+
+hsv_HSVToRGB   ROUT
+
+               STMFD   R13!,{R3-R7,R14}        ;Stack some registers
+
+               CMP     R0,#(360<<16)           ;Is hue 360?
+               MOVEQ   R0,#0                   ;Yes -- make it 0
+
+               MOV     R3,R1                   ;Put saturation in R3
+               BL      div60                   ;Divide hue by 60
+               BIC     R1,R0,#&FF0000          ;Get fractional part in R1
+               MOV     R0,R0,LSR#16            ;And integer part in R0
+
+               MOV     R4,R2,LSR#8             ;For multiplication
+               RSB     R5,R3,#1<<16            ;1-saturation (16.16 form)
+               MOV     R5,R5,LSR#8             ;Shift for division
+               MUL     R5,R4,R5                ;Minimum=value*(1-saturation)
+               MOV     R14,R3,LSR#8            ;Saturation >> 8
+               MOV     R6,R1,LSR#8             ;Fractional >> 8
+               MUL     R6,R14,R6               ;Saturation*fractional
+               RSB     R6,R6,#1<<16            ;1-(previous result)
+               MOV     R6,R6,LSR#8             ;Prepare for multiplication
+               MUL     R6,R4,R6                ;Inverse1=value*(prev result)
+               RSB     R7,R1,#1<<16            ;1-fractional
+               MOV     R7,R7,LSR#8             ;Prepare for multiplication
+               MUL     R7,R14,R7               ;Saturation*(1-fractional)
+               RSB     R7,R7,#1<<16            ;1-(sat*(1-fractional))
+               MOV     R7,R7,LSR#8             ;Prepare for multiplication
+               MUL     R7,R4,R7                ;Value*(1-(sat*(1-frac)))
+
+               ; --- Find out which section number we are in ---
+
+               CMP     R0,#0                   ;Section 0?
+               BNE     %10hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R2                   ;Red = value
+               MOV     R1,R7                   ;Green = inverse2
+               MOV     R2,R5                   ;Blue = minimum
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+10hsv_HSVToRGB CMP     R0,#1                   ;Section 1?
+               BNE     %20hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R6                   ;Red = inverse1
+               MOV     R1,R2                   ;Green = value
+               MOV     R2,R5                   ;Blue = minimum
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+20hsv_HSVToRGB CMP     R0,#2                   ;Section 2?
+               BNE     %30hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R5                   ;Red = minimum
+               MOV     R1,R2                   ;Green = value
+               MOV     R2,R7                   ;Blue = inverse2
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+30hsv_HSVToRGB CMP     R0,#3                   ;Section 3?
+               BNE     %40hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R5                   ;Red = minimum
+               MOV     R1,R6                   ;Green = inverse1
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+40hsv_HSVToRGB CMP     R0,#4                   ;Section 0?
+               BNE     %50hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R7                   ;Red = inverse2
+               MOV     R1,R5                   ;Green = minimum
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+50hsv_HSVToRGB CMP     R0,#5                   ;Section 0?
+               BNE     %60hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R2                   ;Red = value
+               MOV     R1,R5                   ;Green = minimum
+               MOV     R2,R6                   ;Blue = inverse1
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+60hsv_HSVToRGB ADR     R0,convert__error       ;Point to the error message
+               SWI     OS_GenerateError        ;And generate an error
+
+convert__error DCD     1
+               DCB     "Fatal error: hsv_HSVToRGB -- section >5 reached",0
+
+               LTORG
+
+;----- Workspace layout -----------------------------------------------------
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     0
+               DCD     0
+               DCD     0
+               DCD     0
+
+;-- That's all, folks -------------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/colSelect/s/rgb b/StraySrc/Libraries/Sapphire/colSelect/s/rgb
new file mode 100644 (file)
index 0000000..622bd2c
--- /dev/null
@@ -0,0 +1,1602 @@
+;
+; rgb.s
+;
+; Handling the RGB colour model dialogue box
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:divide
+               GET     sapphire:idle
+               GET     sapphire:roVersion
+               GET     sapphire:screen
+               GET     sapphire:win
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx.arrow
+               GET     sapphire:dbx.numWrite
+               GET     sapphire:dbx.slider
+
+               GET     sapphire:_cs.kernel
+               GET     sapphire:_cs.vars
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- rgb_open ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Called by the colour picker
+
+               EXPORT  rgb_open
+rgb_open       ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Stack the link register
+               ADR     R0,rgb__dbName          ;Point to dialogue box name
+               BL      dbox_create             ;Create the dialogue box
+               LDMVSFD R13!,{R1-R3,PC}         ;Return now if it failed
+               STR     R0,[R13,#-4]!           ;Return dialogue handle in R0
+
+               ; --- Attach event handlers and things ---
+
+               ADR     R1,rgb__dbHandler       ;Point to my handler code
+               MOV     R2,R10                  ;Pass colour workspace in R10
+               MOV     R3,R12                  ;Pass my workspace in R12
+               BL      dbox_eventHandler       ;Register my event handler
+               ADR     R1,rgb__dbxDef          ;Point to the control defn
+               BL      dbx_declare             ;Declare it to dbx nicely
+
+               ; --- Set up the workspace ---
+
+               MOV     R0,#0                   ;Set the Red mapping
+               BL      rgb__setMapping         ;Set this as the mapping
+
+               ; --- Set up the dialogue box ---
+
+               LDR     R0,[R13,#0]             ;Load the dialogue handle
+               LDR     R1,rgb__mapping         ;Get the current mapping
+               ADD     R1,R1,R1,LSL #2         ;Multiply by icon offset (5)
+               ADD     R1,R1,#rgbIcon__radioR  ;Add on to get icon number
+               MOV     R2,#1                   ;Please select this icon
+               BL      dbox_select             ;Select the right one
+
+               MOV     R1,#rgbIcon__writeR     ;Get the red writable icon
+               LDR     R2,rgb__red             ;Find the red value
+               LDR     R2,[R2,#0]              ;Load the red value
+               BL      numWrite_set            ;Set it in the icon
+
+               MOV     R1,#rgbIcon__writeG     ;Get the green writable icon
+               LDR     R2,rgb__green           ;Find the green value
+               LDR     R2,[R2,#0]              ;Load the green value
+               BL      numWrite_set            ;Set it in the icon
+
+               MOV     R1,#rgbIcon__writeB     ;Get the blue writable icon
+               LDR     R2,rgb__blue            ;Find the blue value
+               LDR     R2,[R2,#0]              ;Load the blue value
+               BL      numWrite_set            ;Set it in the icon
+               LDMFD   R13!,{R0-R3,R14}        ;Return to caller
+
+rgb__dbName    DCB     "rgb",0
+
+rgb__dbxDef    CONTROL rgbIcon__square,rgbSquare,R10,0,0
+               ECTRL
+
+               SLIDER  rgbIcon__slide1,R10,:INDEX: rgb__sl1Val,                                        slFlag_horizontal + slFlag_colData,0,0,1,100
+               NUMWRT  rgbIcon__writeR,0,100
+               ARROW   rgbIcon__upR,1
+               ARROW   rgbIcon__downR,-1
+
+               SLIDER  rgbIcon__slide2,R10,:INDEX: rgb__sl2Val,                                        slFlag_vertical + slFlag_colData,0,0,1,100
+               NUMWRT  rgbIcon__writeG,0,100
+               ARROW   rgbIcon__upG,1
+               ARROW   rgbIcon__downG,-1
+
+               SLIDER  rgbIcon__slide3,R10,:INDEX: rgb__sl3Val,                                        slFlag_vertical + slFlag_colData,0,0,1,100
+               NUMWRT  rgbIcon__writeB,0,100
+               ARROW   rgbIcon__upB,1
+               ARROW   rgbIcon__downB,-1
+
+               DBXEND
+
+; --- rgb__dbHandler ---
+;
+; On entry:    R0 == dialogue box event code
+;              R1-R7 == depend on the event
+;              R9 == dialogue box handle of RGB panel
+;              R10 == pointer to colour selector workspace
+;              R12 == nothing much
+;
+; On exit:     --
+;
+; Use:         Handles events for the RGB panel.
+
+rgb__dbHandler ROUT
+
+               ; --- Dispatch events to their destinations ---
+
+               CMP     R0,#rgbIcon__radioR     ;Is it the red view button?
+               CMPNE   R0,#rgbIcon__radioG     ;Or the green view button?
+               CMPNE   R0,#rgbIcon__radioB     ;Or the blue view button?
+               BEQ     rgb__setView            ;Yes -- set the new view
+
+               CMP     R0,#csEvent__close      ;Is it a close panel event?
+               BEQ     rgb__closePanel         ;Yes -- destroy the dialogue
+
+               CMP     R0,#csEvent__newRes     ;Is it a resolution change?
+               BEQ     rgb__newRes             ;Yes -- update the piccy then
+
+               CMP     R0,#slider_event        ;Is it a slider event?
+               BEQ     rgb__slChange           ;Yes -- do something then
+
+               CMP     R0,#numWrite_event      ;Is it a writable event?
+               BEQ     rgb__wrChange           ;Yes -- do something then
+
+               CMP     R0,#arrow_event         ;Is it an arrow event?
+               BEQ     rgb__arChange           ;Yes -- do something then
+
+               STMFD   R13!,{R14}              ;Save a register
+               SUB     R14,R0,#rgbIcon__wCols  ;Is it a WIMP colour box?
+               CMP     R14,#16                 ;Check it's in range
+               BLO     rgb__wimpCol            ;Yes -- handle it then
+
+               LDMFD   R13!,{PC}^              ;Unknown -- return to caller
+
+               ; --- Change the panel view ---
+
+rgb__setView   ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               CMP     R0,#rgbIcon__radioG     ;Is it the green button?
+               MOVLT   R3,#0                   ;Lower -- it must be red
+               MOVEQ   R3,#1                   ;Equal -- must be green
+               MOVGT   R3,#2                   ;Greater -- must be blue
+               LDR     R1,rgb__mapping         ;Get the current mapping
+               CMP     R3,R1                   ;Is it the same?
+               LDMEQFD R13!,{R0-R3,PC}^        ;Yes -- return now then
+
+               ; --- Select the correct icon ---
+
+               MOV     R0,R9                   ;Load the dialogue handle
+               ADD     R1,R1,R1,LSL #2         ;Multiply by icon offset (5)
+               ADD     R1,R1,#rgbIcon__radioR  ;Add on to get icon number
+               MOV     R2,#0                   ;Please deselect this icon
+               BL      dbox_select             ;Select the right one
+
+               ADD     R1,R3,R3,LSL #2         ;Multiply by icon offset (5)
+               ADD     R1,R1,#rgbIcon__radioR  ;Add on to get icon number
+               MOV     R2,#1                   ;Please select this icon
+               BL      dbox_select             ;Select the right one
+
+               ; --- Update the dialogue box sliders etc. ---
+
+               MOV     R0,R9                   ;Get the dialogue box handle
+               MOV     R1,#rgbIcon__square     ;Get the colour square
+               BL      dbx_qUpdate             ;Get rid of the crosshair
+               MOV     R0,R3                   ;Pass mapping number
+               BL      rgb__setMapping         ;Redo all the mappings
+               BL      rgb__updateSliders      ;And redraw the sliders
+               MOV     R0,R9                   ;Get the dialogue box handle
+               MOV     R1,#rgbIcon__square     ;Get the colour square
+               BL      dbx_update              ;Redraw it nicely
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               ; --- Update the RGB colour cube view ---
+
+rgb__newRes    ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               MOV     R0,R9                   ;Get the dialogue handle
+               MOV     R1,#rgbIcon__square     ;Get the colour square
+               BL      dbx_qUpdate             ;Get rid of the crosshair
+               BL      dbx_update              ;Redraw it nicely
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               ; --- Update colour values ---
+
+rgb__slChange  ROUT
+
+               STMFD   R13!,{R0-R2,R4,R14}     ;Save some registers
+
+               ; --- Update the main dialogue's colour pot ---
+
+               BL      rgb__colUpdate          ;Update the colour pot
+
+               ; --- Now update the writable icon ---
+
+               LDR     R2,[R13,#8]             ;Load the slider icon
+               SUB     R4,R2,#rgbIcon__slide1  ;Get the slider axis number
+               LDR     R14,rgb__mapping        ;Load the mapping number
+               SUB     R1,R14,R4               ;Find the table index
+               ADR     R14,rgb__writeTbl+2     ;Point to the table
+               LDRB    R1,[R14,R1]             ;Load the icon number
+               MOV     R0,R9                   ;Put dialogue handle in R0
+               MOV     R2,R3                   ;Put slider value in R2
+               BL      numWrite_set            ;And put it in the icon
+
+               ; --- Now work out what else to update ---
+
+               CMP     PC,#0                   ;Clear the Z flag
+               BL      cs_immediate            ;Are we doing immediate ops?
+               LDRCC   R14,[R13,#4]            ;Load the subreason code
+               CMPCC   R14,#slider_sliding     ;Is the slider going still?
+               BLNE    rgb__zUpdate            ;No -- redraw colour square
+
+               BL      rgb__xyUpdate           ;Now move the crosshair
+
+90rgb__slChange        LDMFD   R13!,{R0-R2,R4,PC}^     ;Return to caller
+
+rgb__writeTbl  DCB     rgbIcon__writeR
+               DCB     rgbIcon__writeG
+               DCB     rgbIcon__writeB
+               DCB     rgbIcon__writeR
+               DCB     rgbIcon__writeG
+
+               ; --- He typed something into one of our icons ---
+
+rgb__wrChange  ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+
+               ; --- First, find the value this writable applies to ---
+
+               CMP     R1,#rgbIcon__writeG     ;Which writable icon is it?
+               MOVLT   R1,#0                   ;Red -- remember this map
+               MOVEQ   R1,#1                   ;Green -- remember this
+               MOVGT   R1,#2                   ;Blue -- remember this
+               ADR     R14,rgb__red            ;Point to the mappings
+               LDR     R14,[R14,R1,LSL #2]     ;Translate the colour
+               LDR     R0,[R14,#0]             ;Load the actual value
+               SUBS    R5,R0,R3                ;Is this our value?
+
+               ; --- He's changed the value -- update slider/colour ---
+
+               STRNE   R3,[R14,#0]             ;Save the new value away
+               BLNE    rgb__colUpdate          ;Redraw the colour pot
+               LDR     R0,rgb__mapping         ;Load the mapping number
+               SUB     R3,R1,R0                ;Work out the table index
+               ADR     R14,rgb__slideTbl+2     ;Point to slider icon table
+               LDRB    R1,[R14,R3]             ;Load the icon number
+               LDR     R0,cs__modelDb          ;Load the panel dialogue
+               BLNE    dbx_update              ;Redraw the slider nicely
+
+               ; --- Update the main piccy ---
+
+               CMPEQ   PC,#0                   ;Clear the Z flag
+               BL      cs_immediate            ;Are we doing immediate ops?
+               CMPCC   R2,#numWrite_change     ;Is he just typing numbers?
+               BLNE    rgb__zUpdate            ;No -- redraw colour square
+
+               BL      rgb__xyUpdate           ;Now move the crosshair
+
+90rgb__wrChange        LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+rgb__slideTbl  DCB     rgbIcon__slide2
+               DCB     rgbIcon__slide1
+               DCB     rgbIcon__slide3
+               DCB     rgbIcon__slide2
+               DCB     rgbIcon__slide1
+
+rgb__arChange  ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R4,R2                   ;Look after the bump
+
+               ; --- First, find the value this arrow applies to ---
+
+               CMP     R1,#rgbIcon__upG        ;Which writable icon is it?
+               CMPGT   R1,#rgbIcon__downG      ;There's two for green
+               MOVLT   R3,#0                   ;Red -- remember this map
+               MOVEQ   R3,#1                   ;Green -- remember this
+               MOVGT   R3,#2                   ;Blue -- remember this
+
+               ; --- Now bump the required writable icon ---
+
+               ADR     R14,rgb__writeTbl       ;Point to the icon table
+               LDRB    R1,[R14,R3]             ;Load the correct icon
+               MOV     R0,R9                   ;Pass dialogue in R0
+               BL      numWrite_bump           ;Apply the bump value
+
+               ; --- Now perform the update operation ---
+
+               CMPEQ   PC,#0                   ;Clear the Z flag
+               BL      cs_immediate            ;Are we doing immediates?
+               TEQCS   R4,#0                   ;And is the bump sensible?
+               BEQ     %90rgb__arChange        ;Immediate/end ==> return
+               MOV     R3,R2                   ;Get value in R3 nicely
+               MOVCS   R2,#1                   ;Update always if immediate
+               MOVCC   R2,#0                   ;Default is no update if not
+               TEQ     R4,#0                   ;And is the bump sensible?
+               MOVEQ   R2,#1                   ;No -- then force update
+               BL      rgb__wrChange           ;Handle writable update then
+
+90rgb__arChange        LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+               ; --- Close the panel to open a new one ---
+
+rgb__closePanel        ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R9                   ;Get the dialogue handle
+               BL      dbox_destroy            ;Kill off the dialogue
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               ; --- Handle a click on one of the WIMP colours ---
+               ;
+               ; The WIMP colour number resides in R14 at the moment :-/
+
+rgb__wimpCol   ROUT
+
+               STMFD   R13!,{R0,R1}            ;Save some registers
+               SUB     R13,R13,#80             ;Make space for palette block
+               MOV     R1,R13                  ;Point to my block
+               SWI     Wimp_ReadPalette        ;Read the WIMP palette
+               LDR     R1,[R13,R14,LSL #2]     ;Load the one we want
+               ADD     R13,R13,#80             ;Don't need this now
+
+               ; --- Under RISC OS <3.50, bodge palette entry ---
+               ;
+               ; Because of Acorn stupidity, the ReadPalette values have
+               ; blank lower nibbles.  According to Acorn, I must copy the
+               ; top nibbles into the bottom ones for ColourTrans to be
+               ; happy.  I assume that this has been sorted out on 3.50 and
+               ; later.
+
+               BL      rov_version             ;Get the RISC OS version
+               CMP     R0,#340                 ;It's almost 350 :-)
+               LDRLO   R14,=&F0F0F000          ;A nibble mask
+               ANDLO   R1,R1,R14               ;Clear bottom nibbles
+               ORRLO   R1,R1,R1,LSR #4         ;And duplicate top in bottom
+
+               STR     R1,cs__colour+col_rgb   ;Save this new colour
+               BL      rgb__setValues          ;And redo everything nicely
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rgb__setValues ---
+;
+; On entry:    R10 == address of colour selector instance data
+;
+; On exit:     --
+;
+; Use:         Updates all the values in the dialogue box from the colour
+;              word in the workspace (which is assumed to have changed).
+;              The colour mapping is assumed to still be valid, though.
+
+rgb__setValues ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Unpack the value from the colour RGB word ---
+
+               BL      rgb__unpack             ;Get the percentages out
+
+               ; --- Do the writable icons ---
+
+               LDR     R0,cs__modelDb          ;Get the dialogue handle
+               MOV     R1,#rgbIcon__writeR     ;Get the red writable icon
+               LDR     R2,rgb__red             ;Find the red value
+               LDR     R2,[R2,#0]              ;Load the red value
+               BL      numWrite_set            ;Set it in the icon
+
+               MOV     R1,#rgbIcon__writeG     ;Get the green writable icon
+               LDR     R2,rgb__green           ;Find the green value
+               LDR     R2,[R2,#0]              ;Load the green value
+               BL      numWrite_set            ;Set it in the icon
+
+               MOV     R1,#rgbIcon__writeB     ;Get the blue writable icon
+               LDR     R2,rgb__blue            ;Find the blue value
+               LDR     R2,[R2,#0]              ;Load the blue value
+               BL      numWrite_set            ;Set it in the icon
+
+               ; --- Now do the other controls ---
+
+               BL      rgb__updateSliders      ;Do the slider update
+               BL      cs_colChange            ;Redraw main colour pot
+               BL      rgb__zUpdate            ;Force a recache of z
+               BL      rgb__xyUpdate           ;And a recache of x and y
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rgb__updateSliders ---
+;
+; On entry:    R10 == address of colour selector instance data
+;
+; On exit:     --
+;
+; Use:         Redraws all the sliders.  Because the slider code is so
+;              amazingly intelligent, if the values haven't changed, the
+;              picture you see won't change either.
+
+rgb__updateSliders ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R0,cs__modelDb          ;Get the dialogue handle
+               MOV     R1,#rgbIcon__slide1     ;Get slider 1's number
+               BL      dbx_update              ;Redraw it quickly
+               MOV     R1,#rgbIcon__slide2     ;Get slider 2's number
+               BL      dbx_update              ;Redraw it quickly
+               MOV     R1,#rgbIcon__slide3     ;Get slider 3's number
+               BL      dbx_update              ;Redraw it quickly
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rgb__setMapping ---
+;
+; On entry:    R0 == rotation number (i.e. which colour is on z azis)
+;
+; On exit:     --
+;
+; Use:         Sets up the workspace so that the dialogue box displays the
+;              correct mapping.
+
+rgb__setMapping        ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Reset the mapping number and table ---
+
+               STR     R0,rgb__mapping         ;Save the mapping number
+               ADR     R1,rgb__mappingTbl      ;Point to the table
+               ADD     R1,R1,R0                ;Index it nicely
+
+               LDRB    R14,[R1],#1             ;Load the blue offset
+               ADD     R14,R10,R14             ;Add it to workspace ptr
+               STR     R14,rgb__blue           ;And store nicely
+               MOV     R2,#8                   ;The blue slider colour
+               STR     R2,[R14,#4]             ;Save it in the table
+
+               LDRB    R14,[R1],#1             ;Load the green offset
+               ADD     R14,R10,R14             ;Add it to workspace ptr
+               STR     R14,rgb__green          ;And store nicely
+               MOV     R2,#10                  ;The green slider colour
+               STR     R2,[R14,#4]             ;Save it in the table
+
+               LDRB    R14,[R1],#1             ;Load the red offset
+               ADD     R14,R10,R14             ;Add it to workspace ptr
+               STR     R14,rgb__red            ;And store nicely
+               MOV     R2,#11                  ;The red slider colour
+               STR     R2,[R14,#4]             ;Save it in the table
+
+               BL      rgb__unpack             ;Unpack colour def now
+
+               ; --- Set up the cached values for the diagram ---
+
+               LDR     R14,rgb__sl1Val         ;Load the x value
+               STR     R14,rgb__xPos           ;Save it in the cache
+               LDR     R14,rgb__sl2Val         ;Load the y value
+               STR     R14,rgb__yPos           ;Save it in the cache
+               LDR     R14,rgb__sl3Val         ;Load the z value
+               STR     R14,rgb__zPos           ;Save it in the cache
+
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+               ; --- The mapping table ---
+               ;
+               ; The table is done twice, to give it a `wraparound' effect.
+
+rgb__mappingTbl        DCB     :INDEX: rgb__sl1Val
+               DCB     :INDEX: rgb__sl2Val
+               DCB     :INDEX: rgb__sl3Val
+               DCB     :INDEX: rgb__sl1Val
+               DCB     :INDEX: rgb__sl2Val
+
+; --- rgb__unpack ---
+;
+; On entry:    R10 == address of colour selector instance data
+;
+; On exit:     --
+;
+; Use:         Unpacks the colour definition in the cs data into the
+;              slider values.
+
+rgb__unpack    ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some workspace
+               LDR     R2,cs__colour+col_rgb   ;Get the colour nicely
+
+               ; --- Set up the blue slider ---
+
+               MOV     R0,R2,LSR #24           ;Get the blue colour value
+               BL      rgb__colToPerC          ;Convert it to a percentage
+               LDR     R14,rgb__blue           ;Load the blue entry address
+               STR     R0,[R14]                ;Save the blue value in it
+
+               ; --- Now set up the green one ---
+
+               MOV     R0,R2,LSR #16           ;Get the green colour value
+               BL      rgb__colToPerC          ;Convert it to a percentage
+               LDR     R14,rgb__green          ;Load the green entry address
+               STR     R0,[R14]                ;Save the green value in it
+
+               ; --- Now set up the red one ---
+
+               MOV     R0,R2,LSR #8            ;Get the red colour value
+               BL      rgb__colToPerC          ;Convert it to a percentage
+               LDR     R14,rgb__red            ;Load the red entry address
+               STR     R0,[R14]                ;Save the red value in it
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rgb__colToPerC ---
+;
+; On entry:    R0 == colour to convert, from 0 to 255
+;
+; On exit:     R0 == colour as a percentage
+;
+; Use:         Converts a colour to a percentage.
+;
+; [Generated by Straylight divc]
+; Modified by MDW to (a) be unsigned, and (b) round to nearest.
+
+rgb__colToPerC ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               AND     R0,R0,#&FF              ;Mask off any other bits
+               ADD     R0,R0,R0,LSL #2         ;Multiply by 5 (x5)
+               ADD     R0,R0,R0,LSL #2         ;And by 5 again (x25)
+               MOV     R0,R0,LSL #2            ;And now by 4 (x100)
+               MOV     R1,R0                   ;Keep copy of dividend
+               ADD     R0,R0,#127              ;Make it round to nearest
+               ADD     R0,R0,R0,LSR #8         ;R0 = R0 x 256/255
+               ADD     R0,R0,R0,LSR #16        ;...
+               MOV     R0,R0,LSR #8            ;Div by 256 -- R0 = R0 / 255
+               RSB     R14,R0,R0,LSL #8        ;Multiply by 255
+               SUB     R1,R1,R14               ;Find the difference
+               SUBS    R1,R1,#255              ;This is the remainder
+               ADDGE   R0,R0,#1                ;If we overshot, bump quot
+               ADDLT   R1,R1,#255              ;And chop off remainder
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- rgb__perCToCol ---
+;
+; On entry:    R0 == colour percentage to convert
+;
+; On exit:     R0 == colour value, from 0-255
+;
+; Use:         Converts a percentage to a colour.
+
+rgb__perCToCol ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               RSB     R0,R0,R0,LSL #8         ;Multiply it by 255
+               ADD     R0,R0,#50               ;Add 50 to round to nearest
+               BL      div10                   ;Divide by 10
+               BL      div10                   ;And again (by 100)
+               LDMFD   R13!,{R1,PC}^           ;And return to caller
+
+               LTORG
+
+; --- rgb__colUpdate ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Updates the main dialogue's colour pot.
+
+rgb__colUpdate ROUT
+
+               STMFD   R13!,{R0,R2,R14}        ;Save some registers
+               MOV     R2,#0                   ;Clear prospective colour
+
+               LDR     R0,rgb__blue            ;Get the blue colour address
+               LDR     R0,[R0,#0]              ;Load the blue percentage
+               BL      rgb__perCToCol          ;Convert it to a real colour
+               ORR     R2,R2,R0,LSL #24        ;Move into R2 nicely
+
+               LDR     R0,rgb__green           ;Get the green colour address
+               LDR     R0,[R0,#0]              ;Load the green percentage
+               BL      rgb__perCToCol          ;Convert it to a real colour
+               ORR     R2,R2,R0,LSL #16        ;Move into R2 nicely
+
+               LDR     R0,rgb__red             ;Get the red colour address
+               LDR     R0,[R0,#0]              ;Load the red percentage
+               BL      rgb__perCToCol          ;Convert it to a real colour
+               ORR     R2,R2,R0,LSL #8         ;Move into R2 nicely
+
+               STR     R2,cs__colour+col_rgb   ;Save this as the new colour
+               LDMFD   R13!,{R0,R2,R14}        ;Restore registers
+               B       cs_colChange            ;Update the main box's colour
+
+               LTORG
+
+; --- rgb__zUpdate ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Updates everything following a change to the current z
+;              value.  It doesn't change the writable icon, but it does
+;              most other things.
+
+rgb__zUpdate   ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Make sure that the z coordinate changed ---
+
+               LDR     R2,rgb__sl3Val          ;Load current z slider pos
+               LDR     R0,rgb__zPos            ;Load the cached position
+               CMP     R0,R2                   ;Do they match?
+               LDMEQFD R13!,{R0-R2,PC}^        ;Yes -- nothing doing then
+
+               ; --- Remove crosshairs -- it looks nicer ---
+
+               LDR     R0,cs__modelDb          ;Load the model dialogue
+               MOV     R1,#rgbIcon__square     ;Get the colour square
+               BL      dbx_qUpdate             ;Get rid of the crosshair
+
+               ; --- Now recache the x and y coords to prevent flicker ---
+
+               STR     R2,rgb__zPos            ;Update the cache value
+               LDR     R14,rgb__sl1Val         ;Load the current x value
+               STR     R14,rgb__xPos           ;Save it away
+               LDR     R14,rgb__sl2Val         ;Load the current y value
+               STR     R14,rgb__yPos           ;Save it away
+
+               ; --- Redraw the main square ---
+
+               BL      dbx_update              ;Force a redraw of it
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rgb__xyUpdate ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Updates things following a change to either the x or y
+;              value.
+
+rgb__xyUpdate  ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               LDR     R0,rgb__xPos            ;Load cached x position
+               LDR     R1,rgb__yPos            ;Load cached y position
+               LDR     R2,rgb__sl1Val          ;And the current x pos
+               LDR     R3,rgb__sl2Val          ;And the current y pos
+               CMP     R0,R2                   ;Is the cached x right?
+               CMPEQ   R1,R3                   ;And is the cached y right?
+               LDMEQFD R13!,{R0-R3,PC}^        ;Yes -- return then
+
+               LDR     R0,cs__modelDb          ;Load the dialogue box handle
+               MOV     R1,#rgbIcon__square     ;Load the square icon
+               BL      dbx_qUpdate             ;Quickly redraw it
+               STR     R2,rgb__xPos            ;Recache the x position
+               STR     R3,rgb__yPos            ;Recache the y position
+               BL      dbx_qUpdate             ;Quickly redraw it
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+;----- Plotting the colour square -------------------------------------------
+
+; --- rgb_plotSquare ---
+;
+; On entry:    R0 == left hand side of colour square to plot
+;              R1 == bottom edge of colour square to plot
+;              R2 == which rotation we're plotting
+;              R3 == x step to plot in
+;              R4 == y step to plot in
+;              R5 == z-coordinate value (in 16.16 form)
+;              R6 == pointer to graphics window block
+;
+; On exit:     --
+;
+; Use:         Plots a cross-section through the RGB colour cube.
+
+               EXPORT  rgb_plotSquare
+rgb_plotSquare ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save a job-lot of registers
+
+               ; --- Work out the minimum coordinates ---
+
+               LDMIA   R6,{R8,R9,R11,R12}      ;Load the coordinates out
+               SUB     R7,R12,R1               ;Translate max y to relative
+               SUB     R12,R9,R1               ;Translate min y too
+               SUB     R10,R8,R0               ;Translate min x too
+               SUB     R11,R11,R0              ;Translate max x
+
+               ; --- See if we can do really clever things ---
+
+               STMFD   R13!,{R0,R11}           ;Save our R11 value
+               LDR     R11,[R13,#52]           ;Load the system R11 value
+               BL      screen_getInfo          ;Load the screen information
+               MOV     R8,R0                   ;Look after this address
+               LDMFD   R13!,{R0,R11}           ;Reload our local value
+               LDR     R14,[R8,#screen_bpp]    ;Load current bits/pixel
+               CMP     R14,#16                 ;Is this a 2byte/pixel mode?
+               BEQ     rgb__plot32k            ;Yes -- branch to special bit
+               CMP     R14,#32                 ;Is this a 4byte/pixel mode?
+               BEQ     rgb__plot16m            ;Yes -- branch to special bit
+
+               ; --- Work out rectangle edges ---
+
+               CMP     R10,#0                  ;Is min x too small?
+               MOVLT   R10,#0                  ;Yes -- raise it to 0
+               CMP     R12,#0                  ;Is min y too small?
+               MOVLT   R12,#0                  ;Yes --- raise that too
+               CMP     R11,#255                ;Is the max x too large?
+               MOVGT   R11,#255                ;Yes -- reduce it then
+               CMP     R7,#255                 ;Is the max y too large?
+               MOVGT   R7,#255                 ;Yes -- reduce it then
+
+               SUB     R8,R3,#1                ;Turn the x step to bitmask
+               SUB     R9,R4,#1                ;And the same for y step
+               BIC     R10,R10,R8              ;Round min x down to step
+               BIC     R12,R12,R9              ;And round min y down too
+               BIC     R11,R11,R8              ;Round max x down too
+               BIC     R7,R7,R9                ;And round down max y
+
+               STMFD   R13!,{R7,R10}           ;Save rel. min x and max y
+
+               ADD     R10,R10,R0              ;Now make min x absolute
+               ADD     R12,R12,R1              ;And make min y absolute
+               ADD     R11,R11,R0              ;And make max x absolute
+               ADD     R7,R7,R1                ;And make max y absolute
+
+               ; --- Now work out the z-value ---
+
+               RSB     R5,R5,R5,LSL #8         ;Multiply value by 255
+               ADD     R5,R5,#&8000            ;Make sure we round nicely
+               MOV     R5,R5,LSR #16           ;And make it 0-255
+
+               ; --- Work out the exclusive rectangle sizes ---
+
+               STMFD   R13!,{R11}              ;Save our R11 value
+               LDR     R11,[R13,#56]           ;Load the system R11 value
+               BL      screen_getInfo          ;Load the screen information
+               LDMFD   R13!,{R11}              ;Reload our local value
+
+               LDMIA   R0,{R8,R9}              ;Load the eigen factors out
+               MOV     R14,#1                  ;This will be shifted around
+               SUB     R8,R3,R14,LSL R8        ;Subtract x pixel from x step
+               SUB     R9,R4,R14,LSL R9        ;Subtract y pixel from y step
+
+               ; --- Work out all the shift values ---
+
+               CMP     R2,#0                   ;Is this the red rotation?
+               MOVEQ   R0,#24                  ;Yes -- then x is blue
+               MOVEQ   R1,#16                  ;And y is green
+               MOVEQ   R5,R5,LSL #8            ;And z is red
+
+               CMP     R2,#1                   ;Is this the green rotation?
+               MOVEQ   R0,#8                   ;Yes -- then x is red
+               MOVEQ   R1,#24                  ;And y is blue
+               MOVEQ   R5,R5,LSL #16           ;And z is green
+
+               CMP     R2,#2                   ;Is this the blue rotation?
+               MOVEQ   R0,#16                  ;Yes -- then x is green
+               MOVEQ   R1,#8                   ;And y is red
+               MOVEQ   R5,R5,LSL #24           ;And z is blue
+
+               ; --- Set up the initial palette word ---
+
+               LDMFD   R13!,{R14}              ;Load maximum y palette val
+               ORR     R5,R5,R14,LSL R1        ;Fit that into the palette
+
+               LDMFD   R13!,{R2}               ;Load minimum x palette val
+
+               ; --- Now for the main plotting loop ---
+
+00             MOV     R6,R10                  ;Start on the left hand side
+               MOV     R14,#255                ;Clear out nasty x palette
+               BIC     R5,R5,R14,LSL R0        ;Clear out the right byte
+               ORR     R5,R5,R2,LSL R0         ;And set up the min value
+
+               ; --- Plot the rectangle nicely ---
+
+10             STMFD   R13!,{R0-R4}            ;Save some registers for this
+
+               ; --- Nothing for it but to use ColourTrans ---
+               
+               MOV     R0,R5                   ;Get the palette entry
+               MOV     R3,#&100                ;Please try to dither it
+               MOV     R4,#0                   ;And have normal GCOL action
+               SWI     XColourTrans_SetGCOL    ;Try to set the colour up
+               MOVVS   R3,#0                   ;Try again without dithering
+               MOVVS   R0,R5                   ;Set the palette word again
+               SWIVS   ColourTrans_SetGCOL     ;Set the colour the old way
+
+15             MOV     R0,#4                   ;Move cursor absolute
+               MOV     R1,R6                   ;Get the current x coordinate
+               MOV     R2,R7                   ;And the current y coordinate
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#97                  ;Rectangle fill relative
+               MOV     R1,R8                   ;Rectangle width thingy
+               MOV     R2,R9                   ;Rectangle height thingy
+               SWI     OS_Plot                 ;Plot the rectangle
+               LDMFD   R13!,{R0-R4}            ;Restore a load of registers
+
+               ; --- Now move on to the next square ---
+
+               ADD     R6,R6,R3                ;Add on the x increment
+               CMP     R6,R11                  ;Have we gone too far?
+               ADDLE   R5,R5,R3,LSL R0         ;No -- add on the palette val
+               BLE     %10rgb_plotSquare       ;And go round again
+
+               SUB     R7,R7,R4                ;Subtract the y increment
+               CMP     R7,R12                  ;Have we gone too far?
+               SUBGE   R5,R5,R4,LSL R1         ;No -- subtract palette val
+               BGE     %00rgb_plotSquare       ;And do the next row nicely
+
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               ; --- Fast colour setting routines ---
+
+20             MOV     R1,R5,LSR #8            ;Get hardware colour value
+               MOV     R0,#0                   ;Set the colour
+               SWI     OS_SetColour            ;Set the colour really
+               B       %15rgb_plotSquare       ;And return to main loop
+
+25             AND     R0,R5,#&F800            ;Get the red bits out
+               MOV     R1,R0,LSR #11           ;Shift them down
+               AND     R0,R5,#&F80000          ;Get the green bits
+               ORR     R1,R1,R0,LSR #14        ;Move them in nicely
+               AND     R0,R5,#&F8000000        ;Get the blue bits too
+               ORR     R1,R1,R0,LSR #17        ;Move them in too
+               MOV     R0,#0                   ;Set a raw colour
+               SWI     OS_SetColour            ;Set the colour nicely
+               B       %15rgb_plotSquare       ;And return to main loop
+
+30             MOV     R14,#3                  ;Mask bits off quickly
+               AND     R0,R14,R5,LSR #12       ;Get the red bits
+               AND     R1,R14,R5,LSR #20       ;Get the green bits
+               AND     R2,R14,R5,LSR #28       ;And the blue bits
+               ADD     R1,R1,R1,LSL #2         ;Multiply green by 5
+               ADD     R2,R2,R0,LSL #1         ;Mult red by 2 and add in
+               ADD     R2,R2,R1                ;And add in weighted green
+               MOV     R1,R2,LSR #3            ;Get weighted average
+
+               AND     R0,R5,#&00C00000        ;Get top two green bits
+               ORR     R1,R1,R0,LSR #17        ;Shift into position
+               TST     R5,#&00004000           ;Get red bit two
+               ORRNE   R1,R1,#&4               ;If set, set in colour
+               TST     R5,#&40000000           ;Get blue bit two
+               ORRNE   R1,R1,#&8               ;If set, set in colour
+               TST     R5,#&00008000           ;Get red bit three
+               ORRNE   R1,R1,#&10              ;If set, set in colour
+               TST     R5,#&80000000           ;Get blue bit three
+               ORRNE   R1,R1,#&80              ;If set, set in colour
+
+               MOV     R0,#0                   ;Set raw colour
+               SWI     OS_SetColour            ;Do the colour setting
+               B       %15rgb_plotSquare       ;And return to main loop
+               
+               LTORG
+
+; --- rgb__plot32k ---
+;
+; On entry:    R0 == left side of square to plot
+;              R1 == bottom of square to plot
+;              R2 == rotation number
+;              R3 == x step for rectangles
+;              R4 == y step for rectangles
+;              R5 == current z-value (in 16.16)
+;              R6 == pointer to graphics window block
+;              R7 == unlimited relative max y position to plot
+;              R8 == pointer to screen info block
+;              R10 == unlimited relative min x position to plot
+;              R11 == unlimited relative max x position to plot
+;              R12 == unlimited relative min y position to plot
+;              On stack: saved {R0-R12,R14}
+;
+; On exit:     --
+;
+; Use:         Displays an RGB square on the screen at a given location,
+;              in a 16bpp mode, using direct screen access (TM).
+
+rgb__plot32k   ROUT
+
+               ; --- Prologue: Limit the relative box positions ---
+
+               ADD     R8,R8,#screen_dx        ;Find the pixel positions
+               LDMIA   R8,{R8,R9}              ;Load them into registers
+
+               CMP     R10,#0                  ;Is min x too small?
+               MOVLT   R10,#0                  ;Yes -- raise it to 0
+               CMP     R12,#0                  ;Is min y too small?
+               MOVLT   R12,#0                  ;Yes --- raise that too
+               CMP     R11,#256                ;Is the max x too large?
+               MOVGT   R11,#256                ;Yes -- reduce it then
+               CMP     R7,#256                 ;Is the max y too large?
+               MOVGT   R7,#256                 ;Yes -- reduce it then
+               SUB     R11,R11,R8              ;Make this inclusive
+               SUB     R7,R7,R9                ;Make this inclusive too
+
+               ; --- Act 1: Find addresses of things on the screen ---
+
+               ADD     R9,R0,R10               ;Work out left hand side
+               ADD     R8,R1,R7                ;Work out top of area
+               SUB     R10,R11,R10             ;Work out width of area
+               SUB     R7,R7,R12               ;And the height too
+
+               SUB     R12,R9,R0               ;Work out left offset again
+               SUB     R11,R8,R1               ;And the top offset too
+
+               SUB     R13,R13,#20             ;Space for our vdu vars
+               ADR     R0,rgb__vduVars         ;Point to the var numbers
+               MOV     R1,R13                  ;Point to our output block
+               SWI     OS_ReadVduVariables     ;Get the values nicely
+
+               ; --- Interlude: Set up rectangle sizes ---
+
+               CMP     R3,#8                   ;Make sure rectangles are >8
+               MOVCC   R3,#8                   ;If not, make them bigger
+               MOVCC   R4,#8                   ;(Width and height the same)
+               MOV     R14,R3,LSR #3           ;Work out colour increment
+
+               ; --- Reprise: Convert measurements to pixels ---
+
+               LDMIA   R13!,{R0,R1}            ;Load the x and y eig things
+               MOV     R3,R3,LSR R0            ;Convert pixel counters
+               MOV     R4,R4,LSR R1            ;Convert other pixel counter
+               MOV     R9,R9,LSR R0            ;Convert left hand side
+               MOV     R10,R10,LSR R0          ;Convert width of area
+               MOV     R7,R7,LSR R1            ;Convert area height
+               MOV     R8,R8,LSR R1            ;And the top position
+
+               ; --- Intermission: Pack up pixel counters ---
+               ;
+               ; We pack all this into a word containing the following:
+               ;
+               ; bits 31-24 == x counter reset value
+               ; bits 23-20 == y counter initial value
+               ; bits 19-16 == x counter initial value
+               ; bits 15- 8 == y counter reset value
+               ; bits  7- 0 == colour step value
+               ;
+               ; Can anyone say `Z80 programming techniques'?
+
+               MOV     R12,R12,LSR R0          ;Get left offset in pixels
+               SUB     R6,R3,#1                ;Get the h pixel count -1
+               AND     R0,R12,R6               ;Get the remainder thing
+               SUB     R0,R3,R0                ;And get the correct offset
+
+               ORR     R3,R4,R3,LSL #16        ;Pack x and y counters
+               ORR     R3,R14,R3,LSL #8        ;And move in the colour inc
+
+               RSB     R14,R11,#256            ;Get offset from top
+               MOV     R11,R11,LSR R1          ;Turn offset into pixels
+               MOV     R1,R14,LSR R1           ;Get top offset in pixels
+               SUB     R1,R1,#1                ;Subtract one for niceness
+               SUB     R6,R4,#1                ;Get the v pixel count -1
+               AND     R1,R1,R6                ;Get the remainder thing
+               SUB     R1,R4,R1                ;And get the correct offset
+               ORR     R0,R0,R1,LSL #4         ;Pack into 1 byte
+
+               ORR     R3,R3,R0,LSL #16        ;Put in initial values too
+
+               LDMIA   R13!,{R0,R1,R6}         ;Load other vdu vars
+               SUB     R14,R1,R8               ;Shift origin to top left
+               MLA     R0,R14,R6,R0            ;Work out address of row
+               ADD     R9,R0,R9,LSL #1         ;Work out left address
+               ADD     R8,R9,R10,LSL #1        ;Work out right hand side too
+
+               ; --- Act 2: Set up colour information ---
+
+               AND     R14,R3,#&FF             ;Get the colour step value
+               BIC     R10,R3,#&FF             ;Move packed init values away
+               
+               RSB     R5,R5,R5,LSL #8         ;Multiply z value by 255
+               MOV     R5,R5,LSR #19           ;And make it 0-31
+
+               AND     R3,R10,#&FF000000       ;Get the x pixel count reinit
+               SUB     R3,R3,#&01000000        ;Turn it into a bitmask
+               BIC     R3,R12,R3,LSR #24       ;Round colour down nicely
+               LDR     R12,[R13,#-20]          ;Get the xeig factor
+               MOV     R3,R3,LSL R12           ;Shift colour up to OS units
+               MOV     R3,R3,LSR #3            ;Get the x colour in 0-31
+
+               AND     R4,R10,#&0000FF00       ;Get the y pixel count reinit
+               SUB     R4,R4,#&00000100        ;Turn it into a bitmask
+               BIC     R4,R11,R4,LSR #8        ;Round colour down nicely
+               LDR     R11,[R13,#-16]          ;Get the yeig factor
+               MOV     R4,R4,LSL R11           ;Shift colour up to OS units
+               MOV     R4,R4,LSR #3            ;And the y one too please
+
+               MOV     R12,#&1F                ;This is a useful value
+
+               CMP     R2,#0                   ;Is this the red rotation?
+               MOVEQ   R0,R5,LSL #16           ;Build the colour up...
+               ORREQ   R0,R0,R4,LSL #21        ;Still doing that...
+               ORREQ   R0,R0,R3,LSL #26        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #26           ;And the x-init value
+               MOVEQ   R3,R14,LSL #21          ;Get the y increment right
+               MOVEQ   R4,R14,LSL #26          ;And the x increment
+               MOVEQ   R5,R12,LSL #26          ;Get the x-clear mask
+
+               CMP     R2,#1                   ;Is this the green rotation?
+               MOVEQ   R0,R3,LSL #16           ;Build the colour up...
+               ORREQ   R0,R0,R5,LSL #21        ;Still doing that...
+               ORREQ   R0,R0,R4,LSL #26        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #16           ;And the x-init value
+               MOVEQ   R3,R14,LSL #26          ;Get the y increment right
+               MOVEQ   R4,R14,LSL #16          ;And the x increment
+               MOVEQ   R5,R12,LSL #16          ;Get the x-clear mask
+
+               CMP     R2,#2                   ;Is this the blue rotation?
+               MOVEQ   R0,R4,LSL #16           ;Build the colour up...
+               ORREQ   R0,R0,R3,LSL #21        ;Still doing that...
+               ORREQ   R0,R0,R5,LSL #26        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #21           ;Get the x-init value
+               MOVEQ   R3,R14,LSL #16          ;Get the y increment right
+               MOVEQ   R4,R14,LSL #21          ;And the x increment
+               MOVEQ   R5,R12,LSL #21          ;Get the x-clear mask
+
+               ; --- Act 3. Initialise the pixel counts ---
+
+               MOV     R14,#&F                 ;For reading nibbles
+               AND     R12,R14,R10,LSR #16     ;Get the initial x value
+               AND     R2,R14,R10,LSR #20      ;Get the initial y value too
+               ORR     R2,R10,R2               ;Put that into the count reg
+               SWI     OS_EnterOS              ;Avoid problems with PhysMem
+
+               ; --- Act 4. Plot the bloody thing ---
+
+10rgb__plot32k MOV     R10,R9                  ;Get the current address
+               MOV     R11,#0                  ;Clear the buffer value
+               STMFD   R13!,{R12}              ;Save the x count value
+
+               ; --- Start plotting this row ---
+
+               TST     R10,#2                  ;Is this address aligned?
+               BEQ     %20rgb__plot32k         ;Yes -- start at main loop
+               LDR     R14,[R10,#-2]           ;No -- load word from here
+               MOV     R14,R14,LSL #16         ;Shift all the way up
+               ORR     R14,R0,R14,LSR #16      ;Build the replacement word
+               STR     R14,[R10,#-2]           ;And store in frame buffer
+               B       %25rgb__plot32k         ;Jump to end of loop
+
+               ; --- Main row plotting loop (time critical :-) ) ---
+
+20rgb__plot32k ORR     R11,R0,R11,LSR #16      ;Add colour into buffer
+               TST     R10,#2                  ;Is this an odd address?
+               STRNE   R11,[R10,#-2]           ;Yes -- done both halfwords
+
+25rgb__plot32k ADD     R10,R10,#2              ;Move on to next pixel
+               CMP     R10,R8                  ;Have we finished yet?
+               BHI     %30rgb__plot32k         ;No -- do the rest then
+               SUBS    R12,R12,#1              ;Decrement pixel counter
+               ADDEQ   R0,R0,R4                ;If cleared, add on colour
+               MOVEQ   R12,R2,LSR #24          ;And reinitialise counter
+               B       %20rgb__plot32k         ;Go round for more
+
+               ; --- We've finished; do we have a halfword left over? ---
+
+30rgb__plot32k TST     R10,#2                  ;Is the address odd?
+               LDRNE   R14,[R10,#-2]           ;Yes -- read the old word
+               MOVNE   R11,R11,LSR #16         ;Get buffer value in low hw
+               MOVNE   R14,R14,LSR #16         ;Get screen value in low hw
+               ORRNE   R14,R11,R14,LSL #16     ;Build correct word to write
+               STRNE   R14,[R10,#-2]           ;Store this word away
+
+               ; --- Now move on to the next row ---
+
+               LDMFD   R13!,{R12}              ;Unstack initial x counter
+               ADD     R9,R9,R6                ;Move start address down 1
+               ADD     R8,R8,R6                ;Move end address down 1
+               BIC     R0,R0,R5                ;Clear the x colour section
+               ORR     R0,R0,R1                ;Reintialise the x colour
+               SUB     R2,R2,#1                ;Decrement y counter
+               TST     R2,#&FF                 ;Is it now zero?
+               BICEQ   R2,R2,#&00FF0000        ;Clear unused byte in word
+               ORREQ   R2,R2,R2,LSR #8         ;Yes -- reinitialise
+               SUBEQ   R0,R0,R3                ;And increment the y colour
+               SUBS    R7,R7,#1                ;Decrement scan line counter
+               BCS     %10rgb__plot32k         ;And go back up again
+
+               TEQP    PC,#0                   ;Return to user mode
+               MOV     R0,R0                   ;Keep ARM ecstatically happy
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+rgb__vduVars   DCD     4,5                     ;X and Y eigen factors
+               DCD     149                     ;Start of display memory
+               DCD     12                      ;How high is the screen
+               DCD     6                       ;Width of scan line in pixels
+               DCD     -1
+
+               LTORG
+
+; --- rgb__plot16m ---
+;
+; On entry:    R0 == left side of square to plot
+;              R1 == bottom of square to plot
+;              R2 == rotation number
+;              R3 == x step for rectangles
+;              R4 == y step for rectangles
+;              R5 == current z-value (in 16.16)
+;              R6 == pointer to graphics window block
+;              R7 == unlimited relative max y position to plot
+;              R8 == pointer to screen info block
+;              R10 == unlimited relative min x position to plot
+;              R11 == unlimited relative max x position to plot
+;              R12 == unlimited relative min y position to plot
+;              On stack: saved {R0-R12,R14}
+;
+; On exit:     --
+;
+; Use:         Displays an RGB square on the screen at a given location,
+;              in a 32bpp mode, using direct screen access (TM).
+
+rgb__plot16m   ROUT
+
+               ; --- Prologue: Limit the relative box positions ---
+
+               ADD     R8,R8,#screen_dx        ;Find the pixel positions
+               LDMIA   R8,{R8,R9}              ;Load them into registers
+
+               CMP     R10,#0                  ;Is min x too small?
+               MOVLT   R10,#0                  ;Yes -- raise it to 0
+               CMP     R12,#0                  ;Is min y too small?
+               MOVLT   R12,#0                  ;Yes --- raise that too
+               CMP     R11,#256                ;Is the max x too large?
+               MOVGT   R11,#256                ;Yes -- reduce it then
+               CMP     R7,#256                 ;Is the max y too large?
+               MOVGT   R7,#256                 ;Yes -- reduce it then
+               SUB     R11,R11,R8              ;Make this inclusive
+               SUB     R7,R7,R9                ;Make this inclusive too
+
+               ; --- Act 1: Find addresses of things on the screen ---
+
+               ADD     R9,R0,R10               ;Work out left hand side
+               ADD     R8,R1,R7                ;Work out top of area
+               SUB     R10,R11,R10             ;Work out width of area
+               SUB     R7,R7,R12               ;And the height too
+
+               SUB     R12,R9,R0               ;Work out left offset again
+               SUB     R11,R8,R1               ;And the top offset too
+
+               SUB     R13,R13,#20             ;Space for our vdu vars
+               ADR     R0,rgb__vduVars         ;Point to the var numbers
+               MOV     R1,R13                  ;Point to our output block
+               SWI     OS_ReadVduVariables     ;Get the values nicely
+
+               ; --- Reprise: Convert measurements to pixels ---
+
+               LDMIA   R13!,{R0,R1}            ;Load the x and y eig things
+               MOV     R3,R3,LSR R0            ;Convert pixel counters
+               MOV     R4,R4,LSR R1            ;Convert other pixel counter
+               MOV     R9,R9,LSR R0            ;Convert left hand side
+               MOV     R10,R10,LSR R0          ;Convert width of area
+               MOV     R7,R7,LSR R1            ;Convert area height
+               MOV     R8,R8,LSR R1            ;And the top position
+
+               ; --- Intermission: Pack up pixel counters ---
+               ;
+               ; We pack all this into a word containing the following:
+               ;
+               ; bits 31-24 == x counter reset value
+               ; bits 23-20 == y counter initial value
+               ; bits 19-16 == x counter initial value
+               ; bits 15- 8 == y counter reset value
+               ; bits  7- 0 == colour step value
+               ;
+               ; Can anyone say `Z80 programming techniques'?
+
+               MOV     R12,R12,LSR R0          ;Get left offset in pixels
+               SUB     R6,R3,#1                ;Get the h pixel count -1
+               AND     R0,R12,R6               ;Get the remainder thing
+               SUB     R0,R3,R0                ;And get the correct offset
+
+               ORR     R3,R4,R3,LSL #16        ;Pack x and y counters
+               MOV     R3,R3,LSL #8            ;Move that up one byte
+
+               RSB     R14,R11,#256            ;Get offset from top
+               MOV     R11,R11,LSR R1          ;Turn offset into pixels
+               MOV     R1,R14,LSR R1           ;Get top offset in pixels
+               SUB     R1,R1,#1                ;Subtract one for niceness
+               SUB     R6,R4,#1                ;Get the v pixel count -1
+               AND     R1,R1,R6                ;Get the remainder thing
+               SUB     R1,R4,R1                ;And get the correct offset
+               ORR     R0,R0,R1,LSL #4         ;Pack into 1 byte
+
+               ORR     R3,R3,R0,LSL #16        ;Put in initial values too
+
+               LDMIA   R13!,{R0,R1,R6}         ;Load other vdu vars
+               SUB     R14,R1,R8               ;Shift origin to top left
+               MLA     R0,R14,R6,R0            ;Work out address of row
+               ADD     R9,R0,R9,LSL #2         ;Work out left address
+               ADD     R8,R9,R10,LSL #2        ;Work out right hand side too
+
+               ; --- Act 2: Set up colour information ---
+
+               BIC     R10,R3,#&FF             ;Move packed init values away
+               
+               RSB     R5,R5,R5,LSL #8         ;Multiply z value by 255
+               MOV     R5,R5,LSR #16           ;And make it 0-255
+
+               AND     R3,R10,#&FF000000       ;Get the x pixel count reinit
+               SUB     R3,R3,#&01000000        ;Turn it into a bitmask
+               BIC     R3,R12,R3,LSR #24       ;Round colour down nicely
+               LDR     R12,[R13,#-20]          ;Get the xeig factor
+               MOV     R3,R3,LSL R12           ;Shift colour up to OS units
+               AND     R14,R10,#&FF000000      ;Get the x reinit value
+               MOV     R14,R14,LSR #24         ;Bring it down to earth
+               MOV     R14,R14,LSL R12         ;And turn into OS units
+
+               AND     R4,R10,#&0000FF00       ;Get the y pixel count reinit
+               SUB     R4,R4,#&00000100        ;Turn it into a bitmask
+               BIC     R4,R11,R4,LSR #8        ;Round colour down nicely
+               LDR     R12,[R13,#-16]          ;Get the yeig factor
+               MOV     R4,R4,LSL R12           ;Shift colour up to OS units
+               AND     R11,R10,#&0000FF00      ;Get the y reinit value
+               MOV     R11,R11,LSR #8          ;Bring it down to earth
+               MOV     R11,R11,LSL R12         ;And turn into OS units
+
+               MOV     R12,#&FF                ;This is a useful value
+
+               CMP     R2,#0                   ;Is this the red rotation?
+               MOVEQ   R0,R5,LSL #0            ;Build the colour up...
+               ORREQ   R0,R0,R4,LSL #8         ;Still doing that...
+               ORREQ   R0,R0,R3,LSL #16        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #16           ;And the x-init value
+               MOVEQ   R3,R11,LSL #8           ;Get the y increment right
+               MOVEQ   R4,R14,LSL #16          ;And the x increment
+               MOVEQ   R5,R12,LSL #16          ;Get the x-clear mask
+
+               CMP     R2,#1                   ;Is this the green rotation?
+               MOVEQ   R0,R3,LSL #0            ;Build the colour up...
+               ORREQ   R0,R0,R5,LSL #8         ;Still doing that...
+               ORREQ   R0,R0,R4,LSL #16        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #0            ;And the x-init value
+               MOVEQ   R3,R11,LSL #16          ;Get the y increment right
+               MOVEQ   R4,R14,LSL #0           ;And the x increment
+               MOVEQ   R5,R12,LSL #0           ;Get the x-clear mask
+
+               CMP     R2,#2                   ;Is this the blue rotation?
+               MOVEQ   R0,R4,LSL #0            ;Build the colour up...
+               ORREQ   R0,R0,R3,LSL #8         ;Still doing that...
+               ORREQ   R0,R0,R5,LSL #16        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #8            ;Get the x-init value
+               MOVEQ   R3,R11,LSL #0           ;Get the y increment right
+               MOVEQ   R4,R14,LSL #8           ;And the x increment
+               MOVEQ   R5,R12,LSL #8           ;Get the x-clear mask
+
+               ; --- Act 3. Initialise the pixel counts ---
+
+               MOV     R14,#&F                 ;For reading nibbles
+               AND     R12,R14,R10,LSR #16     ;Get the initial x value
+               AND     R2,R14,R10,LSR #20      ;Get the initial y value too
+               ORR     R2,R10,R2               ;Put that into the count reg
+
+               ; --- Act 4. Plot the bloody thing ---
+
+               SWI     OS_EnterOS              ;Avoid problems with PhysMem    
+
+10rgb__plot16m MOV     R10,R9                  ;Get the current address
+               MOV     R11,R12                 ;Initialise the x counter
+               
+               ; --- Main row plotting loop (time critical :-) ) ---
+
+20rgb__plot16m STR     R0,[R10],#4             ;Store this pixel
+
+25rgb__plot16m CMP     R10,R8                  ;Have we finished yet?
+               BHI     %30rgb__plot16m         ;No -- do the rest then
+               SUBS    R11,R11,#1              ;Decrement pixel counter
+               ADDEQ   R0,R0,R4                ;If cleared, add on colour
+               MOVEQ   R11,R2,LSR #24          ;And reinitialise counter
+               B       %20rgb__plot16m         ;Go round for more
+
+               ; --- We've finished; move on to next row ---
+
+30rgb__plot16m ADD     R9,R9,R6                ;Move start address down 1
+               ADD     R8,R8,R6                ;Move end address down 1
+               BIC     R0,R0,R5                ;Clear the x colour section
+               ORR     R0,R0,R1                ;Reintialise the x colour
+               SUB     R2,R2,#1                ;Decrement y counter
+               TST     R2,#&FF                 ;Is it now zero?
+               BICEQ   R2,R2,#&00FF0000        ;Clear unused byte in word
+               ORREQ   R2,R2,R2,LSR #8         ;Yes -- reinitialise
+               SUBEQ   R0,R0,R3                ;And increment the y colour
+               SUBS    R7,R7,#1                ;Decrement scan line counter
+               BCS     %10rgb__plot16m         ;And go back up again
+
+               TEQP    PC,#0                   ;Return to user mode
+               MOV     R0,R0                   ;Keep ARM ecstatically happy
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- rgb__plotHair ---
+;
+; On entry:    R2 == x coordinate of cross
+;              R3 == y coordinate of cross
+;
+; On exit:     --
+;
+; Use:         Plots the crosshair on an RGB colour square to mark the
+;              current position nicely.
+
+rgb__plotHair  ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               MOV     R0,#4                   ;Move cursor absolute
+               MOV     R1,R2                   ;Get the x coordinate
+               SUB     R2,R3,#256              ;Move down a little bit
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#2                   ;Plot in logical inverse (!)
+               MOV     R1,#0                   ;No x movement please
+               MOV     R2,#512                 ;And plot upwards
+               SWI     OS_Plot                 ;Plot the vertical line
+
+               MOV     R0,#0                   ;Move cursor relative
+               MOV     R1,#-256                ;Move back a bit
+               MOV     R2,#-256                ;Move down a bit
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#2                   ;Plot in logical inverse (!)
+               MOV     R1,#512                 ;Plot the cross beam
+               MOV     R2,#0                   ;No y movement please
+               SWI     OS_Plot                 ;Plot the horizontal line
+
+               MOV     R0,#0                   ;Move cursor relative
+               MOV     R1,#-256                ;Move back a bit
+               MOV     R2,#0                   ;Move back to centre
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#146                 ;Circle relative
+               MOV     R1,#16                  ;Radius 16
+               MOV     R2,#0                   ;Don't screw up calculation
+               SWI     OS_Plot                 ;Plot the circle
+
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Custom dbx controls --------------------------------------------------
+
+; --- rgbSquare ---
+
+rgbSquare      ROUT
+
+               DCD     0,0
+               DCD     dbxMask_redraw + dbxMask_update + dbxMask_click
+
+               CMP     R0,#dbxEvent_update     ;Is it an update event?
+               BEQ     %10rgbSquare            ;Yes -- handle it
+               CMP     R0,#dbxEvent_click      ;Is it a click event?
+               BEQ     %20rgbSquare            ;Yes -- handle it
+
+               ; --- Deal with a redraw event ---
+
+               STMFD   R13!,{R0-R6,R10,R14}    ;Save some registers
+               MOV     R10,R8                  ;Get dbox data in R10
+               STMFD   R13!,{R2,R3}            ;Save bottom left corner
+
+               ; --- Sort out the resolution ---
+
+               BL      cs_resolution           ;Get the current resolution
+               CMP     R0,#0                   ;Is it pixel-level?
+               BLEQ    screen_getInfo          ;Yes -- get screen info
+               ADDEQ   R0,R0,#screen_dx        ;Point to the pixel size
+               LDMEQIA R0,{R3,R4}              ;And load the values
+               ADRNE   R14,rgb__resTable       ;Otherwise point at the table
+               ADDNE   R14,R14,R0              ;Find the correct entry
+               LDRNEB  R3,[R14,#0]             ;Load the square size
+               MOVNE   R4,R3                   ;And do it in both directions
+
+               ; --- Sort out the z value too ---
+
+               LDR     R0,rgb__zPos            ;Get the z slider value
+               MOV     R0,R0,LSL #16           ;Convert to 16.16 form
+               ADD     R0,R0,#50               ;Make it round to nearest
+               BL      div10                   ;Divide it by 10
+               BL      div10                   ;And again -- div by 100
+               MOV     R5,R0                   ;This is the z coordinate
+
+               ; --- Call the main plot code ---
+
+               LDMFD   R13!,{R0,R1}            ;Load the bottom left corner
+               LDR     R2,rgb__mapping         ;Get the colour mapping
+               BL      rgb_plotSquare          ;Do the plotting
+               LDMFD   R13!,{R0-R6,R10,R14}    ;Drop through to update code
+
+               ; --- Plot the crosshair as part of update ---
+
+10rgbSquare    STMFD   R13!,{R0-R5,R10,R14}    ;Save some registers
+               MOV     R10,R8                  ;Find my workspace address
+               SUB     R4,R4,R2                ;Get the icon width
+               SUB     R5,R5,R3                ;And the height
+               LDR     R0,rgb__xPos            ;Load cached x position
+               MUL     R0,R4,R0                ;Scale it to the width
+               ADD     R0,R0,#50               ;Round to nearest on divide
+               BL      div10                   ;And divide down
+               BL      div10                   ;And divide down again
+               ADD     R2,R2,R0                ;Find the x cross position
+               LDR     R0,rgb__yPos            ;Load cached y position
+               MUL     R0,R5,R0                ;Scale it to the height
+               ADD     R0,R0,#50               ;Round to nearest on divide
+               BL      div10                   ;And divide down
+               BL      div10                   ;And divide down again
+               ADD     R3,R3,R0                ;Find the y cross position
+               BL      rgb__plotHair           ;Plot the crosshair nicely
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;And return to caller
+
+rgb__resTable  DCB     0,4,8,16
+
+               ; --- Handle click events on the square ---
+
+20rgbSquare    TST     R2,#5                   ;Is it a real button click?
+               MOVEQS  PC,R14                  ;No -- ignore it then
+               STMFD   R13!,{R0-R5,R10,R14}    ;Save some registers
+
+               ; --- Start the drag operation ---
+
+               MOV     R0,R10                  ;Get dialogue handle
+               BL      dbx_controlBBox         ;Get the bonding box nicely
+               BL      dbox_window             ;Get the window handle
+               MOV     R1,#7                   ;User drag type
+               SUB     R13,R13,#56             ;Make a drag box on the stack
+               STMIA   R13,{R0,R1}             ;Save them away nicely
+               ADD     R14,R13,#24             ;Point to parent box
+               STMIA   R14,{R2-R5}             ;Save the bounding box here
+               MOV     R1,R13                  ;Point to my block
+               SWI     Wimp_DragBox            ;Set up the drag nicely
+               ADD     R13,R13,#56             ;Reclaim the stack space
+
+               ; --- Set up the handlers nicely ---
+
+               MOV     R10,R8                  ;Point to dbox data in R10
+               ADR     R0,rgb__ukEvents        ;Point to unknown handler
+               MOV     R1,#0                   ;Don't care about R4
+               MOV     R2,R10                  ;Pass dbox data in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_unknownHandler      ;Register the handler
+               MOVVC   R0,#2                   ;Call every TV frame
+               ADRVC   R1,rgb__idles           ;Point to the idle handler
+               BLVC    idle_handler            ;Register that too
+               BL      rgb__idles              ;Call idle handler now
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;Return to caller
+
+               LTORG
+
+; --- rgb__idles ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Handles idle events during a drag in the colour square.
+
+rgb__idles     ROUT
+
+               STMFD   R13!,{R0-R5,R10,R14}    ;Save some registers
+               LDR     R0,cs__modelDb          ;Get the dialogue box
+               MOV     R1,#rgbIcon__square     ;Get my icon handle
+               BL      dbx_controlBBox         ;Get my bounding box nicely
+               SUB     R13,R13,#20             ;Get a pointer block
+               MOV     R1,R13                  ;Point at it nicely
+               SWI     Wimp_GetPointerInfo     ;Find the pointer posn
+               LDMIA   R13,{R0,R1}             ;Load pointer coordinates
+               ADD     R13,R13,#20             ;Recover that block
+
+               ; --- Work out the new cross position ---
+
+               SUB     R4,R4,R2                ;Work out the icon width
+               SUB     R5,R5,R3                ;And the icon height
+               SUB     R2,R0,R2                ;Work out the x offset
+               SUB     R3,R1,R3                ;And the y offset
+
+               ADD     R2,R2,R2,LSL #2         ;Multiply x by 5
+               ADD     R2,R2,R2,LSL #2         ;Multiply x by 5 (x25)
+               MOV     R2,R2,LSL #2            ;Multiply x by 4 (x100)
+
+               ADD     R3,R3,R3,LSL #2         ;Multiply y by 5
+               ADD     R3,R3,R3,LSL #2         ;Multiply y by 5 (x25)
+               MOV     R3,R3,LSL #2            ;Multiply y by 4 (x100)
+
+               MOV     R0,R2                   ;Get the x value
+               MOV     R1,R4                   ;And the icon width
+               BL      div_round               ;Divide to get percentage
+               STR     R0,rgb__sl1Val          ;Save the x position
+
+               MOV     R0,R3                   ;Get the y value
+               MOV     R1,R5                   ;And the icon height
+               BL      div_round               ;Divide to get percentage
+               STR     R0,rgb__sl2Val          ;Save the y position
+
+               BL      rgb__xyUpdate           ;Redraw crosshairs if reqd
+               LDR     R0,cs__modelDb          ;Get the dialogue handle
+               MOV     R1,#rgbIcon__slide1     ;Get slider 1's number
+               BL      dbx_update              ;Redraw it quickly
+               MOV     R1,#rgbIcon__slide2     ;Get slider 2's number
+               BL      dbx_update              ;Redraw it quickly
+               BL      rgb__colUpdate          ;Redraw the colour button
+
+               ; --- Now update the correct icons ---
+
+               ADRL    R5,rgb__writeTbl+2      ;Point to icon number table
+               LDR     R14,rgb__mapping        ;And get the current mappiing
+               ADD     R5,R5,R14               ;Find the correct entry
+
+               LDRB    R1,[R5,#0]              ;Load the x icon
+               LDR     R2,rgb__sl1Val          ;Get the new x value
+               BL      numWrite_set            ;Put it in the icon
+               LDRB    R1,[R5,#-1]             ;Load the y icon
+               LDR     R2,rgb__sl2Val          ;Get the new y value
+               BL      numWrite_set            ;Put it in the icon
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;And return to caller
+
+               LTORG
+
+; --- rgb__ukEvents ---
+;
+; On entry:    R0 == event code
+;
+; On exit:     CS if handled
+;
+; Use:         Handles unknown events during a drag in the RGB colour
+;              square.
+
+rgb__ukEvents  ROUT
+
+               CMP     R0,#7                   ;Is it a drag over event?
+               MOVNES  PC,R14                  ;No -- then return to caller
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               BL      rgb__idles              ;Get one last drag position
+               ADR     R0,rgb__ukEvents        ;Point to unknown handler
+               MOV     R1,#0                   ;Don't care about R4
+               MOV     R2,R10                  ;Pass dbox data in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_removeUnknownHandler ;Deregister the handler
+               MOVVC   R0,#2                   ;Call every TV frame
+               ADRVC   R1,rgb__idles           ;Point to the idle handler
+               BLVC    idle_removeHandler      ;Deregister that too
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Icon numbers ---------------------------------------------------------
+
+rgbIcon__square        EQU     0                       ;The main colour square
+rgbIcon__slide1        EQU     1                       ;The x slider (slider 1)
+rgbIcon__slide2        EQU     2                       ;The y slider (slider 2)
+rgbIcon__slide3        EQU     3                       ;The z slider (slider 3)
+
+rgbIcon__radioR        EQU     4                       ;The `Red' radio button
+rgbIcon__writeR        EQU     5                       ;The `Red' writable area
+rgbIcon__upR   EQU     6                       ;The `Red' up arrow button
+rgbIcon__downR EQU     7                       ;The `Red' down arrow button
+
+rgbIcon__radioG        EQU     9                       ;The `Green' radio button
+rgbIcon__writeG        EQU     10                      ;The `Green' writable area
+rgbIcon__upG   EQU     11                      ;The `Green' up arrow button
+rgbIcon__downG EQU     12                      ;The `Green' down arrow buttn
+
+rgbIcon__radioB        EQU     14                      ;The `Blue' radio button
+rgbIcon__writeB        EQU     15                      ;The `Blue' writable area
+rgbIcon__upB   EQU     16                      ;The `Blue' up arrow button
+rgbIcon__downB EQU     17                      ;The `Blue' down arrow button
+
+rgbIcon__wCols EQU     20                      ;Base of the WIMP colours
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/akbd b/StraySrc/Libraries/Sapphire/csapph/h/akbd
new file mode 100644 (file)
index 0000000..239e294
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * akbd.h
+ *
+ * [Generated from akbd, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __akbd_h
+#define __akbd_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  akbd_test
+ *  akbd_translate
+ *  akbd_pollKey
+ */
+
+/* --- akbd_test --- *
+ *
+ * On entry:   R0 == internal key number to test
+ *
+ * On exit:    CS if key was pressed, CC otherwise
+ *
+ * Use:                Informs you whether a given key is currently being pressed.
+ */
+
+extern routine akbd_test;
+
+/* --- akbd_translate --- *
+ *
+ * On entry:   R0 == Wimp key number
+ *
+ * On exit:    R0 == Straylight extended keyset key number
+ *
+ * Use:                Translates a Wimp key number into one of the more specific
+ *             Straylight key numbers.
+ */
+
+extern routine akbd_translate;
+
+/* --- akbd_pollKey --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    CC if a key was in the buffer and
+ *               R0 == wimp translated key code
+ *             else CS and
+ *               R0 corrupted
+ *
+ * Use:                Reports whether the user has typed ahead, and if so what the ;          keypress. Note that the keypresses returned are WIMP-type,
+ *             not Straylight extended ones so you will have to use
+ *             akbd_translate if you need the extended type.
+ *
+ *             This call could be used to allow buffering of keypresses:
+ *             on a Key_Pressed event you would call this routine until
+ *             it returns FALSE and store the codes it returns in a buffer
+ *             along with the code from the event.
+ */
+
+extern routine akbd_pollKey;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/alloc b/StraySrc/Libraries/Sapphire/csapph/h/alloc
new file mode 100644 (file)
index 0000000..10ad4df
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * alloc.h
+ *
+ * [Generated from alloc, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __alloc_h
+#define __alloc_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  alloc_register
+ *  alloc_useOSHeap
+ *  alloc
+ *  free
+ *  alloc_init
+ *  alloc_error
+ */
+
+/* --- alloc_register --- *
+ *
+ * On entry:   R0 == pointer to allocator function
+ *             R1 == pointer to free function
+ *             R2 == workspace pointer to pass to them in R12
+ *
+ * On exit:    --
+ *
+ * Use:                Registers two functions to be used as a heap manager by
+ *             alloc and free.
+ *
+ *             The allocator is entered with R0 as the size of block
+ *             required, and should exit with CC and R0 == pointer to the
+ *             block allocated if successful, CS if there wasn't enough
+ *             memory and generate any other errors that occur.  Registers
+ *             other than R0 must be preserved.
+ *
+ *             The freer is entered with R0 == pointer to block to free.
+ *             It should exit with all registers preserved.  If anything
+ *             goes wrong, it should generate an error.
+ */
+
+extern routine alloc_register;
+
+/* --- alloc_useOSHeap --- *
+ *
+ * On entry:   R1 == pointer to OS_Heap-managed heap to use
+ *
+ * On exit:    --
+ *
+ * Use:                Registers an OS_Heap heap to use to allocate memory when
+ *             alloc is called.
+ */
+
+extern routine alloc_useOSHeap;
+
+/* --- alloc --- *
+ *
+ * On entry:   R0 == size of block to allocate from current heap
+ *
+ * On exit:    R0 == pointer to block and CC if it all worked
+ *             CS if there wasn't enough memory (R0 corrupted)
+ *
+ * Use:                Allocates R0 bytes from a heap manager.  This routine will
+ *             attempt to allocate memory from the current heaps in order
+ *             of registration (i.e. the Sapphire OS_Heap first etc.) until
+ *             either one which can service the request is found, or all
+ *             the heaps have been tried.
+ */
+
+extern routine alloc;
+
+/* --- free --- *
+ *
+ * On entry:   R0 == pointer to block allocated by alloc
+ *
+ * On exit:    --
+ *
+ * Use:                Frees a block allocated by alloc, regardless of which heap
+ *             it came from.
+ */
+
+extern routine free;
+
+/* --- alloc_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the alloc system, and sets it up to use the
+ *             kernel-provided OS_Heap area.
+ */
+
+extern routine alloc_init;
+
+/* --- alloc_error --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    V set and R0 == pointer to an error about not having enough
+ *             memory.
+ *
+ * Use:                Returns an error suitable for displaying to a user if there
+ *             isn't enough memory left.
+ */
+
+extern routine alloc_error;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/banner b/StraySrc/Libraries/Sapphire/csapph/h/banner
new file mode 100644 (file)
index 0000000..b415ca1
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * banner.h
+ *
+ * [Generated from banner, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __banner_h
+#define __banner_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  banner
+ *  bnr_doBanner
+ */
+
+/* --- banner --- *
+ *
+ * On entry:   R0 == pointer to definition block, or 0
+ *             R1 == R12 value to pass to setup routine, if present
+ *
+ * On exit:    --
+ *
+ * Use:                Displays a startup banner and initialises the library and
+ *             client.  This call should be used as a replacement for
+ *             sapphire_libInit.
+ *
+ *             If R0 is 0 on entry, no banner window is used; instead
+ *             an hourglass percentage is displayed to indicate the
+ *             amount of initialisation performed so far.
+ *
+ *             Alternatively, it should point to a table consisting of
+ *             a flags word and optional arguments specified by the flags
+ *             in order.  The options you can specify are a slider and
+ *             percentage count icon (used to display current progress),
+ *             a setup routine, and the leafname of a sprites file to
+ *             attach to the banner window.
+ *
+ *             The setup routine is passed the banner dialogue handle in
+ *             R0.  It should fill in parts of the banner window, such as
+ *             the licencee name and serial number that can't be determined
+ *             until runtime (for safeness), and maybe version information
+ *             too.
+ */
+
+extern routine banner;
+
+/* --- bnr_doBanner --- *
+ *
+ * On entry:   R0 == pointer to definition block, or 0
+ *             R1 == R12 value to pass to setup routine, if present
+ *             R2 == pointer to library initialisation table
+ *
+ * On exit:    --
+ *
+ * Use:                Displays a startup banner and initialises the library and
+ *             client.  This routine is used to support dynamic linking.
+ */
+
+extern routine bnr_doBanner;
+
+/*----- Flags -------------------------------------------------------------*/
+
+#define bFlag_slider ((1<<0))
+
+#define bFlag_counter ((1<<1))
+
+#define bFlag_setup ((1<<2))
+
+#define bFlag_sprites ((1<<3))
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- Macro: BANNER --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Begins construction of a banner block.
+ */
+
+/* --- Macro: BFLAG --- *
+ *
+ * Arguments:  f == flag to set
+ *
+ * Use:                Sets a flag in the banner header, making sure they go in
+ *             order.
+ */
+
+/* --- Macro: BNSLIDE --- *
+ *
+ * Arguments:  icon == icon number of slider in banner window
+ *
+ * Use:                Registers the banner window's slider.
+ */
+
+/* --- Macro: BNCOUNT --- *
+ *
+ * Arguments:  icon == icon number of percentage counter
+ *
+ * Use:                Registers the banner window's percentage counter.
+ */
+
+/* --- Macro: BNSETUP --- *
+ *
+ * Arguments:  rout == address of setup routine
+ *
+ * Use:                Registers the banner window's setup routine.
+ */
+
+/* --- Macro: BNSPRT --- *
+ *
+ * Arguments:  name == leafname of sprite file
+ *
+ * Use:                Registers the banner window's sprite file name.
+ */
+
+/* --- Macro: BNEND --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Terminates a banner window definition.
+ */
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/buttons b/StraySrc/Libraries/Sapphire/csapph/h/buttons
new file mode 100644 (file)
index 0000000..282dccd
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * buttons.h
+ *
+ * [Generated from buttons, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __buttons_h
+#define __buttons_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *   buttons_setup
+ *
+ * Macros provided:
+ *
+ *   BUTTON
+ *   BUTEND
+ *   BCANCEL
+ *   BOK
+ *   BHELP
+ *   BGAP
+ */
+
+/* --- buttons_setup --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == pointer to buttons block
+ *             R2 == buttons base icon
+ *             R3 == number of buttons to allow
+ *
+ * On exit:    R2 == buttons flag mask
+ *             R3 == cancel button icon, or -1
+ *
+ * Use:                Sets up a dialogue box's buttons according to a buttons
+ *             block.
+ */
+
+extern routine buttons_setup;
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- Macro: BUTTON --- *
+ *
+ * Arguments:  msg == message tag to put in button
+ *
+ * Use:                Inserts a text button into a buttons definition block.
+ */
+
+/* --- Macro: BCANCEL --- *
+ *
+ * Arguments:  text == optional text string (default is `Cancel')
+ *
+ * Use:                Inserts a cancel button into a buttons definition block.
+ */
+
+/* --- Macro: BOK --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Inserts an OK button into a buttons definition block.
+ */
+
+/* --- Macro: BHELP --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Inserts a help button into a buttons definition block.
+ */
+
+/* --- Macro: BGAP --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Omits a button in a buttons definition block.
+ */
+
+/* --- Macro: BUTEND --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Terminates a buttons definition block.
+ */
+
+/*----- Button block formats ----------------------------------------------*/
+
+#define bFlag_cancel ((1<<0))
+
+#define bFlag_ok ((1<<1))
+
+#define bFlag_help ((1<<2))
+
+#define bFlag_text ((1<<3))
+
+#define bFlag_last ((1<<31))
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/choices/choices b/StraySrc/Libraries/Sapphire/csapph/h/choices/choices
new file mode 100644 (file)
index 0000000..38c552b
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * choices.h
+ *
+ * [Generated from choices, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __choices_h
+#define __choices_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  choices_useChoices
+ *  choices_find
+ */
+
+/* --- choices_useChoices --- *
+ *
+ * On entry:   R0 == 0 to disable use of `Choices', >0 to enable, or <0 to
+ *                     read
+ *
+ * On exit:    R0 == previous setting
+ *
+ * Use:                This call allows an application to determine whether its
+ *             user-configurable resources are looked for in Acorn's
+ *             `Choices' directory, or only in the application's directory.
+ *
+ *             An application would typically make this call after parsing
+ *             its command-line options, to allow a Network Manager to
+ *             enable the `Choices' support.
+ */
+
+extern routine choices_useChoices;
+
+/* --- choices_find --- *
+ *
+ * On entry:   R0 == pointer to resource filename
+ *             R1 == pointer to buffer to build filename in
+ *             R2 == flags:
+ *                     bit 0 == file will be written to (use Choices$Write)
+ *
+ * On exit:    R0 == pointer to filename
+ *             R1 == pointer to terminating NULL
+ *             CS if the file was found, else CC
+ *
+ * Use:                Locates a user-configurable resource file.  The search order
+ *             depends on (a) whether the file will be written (bit 0 of R2)
+ *             and (b) whether the use of Acorn's `Choices' system is
+ *             enabled.
+ *
+ *             The search order is as follows:
+ *
+ *             * Choices:appName.leaf / <Choices$Write>.appName.leaf
+ *             * res_find(leaf)
+ *
+ *             (i.e. it looks in the `Choices' structure first, and if that
+ *             fails, it will use res_find).
+ */
+
+extern routine choices_find;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/choices/options b/StraySrc/Libraries/Sapphire/csapph/h/choices/options
new file mode 100644 (file)
index 0000000..eb91445
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * options.h
+ *
+ * [Generated from options, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __options_h
+#define __options_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  options_read
+ *  options_write
+ *  optType_string
+ *  optType_integer
+ *  optType_literal
+ *  optType_enum
+ *  optType_bool
+ *  optType_version
+ */
+
+/* --- options_read --- *
+ *
+ * On entry:   R0 == chunk file handle
+ *             R1 == pointer to a chunk name
+ *             R2 == pointer to options definition
+ *             R3,R4 specify address of output block
+ *
+ * On exit:    --
+ *
+ * Use:                Claims the specified options chunk, and reads the data in
+ *             it into a binary block.  Because the output data might be
+ *             in a flex block, the two registers R3,R4 which define its
+ *             address work as follows:
+ *
+ *             R3 == address or offset of data
+ *             R4 == -1 if R3 is address, else flex anchor address
+ */
+
+extern routine options_read;
+
+/* --- options_write --- *
+ *
+ * On entry:   R0 == terminator character to write, 0 for none, or -1 for
+ *                     quoting with 's
+ *             R1 == pointer to name to save
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Writes out an option name, terminated with the character
+ *             given in R0 (which will normally be a space or an `=' sign).
+ */
+
+extern routine options_write;
+
+/* --- optType_string --- *
+ *
+ * Flags:      --
+ *
+ * Data:       (word) buffer size of string
+ *
+ * Use:                Handles string data.  The binary representation is a ctrl
+ *             terminated string.  The textual representation is a sequence
+ *             of characters, which is always output in single quotes,
+ *             although this is not necessary for the input.  The string
+ *             will be truncated to fit in the buffer during reading.
+ */
+
+extern routine optType_string;
+
+/* --- optType_integer --- *
+ *
+ * Flags:      bit 8 == use given default base
+ *
+ * Data:       (word) default base, if bit 8 set
+ *
+ * Use:                Handles integer data.  The binary representation is a 32-
+ *             bit integer value.  The textual representation is the normal
+ *             RISC OS style of numbers (i.e. the base_value notation is
+ *             supported).  Numbers are always output in the default base
+ *             given (or in decimal if there is none given).  Numbers
+ *             being read may always have a sign; numbers will only be
+ *             output with a sign if the default base is decimal.  Uppercase
+ *             letters will be used for output, but any case is acceptable
+ *             for input.
+ *
+ *             Special prefixes allowed are `%' for binary and `&' for hex.
+ *             Such numbers are always output with these prefixes.
+ */
+
+extern routine optType_integer;
+
+/* --- optType_literal --- *
+ *
+ * Flags:      --
+ *
+ * Data:       (string) data to write out (*null* terminated)
+ *
+ * Use:                Reads nothing; leave the name blank.  Writes out the data
+ *             literally.  Note that an extra linefeed is added to the
+ *             end, so don't overdo it.
+ */
+
+extern routine optType_literal;
+
+/* --- optType_enum --- *
+ *
+ * Flags:      bit 8 == quote output string
+ *             bit 9 == don't put an `=' sign in output
+ *
+ * Data:       See below
+ *
+ * Use:                The data is a collection of ctrl-terminated strings, itself
+ *             terminated by a zero-length entry.  The textual
+ *             representation is one of these strings, or an abbreviation
+ *             of one.  The binary representation is a word containing the
+ *             index into the list.
+ */
+
+extern routine optType_enum;
+
+/* --- optType_bool --- *
+ *
+ * Flags:      bit 8 == make flag active low
+ *             bit 9 == use `on'/`off' rather than `true'/`false'; also
+ *                     suppresses the `=' sign
+ *
+ * Data:       (word) bit mask to OR or BIC within word
+ *
+ * Use:                Handles a boolean option.  It will translate between the
+ *             strings `true' or `false' and a bit (or set of bits) within
+ *             a word.
+ */
+
+extern routine optType_bool;
+
+/* --- optType_version --- *
+ *
+ * Flags:      --
+ *
+ * Data:       --
+ *
+ * Use:                Converts between version number strings (of the form
+ *             <int>[.[<digit>[<digit>]]]) and integers.  The version
+ *             number is stored multiplied by 100.
+ */
+
+extern routine optType_version;
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- Options definition block --- */
+
+#define opt_flags 0
+#define opt_length 4
+#define opt_offset 8
+#define opt_type 12
+#define opt_name 16
+
+/* --- Option block flags --- */
+
+#define optFlag_last ((1<<0))
+#define optFlag_ignore ((1<<1))
+
+/* --- Integer type flags --- */
+
+#define intFlag_base ((1<<8))
+
+/* --- Enumeration type flags --- */
+
+#define enumFlag_quote ((1<<8))
+#define enumFlag_noEq ((1<<9))
+
+/* --- Boolean type flags --- */
+
+#define boolFlag_cpl ((1<<8))
+#define boolFlag_onOff ((1<<9))
+
+/* --- Type handler reason codes --- *
+ *
+ * All enter with:
+ *
+ *  R0 == reason code
+ *  R7 == flags read from table
+ *  R8 == address of option name
+ *  R9 == address of type-specific data
+ * R10 == address of binary option
+ */
+
+#define optReason_read 0
+
+#define optReason_write 1
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/choices/prefs b/StraySrc/Libraries/Sapphire/csapph/h/choices/prefs
new file mode 100644 (file)
index 0000000..3fde5e6
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * prefs.h
+ *
+ * [Generated from prefs, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __prefs_h
+#define __prefs_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  prefs_find
+ *  prefs_init
+ */
+
+/* --- prefs_find --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == chunk handle of loaded preferences file
+ *
+ * Use:                Returns the chunk handle of the preferences file.  You can
+ *             then claim your chunk of options from the preferences file
+ *             using options_read.
+ */
+
+extern routine prefs_find;
+
+/* --- prefs_init --- *
+ *
+ * On entry:   R0 == pointer to application name
+ *
+ * On exit:    --
+ *
+ * Use:                Loads the application's preferences file.
+ */
+
+extern routine prefs_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/chunk b/StraySrc/Libraries/Sapphire/csapph/h/chunk
new file mode 100644 (file)
index 0000000..96b5f5e
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * chunk.h
+ *
+ * [Generated from chunk, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __chunk_h
+#define __chunk_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  chunk_create
+ *  chunk_destroy
+ *  chunk_claim
+ *  chunk_makeBinary
+ *  chunk_read
+ *  chunk_enum
+ *  chunk_save
+ */
+
+/* --- chunk_create --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == chunk file handle
+ *             May return an error
+ *
+ * Use:                Creates a new chunk file structure and returns a handle to
+ *             it.
+ */
+
+extern routine chunk_create;
+
+/* --- chunk_destroy --- *
+ *
+ * On entry:   R0 == chunk file handle
+ *
+ * On exit:    --
+ *
+ * Use:                Removes a chunk file structure from memory.  Chunk data in
+ *             flex blocks is freed; chunk claimers who free flex blocks
+ *             should clear the anchors to 0.
+ */
+
+extern routine chunk_destroy;
+
+/* --- chunk_claim --- *
+ *
+ * On entry:   R0 == chunk file handle
+ *             R1 == pointer to chunk name
+ *             R2 == pointer to saver routine, or 0 for none, or -1 for no
+ *                     change
+ *             R3 == R10 value to pass to saver
+ *             R4 == R12 value to pass to saver
+ *
+ * On exit:    R1 == chunk handle/anchor
+ *             CS if the chunk already existed
+ *             May return an error
+ *
+ * Use:                Claims a chunk, installing a save handler for it.  The chunk
+ *             handle returned is actually the address of a flex anchor for
+ *             the chunk's data (use flex_size to find the block's size).
+ *             If the save handle is 0, the data in the flex block (which
+ *             may be modified) is saved directly from the block.  Otherwise
+ *             the save routine is expected to save its data, using xsave.
+ *
+ *             The anchor is followed by 3 unused words -- you can use them
+ *             for whatever you want.
+ *
+ *             Warning: this routine may move flex blocks.
+ */
+
+extern routine chunk_claim;
+
+/* --- chunk_makeBinary --- *
+ *
+ * On entry:   R0 == chunk file handle
+ *             R1 == chunk handle
+ *
+ * On exit:    --
+ *
+ * Use:                Marks a given chunk as containing binary data.
+ */
+
+extern routine chunk_makeBinary;
+
+/* --- chunk_read --- *
+ *
+ * On entry:   R0 == chunk file handle
+ *             R1 == address of a flex anchor
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Merges the data contained in the flex block with that already
+ *             in the chunk file.  If the chunk file is empty, this is
+ *             equivalent to a load.  Data from the flex block is appended
+ *             to chunks already loaded where appropriate.
+ *
+ *             Warning: this routine may move flex blocks.
+ */
+
+extern routine chunk_read;
+
+/* --- chunk_enum --- *
+ *
+ * On entry:   R0 == chunk file handle
+ *             R1 == 0 for first call or continuation value
+ *
+ * On exit:    CC if this isn't over yet, and
+ *               R1 == continuation value for next call
+ *               R2 == pointer to chunk name
+ *             else CS and
+ *               R1 == 0
+ *               R2 preserved
+ *
+ * Use:                Allows you to enumerate the chunks in a chunk file structure.
+ */
+
+extern routine chunk_enum;
+
+/* --- chunk_save --- *
+ *
+ * On entry:   R0 == chunk file handle
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Saves a chunk file to xsave's current output.
+ */
+
+extern routine chunk_save;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/cmdLine b/StraySrc/Libraries/Sapphire/csapph/h/cmdLine
new file mode 100644 (file)
index 0000000..86aaff0
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * cmdLine.h
+ *
+ * [Generated from cmdLine, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __cmdLine_h
+#define __cmdLine_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  cl_next
+ */
+
+/* --- cl_next --- *
+ *
+ * On entry:   R0 == pointer to a command line string (ctrl terminated)
+ *             R1 == pointer to a buffer (may be equal to R0)
+ *
+ * On exit:    CS if another word found, and
+ *               R0 == updated past next word
+ *               R1 preserved, buffer filled with null terminated string
+ *               R2 == pointer to terminating null character
+ *             else CC and
+ *               R0 == pointer to terminating character
+ *               R1 preserved, buffer preserved
+ *               R2 corrupted
+ *
+ * Use:                Extracts the next word from a command line string.  If the
+ *             string is in a writable buffer, you can set R1 == R0 to
+ *             start with.  You can build up a C-like argv array like this:
+ *
+ *                     ; R0 == pointer to command line in writable buffer
+ *
+ *                             MOV     R1,R0
+ *                             ADR     R3,argv
+ *                             MOV     R4,#0
+ *                     loop    BL      cl_next
+ *                             MOVCC   R1,#0
+ *                             STR     R1,[R3],#4
+ *                             ADDCS   R4,#0
+ *                             BCS     loop
+ *
+ *                     ; R0-R3 corrupted
+ *                     ; R4 == argc
+ *
+ *             This routine will handle quoted strings, considering them
+ *             to be single arguments.  Either type of quote will do,
+ *             quote doubling is required to insert quotes in quoted
+ *             strings.
+ */
+
+extern routine cl_next;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/coRoutine b/StraySrc/Libraries/Sapphire/csapph/h/coRoutine
new file mode 100644 (file)
index 0000000..d1a2518
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * coRoutine.h
+ *
+ * [Generated from coRoutine, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __coRoutine_h
+#define __coRoutine_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  coRout_create
+ *  coRout_switch
+ *  coRout_destroy
+ *  coRout_end
+ */
+
+/* --- coRout_create --- *
+ *
+ * On entry:   R0 == pointer to coroutine
+ *             R1 == R10 value to pass to coroutine
+ *             R2 == R12 value to pass to coroutine
+ *             R3 == size of stack to pass (0 for default)
+ *
+ * On exit:    R0 == coroutine handle
+ *             May return an error
+ *
+ * Use:                Creates a new coroutine.  It may be given control using
+ *             coRout_switch.  Its registers are on entry:
+ *
+ *             R0 == its coroutine handle
+ *             R10 == value passed to coRout_create in R1
+ *             R12 == value passed to coRout_create in R2
+ *             R13 == pointer to the stack created for it
+ */
+
+extern routine coRout_create;
+
+/* --- coRout_switch --- *
+ *
+ * On entry:   R0 == coroutine to switch to, or 0 for main
+ *
+ * On exit:    --
+ *
+ * Use:                Switches context to another coroutine.
+ */
+
+extern routine coRout_switch;
+
+/* --- coRout_destroy --- *
+ *
+ * On entry:   R0 == coroutine handle to destroy
+ *
+ * On exit:    --
+ *
+ * Use:                Destroys a coroutine.
+ */
+
+extern routine coRout_destroy;
+
+/* --- coRout_end --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    Doesn't.
+ *
+ * Use:                Terminates the current coroutine.
+ */
+
+extern routine coRout_end;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/colSelect b/StraySrc/Libraries/Sapphire/csapph/h/colSelect
new file mode 100644 (file)
index 0000000..fcc39f2
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * colSelect.h
+ *
+ * [Generated from colSelect, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __colSelect_h
+#define __colSelect_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *   colSelect
+ */
+
+/* --- colSelect --- *
+ *
+ * On entry:   R0 == address of a colour block
+ *             R1 == pointer to routine to call when done
+ *             R2 == R10 to call routine with
+ *             R3 == R12 to call routine with
+ *
+ * On exit:    May return error
+ *
+ * Use:                Displays a colour selector dialogue box.  It allows the user
+ *             to edit a colour (understatement....)
+ */
+
+extern routine colSelect;
+
+/*----- The colour selector handler ---------------------------------------*
+ *
+ * The routine you pass to colSelect is entered with R0 as a reason code,
+ * and other registers containing values which depend on that.  Reason codes
+ * defined are:
+ */
+
+#define csEvent_choice 0
+
+#define csEvent_close 1
+
+/*----- Data structures ---------------------------------------------------*/
+
+#define col_rgb 0
+#define col_model 4
+#define col_data 8
+#define col_size 12
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/colourBox b/StraySrc/Libraries/Sapphire/csapph/h/colourBox
new file mode 100644 (file)
index 0000000..f6cac51
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * colourBox.h
+ *
+ * [Generated from colourBox, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __colourBox_h
+#define __colourBox_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  colourBox
+ */
+
+/* --- colourBox --- *
+ *
+ * On entry:   R0 == pointer to a title string (message tag)
+ *             R1 == the current colour in bottom byte, and flags:
+ *                     bit 8 == allow transparent colour
+ *             R2 == event handler to call
+ *             R3 == R10 value to pass to handler
+ *             R4 == R12 value to pass to handle
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Opens a dialogue box which allows the user to choose
+ *             one of the wimp colours.  A transparent colour is supported,
+ *             and represented as colour 255.
+ */
+
+extern routine colourBox;
+
+/*----- Events ------------------------------------------------------------*/
+
+#define cbEvent_select 0
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/dbox b/StraySrc/Libraries/Sapphire/csapph/h/dbox
new file mode 100644 (file)
index 0000000..8759c92
--- /dev/null
@@ -0,0 +1,539 @@
+/*
+ * dbox.h
+ *
+ * [Generated from dbox, 07 February 1998]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __dbox_h
+#define __dbox_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Sapphire library.
+ *
+ * Sapphire is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Sapphire is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Sapphire.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  dbox_create
+ *  dbox_fromEmbedded
+ *  dbox_fromDefn
+ *  dbox_destroy
+ *  dbox_init
+ *  dbox_open
+ *  dbox_close
+ *  dbox_writePos
+ *  dbox_select
+ *  dbox_shade
+ *  dbox_selectMany
+ *  dbox_shadeMany
+ *  dbox_isSelected
+ *  dbox_radio
+ *  dbox_slab
+ *  dbox_unslab
+ *  dbox_setField
+ *  dbox_getField
+ *  dbox_eventHandler
+ *  dbox_renderTitle
+ *  dbox_setEmbeddedTitle
+ *  dbox_setClickDrag
+ *  dbox_hasTitle
+ *  dbox_window
+ *  dbox_help
+ */
+
+/* --- dbox_create --- *
+ *
+ * On entry:   R0 == pointer to dialogue template name
+ *
+ * On exit:    R0 == dialogue box handle for the dialogue
+ *             May return an error
+ *
+ * Use:                Creates a dialogue box from a template definition.
+ */
+
+extern routine dbox_create;
+
+/* --- dbox_fromEmbedded --- *
+ *
+ * On entry:   R0 == pointer to an embedded template
+ *
+ * On exit:    R0 == dialogue box handle
+ *             May return an error
+ *
+ * Use:                Creates a dialogue box from an embedded template definition.
+ */
+
+extern routine dbox_fromEmbedded;
+
+/* --- dbox_fromDefn --- *
+ *
+ * On entry:   R0 == pointer to a window definition
+ *
+ * On exit:    R0 == dialogue box handle for the dialogue
+ *             May return an error
+ *
+ * Use:                Creates a dialogue box from an immediate window definition,
+ *             rather than a template.  There are several things you need
+ *             to be aware of when you use this call to create a dialogue
+ *             box:
+ *
+ *             * The window definition is not copied, but used directly
+ *               for the duration the dialogue box exists.  It must
+ *               not move for this duration.  When the dialogue is
+ *               destroyed, you can release the memory for the definition,
+ *               although this is your responsibility.
+ *
+ *             * The indirected data is not copied either, so you'll have
+ *               to copy it yourself if you want multiple dialogues from
+ *               the same window definition.
+ *
+ *             * The window definition and the indirected data must both
+ *               be writable.
+ */
+
+extern routine dbox_fromDefn;
+
+/* --- dbox_destroy --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *
+ * On exit:    --
+ *
+ * Use:                Destroys a dialogue box, freeing all the memory it took
+ *             up etc.
+ */
+
+extern routine dbox_destroy;
+
+/* --- dbox_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the dbox system.
+ */
+
+extern routine dbox_init;
+
+/* --- dbox_open --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == how to open the dialogue box
+ *             Other registers depend on R1, and are described at the end
+ *             of this header file
+ *
+ * On exit:    --
+ *
+ * Use:                Displays the dialogue box on the screen in the given manner.
+ */
+
+extern routine dbox_open;
+
+/* --- dbox_close --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *
+ * On exit:    --
+ *
+ * Use:                Closes a dialogue box, by clearing the current menu if
+ *             necessary.
+ */
+
+extern routine dbox_close;
+
+/* --- dbox_writePos --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *
+ * On exit:    --
+ *
+ * Use:                Saves the dialogue's current position so that it will be
+ *             opened here the next time it is created.  If the dialogue
+ *             box was created from a template, the template is updated.
+ *             Otherwise, the new state is written back to the definition
+ *             supplied to dbox_fromDefn.
+ */
+
+extern routine dbox_writePos;
+
+/* --- dbox_select --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon number
+ *             R2 == 0 to deselect the icon, 1 to select it, 2 to toggle
+ *                   its current selected state
+ *
+ * On exit:    --
+ *
+ * Use:                Selects or deselects the specified icon in the Acorn sense
+ *             (i.e. by flipping its selected bit).  The state is only
+ *             changed if required, to reduce flicker.
+ */
+
+extern routine dbox_select;
+
+/* --- dbox_shade --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon number
+ *             R2 == 0 to unshade the icon, 1 to shade it, 2 to toggle its
+ *                   current shaded state
+ *
+ * On exit:    --
+ *
+ * Use:                Makes the icon look dimmer, to indicate that it is not
+ *             available.  It uses its own shading algorithms, rather than
+ *             the WindowManager's, so there are some things you must watch
+ *             out for:
+ *
+ *             * Don't use any other method of shading icons
+ *
+ *             * Don't assume that a shaded icon isn't going to give you
+ *               events.  At the user level, this should have been tidied
+ *               up, but at the Sapphire level, it's still a problem.
+ *               There is a routine in winUtils which will tell you if an
+ *               icon is shaded.
+ *
+ *             This routine has been written so that it only flickers icons
+ *             when they actually need it.
+ */
+
+extern routine dbox_shade;
+
+/* --- dbox_selectMany --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == pointer to icon handle list, -1 terminated
+ *             R2 == select action (0 == unselect, 1 == select, 2 == toggle)
+ *
+ * On exit:    --
+ *
+ * Use:                Changes the select state of a group of icons.
+ */
+
+extern routine dbox_selectMany;
+
+/* --- dbox_shadeMany --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == pointer to icon handle list, -1 terminated
+ *             R2 == shade action (0 == unshade, 1 == shade, 2 == toggle)
+ *
+ * On exit:    --
+ *
+ * Use:                Changes the shade state of a group of icons.
+ */
+
+extern routine dbox_shadeMany;
+
+/* --- dbox_isSelected --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon number
+ *
+ * On exit:    CS if the icon is selected, CC otherwise
+ *
+ * Use:                Returns whether an icon is currently selected.
+ */
+
+extern routine dbox_isSelected;
+
+/* --- dbox_radio --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon handle
+ *
+ * On exit:    --
+ *
+ * Use:                Checks to see if the icon is a radio button as defined by
+ *             Sapphire, i.e. button type 3 (debounced) and non-zero ESG.
+ *             If it is, it selects it, and deselects all other icons with
+ *             this ESG.
+ */
+
+extern routine dbox_radio;
+
+/* --- dbox_slab --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon handle
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Slabs an icon in properly, to give visual feedback when you
+ *             click it.
+ */
+
+extern routine dbox_slab;
+
+/* --- dbox_unslab --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    CS if there are no more slabbed icons after this one, CC
+ *             if there are more left.
+ *
+ * Use:                Unslabs an icon slabbed with dbox_slab.  Icons are unslabbed
+ *             in reverse order to that in which they were slabbed.  The
+ *             carry flag is returned as an indication of whether there
+ *             are any more icons left in the list -- you can unslab all
+ *             icons in one go by doing:
+ *
+ *                             BL      dbox_unslab
+ *                             SUBCC   PC,PC,#12       ;Avoids a label!
+ *
+ *             It is recommended that, if you are going to close a window,
+ *             you unslab icons within it *after* you close, but before you
+ *             actually destroy it, e.g.
+ *
+ *                             LDR     R0,my_dbox
+ *                             BL      dbox_close
+ *                             BL      dbox_unslab
+ *                             BL      dbox_destroy
+ */
+
+extern routine dbox_unslab;
+
+/* --- dbox_setField --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon number to write to (may be -1 for title)
+ *                   flags in top byte if not -1:
+ *                     dbFlag_dots (bit 31) == add `...' if text overflows
+ *             R2 == pointer to string to use
+ *
+ * On exit:    --
+ *
+ * Use:                Writes the string specified into the indirection buffer
+ *             for the given icon.  If the icon is not indirected, an
+ *             error is generated.  If the indirected buffer is too small,
+ *             the string is shortened by chopping off the beginning or
+ *             the end, according to the setting of the icon's right
+ *             justify flag.
+ *
+ *             The icon is only flickered if the text has actually changed.
+ *             The caret is moved correctly if it is within the icon to
+ *             prevent it `falling off' the end and deleting the validation
+ *             string, or being positioned incorrectly in centred icons if
+ *             the length changes.
+ *
+ *             Note that this routine requires a string to already be in
+ *             the buffer, and doesn't perform any substitution or other
+ *             transformations.  This helps to prevent buffer full errors
+ *             and similar problems.
+ */
+
+extern routine dbox_setField;
+
+/* --- dbox_getField --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon number to interrogate
+ *
+ * On exit:    R0, R1 preserved
+ *             R2 == pointer to the icon text
+ *
+ * Use:                Returns a pointer to the text associated with an icon.
+ *             Note that if the icon is *not* indirected, the text will
+ *             be copied into the scratchpad.  Otherwise you get a pointer
+ *             to the actual indirected data.  You shouldn't write to the
+ *             string returned at all -- dbox_setField is specially
+ *             designed to do that sort of thing very well (i.e. not
+ *             flickering the text unless it has to, truncating if it's too
+ *             long, and handling the caret correctly).  You *are* allowed
+ *             to zero terminate the string if you want to, though.
+ *
+ *             Despite all the PRM's assurances to the contrary, chances
+ *             are the text will be terminated by some weird control char,
+ *             so you'll have to handle this, and not just assume it's
+ *             going to be null-terminated.
+ *
+ *             Note: The indirected case is immensely quick -- just load a
+ *             pointer.  The non-indirected case has been optimised as much
+ *             as possible.
+ */
+
+extern routine dbox_getField;
+
+/* --- dbox_eventHandler --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == pointer to handler routine
+ *             R2 == value to pass to handler in R10
+ *             R3 == value to pass to handler in R12
+ *
+ * On exit:    R0 preserved
+ *             R1 == pointer to old handler
+ *             R2 == old R10 value
+ *             R3 == old R12 value
+ *
+ * Use:                Sets up an event handler for a dialogue box, and returns
+ *             the previous one.  If the pointer to handler is 0, there is
+ *             no dialogue box event handler.
+ */
+
+extern routine dbox_eventHandler;
+
+/* --- dbox_renderTitle --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == pointer to redraw block
+ *
+ * On exit:    --
+ *
+ * Use:                Renders a dialogue box's embedded title if there is one.
+ */
+
+extern routine dbox_renderTitle;
+
+/* --- dbox_setEmbeddedTitle --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon which should contain the embedded title
+ *
+ * On exit:    --
+ *
+ * Use:                Declares a given dialogue box as requiring an embedded title
+ *             (rather than the one the WindowManager put on).
+ */
+
+extern routine dbox_setEmbeddedTitle;
+
+/* --- dbox_setClickDrag --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *
+ * On exit:    --
+ *
+ * Use:                Sets a given dialogue box so that the user can move it by
+ *             dragging from any part of the window, not just the title
+ *             bar.
+ */
+
+extern routine dbox_setClickDrag;
+
+/* --- dbox_hasTitle --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *
+ * On exit:    CS if the dialogue box has a title bar, CC if not
+ *
+ * Use:                Informs the caller whether the dialogue box has a title bar.
+ *             This is mainly useful for other library sections which
+ *             conditionally add in embedded titles etc.
+ */
+
+extern routine dbox_hasTitle;
+
+/* --- dbox_window --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *
+ * On exit:    R0 == the dialogue box's window handle
+ *
+ * Use:                Returns the Wimp window handle associated with a dialogue
+ *             box.  This may be useful if you want to perform lowlevel
+ *             Wimp operation on it, or to subclass it using win.
+ */
+
+extern routine dbox_window;
+
+/* --- dbox_help --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Adds a help line to the current help message, read by
+ *             scanning the icon to which the help was sent for an `H'
+ *             validation string.
+ */
+
+extern routine dbox_help;
+
+/*----- Useful constants --------------------------------------------------*/
+
+/* --- Ways of opening dialogue boxes --- */
+
+#define dbOpen_current 0
+#define dbOpen_centre 1
+#define dbOpen_pointer 2
+#define dbOpen_givenY 3
+#define dbOpen_givenXY 4
+
+#define dbOpen_trans (0x00)
+#define dbOpen_persist (0x80)
+#define dbOpen_nonSub (0x40)
+
+/* --- Dialogue box event codes --- */
+
+#define dbEvent_close (-2)
+
+#define dbEvent_help (-3)
+
+#define dbEvent_OK (-4)
+
+#define dbEvent_cancel (-5)
+
+#define dbEvent_redraw (-6)
+
+#define dbEvent_menu (-7)
+
+#define dbEvent_drag (-8)
+
+#define dbEvent_save (-9)
+
+#define dbEvent_load (-10)
+
+#define dbEvent_key (-11)
+
+#define dbEvent_hint (-12)
+
+#define dbEvent_enter (-13)
+
+#define dbEvent_leave (-14)
+
+#define dbEvent_lifeCycle (-15)
+
+/* --- Life cycle codes --- */
+
+#define dblc_create 0
+#define dblc_open 1
+#define dblc_close 2
+#define dblc_destroy 3
+
+/* --- Other values --- */
+
+#define dbFlag_dots ((1<<31))
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/dbx/arrow b/StraySrc/Libraries/Sapphire/csapph/h/dbx/arrow
new file mode 100644 (file)
index 0000000..6e6094d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * arrow.h
+ *
+ * [Generated from arrow, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __arrow_h
+#define __arrow_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  arrow
+ *
+ * Macros provided:
+ *
+ *   ARROW
+ */
+
+/* --- arrow --- *
+ *
+ * Control data:       +0 == increment when clicked with Select
+ *             +4
+ *
+ * Workspace:  --
+ *
+ * Flags:      --
+ *
+ * Use:                Control type for an arrow button.
+ */
+
+extern routine arrow;
+
+/*----- Macros and symbols ------------------------------------------------*/
+
+/* --- Arrow event codes --- */
+
+#define arrow_event (0x80000002)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/dbx/colourPot b/StraySrc/Libraries/Sapphire/csapph/h/dbx/colourPot
new file mode 100644 (file)
index 0000000..55542ef
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * colourPot.h
+ *
+ * [Generated from colourPot, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __colourPot_h
+#define __colourPot_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Controls provided:
+ *
+ *   colourPot
+ *
+ * Macros provided:
+ *
+ *   COLPOT
+ */
+
+/* --- colourPot --- *
+ *
+ * Control data:       +0 == null terminated title string, or empty for default
+ *             +n
+ *
+ * Workspace:  +0 == current colour selected
+ *             +1
+ *
+ * Flags:      bit 8 == allow transparent
+ *
+ * Use:                Provides a `colour button' which allows the user to choose
+ *             a Wimp colour.  Transparent is represented by 255.
+ */
+
+extern routine colourPot;
+
+/*----- Macros and constants ----------------------------------------------*/
+
+/* --- Flags --- */
+
+#define cpFlag_trans ((1<<8))
+
+/* --- Event codes --- */
+
+#define colourPot_event (0x80000006)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/dbx/dbx b/StraySrc/Libraries/Sapphire/csapph/h/dbx/dbx
new file mode 100644 (file)
index 0000000..bfaa182
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * dbx.h
+ *
+ * [Generated from dbx, 07 February 1998]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __dbx_h
+#define __dbx_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Sapphire library.
+ *
+ * Sapphire is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Sapphire is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Sapphire.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  dbx_declare
+ *  dbx_sendEvent
+ *  dbx_findData
+ *  dbx_controlBBox
+ *  dbx_update
+ *  dbx_qUpdate
+ */
+
+/* --- dbx_declare --- *
+ *
+ * On entry:   R0 == dialogue box handle from dbox
+ *             R1 == pointer to dialogue box definition block
+ *
+ * On exit:    --
+ *
+ * Use:                Declares a dialogue box to be dbx-managed, and declares the
+ *             control types of all its controls.
+ */
+
+extern routine dbx_declare;
+
+/* --- dbx_sendEvent --- *
+ *
+ * On entry:   R0 == event code to send
+ *             R1-R7 == depend on the event code
+ *             R10 == dialogue box handle
+ *
+ * On exit:    C flag as set by event handler
+ *
+ * Use:                Sends an event to the specified dialogue box.  This is
+ *             intended to be used by control handlers, hence the unusual
+ *             placing of the dialogue handle in R10.
+ */
+
+extern routine dbx_sendEvent;
+
+/* --- dbx_findData --- *
+ *
+ * On entry:   R0 == icon handle
+ *             R10 == dialogue box handle
+ *
+ * On exit:    If found, CS and
+ *               R8 == pointer to writable control data
+ *               R9 == pointer to static control data
+ *             else CC and
+ *               R8, R9 corrupted
+ *
+ * Use:                Allows a control to find its data when called by client
+ *             code.
+ */
+
+extern routine dbx_findData;
+
+/* --- dbx_controlBBox --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == control icon number
+ *
+ * On exit:    R0,R1 preserved
+ *             R2-R5 == inclusive screen coordinates of icon bounding box
+ *
+ * Use:                Calculates the position *on the screen* of the given control
+ *             icon, and returns it to you as a set of four inclusive
+ *             coordinates (*not* inclusive-exclusve as the WIMP tends to
+ *             return to you)
+ */
+
+extern routine dbx_controlBBox;
+
+/* --- dbx_update --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon number of control to update
+ *
+ * On exit:    --
+ *
+ * Use:                Redraws the specified control immediately.  If the control
+ *             does not redraw itself, this call does nothing.
+ */
+
+extern routine dbx_update;
+
+/* --- dbx_qUpdate --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon number of control to update
+ *
+ * On exit:    --
+ *
+ * Use:                Makes a control quickly update itself in whichever way it
+ *             needs to in order to be perfect again.  It is anticipated
+ *             that this is used to update EORed areas of the control.
+ */
+
+extern routine dbx_qUpdate;
+
+/*----- Standard dbx flags ------------------------------------------------*
+ *
+ * Individual controls may have their own flags starting at bit 8.
+ */
+
+#define dbxFlag_dataR10 ((1<<0))
+#define dbxFlag_dataR12 ((1<<1))
+
+/*----- dbx event codes ---------------------------------------------------*
+ *
+ * All events have:
+ *
+ *             R0 == event code
+ *             R1 == icon handle of control
+ *             R8 == pointer to control workspace
+ *             R9 == pointer to control definition body
+ *             R10 == dialogue box handle
+ *             R12 == control handler workspace
+ */
+
+#define dbxEvent_click 0
+
+#define dbxEvent_redraw 1
+
+#define dbxEvent_key 2
+
+#define dbxEvent_drop 3
+
+#define dbxEvent_help 4
+
+#define dbxEvent_update 5
+
+#define dbxEvent_lifeCycle 6
+
+/* --- dbxEvent_drop subreason codes --- */
+
+#define dbxDrop_load 0
+#define dbxDrop_save 1
+
+/* --- dbx event masks --- */
+
+#define dbxMask_click ((1<<dbxEvent_click))
+#define dbxMask_redraw ((1<<dbxEvent_redraw))
+#define dbxMask_key ((1<<dbxEvent_key))
+#define dbxMask_drop ((1<<dbxEvent_drop))
+#define dbxMask_help ((1<<dbxEvent_help))
+#define dbxMask_update ((1<<dbxEvent_update))
+#define dbxMask_lifeCycle ((1<<dbxEvent_lifeCycle))
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/dbx/fileIcon b/StraySrc/Libraries/Sapphire/csapph/h/dbx/fileIcon
new file mode 100644 (file)
index 0000000..59a0b80
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * fileIcon.h
+ *
+ * [Generated from fileIcon, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __fileIcon_h
+#define __fileIcon_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  fileIcon_sprName
+ *  fileIcon_reAppear
+ *  fileIcon_closed
+ *
+ * Controls provided:
+ *
+ *   fileIcon
+ *
+ * Macros provided:
+ *
+ *   FILEICN
+ */
+
+/* --- fileIcon_sprName --- *
+ *
+ * On entry:   R0 == filetype
+ *             R1 == pointer to filename
+ *
+ * On exit:    R0 == pointer to sprite name to use
+ *
+ * Use:                Works out the sprite name to use for the given filetype and
+ *             name pair.
+ */
+
+extern routine fileIcon_sprName;
+
+/* --- fileIcon_reAppear --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Makes the currently vanished file icon reappear.
+ */
+
+extern routine fileIcon_reAppear;
+
+/* --- fileIcon_closed --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *
+ * On exit:    --
+ *
+ * Use:                Informs fileIcon that the specified dialogue box has closed.
+ */
+
+extern routine fileIcon_closed;
+
+/* --- fileIcon --- *
+ *
+ * Control data:       +0
+ *
+ * Workspace:  +0 == filetype of object to display
+ *             +4 == address of filename
+ *             +8
+ *
+ * Flags:      --
+ *
+ * Use:                Control which displays a filetype icon, and allows it to
+ *             be dragged.
+ */
+
+extern routine fileIcon;
+
+/*----- Macros and symbols ------------------------------------------------*/
+
+#define fIcon_event (0x80000003)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/dbx/numWrite b/StraySrc/Libraries/Sapphire/csapph/h/dbx/numWrite
new file mode 100644 (file)
index 0000000..2c43952
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * numWrite.h
+ *
+ * [Generated from numWrite, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __numWrite_h
+#define __numWrite_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  numWrite_set
+ *  numWrite_read
+ *  numWrite_bump
+ *
+ * Controls provided:
+ *
+ *   numWrite
+ *
+ * Macros provided:
+ *
+ *   NUMWRT
+ */
+
+/* --- numWrite --- *
+ *
+ * Control data:       +0 == minimum value
+ *             +4 == maximum value
+ *             +8
+ *
+ * Workspace:  +0
+ *
+ * Flags:      --
+ *
+ * Use:                Control type for numeric writable icons.
+ */
+
+extern routine numWrite;
+
+/* --- numWrite --- *
+ *
+ * Control data:       +0 == minimum value
+ *             +4 == maximum value
+ *             +8
+ *
+ * Workspace:  +0
+ *
+ * Flags:      --
+ *
+ * Use:                Control type for numeric writable icons.
+ */
+
+extern routine numWrite;
+
+/* --- numWrite_set --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon number within dialogue
+ *             R2 == value to set in the icon
+ *
+ * On exit:    R2 == value actually set
+ *
+ * Use:                Writes the specified numeric value into the given writable
+ *             icon.  The icon must be a dbx control with numWrite type
+ *             for this to work.
+ */
+
+extern routine numWrite_set;
+
+/* --- numWrite_read --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon handle
+ *
+ * On exit:    CC if icon contains a valid integer, and
+ *               R2 == value shown in the icon
+ *             else CS and
+ *               R2 == 0
+ *
+ * Use:                Reads the numeric value within the icon specifed.
+ */
+
+extern routine numWrite_read;
+
+/* --- numWrite_bump --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon handle
+ *             R2 == increment to apply to it
+ *
+ * On exit:    R2 == updated value in the icon
+ *
+ * Use:                Adjusts the value in a writable icon by a given increment.
+ */
+
+extern routine numWrite_bump;
+
+/* --- Macro: NUMWRT --- *
+ *
+ * Arguments:  icon == icon handle of control
+ *             min == minimum representable value
+ *             max == maximum representable value
+ *
+ * Use:                Inserts a definition of a numerical writable icon into
+ *             a dbx dialogue definition table.
+ */
+
+/*----- Constants ---------------------------------------------------------*/
+
+#define numWrite_event (0x80000004)
+
+#define numWrite_change (0)
+#define numWrite_move (1)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/dbx/slider b/StraySrc/Libraries/Sapphire/csapph/h/dbx/slider
new file mode 100644 (file)
index 0000000..6331f2b
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * slider.h
+ *
+ * [Generated from slider, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __slider_h
+#define __slider_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Controls provided:
+ *
+ *  slider
+ *
+ * Macros provided:
+ *
+ *   SLIDER
+ */
+
+/* --- slider --- *
+ *
+ * Control data:       +0 == slider colour (if flags bit 9 clear)
+ *             +1 == background colour
+ *             +2 == separator colour
+ *             +3 == reserved
+ *             +4 == maximum slider value
+ *             +8
+ *
+ * Workspace:  +0 == current slider value
+ *             +4 == slider colour (if flags bit 9 set)
+ *             +5 == reserved, must be 0
+ *             +8
+ *
+ * Flags:      Bit 8 == slider is horizontal if clear, vertical is set
+ *
+ * Use:                Control type for a slider.
+ */
+
+extern routine slider;
+
+/*----- Macros and symbols ------------------------------------------------*/
+
+/* --- Direction flags --- */
+
+#define slFlag_vertical ((1<<8))
+#define slFlag_horizontal (0)
+#define slFlag_colData ((1<<9))
+
+/* --- Slider event codes --- */
+
+#define slider_event (0x80000001)
+
+#define slider_sliding (0)
+#define slider_slid (1)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/dbx/stringSet b/StraySrc/Libraries/Sapphire/csapph/h/dbx/stringSet
new file mode 100644 (file)
index 0000000..c03ea60
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * stringSet.h
+ *
+ * [Generated from stringSet, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __stringSet_h
+#define __stringSet_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  stringSet_setValue
+ *
+ * Controls provided:
+ *
+ *  stringSet
+ *
+ * Macros provided:
+ *
+ *   STRSET
+ */
+
+/* --- stringSet --- *
+ *
+ * Control data:       +0 == address of menu definition
+ *             +4 == address of string table
+ *             +8 == icon number in which to write string
+ *             +12
+ *
+ * Workspace:  +0 == current value of radio selection
+ *             +4
+ *
+ * Flags:      --
+ *
+ * Use:                Provides handling for a `menu button' -- when clicked, a
+ *             menu of possible values appears, from which the user may
+ *             choose an entry.  The chosen string is copied to the icon.
+ */
+
+extern routine stringSet;
+
+/* --- stringSet_setValue --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == icon handle
+ *
+ * On exit:    --
+ *
+ * Use:                Sets the contents of the display area attached to a string
+ *             set control from the current state of the control.
+ */
+
+extern routine stringSet_setValue;
+
+/*----- Macros and symbols ------------------------------------------------*/
+
+#define stringSet_event (0x80000005)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/defHandler b/StraySrc/Libraries/Sapphire/csapph/h/defHandler
new file mode 100644 (file)
index 0000000..f440043
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * defHandler.h
+ *
+ * [Generated from defHandler, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __defHandler_h
+#define __defHandler_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  defHandler
+ */
+
+/* --- defHandler --- *
+ *
+ * On entry:   R0 == Wimp_Poll reason code
+ *             R1 == pointer to Wimp_Poll event block
+ *
+ * On exit:    CS if we handled the event, CC otherwise.
+ *
+ * Use:                Handles events no-one else is interested in.  It's basically
+ *             a catch-all for things that probably should have been
+ *             handled elsewhere, and does some useful tidying up
+ *             operations (like calling Wimp_ProcessKey on key events).
+ */
+
+extern routine defHandler;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/divide b/StraySrc/Libraries/Sapphire/csapph/h/divide
new file mode 100644 (file)
index 0000000..ac784e5
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * divide.h
+ *
+ * [Generated from divide, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __divide_h
+#define __divide_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  divide
+ *  div_unsigned
+ *  div10
+ *  div_round
+ *  div_u64x32
+ */
+
+/* --- divide --- *
+ *
+ * On entry:   R0 == dividend
+ *             R1 == divisor
+ *
+ * On exit:    R0 == quotient
+ *             R1 == remainder
+ *
+ * Use:                A standard divide routine.  Fairly speedy, hopefully.
+ *             The results are always such that
+ *
+ *                     |quotient| <= |(divisor/dividend)|,
+ *
+ *                     |remainder| < |divisor|
+ *
+ *             and
+ *
+ *                     quotient * divisor + remainder == dividend
+ */
+
+extern routine divide;
+
+/* --- div_unsigned --- *
+ *
+ * On entry:   R0 == dividend
+ *             R1 == divisor
+ *
+ * On exit:    R0 == quotient
+ *             R1 == remainder
+ *
+ * Use:                As for divide, except that it considers its operands to be
+ *             unsigned.
+ */
+
+extern routine div_unsigned;
+
+/* --- div10 --- *
+ *
+ * On entry:   R0 == integer to divide
+ *
+ * On exit:    R0 == quotient after division by 10
+ *             R1 == remainder after division by 10
+ *
+ * Use:                Divides an integer very quickly by 10.
+ *
+ * [Generated by Straylight divc]
+ */
+
+extern routine div10;
+
+/* --- div_round --- *
+ *
+ * On entry:   R0 == dividend
+ *             R1 == divisor
+ *
+ * On exit:    R0 == quotient, rounded to nearest integer
+ *             R1 == remainder
+ *
+ * Use:                Calculates a rounded-to-nearest quotient, rather than one
+ *             rounded towards zero, which is what divide returns you.
+ *
+ *             The remainder is fiddled during this process, so that the
+ *             properties
+ *
+ *                     quotient * divisor + remainder == dividend
+ *
+ *             and
+ *
+ *                     |remainder| < |divisor|
+ *
+ *             still hold (so the remainder's sign may well change).
+ */
+
+extern routine div_round;
+
+/* --- div_u64x32 --- *
+ *
+ * On entry:   R0,R1 == dividend (high word in R1)
+ *             R2 == divisor
+ *
+ * On exit:    R0 == quotient
+ *             R1 == remainder
+ *
+ * Use:                Divides a 64-bit unsigned value by a 32-bit unsigned value
+ *             yielding 32-bit unsigned quotient and remainder.  If there
+ *             are more than 32 bits of quotient, the return values are
+ *             undefined.
+ */
+
+extern routine div_u64x32;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/drag b/StraySrc/Libraries/Sapphire/csapph/h/drag
new file mode 100644 (file)
index 0000000..42aed30
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * drag.h
+ *
+ * [Generated from drag, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __drag_h
+#define __drag_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  drag_start
+ *  drag_scroll
+ *  drag_setDash
+ *  drag_cancel
+ *  drag_redraw
+ *  drag_eorColour
+ */
+
+/* --- drag_start --- *
+ *
+ * On entry:   R0 == window containing the drag
+ *             R1 == flags word (see flags below)
+ *             R2 == pointer to drag routine
+ *             R3 == magic number to pass in R9
+ *             R4 == value to pass to routine in R10
+ *             R5 == value to pass to routine in R12
+ *
+ * On exit:    --
+ *
+ * Use:                Starts a drag operation.  Any outstanding drag operation
+ *             is cancelled on the assumption that someone stole our
+ *             UserDragBox event.
+ */
+
+extern routine drag_start;
+
+/* --- drag_scroll --- *
+ *
+ * On entry:   R1 == pointer to window state block
+ *
+ * On exit:    R2,R3 == new scroll positions to set
+ *             R14 == R1+20 (pointer to scroll offsets)
+ *
+ * Use:                Works out the scroll positions which should be set to auto-
+ *             scroll the window.  The algorithm is simple: the window is
+ *             scrolled so that the point beneath the mouse pointer is
+ *             within the window's visible work area.
+ */
+
+extern routine drag_scroll;
+
+/* --- drag_setDash --- *
+ *
+ * On entry:   R0 == dash pattern byte
+ *
+ * On exit:    --
+ *
+ * Use:                Sets the dash pattern to be the given value.
+ */
+
+extern routine drag_setDash;
+
+/* --- drag_cancel --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Cancels the current drag operation.
+ */
+
+extern routine drag_cancel;
+
+/* --- drag_redraw --- *
+ *
+ * On entry:   R1 == pointer to redraw block
+ *
+ * On exit:    --
+ *
+ * Use:                Redraws the drag box, if the redraw takes place in the
+ *             currently dragging window.
+ */
+
+extern routine drag_redraw;
+
+/* --- drag_eorColour --- *
+ *
+ * On entry:   R0 == colour A
+ *             R1 == colour B
+ *
+ * On exit:    --
+ *
+ * Use:                Sets the foreground colour to be an EOR colour such that
+ *             when painted over Wimp colour A, it appears as Wimp colour B.
+ */
+
+extern routine drag_eorColour;
+
+/*----- Flags -------------------------------------------------------------*/
+
+#define drFlag_noUpdate ((1<<0))
+
+/*----- Drag handler events -----------------------------------------------*/
+
+/* --- Note --- *
+ *
+ * The events which request that you draw something are called for each
+ * rectangle of the draw operation -- i.e. do not call Wimp_GetRectangle
+ * because this is done for you.
+ */
+
+#define drEvent_draw 0
+
+#define drEvent_undraw 1
+
+#define drEvent_update 2
+
+#define drEvent_trans 3
+
+#define drEvent_getPos 4
+
+#define drEvent_done 5
+
+#define drEvent_cancel 6
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/draw b/StraySrc/Libraries/Sapphire/csapph/h/draw
new file mode 100644 (file)
index 0000000..7c02165
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * draw.h
+ *
+ * [Generated from draw, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __draw_h
+#define __draw_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  draw_render
+ *  draw_checkValid
+ */
+
+/* --- draw_render --- *
+ *
+ * On entry:   R0 == scale to plot drawfile (16.16 form)
+ *             R1 == pointer to a redraw block
+ *             R2 == pointer to drawfile in memory
+ *             R3 == size of drawfile block
+ *
+ * On exit:    --
+ *
+ * Use:                Renders a DrawFile in a window.  Objects which aren't
+ *             recognised are not rendered.  The objects which are handled
+ *             are as follows:
+ *
+ *             * Font table objects
+ *             * Text objects (in fonts, or in system font)
+ *             * Draw path objects, filled and unfilled, including
+ *               dotted outlines
+ *             * Group objects
+ *             * Tagged objects
+ *             * Sprite objects, rendered as well as we can make it
+ *             * Transformed text, only on RISC OS 3
+ *             * Transformed sprite, only on RISC OS 3
+ */
+
+extern routine draw_render;
+
+/* --- draw_checkValid --- *
+ *
+ * On entry:   R0 == pointer to start of drawfile
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Checks whether a drawfile is basically sound.  This checking
+ *             isn't compulsory, and just checks the initial word and the
+ *             format version number -- nothing very exciting.
+ */
+
+extern routine draw_checkValid;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/dynPtr b/StraySrc/Libraries/Sapphire/csapph/h/dynPtr
new file mode 100644 (file)
index 0000000..533b276
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * dynPtr.h
+ *
+ * [Generated from dynPtr, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __dynPtr_h
+#define __dynPtr_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  dynPtr_change
+ */
+
+/* --- dynPtr_change --- *
+ *
+ * On entry:   R0 == pointer to string to use
+ *             R1 == pointer to pointer name
+ *             R2 == x hot spot
+ *             R3 == y hot spot
+ *
+ * On exit:    --
+ *
+ * Use:                Attaches a string to the default pointer shape.
+ */
+
+extern routine dynPtr_change;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/errorBox b/StraySrc/Libraries/Sapphire/csapph/h/errorBox
new file mode 100644 (file)
index 0000000..7512191
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * errorBox.h
+ *
+ * [Generated from errorBox, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __errorBox_h
+#define __errorBox_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  errorBox_init
+ *  errorBox_beep
+ *  errorBox
+ */
+
+/* --- errorBox_init --- *
+ *
+ * On entry:   R0 == pointer to application name
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the errorBox system nicely.  It creates the
+ *             dialogue box now, and just uses it for the rest of the
+ *             time.
+ */
+
+extern routine errorBox_init;
+
+/* --- errorBox_beep --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Sounds the bell (VDU 7) if the CMOS settings dictate that
+ *             error boxes should cause a beep.
+ */
+
+extern routine errorBox_beep;
+
+/* --- errorBox --- *
+ *
+ * On entry:   R0 == pointer to error block
+ *             R1 == button style code, or pointer to buttons block
+ *
+ * On exit:    R0 == icon number clicked (ordered from the right)
+ *             CS if R0 == 0, else CC
+ *
+ * Use:                Displays an error box on the screen.  The error block
+ *             doesn't have to have a sensible error number, and doesn't
+ *             have to be word aligned, either.
+ *
+ *             Since errorBox claims a dialogue box handle on
+ *             initialisation, it isn't possible for this call to fail.
+ *             Hence it is ideal for reporting problems like `Out of
+ *             memory' or `Too many windows'.
+ *
+ *             The buttons in the error box may be given either by a code
+ *             or by a pointer to a buttons block (these may easily be
+ *             distinguished, since the codes are lower than &8000).
+ *
+ *             Standard button arrangements are given by codes, as follows:
+ *
+ *             0 == Cancel
+ *             1 == OK
+ *             2 == OK, Cancel
+ *             4 == OK, Help
+ *             5 == OK, Cancel, Help
+ */
+
+extern routine errorBox;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/event b/StraySrc/Libraries/Sapphire/csapph/h/event
new file mode 100644 (file)
index 0000000..19ca0a2
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * event.h
+ *
+ * [Generated from event, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __event_h
+#define __event_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  event_preFilter
+ *  event_fakeHandler
+ *  event_postFilter
+ *  event_poll
+ *  event_last
+ *  event_init
+ */
+
+/* --- event_preFilter --- *
+ *
+ * On entry:   R0 == pointer to routine to call
+ *             R1 == R12 value to call routine
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Adds a routine to the pre-filter list. Later added
+ *             routines are called first.
+ */
+
+extern routine event_preFilter;
+
+/* --- event_fakeHandler --- *
+ *
+ * On entry:   R0 == pointer to routine to call
+ *             R1 == R12 value to call routine
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Adds a routine to the fake handler list. Later added
+ *             routines are called first.
+ */
+
+extern routine event_fakeHandler;
+
+/* --- event_postFilter --- *
+ *
+ * On entry:   R0 == pointer to routine to call
+ *             R1 == R12 value to call routine
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Adds a routine to the post-poll list. Later added
+ *             routines are called first.
+ */
+
+extern routine event_postFilter;
+
+/* --- event_poll --- *
+ *
+ * On entry:   R0 == event mask and flags
+ *             R1 == pointer to block to use
+ *             R2 == earliest time to return with NULL event
+ *             R3 == optional pointer to poll word
+ *
+ * On exit:    R0 == reason code
+ *             CS if the event was claimed, CC otherwise
+ *
+ * Use:                This call perform a Wimp_Poll, and dispatches events to
+ *             interested parties.
+ */
+
+extern routine event_poll;
+
+/* --- event_last --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == last event code received from Wimp_Poll
+ *             R1 == pointer to accompanying event data
+ *
+ * Use:                Allows you to read the full event information.  The event
+ *             is the same one currently being or most recently dispatched
+ *             to the postfilter list, i.e. fake events are also returned
+ *             by this call.  If no event has yet been received, the return
+ *             values are undefined.
+ */
+
+extern routine event_last;
+
+/* --- event_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the event system.
+ */
+
+extern routine event_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/except b/StraySrc/Libraries/Sapphire/csapph/h/except
new file mode 100644 (file)
index 0000000..f6b6226
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * except.h
+ *
+ * [Generated from except, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __except_h
+#define __except_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  except_init
+ *  except_fatal
+ *  except_atExit
+ *  except_returnPt
+ */
+
+/* --- except_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the exception handler.
+ */
+
+extern routine except_init;
+
+/* --- except_fatal --- *
+ *
+ * On entry:   R0 == pointer to an error block
+ *
+ * On exit:    Doesn't
+ *
+ * Use:                Reports an error to our /caller's/ error handler.  We quit
+ *             and die at this point.  Don't use unless you have absolutely
+ *             no choice in the matter.
+ */
+
+extern routine except_fatal;
+
+/* --- except_atExit --- *
+ *
+ * On entry:   R0 == pointer to routine to call on exit
+ *             R1 == R12 value to call with
+ *
+ * On exit:    --
+ *
+ * Use:                Registers a routine to get called when the application quits.
+ *             Later-registered routines are called earlier than earlier-
+ *             registered routines, so everything closes down in a nice
+ *             manner.
+ */
+
+extern routine except_atExit;
+
+/* --- except_returnPt --- *
+ *
+ * On entry:   R0 == pointer to exception handler routine
+ *             R1 == R12 value to enter routine with
+ *             R2 == R13 value to enter routine with
+ *
+ * On exit:    --
+ *
+ * Use:                Sets up a routine to be called whenever there's an error.
+ *             The idea is that it should ask the user whether to quit,
+ *             and if not, resume to some known (safe?) state.
+ *
+ *             The routine is called with R0 == pointer to error block, and
+ *             R12 and R13 being the values set up here(*).  It should
+ *             return with R0 == pointer to a routine to resume at, and R1
+ *             being the value to pass to the resume routine in R12.  If
+ *             you decide to quit, just call OS_Exit -- this should tidy
+ *             everything up.
+ *
+ *             Note that the error is held in the scratchpad buffer, so
+ *             you can't use the first 256 bytes of that until you've
+ *             finished with the error message.
+ *
+ *             (*) Actually, R13 is 4 bytes lower because it's assumed that
+ *             it points to a full descending stack that we can use.  This
+ *             shouldn't make any difference as long as you're using R13
+ *             as a full descending stack pointer.
+ */
+
+extern routine except_returnPt;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/fastMove b/StraySrc/Libraries/Sapphire/csapph/h/fastMove
new file mode 100644 (file)
index 0000000..6ac143d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * fastMove.h
+ *
+ * [Generated from fastMove, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __fastMove_h
+#define __fastMove_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  fastMove
+ */
+
+/* --- fastMove --- *
+ *
+ * On entry:   R0 == destination pointer
+ *             R1 == source pointer
+ *             R2 == number of bytes to move
+ *
+ * On exit:    --
+ *
+ * Use:                A very fast block moving routine.  Word aligning is not
+ *             necessary, and the blocks may overlap.  This is basically
+ *             the routine from PRM 2, hacked to cope with overlapping.
+ */
+
+extern routine fastMove;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/fixedPt b/StraySrc/Libraries/Sapphire/csapph/h/fixedPt
new file mode 100644 (file)
index 0000000..e6666a4
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * fixedPt.h
+ *
+ * [Generated from fixedPt, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __fixedPt_h
+#define __fixedPt_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  fxp_atan
+ *  fxp_pol
+ *  fxp_sin
+ *  fxp_cos
+ */
+
+/* --- fxp_atan --- *
+ *
+ * On entry:   R0 == x, in 16.16 fixed point form
+ *
+ * On exit:    R0 == arctan x, in degrees, in 16.16 fixed point
+ *
+ * Use:                Calculates arctan x, hopefully fairly swiftly. The
+ *             accuracy of the result is open to doubt, although
+ *             it's usually good to about 3 significant figures.
+ *             It uses a small lookup table and linear interpolation
+ *             to calculate the result.
+ */
+
+extern routine fxp_atan;
+
+/* --- fxp_pol --- *
+ *
+ * On entry:   R0 == x coordinate
+ *             R1 == y coordinate
+ *
+ * On exit:    R0 == angle in degrees, in 16.16 form
+ *
+ * Use:                Calculates the angle a vector makes with the +ve x axis.
+ *             The angle is given in degrees, rather than radians,
+ *             although this isn't really overly significant; it just
+ *             makes it slightly easier to work with, because it's
+ *             bigger.
+ *
+ *             This routine uses the arctan table and linear
+ *             interpolation, so it's fairly quick, but the accuracy
+ *             of its results is restricted to about 3 significant figures.
+ */
+
+extern routine fxp_pol;
+
+/* --- fxp_sin --- *
+ *
+ * On entry:   R0 == angle in degrees, in 16.16 form
+ *
+ * On exit:    R0 == sin of angle, in 16.16 form
+ *
+ * Use:                Calculates a sin of an angle with a degree of swiftness and
+ *             a lot less accuracy.
+ */
+
+extern routine fxp_sin;
+
+/* --- fxp_cos --- *
+ *
+ * On entry:   R0 == angle in degrees, in 16.16 form
+ *
+ * On exit:    R0 == cos of angle, in 16.16 form
+ *
+ * Use:                Calculates a cos of an angle with a degree of swiftness and
+ *             a lot less accuracy.
+ */
+
+extern routine fxp_cos;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/flex b/StraySrc/Libraries/Sapphire/csapph/h/flex
new file mode 100644 (file)
index 0000000..792d6ce
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * flex.h
+ *
+ * [Generated from flex, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __flex_h
+#define __flex_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  flex_reduce
+ *  flex_compact
+ *  flex_free
+ *  flex_alloc
+ *  flex_size
+ *  flex_extend
+ *  flex_midExtend
+ *  flex_init
+ *  flex_stackPtr
+ *  flex_save
+ *  flex_load
+ *  flex_dump
+ *
+ * Macros provided:
+ *
+ *   FSAVE
+ *   FLOAD
+ */
+
+/* --- flex_reduce --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Compacts the flex heap by one iteration.
+ */
+
+extern routine flex_reduce;
+
+/* --- flex_compact --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Completely compacts the flex heap.
+ */
+
+extern routine flex_compact;
+
+/* --- flex_free --- *
+ *
+ * On entry:   R0 == pointer to the flex anchor
+ *
+ * On exit:    --
+ *
+ * Use:                Frees a flex block allocated by flex_alloc.
+ */
+
+extern routine flex_free;
+
+/* --- flex_alloc --- *
+ *
+ * On entry:   R0 == pointer to a flex anchor
+ *             R1 == desired size of flex block
+ *
+ * On exit:    CS if no memory could be allocated, CC otherwise
+ *
+ * Use:                Allocates a block in the shifting heap.
+ */
+
+extern routine flex_alloc;
+
+/* --- flex_size --- *
+ *
+ * On entry:   R0 == pointer to flex anchor
+ *
+ * On exit:    R0 == size of allocated block
+ *
+ * Use:                Reads the size of a flex block.
+ */
+
+extern routine flex_size;
+
+/* --- flex_extend --- *
+ *
+ * On entry:   R0 == pointer to flex anchor
+ *             R1 == new size of block to set
+ *
+ * On exit:    CS if it failed due to lack of memory, CC otherwise
+ *
+ * Use:                Alters the size of a block to the given value.
+ */
+
+extern routine flex_extend;
+
+/* --- flex_midExtend --- *
+ *
+ * On entry:   R0 == pointer to a flex anchor
+ *             R1 == `at' -- position in block to extend from
+ *             R2 == `by' -- how many bytes to extend (may be -ve)
+ *
+ * On exit:    CS if it failed due to lack of memory, CC otherwise
+ *
+ * Use:                Either creates a gap in a block (by>0) or deletes bytes
+ *             from a block.  This is always done in such a way that the
+ *             byte originally at offset `at' is now at offset `at'+`by'.
+ */
+
+extern routine flex_midExtend;
+
+/* --- flex_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the flex heap for use.
+ */
+
+extern routine flex_init;
+
+/* --- flex_stackPtr --- *
+ *
+ * On entry:   R0 == 0 to read, or value to set
+ *
+ * On exit:    R0 == old value
+ *
+ * Use:                Either reads or writes the flex stack pointer.  This sort
+ *             of thing is useful in exception handlers etc.
+ */
+
+extern routine flex_stackPtr;
+
+/* --- flex_save --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Saves some registers on the flex relocation stack.  R13
+ *             and R14 cannot be saved -- these registers are corrupted
+ *             during this routine's execution.
+ *
+ *             Values saved on the flex relocation stack are adjusted as
+ *             flex moves blocks of memory around, so that they still point
+ *             to the same thing as they did before.  Obviously, values
+ *             which aren't pointers into flex blocks may be corrupted.
+ *             Values pointing to objects deleted (either free blocks, or
+ *             areas removed by flex_midExtend) may also be corrupted.
+ *
+ *             Since this routine takes no arguments, some other method has
+ *             to be used.  The method chosen is to follow the call to
+ *             flex_save with a LDM or STM instruction containing the
+ *             registers to be saved.  This instruction is skipped by the
+ *             routine, and thus not executed.
+ *
+ *             Note that if you give the LDM or STM the same condition code
+ *             as the BL preceding it, it will never be executed, since
+ *             flex_save skips it if the condition is true and it can't be
+ *             executed if the condition is false.
+ */
+
+extern routine flex_save;
+
+/* --- flex_load --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    Registers loaded from relocation stack as requested
+ *
+ * Use:                Restores registers saved on flex's relocation stack.  See
+ *             flex_save for calling information and details about the
+ *             relocation stack.
+ */
+
+extern routine flex_load;
+
+/*----- Useful macros -----------------------------------------------------*/
+
+/* --- Macro: FSAVE --- *
+ *
+ * Arguments:  rList == quoted register list to save on relocation stack
+ *
+ * Use:                Assembles code to write the given register list on the
+ *             flex relocation stack.  The register list should be in the
+ *             same form as that for an STM or LDM instruction.
+ *
+ *             For full details about the flex relocation stack, see
+ *             flex_save.
+ */
+
+/* --- Macro: FLOAD --- *
+ *
+ * Arguments:  rList == quoted register list to read from relocation stack
+ *
+ * Use:                Assembles code to read the given register list from the
+ *             flex relocation stack.  The register list should be in the
+ *             same form as that for an STM or LDM instruction.
+ *
+ *             For full details about the flex relocation stack, see
+ *             flex_save.
+ */
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/fontmenu b/StraySrc/Libraries/Sapphire/csapph/h/fontmenu
new file mode 100644 (file)
index 0000000..fda15ef
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * fontmenu.h
+ *
+ * [Generated from fontmenu, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __fontmenu_h
+#define __fontmenu_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  fm_create
+ *  fm_tickFont
+ *  fm_init
+ */
+
+/* --- fm_create --- *
+ *
+ * On entry:   R0 == current font name
+ *             R1 == handler to call when selection made
+ *             R2 == R10 value to call with
+ *             R3 == R12 value to call with
+ *             R4 == pointer to routine to call to create submenu
+ *                   (ie. menu_create or tms_create)
+ *
+ * On exit:    CS if any fonts exist and
+ *                 R0 == pointer to a menu definition
+ *               R1 == event handler to call
+ *               R2 == R10 value for event handler
+ *               R3 == R12 value for event handler
+ *             else CC and
+ *               R0-R3 corrupted
+ *             May return an error
+ *
+ * Use:                Creates a user menu definition suitable for passing directly
+ *             to (menu|tms)_create. Note however, that the menu defintion
+ *             does *not* include any title; this must be created first.
+ *             If you require items such as the system font, then
+ *             add these to the menu before creating the menu returned
+ *             from this call.
+ */
+
+extern routine fm_create;
+
+/* --- fm_tickFont --- *
+ *
+ * On entry:   R0 == name to tick
+ *
+ * On exit:    --
+ *
+ * Use:                Ticks the font with tht given name in the fontmenu. If
+ *             no font exists then the existing ticks are removed
+ */
+
+extern routine fm_tickFont;
+
+/* --- fm_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the font menu system.
+ */
+
+extern routine fm_init;
+
+/*----- Events ------------------------------------------------------------*/
+
+#define fmEvent_select 0
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/gallery b/StraySrc/Libraries/Sapphire/csapph/h/gallery
new file mode 100644 (file)
index 0000000..0cd55f4
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * gallery.h
+ *
+ * [Generated from gallery, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __gallery_h
+#define __gallery_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  gallery_eventHandler
+ *  gallery_drawBox
+ *  gallery_removeBox
+ *  gallery_reset
+ */
+
+/* --- gallery_eventHandler --- *
+ *
+ * On entry:   R0 == viewer handle
+ *             R1 == pointer to handler routine
+ *             R2 == R10 value to pass to handler
+ *             R3 == R12 value to pass to handler
+ *
+ * On exit:    --
+ *
+ * Use:                Sets up an event handler for the viewer, and adds in
+ *             gallery's own special processing for background drawing.
+ */
+
+extern routine gallery_eventHandler;
+
+/* --- gallery_drawBox --- *
+ *
+ * On entry:   R0-R3 == window relative coords of box to plot
+ *
+ * On exit:    --
+ *
+ * Use:                Draws a box to indicate tht this item hasn't been
+ *             displayed yet.  Use this routine to give a consistant
+ *             look to applications which use the gallery.
+ */
+
+extern routine gallery_drawBox;
+
+/* --- gallery_removeBox --- *
+ *
+ * On entry:   R0-R3 == window relative coords of box to remove
+ *
+ * On exit:    --
+ *
+ * Use:                Removes a previously draw temporary box.  It is assumed that
+ *             the background colour of the viewere is 1.
+ */
+
+extern routine gallery_removeBox;
+
+/* --- gallery_reset --- *
+ *
+ * On entry:   R0 == viewer handle
+ *
+ * On exit:    --
+ *
+ * Use:                Resets all the icons in the gallery to their `undrawn' state.
+ *             Use this before opening the window etc.
+ */
+
+extern routine gallery_reset;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/heap b/StraySrc/Libraries/Sapphire/csapph/h/heap
new file mode 100644 (file)
index 0000000..ff1b6f7
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * heap.h
+ *
+ * [Generated from heap, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __heap_h
+#define __heap_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  heap_init
+ *  heap_useHeap
+ *  heap_info
+ *  heap_alloc
+ *  heap_free
+ *  heap_reAlloc
+ */
+
+/* --- heap_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the heap system for use.
+ */
+
+extern routine heap_init;
+
+/* --- heap_useHeap --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Registers the resizing heap as the current allocator.
+ */
+
+extern routine heap_useHeap;
+
+/* --- heap_info --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == current heap size
+ *             R1 == amount of memory free in the heap
+ *             R2 == size of the largest block free
+ *
+ * Use:                Describes the heap's current status.
+ */
+
+extern routine heap_info;
+
+/* --- heap_alloc --- *
+ *
+ * On entry:   R0 == size of block wanted
+ *
+ * On exit:    CC if enough memory was found and
+ *               R0 == pointer to the block allocated
+ *             else CS and
+ *               R0 corrupted
+ *
+ * Use:                Allocates a block of at least a given size from a heap.  If
+ *             the heap is not big enough, more is claimed from the
+ *             operating system.
+ */
+
+extern routine heap_alloc;
+
+/* --- heap_free --- *
+ *
+ * On entry:   R0 == pointer to a block created with heap_alloc
+ *
+ * On exit:    --
+ *
+ * Use:                Frees a block allocated using heap_alloc.  It tries to
+ *             shrink the heap as much as possible afterwards.
+ */
+
+extern routine heap_free;
+
+/* --- heap_reAlloc --- *
+ *
+ * On entry:   R0 == pointer to block whose size we want to change
+ *             R1 == the new size of the block
+ *
+ * On exit:    CC if block was resized, and
+ *               R0 == pointer to the block (which may have moved)
+ *             else CS and
+ *               R0 corrupted
+ *
+ * Use:                Changes the size of a heap block.  If possible, the block's
+ *             position is unchanged, but this may not always be the case.
+ *
+ *             Note that changing a block's size to 0 is permitted.
+ */
+
+extern routine heap_reAlloc;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/help b/StraySrc/Libraries/Sapphire/csapph/h/help
new file mode 100644 (file)
index 0000000..680a479
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * help.h
+ *
+ * [Generated from help, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __help_h
+#define __help_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  help_init
+ *  help_sendHints
+ *  help_add
+ *  help_reset
+ */
+
+/* --- help_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the help system for use.
+ */
+
+extern routine help_init;
+
+/* --- help_sendHints --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Should be called on a pointer-entering-window event.  It
+ *             enables hint requests for the window beneath the pointer.
+ */
+
+extern routine help_sendHints;
+
+/* --- help_add --- *
+ *
+ * On entry:   R0 == pointer to message string to add
+ *
+ * On exit:    --
+ *
+ * Use:                Adds a line to the help message being built currently.  Note
+ *             that overflows are trapped, and errors are generated if one
+ *             would occur.
+ */
+
+extern routine help_add;
+
+/* --- help_reset --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Resets the help system so that a hint request is sent to an
+ *             icon that the pointer is already over. The proposed use
+ *             is that the caller can change a help message for a given
+ *             icon as soon as it is clicked on.
+ */
+
+extern routine help_reset;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/hour b/StraySrc/Libraries/Sapphire/csapph/h/hour
new file mode 100644 (file)
index 0000000..81883e0
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * hour.h
+ *
+ * [Generated from hour, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __hour_h
+#define __hour_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  hour_init
+ *  hour_on
+ *  hour_off
+ *  hour_percent
+ *  hour_leds
+ *  hour_suspend
+ *  hour_save
+ *  hour_resume
+ *  hour_restore
+ */
+
+/* --- hour_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the hour system, so it will display an hourglass
+ *             when necessary.
+ *
+ *             Since this gets called at a random point during the Sapphire
+ *             initialisation, and we can rely on Hourglass keeping its
+ *             own count, the suggested way of handling everything properly
+ *             is as follows:
+ *
+ *                             SWI     Hourglass_On
+ *                             BL      sapphire_init
+ *                             SWI     Hourglass_Off
+ */
+
+extern routine hour_init;
+
+/* --- hour_on --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Turns the Hourglass on only if it isn't on already.
+ *             Otherwise its status is left as it was.
+ */
+
+extern routine hour_on;
+
+/* --- hour_off --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Turns the Hourglass off if it's only been turned on once.
+ *             If the Hourglass gets turned off, all the information about
+ *             it (percentage and LEDs) get forgotten.
+ */
+
+extern routine hour_off;
+
+/* --- hour_percent --- *
+ *
+ * On entry:   R0 == percentage value to display, or -1 to remove
+ *
+ * On exit:    --
+ *
+ * Use:                Attaches a percentage display to the Hourglass.
+ */
+
+extern routine hour_percent;
+
+/* --- hour_leds --- *
+ *
+ * On entry:   R0 == LED mask EOR value
+ *             R1 == LED mask AND value
+ *
+ * On exit:    --
+ *
+ * Use:                Changes the Hourglass LED status.
+ */
+
+extern routine hour_leds;
+
+/* --- hour_suspend --- *
+ *
+ * On entry:   R0 == pointer to 2 word block to save status in
+ *
+ * On exit:    --
+ *
+ * Use:                Saves the Hourglass state in a block you've pointed at,
+ *             and disables the Hourglass.  Useful if you want to do some
+ *             user interaction without polling (e.g. an error box).
+ */
+
+extern routine hour_suspend;
+
+/* --- hour_save --- *
+ *
+ * On entry:   R0 == pointer to 2 word block to save status in
+ *
+ * On exit:    --
+ *
+ * Use:                Saves the current Hourglass status without altering it.
+ */
+
+extern routine hour_save;
+
+/* --- hour_resume, hour_restore --- *
+ *
+ * On entry:   R0 == pointer to 2 words filled by hour_suspend or hour_save
+ *
+ * On exit:    --
+ *
+ * Use:                Restores the Hourglass state to that saved away by one
+ *             of the previous two calls.  This routine has two names.
+ */
+
+extern routine hour_resume;
+
+/* --- hour_resume, hour_restore --- *
+ *
+ * On entry:   R0 == pointer to 2 words filled by hour_suspend or hour_save
+ *
+ * On exit:    --
+ *
+ * Use:                Restores the Hourglass state to that saved away by one
+ *             of the previous two calls.  This routine has two names.
+ */
+
+extern routine hour_resume;
+extern routine hour_restore;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/ibicon b/StraySrc/Libraries/Sapphire/csapph/h/ibicon
new file mode 100644 (file)
index 0000000..44286d0
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * ibicon.h
+ *
+ * [Generated from ibicon, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __ibicon_h
+#define __ibicon_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  ibicon_create
+ *  ibicon_changeSprite
+ *  ibicon_changeText
+ *  ibicon_remove
+ *  ibicon_init
+ */
+
+/* --- ibicon_create --- *
+ *
+ * On entry:   R0 == pointer to sprite name
+ *             R1 == pointer to text buffer (must be writable if you
+ *                   intend to change the text)
+ *             R2 == icon bar position indicator (`window handle')
+ *             R3 == icon bar priority/icon handle
+ *             R4 == pointer to event handler
+ *             R5 == value to pass in R10
+ *             R6 == value to pass in R12
+ *
+ * On exit:    R0 == ibicon icon handle
+ *             May return an error
+ *
+ * Use:                Places an icon on the icon bar. Your handler is called when
+ *             an event occurs on the icon. On entry to the handler, R10
+ *             and R12 are set up as for above, R0 is the event type, and
+ *             R1 is the ibicon pointer.
+ */
+
+extern routine ibicon_create;
+
+/* --- ibicon_changeSprite --- *
+ *
+ * On entry:   R0 == ibicon pointer
+ *             R1 == pointer to sprite name
+ *
+ * On exit:    --
+ *
+ * Use:                Changes the sprite of the ibicon passed to it.
+ */
+
+extern routine ibicon_changeSprite;
+
+/* --- ibicon_changeText --- *
+ *
+ * On entry:   R0 == ibicon pointer
+ *             R1 == pointer to new text
+ *
+ * On exit:    --
+ *
+ * Use:                Changes the sprite of the ibicon passed to it.
+ */
+
+extern routine ibicon_changeText;
+
+/* --- ibicon_remove --- *
+ *
+ * On entry:   R0 == ibicon icon handle
+ *
+ * On exit:    --
+ *
+ * Use:                Removes the given icon from the icon bar.
+ */
+
+extern routine ibicon_remove;
+
+/* --- ibicon_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the ibicon unit.
+ */
+
+extern routine ibicon_init;
+
+/*----- Event types -------------------------------------------------------*/
+
+#define ibEvent_select 0
+#define ibEvent_menu 1
+#define ibEvent_adjust 2
+#define ibEvent_save 3
+#define ibEvent_load 4
+#define ibEvent_help 5
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/idle b/StraySrc/Libraries/Sapphire/csapph/h/idle
new file mode 100644 (file)
index 0000000..901d5bb
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * idle.h
+ *
+ * [Generated from idle, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __idle_h
+#define __idle_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  idle_handler
+ *  idle_removeHandler
+ *  idle_setAlarm
+ *  idle_removeAlarm
+ *  idle_removeAllAlarms
+ *  idle_init
+ */
+
+/* --- idle_handler --- *
+ *
+ * On entry:   R0 == how frequently to call
+ *             R1 == pointer to routine to call
+ *             R2 == R10 value to call routine with
+ *             R3 == R12 value to call routine with
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Adds a routine to the idle handler list. Later added
+ *             routines are called first. The idle handing routine
+ *             may corrupt R10 and R12.
+ */
+
+extern routine idle_handler;
+
+/* --- idle_removeHandler --- *
+ *
+ * On entry:   R0 == How frequently it was called
+ *             R1 == pointer to routine called
+ *             R2 == R10 value routine is called with
+ *             R3 == R12 value routine is called with
+ *
+ * On exit:    --
+ *
+ * Use:                Removes a routine from the idle handler list.
+ */
+
+extern routine idle_removeHandler;
+
+/* --- idle_setAlarm --- *
+ *
+ * On entry:   R3 == Time to call
+ *             R1 == pointer to routine to call
+ *             R2 == R10 value to call routine with
+ *             R3 == R12 value to call routine with
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Adds a alarm to be called. The idle handing routine
+ *             may corrupt R10 and R12.
+ */
+
+extern routine idle_setAlarm;
+
+/* --- idle_removeAlarm --- *
+ *
+ * On entry:   R0 == When it was to be called
+ *             R1 == pointer to routine called
+ *             R2 == R10 value routine is called with
+ *             R3 == R12 value routine is called with
+ *
+ * On exit:    --
+ *
+ * Use:                Removes a routine from the idle handler list. It has
+ *             no effect if it doesn't exist.
+ */
+
+extern routine idle_removeAlarm;
+
+/* --- idle_removeAllAlarms --- *
+ *
+ * On entry:   R0 == R10 value to look for
+ *
+ * On exit:    --
+ *
+ * Use:                Removes all alarms with the handle that was passed to them
+ *             to be put into R10.  You should not remove an alarm within
+ *             an alarm handler.
+ */
+
+extern routine idle_removeAllAlarms;
+
+/* --- idle_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the idle system.
+ */
+
+extern routine idle_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/intKeys b/StraySrc/Libraries/Sapphire/csapph/h/intKeys
new file mode 100644 (file)
index 0000000..a9522c2
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * intKeys.h
+ *
+ * [Generated from intKeys, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __intKeys_h
+#define __intKeys_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+#define intk_Esc (112)
+#define intk_F1 (113)
+#define intk_F2 (114)
+#define intk_F3 (115)
+#define intk_F4 (20)
+#define intk_F5 (116)
+#define intk_F6 (117)
+#define intk_F7 (22)
+#define intk_F8 (118)
+#define intk_F9 (119)
+#define intk_F10 (30)
+#define intk_F11 (28)
+#define intk_F12 (29)
+
+#define intk_0 (39)
+#define intk_1 (48)
+#define intk_2 (49)
+#define intk_3 (17)
+#define intk_4 (18)
+#define intk_5 (19)
+#define intk_6 (24)
+#define intk_7 (36)
+#define intk_8 (21)
+#define intk_9 (38)
+
+#define intk_BackQ (45)
+#define intk_Minus (40)
+#define intk_Equals (93)
+#define intk_Pound (46)
+#define intk_Backspace (47)
+
+#define intk_LSquare (56)
+#define intk_RSquare (88)
+#define intk_Backslash (120)
+#define intk_Semicolon (87)
+#define intk_Quote (79)
+#define intk_LAngle (102)
+#define intk_RAngle (103)
+#define intk_Slash (104)
+
+#define intk_Tab (96)
+
+#define intk_Ctrl (1)
+#define intk_LCtrl (4)
+#define intk_RCtrl (7)
+
+#define intk_Shift (0)
+#define intk_LShift (3)
+#define intk_RShift (6)
+#define intk_CapsLock (64)
+
+#define intk_Alt (2)
+#define intk_LAlt (5)
+#define intk_RAlt (8)
+
+#define intk_A (65)
+#define intk_B (100)
+#define intk_C (82)
+#define intk_D (50)
+#define intk_E (34)
+#define intk_F (67)
+#define intk_G (83)
+#define intk_H (84)
+#define intk_I (37)
+#define intk_J (69)
+#define intk_K (70)
+#define intk_L (86)
+#define intk_M (101)
+#define intk_N (85)
+#define intk_O (54)
+#define intk_P (55)
+#define intk_Q (16)
+#define intk_R (51)
+#define intk_S (81)
+#define intk_T (35)
+#define intk_U (53)
+#define intk_V (99)
+#define intk_W (33)
+#define intk_X (66)
+#define intk_Y (68)
+#define intk_Z (97)
+
+#define intk_Print (32)
+#define intk_ScrollLock (62)
+#define intk_Break (44)
+
+#define intk_Insert (61)
+#define intk_Home (62)
+#define intk_PageUp (63)
+#define intk_Delete (89)
+#define intk_Copy (105)
+#define intk_PageDown (78)
+
+#define intk_Up (57)
+#define intk_Left (25)
+#define intk_Down (41)
+#define intk_Right (121)
+
+#define intk_NumLock (77)
+#define intk_kSlash (74)
+#define intk_kStar (91)
+#define intk_kHash (90)
+#define intk_kMinus (59)
+#define intk_kPlus (58)
+#define intk_kEnter (60)
+#define intk_kDot (76)
+
+#define intk_k0 (106)
+#define intk_k1 (107)
+#define intk_k2 (124)
+#define intk_k3 (108)
+#define intk_k4 (122)
+#define intk_k5 (123)
+#define intk_k6 (26)
+#define intk_k7 (27)
+#define intk_k8 (42)
+#define intk_k9 (43)
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/keyMap b/StraySrc/Libraries/Sapphire/csapph/h/keyMap
new file mode 100644 (file)
index 0000000..0ae8908
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * keyMap.h
+ *
+ * [Generated from keyMap, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __keyMap_h
+#define __keyMap_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+#define key_cA (0x001)
+#define key_cB (0x002)
+#define key_cC (0x003)
+#define key_cD (0x004)
+#define key_cE (0x005)
+#define key_cF (0x006)
+#define key_cG (0x007)
+#define key_cH (0x008)
+#define key_cI (0x009)
+#define key_cJ (0x00A)
+#define key_cK (0x00B)
+#define key_cL (0x00C)
+#define key_cM (0x00D)
+#define key_cN (0x00E)
+#define key_cO (0x00F)
+#define key_cP (0x010)
+#define key_cQ (0x011)
+#define key_cR (0x012)
+#define key_cS (0x013)
+#define key_cT (0x014)
+#define key_cU (0x015)
+#define key_cV (0x016)
+#define key_cW (0x017)
+#define key_cX (0x018)
+#define key_cY (0x019)
+#define key_cZ (0x01A)
+
+#define key_scA (0x101)
+#define key_scB (0x102)
+#define key_scC (0x103)
+#define key_scD (0x104)
+#define key_scE (0x105)
+#define key_scF (0x106)
+#define key_scG (0x107)
+#define key_scH (0x108)
+#define key_scI (0x109)
+#define key_scJ (0x10A)
+#define key_scK (0x10B)
+#define key_scL (0x10C)
+#define key_scM (0x10D)
+#define key_scN (0x10E)
+#define key_scO (0x10F)
+#define key_scP (0x110)
+#define key_scQ (0x111)
+#define key_scR (0x112)
+#define key_scS (0x113)
+#define key_scT (0x114)
+#define key_scU (0x115)
+#define key_scV (0x116)
+#define key_scW (0x117)
+#define key_scX (0x118)
+#define key_scY (0x119)
+#define key_scZ (0x11A)
+
+#define key_Esc (0x01B)
+#define key_sEsc (0x11B)
+#define key_cEsc (0x13B)
+#define key_scEsc (0x15B)
+
+#define key_Backspace (0x01C)
+#define key_sBackspace (0x11C)
+#define key_cBackspace (0x13C)
+#define key_scBackspace (0x15C)
+
+#define key_Return (0x01D)
+#define key_sReturn (0x11D)
+#define key_cReturn (0x13D)
+#define key_scReturn (0x15D)
+
+#define key_Insert (0x1CD)
+#define key_sInsert (0x1DD)
+#define key_cInsert (0x1ED)
+#define key_scInsert (0x1FD)
+
+#define key_Home (0x01E)
+#define key_sHome (0x11E)
+#define key_cHome (0x13E)
+#define key_scHome (0x15E)
+
+#define key_Delete (0x07F)
+#define key_sDelete (0x17F)
+#define key_cDelete (0x01F)
+#define key_scDelete (0x11F)
+
+#define key_Copy (0x18B)
+#define key_sCopy (0x19B)
+#define key_cCopy (0x1AB)
+#define key_scCopy (0x1BB)
+
+#define key_Tab (0x18A)
+#define key_sTab (0x19A)
+#define key_cTab (0x1AA)
+#define key_scTab (0x1BA)
+
+#define key_Space (0x020)
+#define key_sSpace (0x120)
+#define key_cSpace (0x000)
+#define key_scSpace (0x100)
+
+#define key_c0 (0x130)
+#define key_c1 (0x131)
+#define key_c2 (0x132)
+#define key_c3 (0x133)
+#define key_c4 (0x134)
+#define key_c5 (0x135)
+#define key_c6 (0x136)
+#define key_c7 (0x137)
+#define key_c8 (0x138)
+#define key_c9 (0x139)
+
+#define key_sc0 (0x150)
+#define key_sc1 (0x151)
+#define key_sc2 (0x152)
+#define key_sc3 (0x153)
+#define key_sc4 (0x154)
+#define key_sc5 (0x155)
+#define key_sc6 (0x156)
+#define key_sc7 (0x157)
+#define key_sc8 (0x158)
+#define key_sc9 (0x159)
+
+#define key_k0 (0x1C0)
+#define key_k1 (0x1C1)
+#define key_k2 (0x1C2)
+#define key_k3 (0x1C3)
+#define key_k4 (0x1C4)
+#define key_k5 (0x1C5)
+#define key_k6 (0x1C6)
+#define key_k7 (0x1C7)
+#define key_k8 (0x1C8)
+#define key_k9 (0x1C9)
+
+#define key_sk0 (0x1D0)
+#define key_sk1 (0x1D1)
+#define key_sk2 (0x1D2)
+#define key_sk3 (0x1D3)
+#define key_sk4 (0x1D4)
+#define key_sk5 (0x1D5)
+#define key_sk6 (0x1D6)
+#define key_sk7 (0x1D7)
+#define key_sk8 (0x1D8)
+#define key_sk9 (0x1D9)
+
+#define key_ck0 (0x1E0)
+#define key_ck1 (0x1E1)
+#define key_ck2 (0x1E2)
+#define key_ck3 (0x1E3)
+#define key_ck4 (0x1E4)
+#define key_ck5 (0x1E5)
+#define key_ck6 (0x1E6)
+#define key_ck7 (0x1E7)
+#define key_ck8 (0x1E8)
+#define key_ck9 (0x1E9)
+
+#define key_sck0 (0x1F0)
+#define key_sck1 (0x1F1)
+#define key_sck2 (0x1F2)
+#define key_sck3 (0x1F3)
+#define key_sck4 (0x1F4)
+#define key_sck5 (0x1F5)
+#define key_sck6 (0x1F6)
+#define key_sck7 (0x1F7)
+#define key_sck8 (0x1F8)
+#define key_sck9 (0x1F9)
+
+#define key_cLSquare (0x12B)
+#define key_scLSquare (0x14B)
+
+#define key_cRSquare (0x12D)
+#define key_scRSquare (0x14D)
+
+#define key_cBackslash (0x12C)
+#define key_scBackslash (0x14C)
+
+#define key_cMinus (0x12F)
+#define key_scMinus (0x14F)
+
+#define key_kSlash (0x161)
+#define key_kStar (0x162)
+#define key_kHash (0x163)
+#define key_kMinus (0x164)
+#define key_kPlus (0x165)
+#define key_kEnter (0x166)
+#define key_kDot (0x167)
+
+#define key_skSlash (0x171)
+#define key_skStar (0x172)
+#define key_skHash (0x173)
+#define key_skMinus (0x174)
+#define key_skPlus (0x175)
+#define key_skEnter (0x176)
+#define key_skDot (0x177)
+
+#define key_ckSlash (0x121)
+#define key_ckStar (0x122)
+#define key_ckHash (0x123)
+#define key_ckMinus (0x124)
+#define key_ckPlus (0x125)
+#define key_ckEnter (0x126)
+#define key_ckDot (0x127)
+
+#define key_sckSlash (0x141)
+#define key_sckStar (0x142)
+#define key_sckHash (0x143)
+#define key_sckMinus (0x144)
+#define key_sckPlus (0x145)
+#define key_sckEnter (0x146)
+#define key_sckDot (0x147)
+
+#define key_Print (0x180)
+#define key_F1 (0x181)
+#define key_F2 (0x182)
+#define key_F3 (0x183)
+#define key_F4 (0x184)
+#define key_F5 (0x185)
+#define key_F6 (0x186)
+#define key_F7 (0x187)
+#define key_F8 (0x188)
+#define key_F9 (0x189)
+#define key_F10 (0x1CA)
+#define key_F11 (0x1CB)
+#define key_F12 (0x1CC)
+
+#define key_sPrint (0x190)
+#define key_sF1 (0x191)
+#define key_sF2 (0x192)
+#define key_sF3 (0x193)
+#define key_sF4 (0x194)
+#define key_sF5 (0x195)
+#define key_sF6 (0x196)
+#define key_sF7 (0x197)
+#define key_sF8 (0x198)
+#define key_sF9 (0x199)
+#define key_sF10 (0x1DA)
+#define key_sF11 (0x1DB)
+#define key_sF12 (0x1DC)
+
+#define key_cPrint (0x1A0)
+#define key_cF1 (0x1A1)
+#define key_cF2 (0x1A2)
+#define key_cF3 (0x1A3)
+#define key_cF4 (0x1A4)
+#define key_cF5 (0x1A5)
+#define key_cF6 (0x1A6)
+#define key_cF7 (0x1A7)
+#define key_cF8 (0x1A8)
+#define key_cF9 (0x1A9)
+#define key_cF10 (0x1EA)
+#define key_cF11 (0x1EB)
+#define key_cF12 (0x1EC)
+
+#define key_scPrint (0x1B0)
+#define key_scF1 (0x1B1)
+#define key_scF2 (0x1B2)
+#define key_scF3 (0x1B3)
+#define key_scF4 (0x1B4)
+#define key_scF5 (0x1B5)
+#define key_scF6 (0x1B6)
+#define key_scF7 (0x1B7)
+#define key_scF8 (0x1B8)
+#define key_scF9 (0x1B9)
+#define key_scF10 (0x1FA)
+#define key_scF11 (0x1FB)
+#define key_scF12 (0x1FC)
+
+#define key_Left (0x18C)
+#define key_Right (0x18D)
+#define key_Down (0x18E)
+#define key_Up (0x18F)
+#define key_PageDown (0x1CE)
+#define key_PageUp (0x1CF)
+
+#define key_sLeft (0x19C)
+#define key_sRight (0x19D)
+#define key_sDown (0x19E)
+#define key_sUp (0x19F)
+#define key_sPageDown (0x1DE)
+#define key_sPageUp (0x1DF)
+
+#define key_cLeft (0x1AC)
+#define key_cRight (0x1AD)
+#define key_cDown (0x1AE)
+#define key_cUp (0x1AF)
+#define key_cPageDown (0x1EE)
+#define key_cPageUp (0x1EF)
+
+#define key_scLeft (0x1BC)
+#define key_scRight (0x1BD)
+#define key_scDown (0x1BE)
+#define key_scUp (0x1BF)
+#define key_scPageDown (0x1FE)
+#define key_scPageUp (0x1FF)
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/keyString b/StraySrc/Libraries/Sapphire/csapph/h/keyString
new file mode 100644 (file)
index 0000000..8fb6618
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * keyString.h
+ *
+ * [Generated from keyString, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __keyString_h
+#define __keyString_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  keyString
+ */
+
+/* --- keyString --- *
+ *
+ * On entry:   R0 == key number, from Straylight extended keymap
+ *             R1 == 0 => return full shortcuts (for e.g. writable icons)
+ *                   1 => return abbreviated shortcuts (for e.g. menus)
+ *
+ * On exit:    CS if key number was recognised, and
+ *               R0 == pointer to short cut string
+ *             else CC and
+ *               R0 corrupted
+ *
+ * Use:                Translates a key number into a string suitable for
+ *             displaying to a user, and returns a pointer to the
+ *             translated string.
+ */
+
+extern routine keyString;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/libOpts b/StraySrc/Libraries/Sapphire/csapph/h/libOpts
new file mode 100644 (file)
index 0000000..d6b071f
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * libOpts.h
+ *
+ * [Generated from libOpts, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __libOpts_h
+#define __libOpts_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  libOpts_register
+ *  libOpts_find
+ *
+ * Macros provided:
+ *
+ *  LIBOPT
+ *  LOEND
+ */
+
+/* --- libOpts_register --- *
+ *
+ * On entry:   R0 == address of an options block
+ *
+ * On exit:    --
+ *
+ * Use:                Adds the block given to the library options.
+ */
+
+extern routine libOpts_register;
+
+/* --- libOpts_find --- *
+ *
+ * On entry:   R0 == magic marker word
+ *
+ * On exit:    CS if found, and
+ *               R0 == address of options block
+ *             else CC, and
+ *               R0 corrupted
+ *
+ * Use:                Tries to find an option with the given marker, which will
+ *             normally be a four-character text string.  The first match
+ *             found will be returned.  The options blocks are searched in
+ *             reverse order of registration (i.e. blocks registered later
+ *             will override blocks registered reviously).
+ */
+
+extern routine libOpts_find;
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- Macro: LIBOPT --- *
+ *
+ * Arguments:  name == name of this options subblock (4 characters)
+ *
+ * Use:                Sets up an options subblock with the given name.
+ */
+
+/* --- Macro: LOEND --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Terminates a library options block.
+ */
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/listbox b/StraySrc/Libraries/Sapphire/csapph/h/listbox
new file mode 100644 (file)
index 0000000..e170fb7
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ * listbox.h
+ *
+ * [Generated from listbox, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __listbox_h
+#define __listbox_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  lb_create
+ *  lb_destroy
+ *  lb_eventHandler
+ *  lb_plotString
+ *  lb_update
+ *  lb_updateItem
+ *  lb_select
+ *  lb_isSelected
+ *  lb_clearSelection
+ *  lb_clickS
+ *  lb_clickM
+ *  lb_drag
+ *  lb_inserted
+ *  lb_removed
+ *  lb_init
+ */
+
+/* --- lb_create --- *
+ *
+ * On entry:   R0 == pointer to list manager description block
+ *             R1 == pointer to the list
+ *             R2 == pointer to a width function
+ *             R3 == The height of each item
+ *             R4 == parent window handle or
+ *                   pointer to window block if R5 == -1
+ *             R5 == parent icon handle or -1 if not a pane
+ *
+ * On exit:    R0 == listbox handle
+ *             R1 == window handle of list box
+ *             May return an error (R1 corrupted)
+ */
+
+extern routine lb_create;
+
+/* --- lb_destroy --- *
+ *
+ * On entry:   R0 == listbox handle
+ *
+ * On exit:    --
+ *
+ * Use:                Destroys the given listbox.
+ */
+
+extern routine lb_destroy;
+
+/* --- lb_eventHandler --- *
+ *
+ * On entry:   R0 == listbox handle
+ *             R1 == handler function
+ *             R2 == R10 value to pass
+ *             R3 == R12 value to pass
+ *
+ * On exit:    --
+ *
+ * Use:                Registers an event handler for the given listbox.
+ */
+
+extern routine lb_eventHandler;
+
+/* --- lb_plotString --- *
+ *
+ * On entry:   R0 == pointer to a string
+ *             R1 == pointer to the list item
+ *             R2-R5 == window coordinates to plot it
+ *             R10 == pointer to the listbox
+ *
+ * On exit:    --
+ *
+ * Use:                Plots a list item consisting of a single string.  It assumes
+ *             the default selection model.
+ */
+
+extern routine lb_plotString;
+
+/* --- lb_update --- *
+ *
+ * On entry:   R0 == listbox handle
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Updates the entire listbox prettily
+ */
+
+extern routine lb_update;
+
+/* --- lb_updateItem --- *
+ *
+ * On entry:   R0 == list box handle
+ *             R1 == list item handle
+ *
+ * On exit:    --
+ *
+ * Use:                Redraws a list item to reflect a change in its state.
+ */
+
+extern routine lb_updateItem;
+
+/* --- lb_select --- *
+ *
+ * On entry:   R0 == listbox handle
+ *             R1 == item handle
+ *             R2 == 0 to unselect, 1 to select, or 2 to toggle
+ *
+ * On exit:    --
+ *
+ * Use:                Selects or deselects a listbox item, nicely and without
+ *             flickering it.
+ */
+
+extern routine lb_select;
+
+/* --- lb_isSelected --- *
+ *
+ * On entry:   R0 == listbox handle
+ *             R1 == item handle
+ *
+ * On exit:    CS if item is selected, else CC
+ *
+ * Use:                Informs you whether an item is selected.
+ */
+
+extern routine lb_isSelected;
+
+/* --- lb_clearSelection --- *
+ *
+ * On entry:   R0 == listbox handle
+ *             R1 == item handle of item to ignore (or 0 for none)
+ *
+ * On exit:    --
+ *
+ * Use:                Deselects all items in the listbox.
+ */
+
+extern routine lb_clearSelection;
+
+/* --- lb_clickS --- *
+ *
+ * On entry:   R0 == listbox handle
+ *             R1 == pointer to list item
+ *             R3 == mouse button status
+ *
+ * On exit:    --
+ *
+ * Use:                Provides a default action for clicking on an item in a
+ *             list box.
+ *
+ *             Only one selection is possible at any one time.
+ */
+
+extern routine lb_clickS;
+
+/* --- lb_clickM --- *
+ *
+ * On entry:   R0 == listbox handle
+ *             R1 == pointer to list item
+ *             R3 == mouse button status
+ *
+ * On exit:    --
+ *
+ * Use:                Provides a default action for clicking on an item in a
+ *             list box.
+ *
+ *             The multiple selection model is used.
+ */
+
+extern routine lb_clickM;
+
+/* --- lb_drag --- *
+ *
+ * On entry:   R1 == pointer to list item
+ *             R2 == window relative y position
+ *             R3 == mouse button status
+ *             R10 == listbox handle
+ *
+ * On exit:    --
+ *
+ * Use:                Starts a drag operation to allow for easy multiple
+ *             selection.
+ */
+
+extern routine lb_drag;
+
+/* --- lb_inserted --- *
+ *
+ * On entry:   R0 == pointer to the listbox
+ *             R1 == pointer to the new item
+ *
+ * On exit:    --
+ *
+ * Use:                Informs the listbox that an item has been inserted,
+ *             and causes a flicker free insert to occur if possible.
+ */
+
+extern routine lb_inserted;
+
+/* --- lb_removed --- *
+ *
+ * On entry:   R0 == pointer to the listbox
+ *             R1 == index of item removed
+ *
+ * On exit:    --
+ *
+ * Use:                Informs the listbox that an item has been removed, and
+ *             causes a flicker free remove to occur, if possible.
+ */
+
+extern routine lb_removed;
+
+/* --- lb_window --- *
+ *
+ * On entry:   R0 == listbox handle
+ *
+ * On exit:    R0 == window handle
+ *
+ * Use:                Returns the window handle of the listbox
+ */
+
+extern routine lb_window;
+
+/* --- lb_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the listbox unit.
+ */
+
+extern routine lb_init;
+
+/*----- List events -------------------------------------------------------*/
+
+#define lbEvent_close 0
+
+#define lbEvent_redraw 1
+#define lbEvent_click 2
+#define lbEvent_menu 3
+#define lbEvent_drag 4
+#define lbEvent_help 5
+#define lbEvent_drop 6
+
+#define lbDrop_load 0
+#define lbDrop_save 1
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/llistMan b/StraySrc/Libraries/Sapphire/csapph/h/llistMan
new file mode 100644 (file)
index 0000000..e110d36
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * llistMan.h
+ *
+ * [Generated from llistMan, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __llistMan_h
+#define __llistMan_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  llist_create
+ *  llist_destroy
+ *  llist_addItem
+ *  llist_removeItem
+ *  llist_reinsert
+ *  llist_setFlags
+ *  llist_items
+ *  llist_enumerate
+ *  llist_itemToIndex
+ *  llist_indexToItem
+ *  llist_registerSort
+ *  llist_init
+ *  llist_desc
+ */
+
+/* --- llist_create --- *
+ *
+ * On entry:   R0 == pointer to 12 byte list head to fill in
+ *             R1 == sort routine to use (0 for none)
+ *
+ * On exit:    List head filled in appropriately
+ *
+ * Use:                This call set up list. It must be made just once, before
+ *             and other list alls are made. On entry, R0 must point to
+ *             12 bytes in memory, which is filled in by this call.
+ *             Example code may look like:
+ *
+ *                     ADR     R0,myList
+ *                     LDR     R1,=myStrCmp
+ *                     BL      llist_create
+ *
+ *                       .
+ *                         .
+ *                       .
+ *
+ *                     mylist  DCD     0,0
+ */
+
+extern routine llist_create;
+
+/* --- llist_destroy --- *
+ *
+ * On entry:   R0 == pointer to list head
+ *
+ * On exit:    R0 corrupted
+ *
+ * Use:                Destroys the given list.
+ */
+
+extern routine llist_destroy;
+
+/* --- llist_addItem --- *
+ *
+ * On entry:   R0 == pointer to list head
+ *             R1 == pointer to user data (or 0 if none to copy)
+ *             R2 == size of user data
+ *
+ * On exit:    R0 preserved
+ *             R1 == pointer to the new user data
+ *             May return an error
+ *
+ * Use:                This call will add an item to a list. Notice that the
+ *             item is entirely allocated by the list manager, it does not
+ *             point to the data that you supply it, instead it
+ *             copies the data into the newly created item. For this reason
+ *             if 0 is supplied as the user data, nothing is copied.
+ *             It is the returned user data pointer, that must be
+ *             used to reference the item in other llist calls.
+ */
+
+extern routine llist_addItem;
+
+/* --- llist_removeItem --- *
+ *
+ * On entry:   R0 == list head pointer
+ *             R1 == pointer to item to remove (as returned by addItem)
+ *
+ * On exit:    --
+ *
+ * Use:                This call removes the item from the given list. All
+ *             memory taken up by the item is freed. If the value
+ *             passed in R1 is not an item in the list, then all hell is
+ *             likely to break loose, so I don't advise making this mistake.
+ */
+
+extern routine llist_removeItem;
+
+/* --- llist_reinsert --- *
+ *
+ * On entry:   R0 == pointer to list head
+ *             R1 == item to reinsert
+ *
+ * On exit:    --
+ *
+ * Use:                Reinserts the given item into the list. This call is
+ *             used if the item is updated in such a way that its
+ *             position in the list may change.
+ */
+
+extern routine llist_reinsert;
+
+/* --- llist_setFlags --- *
+ *
+ * On entry:   R1 == pointer to list item
+ *             R2 == BIC word
+ *             R3 == EOR word
+ *
+ * On exit:    R2 == the new flags word
+ *
+ * Use:                Sets the flags associated with the given item. If you
+ *             just wish to read them, set R2 and R3 to 0.
+ */
+
+extern routine llist_setFlags;
+
+/* --- llist_items --- *
+ *
+ * On entry:   R0 == pointer to list head
+ *
+ * On exit:    R1 == number of items in list
+ *
+ * Use:                Returns the number of items in the list given. This is
+ *             a cached value, and so is very fast.
+ */
+
+extern routine llist_items;
+
+/* --- llist_enumerate --- *
+ *
+ * On entry:   R0 == pointer to list head
+ *             R1 == pointer to item (0 for first)
+ *             R2 == mask word
+ *             R3 == test word
+ *
+ * On exit:    CS and R1 == next item that matches
+ *             CC and R1 corrupted if no more items
+ *
+ * Use:                This calls return each item in the list, one at a time,
+ *             as long as the item matches the pattern given.
+ */
+
+extern routine llist_enumerate;
+
+/* --- llist_itemToIndex --- *
+ *
+ * On entry:   R0 == pointer to list head
+ *             R1 == point to the item
+ *
+ * On exit:    R1 == index of the item, -1 if it's not there
+ *
+ * Use:                Returns the index of the item given, indexed from 0.
+ */
+
+extern routine llist_itemToIndex;
+
+/* --- llist_indexToItem --- *
+ *
+ * On entry:   R0 == pointer to list head
+ *             R1 == point to the index (indexed from 0)
+ *
+ * On exit:    R1 == the item itself, or 0 if index doesn't exist
+ *
+ * Use:                Returns the index of the item given, indexed from 0.
+ */
+
+extern routine llist_indexToItem;
+
+/* --- llist_registerSort --- *
+ *
+ * On entry:   R0 == pointer to list head
+ *             R1 == pointer to new sort routine
+ *
+ * On exit:    --
+ *
+ * Use:                Registers a new sort routine to be used on the given
+ *             list. This call will also cause a complete resort
+ *             of the given list using a mergesort algorithm -- O(n log n).
+ */
+
+extern routine llist_registerSort;
+
+/* --- llist_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the llistMan unit.
+ */
+
+extern routine llist_init;
+
+/* --- llist_desc --- *
+ *
+ * A llist decription for use with listbox
+ */
+
+extern routine llist_desc;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/mbox b/StraySrc/Libraries/Sapphire/csapph/h/mbox
new file mode 100644 (file)
index 0000000..ca32a4a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * mbox.h
+ *
+ * [Generated from mbox, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __mbox_h
+#define __mbox_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  mbox
+ */
+
+/* --- mbox --- *
+ *
+ * On entry:   R0 == dialogue box handle
+ *             R1 == pointer to help message tag for dialogue box
+ *             R2 == icon handle for embedded title
+ *
+ * On exit:    --
+ *
+ * Use:                Displays a `monologue' box (i.e. a dialogue box which just
+ *             displays information to the user) on the screen and sets up
+ *             an event handler for it.  The dialogue box is destroyed when
+ *             it is closed.
+ *
+ *             If the dialogue box does not have a title bar (read by
+ *             dbox_hasTitle) then R2 is used to give the monologue box
+ *             an embedded title.  R2 is not used otherwise, and thus may
+ *             safely contain any old rubbish.
+ */
+
+extern routine mbox;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/mem b/StraySrc/Libraries/Sapphire/csapph/h/mem
new file mode 100644 (file)
index 0000000..d369f2e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * mem.h
+ *
+ * [Generated from mem, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __mem_h
+#define __mem_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  mem_set
+ */
+
+/* --- mem_set --- *
+ *
+ * On entry:   R0 == pointer to a block of memory (word-aligned)
+ *             R1 == size of the block
+ *             R2 == word value to store in the block
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises a block by filling every word within it with the
+ *             same value.  This is normally 0, although maybe MOVS PC,#0
+ *             might be useful too.
+ */
+
+extern routine mem_set;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/menu b/StraySrc/Libraries/Sapphire/csapph/h/menu
new file mode 100644 (file)
index 0000000..8f4214e
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * menu.h
+ *
+ * [Generated from menu, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __menu_h
+#define __menu_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  menu_create
+ *  menu_help
+ *  menu_init
+ */
+
+/* --- menu_create --- *
+ *
+ * On entry:   R0 == pointer to menu definition table
+ *             R1 == event handler to use
+ *             R2 == R10 value for handler
+ *             R3 == R12 value for handler
+ *
+ * On exit:    --
+ *
+ * Use:                Creates a menu from the given menu definition
+ *             table. If this call is called more than once before
+ *             a menu is opened then the menu definiton are concatenated
+ *             into a large menu. Only the first menu title read is
+ *             taken notice of. Notice therefore, that the call doesn't
+ *             actually open a menu.
+ */
+
+extern routine menu_create;
+
+/* --- menu_help --- *
+ *
+ * On entry:   R0 == pointer to base message tag
+ *             R1 == index of menu item
+ *
+ * On exit:    --
+ *
+ * Use:                Adds a string to the help message found by adding the menu
+ *             item number to the base message tag.
+ */
+
+extern routine menu_help;
+
+/* --- menu_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the menu system.
+ */
+
+extern routine menu_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/menuDefs b/StraySrc/Libraries/Sapphire/csapph/h/menuDefs
new file mode 100644 (file)
index 0000000..62e244b
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * menuDefs.h
+ *
+ * [Generated from menuDefs, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __menuDefs_h
+#define __menuDefs_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Macros provided:
+ *
+ *   BITSPEC
+ *   SETBIT
+ *   NEWITEM
+ *   MENU
+ *   MENUI
+ *   TEAROFF
+ *   TEAROFFI
+ *   R12DATA
+ *   MAKEME
+ *   MHEIGHT
+ *   GLOBALM
+ *   ITEM
+ *   ITEWI
+ *   SHADE
+ *   ISHADE
+ *   SWITCH
+ *   RADIO
+ *   SPRITE
+ *   HALFSZ
+ *   SUBWARN
+ *   SUBMENU
+ *   NOWARN
+ *   RULEOFF
+ *   MENUEND
+ */
+
+/*----- Constants for menus -----------------------------------------------*
+ *
+ * In the descriptions of flags below, the data required in the packed menu
+ * definition is shown in the comments.  Insert items in the order of the
+ * bit precedences of the flags.
+ *
+ * Note -- a (*) following a description means the flag is only supported by
+ * tms (the tearoff system), and a (+) means that the flag is only supported
+ * by menu (the WIMP system).
+ */
+
+/* --- Flags for menu titles and items --- */
+
+#define mFlag_indirect ((1<<0))
+
+#define mFlag_R12 ((1<<16))
+
+#define mFlag_noTrans ((1<<19))
+
+/* --- Menu title flags --- */
+
+#define mFlag_tearoff ((1<<1))
+
+#define mFlag_makeMe ((1<<2))
+
+#define mFlag_maxHeight ((1<<3))
+
+#define mFlag_global ((1<<4))
+
+/* --- Menu item flags --- */
+
+#define mFlag_shortCut ((1<<1))
+
+#define mFlag_iShortCut ((1<<2))
+
+#define mFlag_shade ((1<<3))
+
+#define mFlag_invShade ((1<<4))
+
+#define mFlag_switch ((1<<5))
+
+#define mFlag_radio ((1<<6))
+
+#define mFlag_sprite ((1<<7))
+
+#define mFlag_halfSize ((1<<8))
+
+#define mFlag_subWarn ((1<<9))
+
+#define mFlag_subMenu ((1<<10))
+
+#define mFlag_noWarn ((1<<17))
+
+#define mFlag_ruleOff ((1<<18))
+
+#define mFlag_end ((1<<31))
+
+/* --- Event codes --- *
+ *
+ * Event codes are returned in R0, with R1 being the item number within
+ * the packed menu definition, indexed from 0.
+ *
+ * Note: mEvent_deleted is only sent to the topmost menu title by the
+ * standard menu system, but is sent to the titles of all menus being closed
+ * by TMS.  If you are converting from one to the other, bear this in mind.
+ */
+
+#define mEvent_select (0)
+
+#define mEvent_subMenu (1)
+
+#define mEvent_deleted (2)
+
+#define mEvent_help (3)
+
+/*----- Menu creation macros ----------------------------------------------*/
+
+/* --- Note to reader --- *
+ *
+ * These macros make a lot of use of private constants and variables.  Try to
+ * avoid examining these too closely, because you'll probably get lost.
+ */
+
+/* --- Set up the variables --- */
+
+/* --- Macro: BITSPEC --- *
+ *
+ * Arguments:  offset == offset into workspace of target word
+ *             bit == bitmask with a 1 in the position of the bit
+ *
+ * Use:                Assembles a bit specification referencing the described bit.
+ *             The bit is described by a mask word rather than a bit
+ *             position, because it is expected that you will already have
+ *             set up constants for bit masks.
+ */
+
+/* --- Macro: SETBIT --- *
+ *
+ * Arguments:  flag == which menu flag above to set
+ *
+ * Use:                Sets a bit within the current item or menu title's flags
+ *             word.  It ensures that items are inserted in the correct
+ *             order.
+ */
+
+/* --- Macro: NEWITEM --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Starts a new menu item or menu title.  It also inserts a new
+ *             flags word in the current position.
+ */
+
+/* --- Macro: MENU --- *
+ *
+ * Arguments:  title == the menu's title string/message tag
+ *
+ * Use:                Creates a nonindirected menu title and starts a new menu.
+ */
+
+/* --- Macro: MENUI --- *
+ *
+ * Arguments:  title == offset to title pointer in client's workspace
+ *
+ * Use:                Creates an indirected menu title and starts a new menu.
+ */
+
+/* --- Macro: TEAROFF --- *
+ *
+ * Arguments:  title == menu's title string/message tag
+ *
+ * Use:                Creates a nonindirected tearoff menu title and starts a new
+ *             menu.
+ */
+
+/* --- Macro: TEARI --- *
+ *
+ * Arguments:  title == offset to title pointer in client's workspace
+ *
+ * Use:                Creates an indirected tearoff menu title and starts a new
+ *             menu.
+ */
+
+/* --- Macro: R12DATA --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Sets the current menu item or menu title to use the client's
+ *             R12 pointer rather than its R10 pointer for workspace.
+ */
+
+/* --- Macro: NOTRANS --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Disables message translation of the current item or menu
+ *             title.  This is useful if you're building the item or title
+ *             text dynamically.
+ */
+
+/* --- Macro: MAKEME --- *
+ *
+ * Arguments:  makeProc == pointer to procedure which will remake the menu
+ *
+ * Use:                Sets the current menu to require being remade from scratch
+ *             when being updated (e.g. after an item is selected).
+ */
+
+/* --- Macro: MHEIGHT --- *
+ *
+ * Arguments:  height == maximum permitted height for menu in OS units
+ *
+ * Use:                Sets the menu's maximum allowable height.
+ */
+
+/* --- Macro: GLOBALM --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Sets the menu's maximum allowable height.
+ */
+
+/* --- Macro: ITEM --- *
+ *
+ * Arguments:  text == item's text string/message tag
+ *
+ * Use:                Creates a new nonindirected menu item.
+ */
+
+/* --- Macro: ITEMI --- *
+ *
+ * Arguments:  text == offset of pointer to menu text
+ *
+ * Use:                Creates a new indirected menu item
+ */
+
+/* --- Macro: SHADE --- *
+ *
+ * Arguments:  $offset,$bit == bitspec of item's `shaded' bit
+ *
+ * Use:                Sets the current item to be shadable.
+ */
+
+/* --- Macro: ISHADE --- *
+ *
+ * Arguments:  offset,$bit == bitspec of item's `unshaded' bit
+ *
+ * Use:                Sets the current item to be inverse shadable.
+ */
+
+/* --- Macro: SWITCH --- *
+ *
+ * Arguments:  offset,$bit == bitspec of item's `ticked' bit
+ *
+ * Use:                Sets the current item to be tickable.
+ */
+
+/* --- Macro: RADIO --- *
+ *
+ * Arguments:  group == offset of this item's radio group selector
+ *             selector == value of selector to blob this item
+ *
+ * Use:                Marks this item as a radio item, so that it is blobbed (or
+ *             ticked under the WIMP menu system) when the selector in the
+ *             client's workspace matches the item's selector.
+ */
+
+/* --- Macro: SPRITE --- *
+ *
+ * Arguments:  sprite == EITHER address of validation string, OR offset of
+ *               sprite name pointer (if area argument given)
+ *             area == (optional) sprite area, or -1 for resspr_area
+ *
+ * Use:                Adds a sprite to the menu item definition.
+ */
+
+/* --- Macro: HALFSZ --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Sets the item to display its sprite at half size
+ */
+
+/* --- Macro: SUBWARN --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Sets the item to generate submenu warnings when its submenu
+ *             arrow is pointed at.
+ */
+
+/* --- Macro: SUBMENU --- *
+ *
+ * Arguments:  subMenu == pointer to packed definition of the submenu
+ *             handler == pointer to handler routine
+ *
+ * Use:                Attaches the given menu as a submenu of this item.
+ */
+
+/* --- Macro: NOWARN --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Prevents this item from returning submenu events if it is
+ *             shaded.
+ */
+
+/* --- Macro: RULEOFF --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Inserts a ruleoff after the current item, assuming there are
+ *             some more items after it.
+ */
+
+/* --- Macro: MENUEND --- *
+ *
+ * Arguments:  --
+ *
+ * Use:                Finishes off the current menu.
+ */
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/msgs b/StraySrc/Libraries/Sapphire/csapph/h/msgs
new file mode 100644 (file)
index 0000000..32fba4e
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * msgs.h
+ *
+ * [Generated from msgs, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __msgs_h
+#define __msgs_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  msgs_load
+ *  msgs_build
+ *  msgs_error
+ *  msgs_lookup
+ *  msgs_init
+ */
+
+/* --- msgs_load --- *
+ *
+ * On entry:   R0 == pointer to filename
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Reads in the given messages file.
+ */
+
+extern routine msgs_load;
+
+/* --- msgs_build --- *
+ *
+ * On entry:   R0 == pointer to a message string
+ *             R1 == pointer to output buffer
+ *
+ * On exit:    R0 == pointer to buffer (R1 on entry)
+ *             R1 == pointer to terminating null
+ *
+ * Use:                Builds a message string, by substituting message references
+ *             by their values.  Each reference of the form `$tag' (or
+ *             optionally `$(tag)', to avoid having to have a trailing)
+ *             space is replaced by the actual message.  A literal `$' sign
+ *             may be represented as `$$'.
+ */
+
+extern routine msgs_build;
+
+/* --- msgs_error --- *
+ *
+ * On entry:   R0 == pointer to an error skeleton string:
+ *                     R0+0 == error number
+ *                     R0+4 == message tag-and-default (null-terminated)
+ *             R2-R11 == filler strings (not message tags)
+ *
+ * On exit:    R0 == pointer to translated error message (in error buffer)
+ *             R1 == pointer to null terminator of message
+ *
+ * Use:                Performs string sustitution on an error message (as done by
+ *             str_subst), but translating the error string.
+ */
+
+extern routine msgs_error;
+
+/* --- msgs_lookup --- *
+ *
+ * On entry:   R0 == message tag (and default message)
+ *
+ * On exit:    R0 == pointer to located message
+ *
+ * Use:                Returns the real message from its tag. If the tag does not
+ *             exist, then the default message is used. If that is not
+ *             supplied, then the tag name itself is returned (ie. R0
+ *             is preserved).
+ */
+
+extern routine msgs_lookup;
+
+/* --- msgs_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the message system.
+ */
+
+extern routine msgs_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/nopoll b/StraySrc/Libraries/Sapphire/csapph/h/nopoll
new file mode 100644 (file)
index 0000000..20a30b7
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * nopoll.h
+ *
+ * [Generated from nopoll, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __nopoll_h
+#define __nopoll_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  nopoll_open
+ *  nopoll_close
+ *  nopoll_init
+ *  nopoll_process
+ */
+
+/* --- nopoll_open --- *
+ *
+ * On entry:   R0 == a window handle to take over
+ *
+ * On exit:    --
+ *
+ * Use:                Sets up the window with the given handle to be a nonpolling
+ *             dialogue box.  The window must already be open on the screen.
+ *             This call will force it to be painted on the screen, and
+ *             then start faking events for it.
+ */
+
+extern routine nopoll_open;
+
+/* --- nopoll_close --- *
+ *
+ * On entry:   R0 == return value for nopoll_process (can be anything)
+ *
+ * On exit:    --
+ *
+ * Use:                Tells nopoll that the nonpolling window has been killed,
+ *             and hence that polling can return to normal again.  You can
+ *             specify a return value to give from nopoll_process (if that
+ *             system is being used).
+ */
+
+extern routine nopoll_close;
+
+/* --- nopoll_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises nopoll so it can be used.
+ */
+
+extern routine nopoll_init;
+
+/* --- nopoll_process --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == value passed to nopoll_close
+ *
+ * Use:                Processes a nonpolling window until it calls nopoll_close.
+ *             It then returns the value passed to nopoll_close in R0,
+ *             which can be defined in any way you want.
+ *
+ *             Some notes on the use of this routine:
+ *
+ *             * It calls event_poll, so any functions that get called
+ *               after the normal event_poll don't get called.  Since the
+ *               Wimp isn't actually being polled at all, this isn't a
+ *               real problem as long as your handlers are registered at the
+ *               event filter level or higher (e.g. win event handlers or
+ *               even dbox handlers).
+ *
+ *             * It uses up an extra 256 bytes of stack for a poll block.
+ *               If you think you might miss this stack space, then you'd
+ *               better not use this routine.
+ *
+ *             * It isn't reentrant, but then again, nor is the rest of the
+ *               nopoll system -- you can only have one nonpolling box open
+ *               at a time.
+ */
+
+extern routine nopoll_process;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/note b/StraySrc/Libraries/Sapphire/csapph/h/note
new file mode 100644 (file)
index 0000000..5eea2fb
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * note.h
+ *
+ * [Generated from note, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __note_h
+#define __note_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  note
+ */
+
+/* --- note --- *
+ *
+ * On entry:   R0 == pointer to a piece of text to display
+ *
+ * On exit:    --
+ *
+ * Use:                Displays some text in a small window.
+ */
+
+extern routine note;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/pane b/StraySrc/Libraries/Sapphire/csapph/h/pane
new file mode 100644 (file)
index 0000000..242abe5
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * pane.h
+ *
+ * [Generated from pane, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __pane_h
+#define __pane_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  pane_add
+ *  pane_remove
+ *  pane_closed
+ *  pane_deleted
+ *  pane_swap
+ *  pane_open
+ *  pane_init
+ */
+
+/* --- pane_add --- *
+ *
+ * On entry:   R0 == window handle of parent window
+ *             R1 == icon handle in parent window
+ *             R2 == window handle of pane window
+ *
+ * On exit:    May return an error
+ *
+ * Use:                This call registers a pane to be associated with the given
+ *             window. The pane is always opened to fit exactly within
+ *             the given icon -- border widths are taken into account
+ *             if there are scroll bars etc.
+ *
+ *             You must call pane_closed if the parent window is closed,
+ *             since there is no way for pane to trap this occurence.
+ */
+
+extern routine pane_add;
+
+/* --- pane_remove --- *
+ *
+ * On entry:   R0 == window handle for which pane was registered
+ *             R1 == window handle of the pane window itself
+ *
+ * On exit:    --
+ *
+ * Use:                Removes the pane from the given window. This call will
+ *             close the given pane, but will not actually delete it
+ *             (ie. with a Wimp_DeleteWindow).
+ */
+
+extern routine pane_remove;
+
+/* --- pane_closed --- *
+ *
+ * On entry:   R0 == window handle of parent
+ *
+ * On exit:    --
+ *
+ * Use:                Informs pane that a parent window has closed.
+ *             All associated panes are then closed.
+ */
+
+extern routine pane_closed;
+
+/* --- pane_deleted --- *
+ *
+ * On entry:   R0 == window handle of parent
+ *
+ * On exit:    --
+ *
+ * Use:                Informs pane that a parent window has been deleted.
+ *             All associated panes are then closed, and there
+ *             registration with the pane library module is
+ *             terminated.
+ */
+
+extern routine pane_deleted;
+
+/* --- pane_swap --- *
+ *
+ * On entry:   R0 == window handle of parent window
+ *             R1 == icon handle within parent window
+ *             R2 == window handle of new pane
+ *
+ * On exit:    --
+ *
+ * Use:                This call will replace the pane in associated with icon R1
+ *             in window R0, with the pane in R2.
+ *
+ *             The exisiting pane is closed, and the new pane is
+ *             opened in it's place. No error is generated if the existing
+ *             pane does not exist; this allows the caller to delete the
+ *             window before doing the swap.
+ */
+
+extern routine pane_swap;
+
+/* --- pane_open --- *
+ *
+ * On entry:   R0 == window handle
+ *
+ * On exit:    --
+ *
+ * Use:                Opens all the panes associated with the given window.
+ */
+
+extern routine pane_open;
+
+/* --- pane_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the pane unit.
+ */
+
+extern routine pane_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/progInfo b/StraySrc/Libraries/Sapphire/csapph/h/progInfo
new file mode 100644 (file)
index 0000000..b77a2f0
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * progInfo.h
+ *
+ * [Generated from progInfo, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __progInfo_h
+#define __progInfo_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  progInfo
+ */
+
+/* --- progInfo --- *
+ *
+ * On entry:   R0 == pointer to purpose string
+ *             R1 == pointer to author string
+ *             R2 == pointer to version string
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Displays an `About this program' dialogue box on the screen.
+ */
+
+extern routine progInfo;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/ptr b/StraySrc/Libraries/Sapphire/csapph/h/ptr
new file mode 100644 (file)
index 0000000..62733d8
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * ptr.h
+ *
+ * [Generated from ptr, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __ptr_h
+#define __ptr_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  ptr_setShape
+ *  ptr_resetShape
+ *  ptr_blinkOn
+ *  ptr_blinkOff
+ *  ptr_init
+ */
+
+/* --- ptr_setShape --- *
+ *
+ * On entry:   R0 == sprite name
+ *             R1 == x offset of hot spot
+ *             R2 == y offset of hot spot
+ *
+ * On exit:    --
+ *
+ * Use:                Set the pointer sprite to the given name. The sprite area
+ *             used is that returned from resspre_area.
+ */
+
+extern routine ptr_setShape;
+
+/* --- ptr_resetShape --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Resets the pointer shape to the default.
+ */
+
+extern routine ptr_resetShape;
+
+/* --- ptr_blinkOn --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Makes the caret blink while it is in a window owned by your
+ *             application.
+ */
+
+extern routine ptr_blinkOn;
+
+/* --- ptr_blinkOff --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Turns the caret blinking off.
+ */
+
+extern routine ptr_blinkOff;
+
+/* --- ptr_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the ptr system.
+ */
+
+extern routine ptr_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/rand b/StraySrc/Libraries/Sapphire/csapph/h/rand
new file mode 100644 (file)
index 0000000..d1fa365
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * rand.h
+ *
+ * [Generated from rand, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __rand_h
+#define __rand_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  rand
+ *  rand_setSeed
+ *  rnd
+ *  rand_init
+ */
+
+/* --- rand --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == a pseudorandom number between 0 and &7FFFFFFF
+ *
+ * Use:                Returns a pseudorandom number.  The algorithm used is the
+ *             additive generator found in Knuth.  The table is generated
+ *             from the current monotonic time using a linear congruential
+ *             generator.  Randomness is fairly good, and it's very quick.
+ */
+
+extern routine rand;
+
+/* --- rand_setSeed --- *
+ *
+ * On entry:   R0 == a pseudorandom seed
+ *
+ * On exit:    --
+ *
+ * Use:                Sets up the random number generator (rand) to the given start
+ *             position.  The table of values is initialised from the seed
+ *             in a psuedorandom manner, using a linear congruential
+ *             generator.
+ */
+
+extern routine rand_setSeed;
+
+/* --- rnd --- *
+ *
+ * On entry:   R0 == start value (inclusive)
+ *             R1 == end value (inclusive)
+ *
+ * On exit:    R0 == random number between the boundaries given
+ *
+ * Use:                Returns a random integer between the boundaries given.
+ *             The distribution is slightly skewed towards lower numbers,
+ *             but there's not a lot I can do about this, folks.
+ */
+
+extern routine rnd;
+
+/* --- rand_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialise the random number table.
+ */
+
+extern routine rand_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/repeater b/StraySrc/Libraries/Sapphire/csapph/h/repeater
new file mode 100644 (file)
index 0000000..605465a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * repeater.h
+ *
+ * [Generated from repeater, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __repeater_h
+#define __repeater_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  repeater
+ *  rpt_end
+ */
+
+/* --- repeater --- *
+ *
+ * On entry:   R0 == pointer to routine to call
+ *             R1 == R10 value to pass to routine
+ *             R2 == R12 value to pass to routine
+ *
+ * On exit:    --
+ *
+ * Use:                Calls a routine (a) immediately, (b) after the configured
+ *             keyboard delay rate and (c) repeatedly after the configured
+ *             keyboard repeat rate.  Calls stop when the user stops
+ *             pressing the mouse button.
+ *
+ *             The routine is called with R0 containing either the number
+ *             of missed calls since the last one (normally this is 1) --
+ *             this is intended to be used to implement a kind of buffering
+ *             of repeats if the operation being performed is a lengthy one
+ *             -- and with 0 to indicate that the operation is now
+ *             completed.
+ */
+
+extern routine repeater;
+
+/* --- rpt_end --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *               
+ * Use:                Ends a repeater before the drag is released. No final
+ *             0 is sent to the handler.
+ */
+
+extern routine rpt_end;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/report b/StraySrc/Libraries/Sapphire/csapph/h/report
new file mode 100644 (file)
index 0000000..3a7184e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * report.h
+ *
+ * [Generated from report, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __report_h
+#define __report_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  report_register
+ *  report_catchAll
+ *  report_error
+ */
+
+/* --- report_register --- *
+ *
+ * On entry:   R0 == pointer to routine to use
+ *             R1 == R12 to pass to the routine
+ *             R2 == stack pointer to set when it gets control
+ *
+ * On exit:    --
+ *
+ * Use:                Registers a resume point so that the application can recover
+ *             from errors.  Error messages are reported using errorBox.
+ */
+
+extern routine report_register;
+
+/* --- report_catchAll --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R13 modified
+ *
+ * Use:                Sets up an exception handler to catch errors and other SEH
+ *             exceptions.  Errors are reported in the usual way, and the
+ *             user is given the option to close the application.  Other
+ *             exceptions are reported as errors.
+ */
+
+extern routine report_catchAll;
+
+/* --- report_error --- *
+ *
+ * On entry:   R0 == pointer to error
+ *
+ * On exit:    --
+ *
+ * Use:                Prompts the user about quitting the application in response
+ *             to a really bad error.  If the user decides to quit, we
+ *             quit.  Otherwise we return.
+ */
+
+extern routine report_error;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/res b/StraySrc/Libraries/Sapphire/csapph/h/res
new file mode 100644 (file)
index 0000000..9e56fb5
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * res.h
+ *
+ * [Generated from res, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __res_h
+#define __res_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  res_exists
+ *  res_country
+ *  res_find
+ *  res_init
+ */
+
+/* --- res_exists --- *
+ *
+ * On entry:   R0 == pointer to pathname
+ *
+ * On exit:    CS if the file exists, CC otherwise
+ *
+ * Use:                Tries to find the named file.  The file is deemed to exist
+ *             if OS_File can return a valid object type for it (i.e. not
+ *             `non-existant object' or actually raising errors).
+ */
+
+extern routine res_exists;
+
+/* --- res_country --- *
+ *
+ * On entry:   R0 == pointer to a buffer to use
+ *
+ * On exit:    R0 == pointer to country name (may not be in the buffer)
+ *
+ * Use:                Reads the name of the current country.  If no name can be
+ *             found, it returns a pointer to the string `UK' which should
+ *             do as a suitable default
+ */
+
+extern routine res_country;
+
+/* --- res_find --- *
+ *
+ * On entry:   R0 == pointer to resource filename
+ *             R1 == pointer to buffer to build filename in
+ *
+ * On exit:    R0 == pointer to start of full pathname (R1 on entry)
+ *             R1 == pointer to terminating null character
+ *             CS if the file could actually be found, CC otherwise
+ *
+ * Use:                Locates a resource file.  It searches, in order:
+ *
+ *             * resPrefix.Resources.leaf[suffix]
+ *             * resPrefix.Resources.country.leaf[suffix]
+ *             * resPrefix.leaf[suffix]
+ *
+ *             returning the last if none of them could be found.  Note
+ *             that `country' here is the currently configured country
+ *             setting, and `suffix' is the WIMP mode aspect ratio suffix
+ *             for the current mode (RISC OS 3 only).
+ */
+
+extern routine res_find;
+
+/* --- res_init --- *
+ *
+ * On entry:   R0 == pointer to application name
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the resource prefix to <appname$Dir>
+ */
+
+extern routine res_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/resources b/StraySrc/Libraries/Sapphire/csapph/h/resources
new file mode 100644 (file)
index 0000000..b6c63d1
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * resources.h
+ *
+ * [Generated from resources, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __resources_h
+#define __resources_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  resource_init
+ *  resource_find
+ */
+
+/* --- resources_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the shared resource system, setting up the
+ *             link to the SapphRes DLL.  Note that this initialisation is
+ *             /not/ performed automatically.
+ */
+
+extern routine resources_init;
+
+/* --- resources_find --- *
+ *
+ * On entry:   R0 == resource code
+ *             R1 == pointer to name (only for rsType_template)
+ *
+ * On exit:    CS if found, and
+ *               R0 == pointer to resource
+ *               R1 == pointer to resource limit (only for rsType_message)
+ *             else CC and
+ *               R0,R1 preserved
+ *
+ * Use:                Locates resources in the shared resource DLL.
+ */
+
+extern routine resources_find;
+
+/*----- Resource types ----------------------------------------------------*/
+
+#define rsType_sprite 0
+#define rsType_message 1
+#define rsType_template 2
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/resspr b/StraySrc/Libraries/Sapphire/csapph/h/resspr
new file mode 100644 (file)
index 0000000..e6eb7a3
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * resspr.h
+ *
+ * [Generated from resspr, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __resspr_h
+#define __resspr_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  resspr_load
+ *  resspr_area
+ *  resspr_init
+ */
+
+/* --- resspr_load --- *
+ *
+ * On entry:   R0 == pointer to filename
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Loads a sprite file into memory and allows it to be
+ *             referenced through resspr_area.  Note that Straylight's
+ *             Sprinkle module must be loaded if more than one sprite file
+ *             is to be used for resources.
+ */
+
+extern routine resspr_load;
+
+/* --- resspr_area --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == pointer to application's sprite area
+ *
+ * Use:                Locates the application's `Sprites' resource in memory and
+ *             returns a pointer to it.  If the resource has not been
+ *             loaded, 1 is returned, to indicate to use the WIMP area.
+ *             If multiple sprite files have been loaded, this call returns
+ *             the address of the first: they will have been linked together
+ *             so that Sprinkle will treat them as one big area.
+ */
+
+extern routine resspr_area;
+
+/* --- resspr_init --- *
+ *
+ * On entry:   R0 == pointer to application name
+ *
+ * On exit:    --
+ *
+ * Use:                Initalises resspr, loading the Sprites resource.
+ */
+
+extern routine resspr_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/roVersion b/StraySrc/Libraries/Sapphire/csapph/h/roVersion
new file mode 100644 (file)
index 0000000..7df576c
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * roVersion.h
+ *
+ * [Generated from roVersion, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __roVersion_h
+#define __roVersion_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  rov_init
+ *  rov_version
+ */
+
+/* --- rov_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Sets up the OS version in a cache.
+ */
+
+extern routine rov_init;
+
+/* --- rov_version --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == current RISC OS version
+ *
+ * Use:                Returns the current operating system version number.
+ */
+
+extern routine rov_version;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/sapphire b/StraySrc/Libraries/Sapphire/csapph/h/sapphire
new file mode 100644 (file)
index 0000000..761f1ce
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * sapphire.h
+ *
+ * Definitions for using Sapphire from C
+ *
+ * © 1995 Straylight
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma force_top_level
+#pragma include_only_once
+
+#ifndef __sapphire_h
+#define __sapphire_h
+
+/*----- Note --------------------------------------------------------------*
+ *
+ * This header file contains definitions and directives which are highly
+ * compiler specific.  Only use /genuine/ Norcroft ARM C compilers!
+ */
+
+/*----- Important types ---------------------------------------------------*/
+
+/* --- error --- *
+ *
+ * Defines the layout of a RISC OS error /again/.  If you're using
+ * _kernel_oserror, then #define error _kernel_oserror some time, and
+ * everything should be OK.
+ */
+
+#ifndef error
+  typedef struct
+  {
+    int errnum;
+    char errmess[252];
+  }
+  error;
+#endif
+
+/* --- regset --- *
+ *
+ * Defines a register block, which is the only sane way of fiddling with
+ * registers from C.
+ */
+
+typedef struct
+{
+  int r[13];
+  unsigned int flags;
+}
+regset;
+
+/* --- Hacky definition of a routine --- *
+ *
+ * This prevents attempts to call Sapphire routines directly, while still
+ * making references to routines look sensible, and preventing fiddling
+ * with the code, which would (of course) be a Bad Thing.
+ */
+
+typedef struct _opaque routine[];
+
+/* --- size_t --- *
+ *
+ * In case no-one else has defined it yet.
+ */
+
+#ifndef __size_t
+#define __size_t
+  typedef unsigned size_t;
+#endif
+
+/*----- Sapphire-to-C veneers ---------------------------------------------*/
+
+/* --- __sapph_veneer --- *
+ *
+ * This routine is used internally by the _sapph macro to build
+ * callable-from-Sapphire functions in C.
+ */
+
+extern void __sapph_veneer(void);
+
+/* --- _sapph --- *
+ *
+ * Allows you to build callable-from-Sapphire functions in C.  The syntax
+ * is
+ *
+ *   _sapph(foo)(regset *r,<struct> *obj,<struct> *wsp,char *scratch)
+ *   {
+ *     // ...
+ *   }
+ *
+ * The routine must return an int built by using the macros below, for
+ * setting flags on exit.
+ *
+ * The obj and wsp pointers are the values of R10 and R12 respectively on
+ * entry.  Conventionally, these are `object' pointers (like a `this' pointer
+ * in C++) and `workspace' pointers (not really used in C), but can actually
+ * be anything you like.  If you're not interested in the values, you
+ * are allowed to omit them.  For example,
+ *
+ *   _sapph(foo)(regset *r,<struct> *obj)
+ *
+ * is also permissable, because of the way that APCS works.  If you're
+ * feeling adventurous, you can use extra arguments to pull off values
+ * of R0 onwards off the stack.  This starts getting a bit hacky, though.
+ * Alternatively, you can use variadic arguments and fiddle with stdarg
+ * to access these.  This isn't really recommended.
+ *
+ * For reference, the code built by the macro is as follows:
+ *
+ *             STMFD R13!,{R14}
+ *             MOV R14,PC
+ *             B csapph_veneer
+ */
+
+#define _sapph(name) \
+  void name(void){_word(0xE92D4000);_word(0xE1A0E00F);__sapph_veneer();} \
+  int __sapph__##name
+
+/* --- Macros for returning flags --- *
+ *
+ * You can OR these together using the | operator to obtain interesting
+ * effects.  For example,
+ *
+ *   return (V_set | C_clear);
+ *
+ * would return V set, and C clear, but the other two flags would be
+ * preserved.  The default (0) is to preserve all the flags.
+ *
+ * If you really want to be strange, nibble 1 is used to BIC the flags,
+ * and nibble 0 is EORed with them.  Alternatively, you can fiddle with
+ * the `flags' member of the regset structure.
+ */
+
+#define V_set  0x11
+#define V_clear        0x10
+
+#define C_set  0x22
+#define C_clear        0x20
+
+#define Z_set  0x44
+#define Z_clear        0x40
+
+#define N_set  0x88
+#define N_clear        0x80
+
+/* --- C-to-Sapphire veneers --- */
+
+/* --- call --- *
+ *
+ * Arguments:  routine p == the routine to call
+ *             regset *r == pointer to register block to use
+ *
+ * Returns:    Zero, if no error was returned, or a pointer to the error.
+ *
+ * Use:                Calls a general Sapphire routine.  The routine is entered
+ *             with registers as defined in the regset block.  Flags are
+ *             returned in the `flags' member of the regset.  The flags
+ *             are all cleared on entry to the routine.
+ */
+
+extern error *call(routine /* p */, regset */* r */);
+
+/* --- _call, _callx --- *
+ *
+ * Arguments:  routine p == the routine to call
+ *             unsigned flags == various flags controlling arguments
+ *             ... == a list of arguments and things
+ *
+ * Returns:    For _call, the _return register (0 by default).  For _callx,
+ *             zero if no error, or a pointer to the error.
+ *
+ * Use:                Calls a Sapphire routine.  Only R0-R9 can be passed.  The
+ *             flags are described below.  The optional arguments are in
+ *             the following order:
+ *
+ *             Input registers:        One word for each input register
+ *             Output registers:       Address to store each reg value
+ *             Flags address:          Address to store PC+flags value
+ *             Block contents:         Build contents of local block at end
+ */
+
+extern int _call(routine /* p */, unsigned /* flags */, ...);
+extern error *_callx(routine /* p */, unsigned /* flags */, ...);
+
+/*----- SWI veneers -------------------------------------------------------*/
+
+/* --- swi --- *
+ *
+ * Arguments:  int swi == SWI number to call
+ *             regset *r == registers to pass
+ *
+ * Returns:    Pointer to error, or 0
+ *
+ * Use:                Calls a SWI.  Returned registers are stored in the regset,
+ *             as are the flags.
+ */
+
+extern error *swi(int /* swi */, regset */* r */);
+
+/* --- _swi, _swix --- *
+ *
+ * Arguments:  int swi == number of the SWI to call
+ *             unsigned flags == various flags controlling arguments
+ *             ... == a list of arguments and things
+ *
+ * Returns:    For _swi, the _return register (0 by default).  For _swix,
+ *             zero if no error, or a pointer to the error.
+ *
+ * Use:                Calls a SWI.  The flags are described below.  The optional
+ *             arguments are as above.
+ */
+
+extern int _swi(int /* swi */, unsigned /* flags */, ...);
+extern error *_swix(int /* swi */, unsigned /* flags */, ...);
+
+/*----- Flags for the veneers ---------------------------------------------*/
+
+/* --- _flags -- return or output processor flags --- */
+
+#define _flags         (0x10)
+
+/* --- _in and _inr -- input a register, or a range of registers --- */
+
+#define _in(r)         (1u << (r))
+#define _inr(ra,rb)    (((~0) << (ra)) ^ ((~0) << ((rb)+1)))
+
+/* --- _out and _outr -- output a register, or a range of registers --- */
+
+#define _out(r)                (1u << (31-((r) == _flags ? 10 : (r))))
+#define _outr(ra,rb)   (((~0) << (31-(rb))) ^ ((~0) << (32-(ra))))
+
+/* --- _block -- point a register at block built from arguments --- */
+
+#define _block(r)      (((r) << 12) | 0x800)
+
+/* --- _return -- return register from _swi (not _swix) --- */
+
+#define _return(r)     ((r) == _flags ? 0xF0000 : (r) << 16)
+
+/* --- Constants for ARM processor flags --- */
+
+#define _n             (0x80000000u)
+#define _z             (0x40000000u)
+#define _c             (0x20000000u)
+#define _v             (0x10000000u)
+
+/* --- Acorn style capital-letter macros --- */
+
+#define _FLAGS         _flags
+#define _IN(x)         _in(x)
+#define _INR(x,y)      _inr(x,y)
+#define _OUT(x)                _out(x)
+#define _OUTR(x,y)     _outr(x,y)
+#define _BLOCK(x)      _block(x)
+#define _RETURN(x)     _return(x)
+#define _N             _n
+#define _Z             _z
+#define _C             _c
+#define _V             _v
+
+/*----- C library support -------------------------------------------------*
+ *
+ * We have to mess about with some bits of the header files, mainly to
+ * point the compiler at bits of Sapphire instead of the normal library.
+ * To support a dynamically linked environment, we need to access static
+ * data items through `finder' functions, declared __pure to allow the
+ * compiler to optimise slightly better.
+ */
+
+/* --- errno --- */
+
+#ifdef errno
+  #undef errno
+#endif
+extern __pure int *cmath_errno(void);
+#define errno (*cmath_errno())
+
+/* --- math --- *
+ *
+ * Sapphire's normal `sqrt' routine is an integer square root (courtesy of
+ * David Seal), so we need to cheat a bit here.
+ */
+
+#ifdef HUGE_VAL
+  #undef HUGE_VAL
+#endif
+extern __pure double cmath_huge(void);
+#define HUGE_VAL (cmath_huge())
+
+#define sqrt(x) __sapph_sqrt(x)
+
+/* --- ctype --- *
+ *
+ * We define macros for toupper and tolower, since this is very simple under
+ * the Sapphire implementation of ctype.
+ */
+
+#ifdef __ctype
+  #undef __ctype
+#endif
+extern __pure char *ctype_findTable(void);
+#define __ctype (ctype_findTable())
+
+#define tolower(c) (isupper(c) ? __ctype[c+256] : c)
+#define toupper(c) (islower(c) ? __ctype[c+256] : c)
+
+/* --- Memory moving routines --- */
+
+extern void fastMove(void * /* a */, void */* b */, size_t /* s */);
+#define memmove(a, b, s) fastMove(a, b, s)
+#define memcpy(a, b, s) fastMove(a, b, s)
+
+/*----- Basic Sapphire routines -------------------------------------------*/
+
+/* --- Access to Sapphire environment block --- */
+
+extern __pure char *__sapph_scratchpad(void);
+#define scratchpad (__sapph_scratchpad())
+#define scratch(t) ((t)__scratchpad())
+/* `scratchpad' is the address of a buffer of at least 256 bytes, which
+ * you can use more or less as you want to.
+ */
+
+/* --- Simple string functions --- *
+ *
+ * These functions are veneers onto the standard Sapphire routines.  Hence
+ * their behaviour deviates slightly from the ANSI definitions.  The Sapphire
+ * implementations have been written mainly for simplicity and size, rather
+ * than speed.  If string handling becomes time critical, it's probably a
+ * good idea to use better lookup structures.
+ */
+
+#define strcpy(d, s) str_cpy(d, s)
+extern char *strcpy(char */* d */, const char */* s */);
+/* Copies a string from source to destination.  Note: Returns pointer to
+ * terminating null byte, /not/ input value of d as required by ANSI.  We
+ * think it's more useful like this, and the ANSI result isn't used often
+ * enough for compatiblity to be an issue.
+ */
+
+#define strlen(s) str_len(s)
+extern int strlen(const char */* s */);
+/* Returns the length of a string.
+ */
+
+extern char *strsubst(const char */* skel */, char */* buff */, ...);
+/* Veneer to Sapphire's str_subst routine.  In summary, it copies the
+ * skeleton string to the buffer, replacing placeholders of the form
+ * %[<type>]<n>, where <type> is: `s' string, `x' hex number, `i' decimal
+ * integer, `c' single character, and <n> is the argument number, from 0
+ * through 9.  Returns a pointer to the beginning of the buffer.
+ */
+
+extern int strcmp(const char * /* a */, const char */* b */);
+/* Compares two strings, returning <0, ==0 or >0 according to whether a<b,
+ * a==b or a>b.
+ */
+
+extern int stricmp(const char */* a */, const char */* b */);
+/* Compares to strings in a case-insensitive manner.  Returns as strcmp.
+ */
+
+extern char *strbuffer(void);
+/* Returns the address of a 256-byte buffer.  There are two buffers, which
+ * are returned alternately.
+ */
+
+extern error *strerror(int /* num */, const char */* string */, ...);
+/* Builds an error in a buffer, as returned by strbuffer.  The string
+ * contains placeholders as for strsubst.
+ */
+
+/* --- Message routines --- */
+
+#define msgs_lookup(tag) __sapph_msgs_lookup(tag)
+extern char *msgs_lookup(const char */* tag */);
+/* Translates the given message tag into a string.  The tag has the form
+ * <name>[`:'<default>] -- if the name couldn't be found, and a default was
+ * specified, the default is returned.  We prefer to use plain tags, and
+ * put all messages in the messages file, unless it's possible that the
+ * messages haven't been loaded yet.
+ */
+
+#define msgs_error __sapph_msgs_error
+extern error *msgs_error(int /* num */, const char */* tag */, ...);
+/* Builds an error message, like strerror, except that the string is
+ * translated first.
+ */
+
+/* --- Memory allocation --- */
+
+extern void *malloc(size_t /* size */);
+/* Allocate a block of memory from a heap.  The block won't move around.
+ */
+
+#define free(p) __sapph_free(p)
+extern void free(void * /* p */);
+/* Free a block of memory allocated by malloc.
+ */
+
+#define alloc_error(x) __sapph_alloc_error(x)
+extern error *alloc_error(void);
+/* Return a pointer to an error about lack of memory.  This is used to
+ * build helpful error messages to send to the user.
+ */
+
+
+#define flex_alloc(a,s) __sapph_flex_alloc(a,s)
+extern void *flex_alloc(void */* a */, size_t /* s */);
+/* Allocate a block from the flex heap.  Returns a pointer to the block,
+ * or zero if no memory.
+ */
+
+#define flex_free(a) __sapph_flex_free(a)
+extern void flex_free(void */* a */);
+/* Frees a flex block.
+ */
+
+#define flex_size(a) __sapph_flex_size(a)
+extern size_t flex_size(void */* a */);
+/* Returns the size of a flex block.
+ */
+
+#define flex_extend(a,s) __sapph_flex_extend(a,s)
+extern void *flex_extend(void */* a */, size_t /* s */);
+/* Resize a block.  s is the new size.  Returns a pointer to the block, or
+ * zero.
+ */
+
+#define flex_midExtend(a, w, b) __sapph_flex_midExtend(a, w, b)
+extern void *flex_midExtend(void */* a */, size_t /* w */, int /* b */);
+/* Inserts b bytes in the block at offset w.  Returns a pointer to the block
+ * or zero.
+ */
+
+#define flex_save(p) __sapph_flex_save(p)
+extern void flex_save(void */* p */);
+/* Saves a pointer p on the relocation stack.
+ */
+
+#define flex_load(x) __sapph_flex_load(x)
+extern void *flex_load(void);
+/* Restores a pointer from the relocation stack.
+ */
+
+/*----- Sapphire routines -------------------------------------------------*/
+
+/* --- sapphire_init --- *
+ *
+ * On entry:   R0 == pointer to application name
+ *             R1 == application's workspace size
+ *             R2 == size of stack required
+ *
+ * On exit:    R10 == pointer to heap base
+ *             R11 == pointer to ScratchPad
+ *             R12 == pointer to application workspace
+ *             R13 == pointer to full descending stack
+ *             Other registers are corrupted
+ *
+ * Use:                Initialises the Sapphire kernel, sets up the memory map,
+ *             and allocates workspace for library and client units.  The
+ *             initialisation performed is fairly minimal; in particular,
+ *             the library units are not initialised -- you must call
+ *             sapphire_libInit for this to take place.  This allows you
+ *             to check command line arguments etc. before initialising
+ *             the Wimp.
+ */
+
+extern routine sapphire_init;
+
+/* --- sapphire_disable --- *
+ *
+ * On entry:   R0 == pointer to 0-terminated list of initialise routines
+ *
+ * On exit:    --
+ *
+ * Use:                Prevents the given initialisation routines from being called.
+ *             This is mainly useful in the dynamic-linking environment,
+ *             where all Sapphire units are normally active.  This routine
+ *             allows you to inactivate units which for example do not
+ *             have the resources they require, or use up unnecesary
+ *             memory.
+ */
+
+extern routine sapphire_disable;
+
+/* --- sapphire_libInit --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the Sapphire library and client units.
+ */
+
+extern routine sapphire_libInit;
+
+/* --- sapphire_doInit --- *
+ *
+ * On entry:   R0 == pointer to application name
+ *             R1 == client workspace size
+ *             R2 == requested stack size
+ *             R3 == pointer to initialisation table
+ *
+ * On exit:    R10 == base address of Sapphire heap
+ *             R11 == pointer to scratchpad and global data
+ *             R12 == pointer to client global workspace
+ *             R13 == pointer to a full descendion stack
+ *
+ * Use:                Performs initialisation of the Sapphire library and the
+ *             client's sections.  This is intended for use by the Sapphire
+ *             stub, while initialising the dynamically linked version of
+ *             Sapphire.
+ */
+
+extern routine sapphire_doInit;
+
+/* --- sapphire_doLibInit --- *
+ *
+ * On entry:   R0 == address of library initialisation table
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises all currently uninitialised library units.
+ */
+
+extern routine sapphire_doLibInit;
+
+/* --- sapphire_doDisable --- *
+ *
+ * On entry:   R0 == pointer to list of initialise routines to disable
+ *             R1 == pointer to initialisation table
+ *
+ * On exit:    --
+ *
+ * Use:                Prevents the given initialisation routines from being
+ *             called.  This is mainly useful in a dynamically linked
+ *             environment.
+ */
+
+extern routine sapphire_doDisable;
+
+/* --- sapphire_heapAddr --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R1 == pointer to the heap base (for passing to OS_Heap)
+ *
+ * Use:                Returns the address of the Sapphire heap.
+ */
+
+extern routine sapphire_heapAddr;
+
+/* --- sapphire_appName --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == pointer to application name (NULL terminated)
+ *
+ * Use:                Returns a pointer to the application's name.
+ */
+
+extern routine sapphire_appName;
+
+/* --- sapphire_resetStack --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R13 == stack pointer
+ *
+ * Use:                Resets R13 to point to the top of the stack.
+ */
+
+extern routine sapphire_resetStack;
+
+/* --- sapphire_global --- *
+ *
+ * On entry:   R0 == magic identifier for global variable
+ *             R1 == size of area required
+ *
+ * On exit:    R0 == pointer to area
+ *             CS if the area already exists, CC otherwise
+ *
+ * Use:                Locates (and creates if necessary) a `named' global area
+ *             which can be used for inter-section communication without
+ *             the necessity for dependencies.
+ *
+ *             There is a limit on the number of global areas allowed, but
+ *             this can be raised fairly easily if necessary.
+ *
+ *             If an area can't be created, an error is generated.
+ */
+
+extern routine sapphire_global;
+
+/* --- Data relative to R11 --- */
+
+#define sapph__R11 0
+
+#define sapph_scratchpad (sapph__R11-0)
+#define sapph_workspace (sapph__R11-4)
+#define sapph_stackBase (sapph__R11-8)
+#define sapph_heapBase (sapph__R11-12)
+#define sapph_appName (sapph__R11-16)
+#define sapph_clientWS (sapph__R11-20)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/saveWarn b/StraySrc/Libraries/Sapphire/csapph/h/saveWarn
new file mode 100644 (file)
index 0000000..4e85fe0
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * saveWarn.h
+ *
+ * [Generated from saveWarn, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __saveWarn_h
+#define __saveWarn_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  saveWarn
+ *  saveWarn_saved
+ *  saveWarn_close
+ */
+
+/* --- saveWarn --- *
+ *
+ * On entry:   R0 == estimated size of data
+ *             R1 == file type of the data
+ *             R2 == pointer to name of the file
+ *             R3 == pointer to handler block
+ *             R4 == value to pass to handlers in R10
+ *             R5 == value to pass to handlers in R12
+ *             R6 == flags (in bottom two bits)
+ *
+ * On exit:    --
+ *
+ * Use:                Displays a warning box allowing the user to save a modified
+ *             document.  The flags in R6 are as follows:
+ *
+ *             Bit 0   File is safe; don't give a warning
+ *             Bit 1   File's name is sensible; display it in the warning
+ *
+ *             The handler block is the same as that passed to saveAs (q.v.)
+ *             with an extra entry point on the very beginning, which is
+ *             expected to remove the document from memory.  This entry
+ *             point is not passed any arguments except for R10 and R12.
+ *
+ *             In order for the system to work, you must call various
+ *             saveWarn routines from your saveAs entry points:
+ *
+ *             saveWarn_saved from saEntry__success
+ *             saveWarn_close from saEntry__closed
+ */
+
+extern routine saveWarn;
+
+/* --- saveWarn_saved --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Informs saveWarn that the document has been saved.  If
+ *             saveWarn is not operating, this call is ignored.  You should
+ *             only call this routine if the document is *safe*, rather than
+ *             RAM transferred to another application, for example.
+ */
+
+extern routine saveWarn_saved;
+
+/* --- saveWarn_close --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Informs saveWarn that the save dialogue box has been closed.
+ *             If the document is now saved, then it is removed from
+ *             memory.
+ */
+
+extern routine saveWarn_close;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/screen b/StraySrc/Libraries/Sapphire/csapph/h/screen
new file mode 100644 (file)
index 0000000..ee5f389
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * screen.h
+ *
+ * [Generated from screen, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __screen_h
+#define __screen_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  screen_getInfo
+ *  screen_cache
+ *  screen_justChangedMode
+ *  screen_init
+ */
+
+/* --- screen_getInfo --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == pointer to screen information block
+ *
+ * Use:                This call returns a pointer to a block of information
+ *             about the current screen modes.  The format of this block
+ *             is defined above.
+ */
+
+extern routine screen_getInfo;
+
+/* --- screen_cache --- *
+ *
+ * On entry:   R12 points to workspace
+ *
+ * On exit:    --
+ *
+ * Use:                Caches screen information for the current mode.
+ */
+
+extern routine screen_cache;
+
+/* --- screen_justChangedMode --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    CS if last event was a mode change, CC otherwise
+ *
+ * Use:                Informs the caller if the last event was a mode change.
+ *             The system ignores open window requests when making it's
+ *             decision.
+ */
+
+extern routine screen_justChangedMode;
+
+/* --- screen_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the screen unit.
+ */
+
+extern routine screen_init;
+
+/*----- Data offsets ------------------------------------------------------*/
+
+#define screen_xEig 0
+#define screen_yEig 4
+#define screen_bpp 8
+#define screen_width 12
+#define screen_height 16
+#define screen_dx 20
+#define screen_dy 24
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/seh b/StraySrc/Libraries/Sapphire/csapph/h/seh
new file mode 100644 (file)
index 0000000..f0d92c8
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * seh.h
+ *
+ * [Generated from seh, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __seh_h
+#define __seh_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  seh_try
+ *  seh_unTry
+ *  seh_throw
+ *  seh_throwErrors
+ *  seh_setListBase
+ *  seh_init
+ */
+
+/* --- seh_try --- *
+ *
+ * On entry:   R0 == pointer to catch definition block
+ *
+ * On exit:    R13 dropped by a (small) amount
+ *
+ * Use:                Inserts an exception handler at the current position.
+ *             Exceptions are matched against those described in the catch
+ *             block.  If there is a handler for the exception, the
+ *             corresponding handler is called, and expected to resume
+ *             normally.  Otherwise the tidy-up routine is called and we
+ *             unwind the stack further to find an appropriate handler.
+ *
+ *             The catch block has the following format:
+ *
+ *             word    B to tidy-up routine
+ *             word    1st exception mask
+ *             word    1st B to catch routine
+ *             word    2nd exception mask
+ *             word    2nd B to catch routine
+ *             ...
+ *             word    0
+ *
+ *             An exception mask contains two halfwords.  Bits 16-31 are the
+ *             class to match, or -1 for all classes.  Bits 0-15 are the
+ *             subtype to match, or -1 for all subtypes.  You can do really
+ *             odd things if you set bits 16-31 to -1 and leave 0-15
+ *             matching specific subtypes -- do this at your own risk.
+ */
+
+extern routine seh_try;
+
+/* --- seh_unTry --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R13 moved to position before corresponding seh_try
+ *
+ * Use:                Removes the try block marker in the stack at the current
+ *             position.  Note that the stack will be unwound to where it
+ *             was when seh_try was called.
+ */
+
+extern routine seh_unTry;
+
+/* --- seh_throw --- *
+ *
+ * On entry:   R0 == exception to match
+ *             R1-R3 == useful bits of information
+ *
+ * On exit:    Doesn't return, unless you've done something /really/ odd
+ *
+ * Use:                Throws an exception.  The stack is unwound until we find
+ *             a handler which can cope.  If there is no handler, we abort
+ *             the program.
+ */
+
+extern routine seh_throw;
+
+/* --- seh_throwErrors --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Sets up an except-style error handler to throw errors
+ *             as SEH exceptions.
+ */
+
+extern routine seh_throwErrors;
+
+/* --- seh_setListBase --- *
+ *
+ * On entry:   R0 == pointer to try block list base, or 0 to use global
+ *
+ * On exit:    --
+ *
+ * Use:                Sets the try block list base.  This should only be used by
+ *             coroutine providers, like coRoutine and thread.
+ */
+
+extern routine seh_setListBase;
+
+/* --- seh_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises SEH's facilities.
+ */
+
+extern routine seh_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/sprite b/StraySrc/Libraries/Sapphire/csapph/h/sprite
new file mode 100644 (file)
index 0000000..00e799e
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * sprite.h
+ *
+ * [Generated from sprite, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __sprite_h
+#define __sprite_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  sprite_op
+ *  sprite_getTable
+ *  sprite_plot
+ */
+
+/* --- sprite_op --- *
+ *
+ * On entry:   R0,R2-R7 ==  SpriteOp parameters (R1 set up here)
+ *
+ * On exit:    Registers and flags altered as for the SpriteOp
+ *
+ * Use:                Performs an OS_SpriteOp with the given arguments, using
+ *             the appication's Sprites resource as the sprite area.
+ */
+
+extern routine sprite_op;
+
+/* --- sprite_getTable --- *
+ *
+ * On entry:   R0 == pointer to a sprite
+ *             R1 == pointer to buffer for translate table
+ *
+ * On exit:    --
+ *
+ * Use:                Creates a colour translate table for the given sprite in
+ *             the specified buffer.
+ *
+ *             If you have a sprite name but no pointer, use OS_SpriteOp
+ *             24 to find the pointer -- this will make further sprite ops
+ *             on the sprite much quicker.
+ */
+
+extern routine sprite_getTable;
+
+/* --- sprite_plot --- *
+ *
+ * On entry:   R0 == pointer to a sprite
+ *             R1 == x coordinate to plot at
+ *             R2 == y coordinate to plot at
+ *             R3 == pointer to scale block, or 0 for 1:1
+ *
+ * On exit:    CS if the sprite was plotted OK, else CC
+ *
+ * Use:                Plots a sprite on the screen.  The scaling refers to the
+ *             sprite proper: /this/ routine takes care of odd pixel
+ *             sizes and things, so sprites don't appear squashed or
+ *             stretched unless you really want them to.
+ *
+ *             We return C clear on exit if we couldn't plot the sprite;
+ *             typically this would be if the sprite's mode is undefined.
+ */
+
+extern routine sprite_plot;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/sqrt b/StraySrc/Libraries/Sapphire/csapph/h/sqrt
new file mode 100644 (file)
index 0000000..63b6ca1
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * sqrt.h
+ *
+ * [Generated from sqrt, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __sqrt_h
+#define __sqrt_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  sqrt
+ */
+
+/* --- sqrt --- *
+ *
+ * On entry:   R0 == value to square-root
+ *
+ * On exit:    R0 == the result
+ *
+ * Use:                Evaluates the square root of the number given.  This routine
+ *             is constructed from the information supplied by David Seal,
+ *             and is *extremely* fast.
+ */
+
+extern routine sqrt;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/string b/StraySrc/Libraries/Sapphire/csapph/h/string
new file mode 100644 (file)
index 0000000..0352a2a
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * string.h
+ *
+ * [Generated from string, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __string_h
+#define __string_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  str_cpy
+ *  str_len
+ *  str_cmp
+ *  str_icmp
+ *  str_index
+ *  str_match
+ *  str_subst
+ *  str_error
+ *  str_buffer
+ */
+
+/* --- str_cpy --- *
+ *
+ * On entry:   R0 == destination string
+ *             R1 == source string
+ *
+ * On exit:    R0 == pointer to terminator of destination
+ *
+ * Use:                Copies a string from one block to another.  It leaves the
+ *             destination pointer at the end of the string so that any
+ *             subsequent copies concatenate other bits on the same string.
+ *             Single characters can of course be appended with
+ *
+ *                     MOV     Rx,#&cc
+ *                     STRB    Rx,[R0],#1
+ */
+
+extern routine str_cpy;
+
+/* --- str_len --- *
+ *
+ * On entry:   R0 == pointer to string
+ *
+ * On exit:    R0 == length of the string
+ *
+ * Use:                Calculates the length of a string.
+ */
+
+extern routine str_len;
+
+/* --- str_cmp --- *
+ *
+ * On entry:   R0 == pointer to string A
+ *             R1 == pointer to string B
+ *
+ * On exit:    Flags as appropriate
+ *
+ * Use:                Case-sensitively compares two strings.  You can use the
+ *             normal ARM condition codes after the compare, so you can
+ *             treat this fairly much like a normal CMP.
+ */
+
+extern routine str_cmp;
+
+/* --- str_icmp --- *
+ *
+ * On entry:   R0 == pointer to string A
+ *             R1 == pointer to string B
+ *
+ * On exit:    Flags as appropriate
+ *
+ * Use:                As for str_cmp above, but case-insensitive.
+ */
+
+extern routine str_icmp;
+
+/* --- str_index --- *
+ *
+ * On entry:   R0 == pointer to name table
+ *             R1 == index into name table
+ *
+ * On exit:    CS if index good, and
+ *               R0 == address of R0th string in table
+ *             else CC and
+ *               R0 corrupted
+ *
+ * Use:                Finds an indexed string in a table.  The table consists of
+ *             ctrl-terminated strings, with no separation.  The table is
+ *             terminated by a zero-length entry.
+ */
+
+extern routine str_index;
+
+/* --- str_find --- *
+ *
+ * On entry:   R0 == pointer to name table
+ *             R1 == string to match in table
+ *
+ * On exit:    CS if match found, and
+ *               R0 == index of string matched
+ *             else CC and
+ *               R0 corrupted
+ *
+ * Use:                Looks up a string in a table.  The table consists of
+ *             ctrl-terminated strings, with no separation.  The table is
+ *             terminated by a zero-length entry.
+ */
+
+extern routine str_match;
+
+/* --- str_subst --- *
+ *
+ * On entry:   R0 == Pointer to skeleton
+ *             R1 == Pointer to output buffer
+ *             R2-R11 == Pointer to filler strings (optional)
+ *
+ * On exit:    R0 == Pointer to start of buffer
+ *             R1 == Pointer to terminating null
+ *
+ * Use:                Performs string substitution, filling in a skeleton string
+ *             containing placeholders with `filler' strings.  The
+ *             placeholders are actually rather powerful.  The syntax of
+ *             these is as follows:
+ *
+ *                     `%' [<type>] <digit>
+ *
+ *             (spaces are for clarity -- in fact you must not include
+ *             spaces in the format string.)
+ *
+ *             <digit> is any charater between `0' and `9'.  It refers to
+ *             registers R2-R11 (so `0' means R2, `5' is R7 etc.)  How the
+ *             value is interpreted is determined by <type>.
+ *
+ *             <type> is one of:
+ *
+ *             s       String.  This is the default.  The register is
+ *                     considered to be a pointer to an ASCII string
+ *                     (control terminated).
+ *
+ *             i       Integer.  The (signed) decimal representation is
+ *                     inserted.  Leading zeros are suppressed.
+ *
+ *             x       Hex fullword.  The hexadecimal representation of the
+ *                     register is inserted.  Leading zeros are included.
+ *
+ *             b       Hex byte.  The hexadecimal representation of the
+ *                     least significant byte is inserted.  Leading zeros
+ *                     are included.
+ *
+ *             c       Character.  The ASCII character corresponding to the
+ *                     least significant byte is inserted.
+ */
+
+extern routine str_subst;
+
+/* --- str_error --- *
+ *
+ * On entry:   R0 == Pointer to skeleton
+ *             R2-R11 == Pointers to fillin strings
+ *
+ * On exit:    R0 == Pointer to error in buffer
+ *             R1 == Pointer to terminator
+ *
+ * Use:                Fills in an error skeleton (containing a 4 byte error number
+ *             and a control terminated skeleton string as for str_subst)
+ *             and returns the address of the filled in error block.  The
+ *             error block is stored in a buffer obtained from str_buffer.
+ *
+ *             Filler strings may be held in the scratchpad.
+ */
+
+extern routine str_error;
+
+/* --- str_buffer --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R1 == pointer to the next free buffer
+ *
+ * Use:                Returns a pointer to a 256-byte buffer.  There are at present
+ *             2 buffers, which are returned alternately.
+ */
+
+extern routine str_buffer;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/subAlloc b/StraySrc/Libraries/Sapphire/csapph/h/subAlloc
new file mode 100644 (file)
index 0000000..7637c2a
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * subAlloc.h
+ *
+ * [Generated from subAlloc, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __subAlloc_h
+#define __subAlloc_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  sub_alloc
+ *  sub_free
+ *  sub_init
+ */
+
+/* --- sub_alloc --- *
+ *
+ * On entry:   R0 == size of block to allocate
+ *
+ * On exit:    R0 == pointer to block allocated
+ *             May return an error
+ *
+ * Use:                Allocates a block of the size specified, typically very
+ *             quickly indeed.
+ *
+ *             If the size is not one of those supported (currently
+ *             supported sizes are 8-40 inclusive in 4 byte increments),
+ *             the behaviour is undefined (but very predictable).
+ */
+
+extern routine sub_alloc;
+
+/* --- sub_free --- *
+ *
+ * On entry:   R0 == pointer to block
+ *             R1 == size of the block
+ *
+ * On exit:    --
+ *
+ * Use:                Frees a block allocated using sub_alloc.
+ */
+
+extern routine sub_free;
+
+/* --- sub_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the suballocation system for use.
+ */
+
+extern routine sub_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/template b/StraySrc/Libraries/Sapphire/csapph/h/template
new file mode 100644 (file)
index 0000000..034b1d1
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * template.h
+ *
+ * [Generated from template, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __template_h
+#define __template_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  template_find
+ *  template_copy
+ *  template_embedded
+ *  template_free
+ *  template_load
+ *  template_init
+ */
+
+/* --- template_find --- *
+ *
+ * On entry:   R0 == pointer to name to match
+ *
+ * On exit:    R0 == pointer to window definition if found
+ *             May return an error
+ *
+ * Use:                Locates a template in the list and gives you a pointer to
+ *             the corresponding window defintion.  You may update the
+ *             definition to store an updated window state if you really
+ *             want to.
+ */
+
+extern routine template_find;
+
+/* --- template_copy --- *
+ *
+ * On entry:   R0 == pointer to name to match
+ *
+ * On exit:    R0 == pointer to copy of a window definition
+ *             May return an error
+ *
+ * Use:                Returns a copy of a window template (for the use of the
+ *             dialogue box system mainly), including all indirected data
+ *             set up properly and everything.  The copy is writable.  To
+ *             get rid of the copy, call template_free.
+ */
+
+extern routine template_copy;
+
+/* --- template_embedded --- *
+ *
+ * On entry:   R0 == pointer to embedded template definition
+ *
+ * On exit:    R0 == pointer to copy (as for template_copy)
+ *
+ * Use:                Extracts an embedded template into a template block.
+ *             Embedded templates can be generated using the templAOF
+ *             program, and then linked into your application.
+ */
+
+extern routine template_embedded;
+
+/* --- template_free --- *
+ *
+ * On entry:   R0 == pointer to block allocated with template_copy
+ *
+ * On exit:    --
+ *
+ * Use:                Frees a template copy created using template_copy.
+ */
+
+extern routine template_free;
+
+/* --- template_load --- *
+ *
+ * On entry:   R0 == pointer to name of template file to load
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Loads the specified template file, and adds its window
+ *             definitions into the template list so they can be used when
+ *             creating dialogue boxes or windows.
+ *
+ *             If the templates can't be loaded (e.g. there isn't enough
+ *             memory) an error is generated (and can be caught using the
+ *             standard Sapphire except mechanism).
+ */
+
+extern routine template_load;
+
+/* --- template_init --- *
+ *
+ * On entry:   R0 == pointer to application name
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the template list and font array, and loads the
+ *             `Templates' resource file.
+ */
+
+extern routine template_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/thread b/StraySrc/Libraries/Sapphire/csapph/h/thread
new file mode 100644 (file)
index 0000000..e731bad
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * thread.h
+ *
+ * [Generated from thread, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __thread_h
+#define __thread_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  thread_create
+ *  thread_setPriority
+ *  thread_setTimeSlice
+ *  thread_destroy
+ *  thread_suspend
+ *  thread_resume
+ *  thread_yield
+ *  thread_createSem
+ *  thread_destroySem
+ *  thread_threaded
+ *  thread_wait
+ *  thread_signal
+ *  thread_init
+ *  thread_enterCrit
+ *  thread_leaveCrit
+ *  thread_errorHandler
+ */
+
+/* --- thread_create --- *
+ *
+ * On entry:   R0 == size of stack to allocate, or 0 for a default
+ *             R1 == pointer to thread routine
+ *             R2 == workspace pointer to pass in R10
+ *             R3 == workspace pointer to pass in R12
+ *
+ * On exit:    R0 == thread handle for the thread
+ *             May return an error
+ *
+ * Use:                Creates a new thread running `in the background' (i.e. over
+ *             idle events).
+ *
+ *             The thread is passed control with the registers R10 and R12
+ *             set up from R1 and R2 passed to this routine and R13 pointing
+ *             to the top of a stack chunk.  R0 on entry contains the
+ *             thread's handle.  The thread is passed the scratchpad
+ *             address (in R11).  The values of other registers are
+ *             indeterminate and must not be relied upon.
+ *
+ *             The default stack size for a new thread is 1K, although this
+ *             may change in future.
+ *
+ *             The thread may exit by calling thread_destroy or by
+ *             returning in the normal way.
+ */
+
+extern routine thread_create;
+
+/* --- thread_setPriority --- *
+ *
+ * On entry:   R0 == thread handle
+ *             R1 == new priority to set
+ *
+ * On exit:    --
+ *
+ * Use:                Changes the priority of a thread.  The priority if a thread
+ *             is a signed integer.  The highest priority thread is the one
+ *             which runs.  If more than one thread has maximum priority,
+ *             they are run in a cyclical order.
+ */
+
+extern routine thread_setPriority;
+
+/* --- thread_setTimeSlice --- *
+ *
+ * On entry:   R0 == thread handle
+ *             R1 == new timeslice size, in centiseconds
+ *
+ * On exit:    --
+ *
+ * Use:                Changes a thread's timeslice size.  Specify 0 to indicate
+ *             that thread shouldn't be pre-empted.
+ */
+
+extern routine thread_setTimeSlice;
+
+/* --- thread_destroy --- *
+ *
+ * On entry:   R0 == thread handle to destroy, if not executing a thread
+ *
+ * On exit:    --
+ *
+ * Use:                Destroys either the current thread or a thread with the
+ *             the given handle if no thread is executing currently.  You
+ *             can't destroy an arbitrary thread while running in one.
+ *
+ *             If a thread is waiting for a semaphore, it is removed from
+ *             the waiting list.
+ */
+
+extern routine thread_destroy;
+
+/* --- thread_suspend --- *
+ *
+ * On entry:   R0 == thread handle, or 0 for the current thread
+ *
+ * On exit:    --
+ *
+ * Use:                Suspends a thread's execution.  If a thread is currently
+ *             running, that thread is suspended.  Otherwise, any thread
+ *             may be suspended.
+ *
+ *             If the thread is currently claiming semaphores, the
+ *             semaphores are not released, because we don't whether the
+ *             system is in a fit state for this.
+ *
+ *             Thread suspensions are counted.  i.e. if you suspend a thread
+ *             5 times, you have to resume it 5 times for it to become
+ *             active again.
+ */
+
+extern routine thread_suspend;
+
+/* --- thread_resume --- *
+ *
+ * On entry:   R0 == thread handle
+ *
+ * On exit:    --
+ *
+ * Use:                Allows a suspended thread to continue operations.  If you
+ *             resume a thread more times than it has been suspended,
+ *             any excess resumes are ignored.  You can't resume a thread
+ *             to stop it being blocked by a semaphore.
+ */
+
+extern routine thread_resume;
+
+/* --- thread_yield --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Pauses the thread for a while.  You only need to use this
+ *             call if you have stopped the current thread from being
+ *             timesliced.
+ */
+
+extern routine thread_yield;
+
+/* --- thread_createSem --- *
+ *
+ * On entry:   R0 == initial value for semaphore (0 for counter, 1 for
+ *                   mutex)
+ *
+ * On exit:    R0 == semaphore handle and V clear if all went well
+ *             R0 == pointer to error and V set if something went wrong
+ *
+ * Use:                Creates a semaphore with the given initial counter value.
+ *
+ *             The semaphore can be used to provide serialised access to
+ *             a resource by initialising its value to 1 and performing the
+ *             following:
+ *
+ *             thread_wait(mySemaphore)
+ *             //
+ *             // Do things with the resource
+ *             //
+ *             thread_signal(mySemaphore)
+ *
+ *             Or you can inform a thread that it has items in its input
+ *             queue by having the following in the thread code:
+ *
+ *             while true
+ *               thread_wait(theSemaphore)
+ *               getFromQueue(myQueue,item)
+ *               process(item)
+ *             endWhile
+ *
+ *             and when inserting queue items:
+ *
+ *             addToQueue(item)
+ *             thread_signal(theSemaphore)
+ *
+ *             It is distinctly possible that input queue management will
+ *             be introduced in a separate Sapphire module.
+ */
+
+extern routine thread_createSem;
+
+/* --- thread_destroySem --- *
+ *
+ * On entry:   R0 == semaphore handle
+ *
+ * On exit:    --
+ *
+ * Use:                Destroys a semaphore when it's no use any more.  If threads
+ *             are waiting for it, an error is generated.
+ */
+
+extern routine thread_destroySem;
+
+/* --- thread_threaded --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    CS if currently running a thread, CC otherwise
+ *
+ * Use:                Informs the caller whether a thread is currently executing.
+ */
+
+extern routine thread_threaded;
+
+/* --- thread_wait --- *
+ *
+ * On entry:   R0 == semaphore handle
+ *
+ * On exit:    If successful, R0 preserved and V clear.
+ *             If failed, R0 == pointer to error block and V set
+ *
+ * Use:                Waits on a sempahore.  The algorithm actually is as follows:
+ *
+ *             if semaphore.counter == 0 then
+ *               addToWaitingList(semaphore,currentThread)
+ *               suspend(currentThread)
+ *             else
+ *               semaphore.counter -= 1
+ *             endIf
+ *
+ *             See thread_createSem for suggestions on how to make use of
+ *             semaphores.
+ */
+
+extern routine thread_wait;
+
+/* --- thread_signal --- *
+ *
+ * On entry:   R0 == semaphore handle
+ *
+ * On exit:    --
+ *
+ * Use:                Increments a semaphore's counter if no threads are waiting
+ *             for it, or releases a thread waiting for the semaphore.
+ *
+ *             The actual algorithm is shown below:
+ *
+ *             if semaphore.waitingList != 0 then
+ *               thread = removeFromWaitingList(semaphore)
+ *               unSuspend(thread)
+ *             else
+ *               semaphore.counter += 1;
+ *             endif
+ *
+ *             See thread_createSem for suggestions on how to make use of
+ *             semaphores.
+ */
+
+extern routine thread_signal;
+
+/* --- thread_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the thread system for use.
+ */
+
+extern routine thread_init;
+
+/* --- thread_enterCrit --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Declares that the current thread is about to enter a
+ *             critical section and must not be interrupted.
+ */
+
+extern routine thread_enterCrit;
+
+/* --- thread_leaveCrit --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Declares that the current thread has left the critical
+ *             section and can be interrupted again.
+ */
+
+extern routine thread_leaveCrit;
+
+/* --- thread_errorHandler --- *
+ *
+ * On entry:   R0 == pointer to routine to call
+ *             R1 == R12 value to call with
+ *             R2 == R13 value to call with
+ *
+ * On exit:    --
+ *
+ * Use:                Sets up the error handler for a thread.
+ */
+
+extern routine thread_errorHandler;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/tms b/StraySrc/Libraries/Sapphire/csapph/h/tms
new file mode 100644 (file)
index 0000000..8fd7b12
--- /dev/null
@@ -0,0 +1,380 @@
+pendent extension colours.
+          R8=Window block to read from / 0 for default (!Config) settings.
+       \X R0=colour value read / old value if writing it. This is of the
+             form &BBGGRRZZ as above.
+
+Zap_FindInput
+This call works out the current position of the 'input focus' in a window. If
+the input caret is in this window then it returns it's offset. Otherwise it
+returns the 'point' position (usually marked by an empty square).
+       \E R8/R9
+       \X R0=most suitable offset to insert data.
+
+Zap_ClipCache
+This call moves the cache reference point (w_cline/coff/clogl etc) to a given
+point (using e_clnoff).
+       \E R0=Offset in line to move the cache reference point to. R8/R9
+
+Zap_ModeData
+This call reads or write the mode dependant options that Zap handles
+automatically for you. See also Zap_ModeColour. Currently there is only one
+word per mode storing the width and things like whether auto-indent is on or
+not. You should use this call with R8=0 to write sensible default values if
+your mode starts up and finds its mode word is zero. If you don't then the
+default Text mode values will be used.
+       \E R0=value to write / -1 to read
+          R1=mode number
+          R2=variable number to read write
+          R8=window concerned / 0 for the default (!Config) settings.
+       \X R0=variable value if read / old value if written
+       Variables num:  0       b0-b15  stores the "width" for this mode
+                               b16     auto indent bit (b16 of w_format)
+                               b17     auto width bit (b6 of w_flags)
+                               b18     strip spaces bit (b18 of w_format)
+                               b19-b21 tab mode bits (b9-b11 of w_flags)
+                                       b19-b20 0=Unix 1=Edit 2=Coltab
+                                       b21=insert tabs as spaces
+                               b22     hex entry mode bit (b5 of w_flags)
+                               b23     overwrite bit (b1 of w_flags)
+                               b24-b31 display bits (b8-b15 of w_format)
+                                       b24=line numbers shown
+                                       b25=line numbers as lines (not addr)
+                                       b26=line numbers in hex
+                                       b27=logical line nums (not physical)
+                                       b28-29 0=no tabs 1=spaces 2=> 3=->
+                                       b30=line edit paradigm
+                                       b31=non standard editing
+                       1       b0-b2   Line number width
+                               b3      Line number colons
+                               b4      Internal use : font sub-styles off
+                               b5      Infinite window wrap
+                               b6      Use line selection paradigm
+                               b7      Spell-as-you-type
+                               b8      Big endian          (b17 of w_format)
+                               b9      Reserved
+                               b10     Reserved
+                               b11     Reserved
+                               b12     Set if linewrap mode on (b26 w_flags)
+                               b13     Set if wordwrap mode on (b13 w_flags)
+                               b14     Reserved
+                               b15     Reserved
+                               b21     Free mouse clicks   (b21 of w_format)
+                               b22     Auto soft wrap      (b22 of w_format)
+                               b23     Confined cursor U/D (b23 of w_format)
+                               b24     Confined cursor ->  (b24 of w_format)
+                               b25     Smart shift-cursor  (b25 of w_format)
+                               b26     Window-wrap         (b26 of w_format)
+                               b27     Soft-wrap           (b27 of w_format)
+                               ...other bits reserved...
+                       2+      reserved.
+
+Zap_WhichMode
+This call decides which mode a given file should be displayed in.
+       \E R0=load address of file (containing the filetype)
+          R1=filename pointer / 0 if not known
+             b31=flag to determine the meaning of R10 on exit
+       \X R0=address of a data block of info about this file mode. 
+          R10=If b31 of R1 was clear on entry then this is the mode number
+              of the default mode the file is loaded into (the mode is
+              loaded if necessary). If is was set then this is a pointer
+              to the mode name (mode not necessarily loaded).
+
+Zap_ModeNumber
+This calls turns a mode name (given by a string) into a mode number. The mode
+is loaded if not already resident in memory.
+       \E R0=mode name string terminated by <= space (&20)
+       \X R0=mode number or -1 if not found.
+
+Zap_SendDataSave
+This call initiates the save protocol, saving data to another window or
+application via RAM transfer or WimpScrap. It sends the data_save message and
+all replies are handled automatically.
+       \E R2=proposed file/leaf name of the data (or 0 to use the file's)
+          R3=destination window handle or task handle
+          R4=destination icon handle (if R3=-2)
+          R5/R6=destination mouse coords (if applicable)
+          R7=routine to call after save finished (or 0 if none).
+          R8/R9=R8<>0 => Save whole file R8=window block R9=file block
+                R8=0  => Save currently selected region.
+                (or set b1 of R10 to save an arbitrary region).
+          R10=b0-b15 flags:
+              b0 set => External edit flag. In this case R3=ext edit
+                        job handle and R4=ext edit task handle and
+                        external edit message sent instead.
+              b1 set => R8=start address of data to save
+                        R9=size of the data to save
+                        b16-b31 of R10=filetype of data to save.
+              b16-b31 = extra data (see b1)
+          R11=data to pass to routine in R7 (if used).
+       \X Data transfer protocol initiated.
+       Sub pointed to by R7 is called with R11 as passed above and should
+       preserve R1+ as usual.
+
+Zap_Warning
+Warns the user without generating an error. This opens a window with the
+given message and pauses for the message to be seen before returning. Wimp
+Poll is not called.
+       \E R0=warning message
+          R1=time to leave message open in cs (0 for default delay)
+             + flags:
+               b31 => Don't beep when opening the window
+          R8/R9=window in which to show the warning.
+
+Zap_AllWindow
+Calls a given subroutine once for each valid Zap window. See also
+Zap_EachWindow.
+       \E R0-R7=arguments to pass to the sub
+          R10=address of the sub to call (which must preserve all registers
+              except R0, and is called once for each window with R8/R9
+              set up to be that window).
+
+Zap_ReadMenu
+Converts a text file of the same format of Zap's 'Menu' file into a Zap menu
+structure.
+       \E R0=start of a zero terminated menu text file (stored in memory)
+       \X R0=pointer to heap block containing the following information
+               #0 Number of valid menu handles for this file (first
+                  number appearing in the file)
+               #4 Pointer to the menu structure (in Zap-Wimp format) for
+                  handle 0 (or 0 if handle 0 not used)
+               #8 Pointer to structure for handle 1
+               #12 Pointer to structure for handle 2 etc.
+
+Zap_LoadMenu
+Converts a text menu file to a Zap menu structure.
+       \E R0=pointer to filename of the menu file
+       \X R0=list of menu handles as for Zap_ReadMenu
+
+Zap_OpenMenu
+Opens a menu on the screen. The menu structure is handled automatically once
+it has been opened.
+       \E R1=pointer to Zap-Wimp menu structure
+          R2=mouse x to open at
+          R3=mouse y to open at
+          R8/R9=window the menu is being opened on or 0's for none (eg the
+                iconbar menu).
+
+Zap_CallBack
+Schedules a subroutine to be called again at a certain time but using wimp
+null events.
+       \E R1=(earliest) monotonic time to call back at (>0)
+             or -(smallest delay before calling back) =< 0.
+          R2=address of routine to call.
+          R3=data to pass to the routine in R11.
+       The routine pointed to by R2 has conditions:
+        \E R1=current time R11=value passed in R3
+        \X (must save R1+ as usual)
+
+Zap_DragBox
+Starts a wimp drag box making sure you get called when it's finished.
+       \E R0=b0 set if you wish to be called repeatedly during the drag
+             b1+ reserved (set to 0)
+          R1=drag box block to be passed to Wimp_DragBox
+          R2=address of routine to call.
+          R3=data to pass to the routine in R11.
+       The routine pointed to by R2 has conditions:
+        \E R0=reason code 1=drag in progress 2=drag has just finished
+           R1=drag box posn as returned by wimp if R0=2
+           R11=value passed in R3
+        \X (must save R1+ as usual)
+
+Zap_SendMessage
+Sends a wimp message and logs the message number (my_ref) so that any reply
+can be forwarded to you. The message reference is held for at least a minute
+and only deleted on a null event.
+ E R0=b0-b27 message action number (to go in R1,#16)
+      b28    set if you are interested in the reply.
+      b29    set if you want to be called when message deleted
+      b30-31 00 => Just send the message (with code 17)
+            01 => Just acknowledge the message (with code 19)
+            10 => Send the message recorded (with code 18) and call the
+                  reply code if the message replied to.
+            11 => Send the message recorded (with code 18) and call the
+                  reply code if the message replied to or bounces.
+   R1=message block
+   R2=dest task handle/window handle
+   R3=b31 clear => This is the message length (is rounded up to next word)
+      b31 set  => This is the offset of a string ending the message.
+   R4=icon handle if R2=-2 (iconbar) [not used otherwise]
+   R5=address of routine to call when message replied to [if b28 of R0]
+      (zero as a value means that you want any replies to be dealt with
+       as if they were normal messages and not a reply)
+   R6=private word to pass to routine on a reply [if b28 of R0]
+ X The message is sent as an original message. Hence the my_ref, length
+   and message action fields are filled in for you. R0=task handle of the
+   dest task (R2 on exit from Wimp_SendMessage)
+       Routine in R5 called with:
+               ;E R0=message type
+                       0 => message being removed from log list (see b29)
+                       17 => message replied to as normal
+                       19 => message bounced
+                  R1=message block
+                  R2=message number (R1!16) R11=private word R12=Zap's etc
+               ;X You can corrupt R0-R11 if R0=17,19
+                  You should save R1-R11 if R0=0
+
+Zap_Reply
+Replies to a message. It copies my_ref to your_ref for you can reads the task
+handle of the task to reply to from the message block. The length word is
+assumed to be unchanged.
+ E R0=message action number (as for SendMessage)
+   R1=message block (with ref etc)
+   R5/R6=routine to handle the reply if b28 of R0 (as for SendMessage)
+
+Zap_Extend
+Changes the size of a heap block, making it smaller or bigger as for OS_Heap
+with the extend action code.
+ \E R0=pointer to the heap block R1=signed change in the size
+ \X R0=new heap block pointer (it may have moved)
+
+Zap_ModeColourNum
+Reads/writes the size of the colour palette used by a given mode. Maximum
+size of a palette is currently 256 colours. Use R8=0 to read the default
+values. NB If you enlarge the palette then please write some sensible values
+for the new entries!
+ \E R0=new size of palette (in number of colours) / -1 to read
+    R1=mode number R8/R9=window or R8=0 for the default options.
+ \X R0=old size / read size.
+
+Zap_CreateThrowback
+Creates a throwback buffer ready for lines being inserted by Zap_Throwback.
+ ;E R0=suggested width of window / 0 to use default width
+ ;X R0=window offset of window R8/R9=newly created throwback window
+
+Zap_Throwback
+Inserts a line in a throwback file for you.
+ \E R0=file offset or line number of line with info on it
+       set b31 to suppress this being printed automatically.
+    R1=filename (of the file that R0 is an offset in)
+    R2=information string to print after the line number (eg "Bad syntax")
+    R3=string to precede filename  (eg "Errors in file:")
+    R4=file offset of linked file / -1 if may not be loaded
+    R5=flags to use for the new entry (see f_links,#12)
+    R6=string to precede new info block (eg "Line num  Error")
+    R7=string to go after filename (eg 10,"Search string: fred")
+    R8/R9=throwback window to add entry to
+ \X Throwback entry added and new title block given if file (or flags)
+    have changed KB #
+    The line number field is 10 characters wide if not suppressed.
+
+Zap_TestModeName
+This calls determines whether or not a given mode is loaded. It returns
+the mode number of the given mode or -1 if the mode is not loaded.
+       \E R0=mode name string terminated by <= space (&20)
+       \X R0=mode number or -1 if not loaded.
+
+Zap_UpdateArea
+Forces an immediate redraw of a window area. The area in given in x,y
+character col, row coordinates.
+       \E R1=redraw block (as for Wimp but in character coords -
+             ie window handle, min x col, min y row, max x col, max y row)
+          R8/R9 = window
+       \X Coordinates in R1 changed to OS coords and window updated
+
+Zap_UpdateWindow
+Forces an immediate redraw of a window area. Entry and exit as for
+Zap_UpdateArea except that coordinates are given in Window work area
+OS coords. (Internally UpdateArea calls UpdateWindow after coordinate
+conversion).
+
+Zap_UpdateWholeWindow
+Force immediate redraw of the whole window
+       \E R8/R9 = window
+
+Zap_AllFiles
+Calls a given subroutine once for each valid Zap file. See also
+Zap_AllWindows and Zap_EachWindow.
+       \E R0-R7=arguments to pass to the sub
+          R10=address of the sub to call (which must preserve all registers
+              except R0, and is called once for each file with R9 set up
+              and R8 = 0.
+
+Zap_ReadValidateCommand
+Translates a string into an executable block of command information.
+        E R10=pointer to string terminated by <&20
+        X R0=-1 => args invalid (only tested if command loaded)
+             0  => all ok
+             1  => args valid for keymaps only (uses n form)
+          R1=parameter
+          R6=parameter type 0=none 1=num 2=usekeynum 3=stringblock 4=data
+          R7=command address
+          R10 updated to next non-white space which is not a ':'
+          CS if an external module has been loaded as a consequence
+          CC otherwise.
+          Error is generated if the command cannot be found.
+          (String of commands concatenated to a single Multicommand)
+          (:<return> skipped so can have multiple lines)
+
+Zap_ProcessKeyCommand
+Calls a command using the same routine as used when a command is bound to a
+key.  For use mainly with Zap_ReadValidateCommand.
+        \E R0=data => The byte/word if mode 1/2 and ptr to data if mode 3+
+           R2=call type with learn flag (usually 0)
+           R7=command address
+           R8-R10=window/file/cursor or 0
+\X Command called once with R1=1
+
+Zap_ReturnWord
+Calls the text mode e_returnword entry with given delimiters. This is mostly
+of use to commands such as SelectUntil.
+       \E R0=flags
+             b0 => list are non-delimiters not delimiters
+             b1 => control characters form an implicit list
+             b2 => control characters are non-delimiters not delimiters
+          R1=list
+       \X R0=file offset
+          R1=length
+
+Zap_DoReplaceArea
+Acts like Zap_ReplaceArea, only does not involve the mode, i.e. it uses
+Zap_DoCommand, rather than Zap_Command.
+       \E R1=file offset of original data
+          R2=length of original data
+          R3=address of replacement data
+          R4=length of replacement data R9
+Calls Zap_ReplaceArea with R8=0
+
+Zap_LogicalLine
+Replaces e_clnlog in a manner which allows processing of the returned
+parameters.  Entry and exit conditions are exactly as for e_clnlog:
+       \E R0=logical line number R8/R9
+       \X R0=file offset of line start
+          R1=physical line number
+
+Zap_PhysicalLine
+Replaces e_clnphy in a manner which allows processing of the returned
+parameters.  Entry and exit conditions are exactly as for e_clnphy:
+       \E R0=physical line number R8/R9
+       \X R0=file offset of line start
+          R1=logical line number
+
+Zap_OffsetLine
+Replaces e_clnoff in a manner which allows processing of the returned
+parameters.  Entry and exit conditions are exactly as for e_clnoff:
+       \E R0=file offset R8/R9
+       \X R0=physical line number
+          R1=file offset of physical line start
+          R2=logical line number
+
+Zap_NextLine
+Replaces e_nextline in a manner which allows processing of the returned
+parameters.  Entry and exit conditions are exactly as for e_nextline:
+       \E R0=file offset of first 'shiftable' character
+          R1=signed change in file offset of this character R8/R9
+       \X R0=file offset of first 'shiftable' line
+          R1=physical line number of this line #
+          You must preserve the split offset and split size of the file.
+
+Note that in the above four calls, the mode called is the mode specified by
+the window block in R8.  Calling the entry points of arbitrary modes is
+currently only possible with this mechanism by manually poking the mode
+number in temporarily.
+\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\ 5\eÀ\83Øÿ\1f\8bó\8bú]Ë\0U\8bì\8b×\8bÞ\1eÅv
+\8bþ\8cØ\8eÀ3À¹ÿÿò®÷ÑÄ~\ 6\8bÇt\ 4¥Ië\ 6¨\ 1t\ 2¤IÑéó¥\13Éó¤\8bó\8bú\1f\8cÂ]ËU\8bì\8b×\8bÞ\1eÄ~\ 63À¹ÿÿò®\8duÿÄ~
+¹ÿÿò®÷Ñt\ 3+ùA+ù\8cÀ\8eØ\8eF\b\87þ\8bF\ 6\vÉu\ 5¥IIë\b÷Æ\ 1\0t\ 2¤IÑéó¥\13Éó¤\8bó\8bú\1f\8cÂ]ËU\8bì\8bN\fã8WÄ~\ 6\8b×÷Út\f\eÛ#Ó\ 3Ñ\87Ñ+Ñ\8bF
+\8aàÑéó«\13Éóª\87Ñã\10\8cÃ\81ï\ 3\8eÃÑéó«\13Éóª_\8bF\ 6\8bV\b]ËU\8bì\83ì VW\16\a¹\10\0\8d~àó«\1e\aÅv
+Àt\14\8bø\8bȰ\ 1\80á\aÒà±\ 3Óï\bCàëçÅv\ 6\8cØ\vÆu\ 5&Å6\94_¬%ÿ\0u\ fN&\896\94_&\8c\1e\96_\8eØëH\8bø\8bȰ\ 1\80á\aÒà±\ 3Óï"Càu×\8dDÿ&£\94_&\8c\1e\96_¬%ÿ\0u\ 5\8dDÿë\18\8bø\8bȰ\ 1\80á\aÒà±\ 3Óï"Càtá\88dÿ\96&\87\ 6\94_\8cÚ\ 6\1f_^\8bå]Ë\0U\8bì\83ì\ 2VW\1eÄ~
+\ 6\1f3À¹ÿÿò®÷Ñu\ 1Iã>I\89NþÄ~\ 6\8bß3À¹ÿÿò®÷Ñu\ 1I\8bÑ+Vþv)\8bû\8bv
\8bû\8bÊò®u\e\8bÑ\8bß\8bNþã\ 4ó¦uç\8dGÿ\8cÂë
+ÄF\ 6\8cÂë\ 3\99\1f_^\8bå]Ë\0U\8bì\8bN\ e
\ No newline at end of file
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/transWin b/StraySrc/Libraries/Sapphire/csapph/h/transWin
new file mode 100644 (file)
index 0000000..d64be97
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * transWin.h
+ *
+ * [Generated from transWin, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __transWin_h
+#define __transWin_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  transWin_subWaiting
+ *  transWin_openSub
+ *  transWin_register
+ *  transWin_close
+ *  transWin_init
+ */
+
+/* --- transWin_subWaiting --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    CS if a submenu is waiting to be opened, CC otherwise
+ *
+ * Use:                Informs the caller whether the menu system is waiting for
+ *             a submenu to be attached.
+ */
+
+extern routine transWin_subWaiting;
+
+/* --- transWin_openSub --- *
+ *
+ * On entry:   R0 == window handle to open
+ *
+ * On exit:    --
+ *
+ * Use:                Opens the given window as a submenu.
+ */
+
+extern routine transWin_openSub;
+
+/* --- transWin_register --- *
+ *
+ * On entry:   R0 == window handle to register
+ *
+ * On exit:    --
+ *
+ * Use:                Registers a window as being the current transient window.
+ */
+
+extern routine transWin_register;
+
+/* --- transWin_close --- *
+ *
+ * On entry:   R0 == window handle to close
+ *
+ * On exit:    --
+ *
+ * Use:                Closes the current transient window.
+ */
+
+extern routine transWin_close;
+
+/* --- transWin_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the transWin system.
+ */
+
+extern routine transWin_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/tspr b/StraySrc/Libraries/Sapphire/csapph/h/tspr
new file mode 100644 (file)
index 0000000..ea59906
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * tspr.h
+ *
+ * [Generated from tspr, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __tspr_h
+#define __tspr_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  tspr_getSprAddr
+ *  tspr_borderWidths
+ *  tspr_adjustBox
+ */
+
+/* --- tspr_getSprAddr --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == pointer to tool sprites, or 0 if none
+ *
+ * Use:                Returns a pointer to the toolsprites. If the user is using
+ *             RISC OS 2, or there are no toolsprites defined, then
+ *             0 is returned.
+ */
+
+extern routine tspr_getSprAddr;
+
+/* --- tspr_borderWidths --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == title bar height
+ *             R1 == vertical scroll bar width
+ *             R2 == horizontal scroll bar height
+ *
+ * Use:                Return the width of window tools by looking at the
+ *             sprites associated with them, rather than creating
+ *             a temporary window.
+ */
+
+extern routine tspr_borderWidths;
+
+/* --- tspr_adjustBox --- *
+ *
+ * On entry:   R1 == pointer to Wimp_OpenWindow block to modify
+ *
+ * On exit:    Block updated in place
+ *
+ * Use:                Updates the open block to ensure that the window is opened
+ *             on the screen.
+ */
+
+extern routine tspr_adjustBox;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/viewer b/StraySrc/Libraries/Sapphire/csapph/h/viewer
new file mode 100644 (file)
index 0000000..3d72d9e
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * viewer.h
+ *
+ * [Generated from viewer, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __viewer_h
+#define __viewer_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  viewer_create
+ *  viewer_destroy
+ *  viewer_open
+ *  viewer_close
+ *  viewer_eventHandler
+ *  viewer_select
+ *  viewer_isSelected
+ *  viewer_selectAll
+ *  viewer_click
+ *  viewer_dragSelection
+ *  viewer_window
+ *  viewer_update
+ *  viewer_setTitle
+ *  viewer_rescan
+ */
+
+/* --- viewer_create --- *
+ *
+ * On entry:   R0 == pointer to a viewer definition block
+ *             R1 == pointer to a list
+ *             R2 == sprite area for window
+ *
+ * On exit:    R0 == viewer handle
+ *             May return an error
+ *
+ * Use:                Creates a viewer window.  The viewer definition block
+ *             contains various interesting bits of information about the
+ *             viewer which are likely to be known at assembly time:
+ *
+ *             (word)   address of a list manager definition block
+ *             (word)   address of a shape handler function (or 0)
+ *             (word)   standard width of icons
+ *             (word)   standard height of icons
+ *             (string) banner text message tag, or empty
+ *
+ *             The shape function is used to allow viewer icons to have a
+ *             non-rectangular shape.  The function is called with a reason
+ *             code in R0; entry and exit conditions depend on this:
+ *
+ *                                                     vwShape_size
+ *             On entry
+ *               R1 == pointer to list item
+ *               R2 == standard width of icon
+ *               R3 == standard height of icon
+ *
+ *             On exit
+ *               R2 == width of this icon
+ *               R3 == height of this icon
+ *
+ *             Use
+ *               This routine is used to find the actual size of an icon.
+ *               The icons are aligned on a grid according to the largest
+ *               one: this routine is used to find out which one that is.
+ *
+ *                                                     vwShape_intersects
+ *             On entry
+ *               R1 == pointer to list item
+ *               R2 == address of bounding box of this icon
+ *               R3 == address of bounding box to compare
+ *
+ *             On exit
+ *               CS if boxes intersect, else CC
+ *
+ *             Use
+ *               For detecting mouse clicks etc. on an icon.  viewer has
+ *               already ensured that the box in R3 intersects with the
+ *               bounding box, so for rectangular icons, you can just return
+ *               with C set always.  This entry is provided so that you
+ *               can check against the sprite and text of a text+sprite
+ *               icon separately.
+ *
+ *             More reason codes may be added later; it will always be
+ *             sensible to return immediately preserving all registers and
+ *             flags.
+ */
+
+extern routine viewer_create;
+
+/* --- viewer_destroy --- *
+ *
+ * On entry:   R0 == viewer handle
+ *
+ * On exit:    --
+ *
+ * Use:                Destroys a viewer, removing it from the screen etc.
+ */
+
+extern routine viewer_destroy;
+
+/* --- viewer_open --- *
+ *
+ * On entry:   R0 == viewer handle
+ *             R1 == opening style
+ *             R2,R3 == extra arguments
+ *
+ * On exit:    --
+ *
+ * Use:                Opens a viewer window on the screen.
+ */
+
+extern routine viewer_open;
+
+/* --- viewer_close --- *
+ *
+ * On entry:   R0 == viewer handle
+ *
+ * On exit:    --
+ *
+ * Use:                Closes a viewer window.
+ */
+
+extern routine viewer_close;
+
+/* --- viewer_eventHandler --- *
+ *
+ * On entry:   R0 == viewer handle
+ *             R1 == pointer to event handler
+ *             R2 == value to pass in R10
+ *             R3 == value to pass in R12
+ *
+ * On exit:    R1-R3 == old values
+ *
+ * Use:                Sets up the event handle for the viewer.
+ */
+
+extern routine viewer_eventHandler;
+
+/* --- viewer_select --- *
+ *
+ * On entry:   R0 == viewer handle
+ *             R1 == icon handle
+ *             R2 == 0 to unselect, 1 to select or 2 to toggle
+ *
+ * On exit:    --
+ *
+ * Use:                Selects an icon, or maybe unselects it.  Whatever, it doesn't
+ *             flicker if it doesn't need to.
+ */
+
+extern routine viewer_select;
+
+/* --- viewer_isSelected --- *
+ *
+ * On entry:   R0 == viewer handle
+ *             R1 == icon handle
+ *
+ * On exit:    CS if icon is selected, else CC
+ *
+ * Use:                Informs you whether an icon is selected.
+ */
+
+extern routine viewer_isSelected;
+
+/* --- viewer_selectAll --- *
+ *
+ * On entry:   R0 == viewer handle
+ *             R2 == 0 to deselect, or 1 to select
+ *
+ * On exit:    --
+ *
+ * Use:                Selects or deselects all the icons in a viewer.
+ */
+
+extern routine viewer_selectAll;
+
+/* --- viewer_click --- *
+ *
+ * On entry:   R0 == viewer handle
+ *             R1 == icon handle (or 0)
+ *             R2 == mouse button state
+ *
+ * On exit:    --
+ *
+ * Use:                Handles a click, drag etc. according to the standard
+ *             selection model.
+ */
+
+extern routine viewer_click;
+
+/* --- viewer_dragSelection --- *
+ *
+ * On entry:   R0 == viewer handle
+ *
+ * On exit:    --
+ *
+ * Use:                Starts a drag of the icons within the viewer.  When the drag
+ *             is finished, you get sent a vwEvent_dragged event.
+ */
+
+extern routine viewer_dragSelection;
+
+/* --- viewer_window --- *
+ *
+ * On entry:   R0 == viewer handle
+ *
+ * On exit:    R0 == window handle
+ *
+ * Use:                Returns the window handle of the viewer.
+ */
+
+extern routine viewer_window;
+
+/* --- viewer_update --- *
+ *
+ * On entry:   R0 == viewer handle
+ *             R1 == icon handle
+ *
+ * On exit:    --
+ *
+ * Use:                Updates (redraws) a given icon.
+ */
+
+extern routine viewer_update;
+
+/* --- viewer_setTitle --- *
+ *
+ * On entry:   R0 == viewer handle
+ *             R1 == title string
+ *
+ * On exit:    --
+ *
+ * Use:                Sets the viewer window's title.
+ */
+
+extern routine viewer_setTitle;
+
+/* --- viewer_rescan --- *
+ *
+ * On entry:   R0 == viewer handle
+ *
+ * On exit:    --
+ *
+ * Use:                Rescans all the icons in the viewer and forces a redraw,
+ *             in case icons have been added or deleted (or renamed).  Note
+ *             that the redraw is done *anyway* -- it's your responsibility
+ *             to avoid calling this routine when you don't need to.
+ */
+
+extern routine viewer_rescan;
+
+/*----- Shape function reason codes ---------------------------------------*/
+
+#define vwShape_size 0
+
+#define vwShape_intersects 1
+
+#define vwShape_slowBit 2
+
+/*----- Viewer event codes ------------------------------------------------*/
+
+#define vwEvent_close 0
+
+#define vwEvent_click 1
+
+#define vwEvent_double 2
+
+#define vwEvent_drag 3
+
+#define vwEvent_menu 4
+
+#define vwEvent_redraw 5
+
+#define vwEvent_drop 6
+
+#define vwEvent_help 7
+
+#define vwEvent_key 8
+
+#define vwEvent_dragged 9
+
+#define vwEvent_sprite 10
+
+#define vwEvent_open 11
+
+#define vwEvent_draw 12
+
+#define vwEvent_unDraw 13
+
+#define vwDrop_save 0
+#define vwDrop_load 1
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/warning b/StraySrc/Libraries/Sapphire/csapph/h/warning
new file mode 100644 (file)
index 0000000..2cdcdd8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * warning.h
+ *
+ * [Generated from warning, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif1
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __warning_h
+#define __warning_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  warning
+ *  warn_init
+ */
+
+/* --- warning --- *
+ *
+ * On entry:   R0 == pointer to warning text to display
+ *             R1 == pointer to buttons block
+ *
+ * On exit:    R0 == button that was clicked
+ *             CS if this was default, CC otherwise
+ *
+ * Use:                Displays a warning to the user.  The warning box can have up
+ *             to five buttons (because it's too small for any more than
+ *             that).  These are placed in a column on the right hand side
+ *             of the dialogue.  The buttons are numbered from 0 up to 4
+ *             from the bottom upwards, 0 being the default.  You can
+ *             choose one button to be `Cancel', in which case pressing
+ *             escape will activate it.
+ */
+
+extern routine warning;
+
+/* --- warn_init --- *
+ *
+ * On entry:   R0 == program name
+ *
+ * On exit:    --
+ *
+ * Use:                Sets up the Warning dialogue box for use.
+ */
+
+extern routine warn_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/wimp b/StraySrc/Libraries/Sapphire/csapph/h/wimp
new file mode 100644 (file)
index 0000000..c13455b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * wimp.h
+ *
+ * [Generated from wimp, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __wimp_h
+#define __wimp_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  wimp_init
+ *  wimp_taskHandle
+ *  wimp_version
+ *  wimp_strWidth
+ */
+
+/* --- wimp_init --- *
+ *
+ * On entry:   R0 == pointer to application name
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the WindowManager, and stores away useful
+ *             snippets of information, like the task handle we've been
+ *             given.  It also registers an exit handler so that the Wimp
+ *             gets closed down.
+ */
+
+extern routine wimp_init;
+
+/* --- wimp_taskHandle --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == the application's task handle
+ *
+ * Use:                Returns the application's task handle.
+ */
+
+extern routine wimp_taskHandle;
+
+/* --- wimp_version --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    R0 == the WIMP's version number (may not be the one the
+ *                   client asked for)
+ *
+ * Use:                Returns the WindowManager's version number.
+ */
+
+extern routine wimp_version;
+
+/* --- wimp_strWidth --- *
+ *
+ * On entry:   R0 == pointer to a string
+ *
+ * On exit:    R0 == width of the string in OS units
+ *
+ * Use:                Returns the width of a string, as it would be displayed in
+ *             an icon (i.e. taking into account things like the current
+ *             desktop font etc.)  The width is exact, so if you want to
+ *             e.g. draw a box round it, you'll have to add on a little
+ *             clearance at each end.  8 OS units seems to be a good size
+ *             for the clearance (so the total width you'd use is given by
+ *             wimp_strWidth(string)+16, because it has two ends).
+ */
+
+extern routine wimp_strWidth;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/win b/StraySrc/Libraries/Sapphire/csapph/h/win
new file mode 100644 (file)
index 0000000..0cf3a72
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * win.h
+ *
+ * [Generated from win, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __win_h
+#define __win_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  win_eventHandler
+ *  win_removeEventHandler
+ *  win_swapWindow
+ *  win_windowDeleted
+ *  win_unknownHandler
+ *  win_removeUnknownHandler
+ *  win_init
+ */
+
+/* --- win_eventHandler --- *
+ *
+ * On entry:   R0 == window handle
+ *             R1 == pointer to routine to call
+ *             R2 == R10 value to call routine with
+ *             R3 == R12 value to call routine with
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Adds a routine to the event handler list. Later added
+ *             routines are called first. The event handing routine
+ *             must preserve all the registers, but may alter the carry
+ *             flag. If it returns with carry set, then no more event
+ *             handlers, OR post-filters, will be called.
+ */
+
+extern routine win_eventHandler;
+
+/* --- win_removeEventHandler --- *
+ *
+ * On entry:   R0 == window handle
+ *             R1 == pointer to routine called
+ *             R2 == R10 value routine is called with
+ *             R3 == R12 value routine is called with
+ *
+ * On exit:    --
+ *
+ * Use:                Removes a routine to the event handler list.
+ */
+
+extern routine win_removeEventHandler;
+
+/* --- win_swapWindow --- *
+ *
+ * On entry:   R0 == old window handle
+ *             R1 == new window handle
+ *
+ * On exit:    --
+ *
+ * Use:                Searches for all the event handlers for window R0, and
+ *             changes the window handle for R1.  This is designed for
+ *             situations in wihich a window has been deleted and
+ *             recreated.
+ */
+
+extern routine win_swapWindow;
+
+/* --- win_windowDeleted --- *
+ *
+ * On entry:   R0 == window handle
+ *
+ * On exit:    --
+ *
+ * Use:                Removes all the event handlers associated with the given
+ *             window handle.  It is intended to be used when a window
+ *             has been deleted.
+ */
+
+extern routine win_windowDeleted;
+
+/* --- win_unknownHandler --- *
+ *
+ * On entry:   R0 == pointer to routine to call
+ *             R1 == R4 value to call routine with
+ *             R2 == R10 value to call routine with
+ *             R3 == R12 value to call routine with
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Adds a rountine to the event handler list. Later added
+ *             routines are called first. The event handing routine
+ *             must preserve all the registers, but may alter the carry
+ *             flag. If it returns with carry set, then no more event
+ *             handlers, OR post-filters, will be called.
+ */
+
+extern routine win_unknownHandler;
+
+/* --- win_removeUnknownHandler --- *
+ *
+ * On entry:   R0 == pointer to routine called
+ *             R1 == R4 value routine is called with
+ *             R2 == R10 value routine is called with
+ *             R3 == R12 value routine is called with
+ *
+ * On exit:    --
+ *
+ * Use:                Removes a routine to the unknown handler list.
+ */
+
+extern routine win_removeUnknownHandler;
+
+/* --- win_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the win system.
+ */
+
+extern routine win_init;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/winUtils b/StraySrc/Libraries/Sapphire/csapph/h/winUtils
new file mode 100644 (file)
index 0000000..6b6cff4
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * winUtils.h
+ *
+ * [Generated from winUtils, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __winUtils_h
+#define __winUtils_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  winUtils_setTitle
+ *  winUtils_setPosition
+ *  winUtils_findValid
+ *  winUtils_shaded
+ */
+
+/* --- winUtils_setTitle --- *
+ *
+ * On entry:   R0 == pointer to string to set in title
+ *             R1 == pointer to title bar buffer
+ *             R2 == window handle to write to
+ *
+ * On exit:    --
+ *
+ * Use:                Sets a window's title string.  If the string is different,
+ *             the title is redrawn.  The contortion to do this is
+ *             unpleasant, and is not to be performed in public.
+ */
+
+extern routine winUtils_setTitle;
+
+/* --- winUtils_setPosition --- *
+ *
+ * On entry:   R0 == window opening style
+ *             R1 == pointer to window state block
+ *             R2,R3 == extra arguments for displaying the window
+ *
+ * On exit:    R2,R3 contain position for opening with Wimp_CreateMenu
+ *
+ * Use:                Modifies the window state block pointed to by R0 so that the
+ *             window appears as required in the given opening style.  The
+ *             window is always moved to the top.
+ */
+
+extern routine winUtils_setPosition;
+
+/* --- winUtils_findValid --- *
+ *
+ * On entry:   R0 == pointer to icon block
+ *             R1 == character to find in block (not case-sensitive)
+ *             R2 == old pointer to search from, or 0
+ *
+ * On exit:    R1 == character forced to lower case
+ *             CS if found, and
+ *               R2 points to command string
+ *             else CC and
+ *               R2 corrupted
+ *
+ * Use:                Tries to find a validation string command in the given
+ *             icon block.
+ */
+
+extern routine winUtils_findValid;
+
+/* --- winUtils_shaded --- *
+ *
+ * On entry:   R0 == window handle
+ *             R1 == icon handle
+ *
+ * On exit:    CS if icon is shaded, CC otherwise
+ *
+ * Use:                Informs caller whether an icon is shaded in the Sapphire
+ *             sense (ESG 31 or shaded bit set).
+ */
+
+extern routine winUtils_shaded;
+
+/* --- Opening styles for winUtils_setPosition --- *
+ *
+ * These are actually the same as the dbox_open styles, without the flags
+ * bits.
+ */
+
+#define wStyle_current 0
+#define wStyle_centre 1
+#define wStyle_pointer 2
+#define wStyle_givenY 3
+#define wStyle_givenXY 4
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/writable b/StraySrc/Libraries/Sapphire/csapph/h/writable
new file mode 100644 (file)
index 0000000..84df96f
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * writable.h
+ *
+ * [Generated from writable, 25 September 1996]
+ */
+
+#if !defined(__CC_NORCROFT) || !defined(__arm)
+  #error You must use the Norcroft ARM Compiler for Sapphire programs
+#endif
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __writable_h
+#define __writable_h
+
+#ifndef __sapphire_h
+  #include "sapphire.h"
+#endif
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *   writable
+ *   wrt_init
+ *
+ * Macros provided:
+ *
+ *   WRTABLE
+ */
+
+/* --- writable --- *
+ *
+ * On entry:   R0 == pointer to writable dialogue block
+ *             R1 == pointer to default string to display, or 0 for null
+ *             R2 == pointer to routine to call when string set
+ *             R3 == value to pass to routine in R10
+ *             R4 == value to pass to routine in R12
+ *
+ * On exit:    R0 == dialogue handle of created dialogue box
+ *             May return an error
+ *
+ * Use:                Displays a writable dialogue box, i.e. one with a writable
+ *             icon and OK button, used instead of writable menu items,
+ *             for reasons to do with caret blinking and pointer changing.
+ *
+ *             The writable dialogue block consists of:
+ *
+ *             Size    Meaning
+ *             ~~~~    ~~~~~~~
+ *             4       Flags (see below)
+ *             n       Validation string to use, may be null
+ *             m       Title string (message tag) to display
+ *
+ *             The flags are:
+ *
+ *             Bit     Meaning
+ *             ~~~     ~~~~~~~
+ *             0-7     Maximum string length
+ *             8       Right align text in writable icon
+ *             9-31    Reserved; must be 0
+ *
+ *             The routine returns a dialogue handle because you may want
+ *             to attach a numWrite control to the writable icon, which
+ *             is icon number 0.
+ *
+ *             The handler routine is passed:
+ *
+ *             R0 == pointer to string typed in
+ *             R1 == dialogue box handle (for numWrite again)
+ *             R10, R12 as set up here
+ *
+ *             It must preserve all registers.  If the carry flag is set
+ *             on exit, the dialogue box will not be closed.  If it is
+ *             clear, the dialogue may be closed depending on the button
+ *             status.
+ *
+ *             Note that this routine does *not* require a template --
+ *             a suitable window is generated at run-time.
+ */
+
+extern routine writable;
+
+/* --- wrt_init --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Initialises the writable dialogue box for use.
+ */
+
+extern routine wrt_init;
+
+/* --- Useful constants --- */
+
+#define wrtFlag_rAlign ((1<<8))
+
+/* --- Macro: WRTABLE --- *
+ *
+ * Arguments:  len == maximum string length to allow
+ *             flags == other flags to set
+ *             valid == (optional) validation string
+ *             title == title message tag string
+ *
+ * Use:                Builds a writable definition block.
+ */
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/xfer/load b/StraySrc/Libraries/Sapphire/csapph/h/xfer/load
new file mode 100644 (file)
index 0000000..9837e93
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * load.h
+ *
+ * [Generated from load, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __load_h
+#define __load_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  load
+ *  load_initBuf
+ *  load_killBuf
+ *  load_extendBuf
+ *  load_doneBuf
+ *  load_file
+ */
+
+/* --- load --- *
+ *
+ * On entry:   R0 == pointer to entry point block
+ *             R1 == value of R10 to pass to entry points
+ *             R2 == value of R12 to pass to entry points
+ *
+ * On exit:    --
+ *
+ * Use:                Attempts to load a file after receipt of a Message_DataSave,
+ *             Message_DataLoad or Message_DataOpen.  If user entries for
+ *             RAM transfer are provided, this is attempted, although the
+ *             entries must also be aware that file transfer may be
+ *             required.
+ */
+
+extern routine load;
+
+/* --- load_initBuf --- *
+ *
+ * On entry:   R1 == estimated file size
+ *             R2 == pointer to flex anchor (unallocated)
+ *
+ * On exit:    R0 == pointer to buffer start
+ *             R1 == buffer size
+ *             May return an error
+ *
+ * Use:                Initialises a flex block for use as a RAM transfer buffer.
+ *             This routine is suitable for use as the initBuf routine for
+ *             RAM transfer loading.
+ */
+
+extern routine load_initBuf;
+
+/* --- load_killBuf --- *
+ *
+ * On entry:   R2 == pointer to flex anchor
+ *
+ * On exit:    --
+ *
+ * Use:                Frees a flex block.  This routine should be used to free
+ *             the buffer used for RAM transfer.
+ */
+
+extern routine load_killBuf;
+
+/* --- load_extendBuf --- *
+ *
+ * On entry:   R0 == pointer to previous buffer
+ *             R1 == size of previous buffer
+ *             R2 == pointer to flex anchor
+ *
+ * On exit:    R0 == pointer to a new buffer
+ *             R1 == size of the new buffer
+ *             May return an error
+ *
+ * Use:                Extends the flex block if it was initially too small.
+ *             This routine is designed to be used as the extend routine
+ *             during RAM transfer.
+ */
+
+extern routine load_extendBuf;
+
+/* --- load_doneBuf --- *
+ *
+ * On entry:   R1 == actual size of data
+ *             R2 == pointer to flex anchor
+ *
+ * On exit:    --
+ *
+ * Use:                Sets the block into which the data has been loaded to the
+ *             correct exact size.
+ */
+
+extern routine load_doneBuf;
+
+/* --- load_file --- *
+ *
+ * On entry:   R1 == pointer to filename to load
+ *             R2 == pointer to flex anchor
+ *
+ * On exit:    R0 == size of file loaded
+ *             May return an error
+ *
+ * Use:                Loads a named file into a flex block for your delectation.
+ */
+
+extern routine load_file;
+
+/*----- User entry points -------------------------------------------------*/
+
+#define lEntry__initBuf 0
+
+#define lEntry__killBuf 4
+
+#define lEntry__extend 8
+
+#define lEntry__doneBuf 12
+
+#define lEntry__file 16
+
+#define lEntry__done 20
+
+#define lEntry__failed 24
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/xfer/save b/StraySrc/Libraries/Sapphire/csapph/h/xfer/save
new file mode 100644 (file)
index 0000000..c9a4082
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * save.h
+ *
+ * [Generated from save, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __save_h
+#define __save_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  save
+ */
+
+/* --- save --- *
+ *
+ * On entry:   R0 == window handle to send to
+ *             R1 == icon handle to send to
+ *             R2 == estimated size of the data
+ *             R3 == file type of data to send and flag:
+ *                   bit 31: use R8 as below
+ *             R4 == pointer to name of file (may be full path)
+ *             R5 == address of handler block
+ *             R6 == value to pass handlers in R10
+ *             R7 == value to pass handlers in R12
+ *             R8 == pointer to extra handler block (only if bit 31 of R3)
+ *
+ * On exit:    --
+ *
+ * Use:                Starts a save operation to another application.  The extra
+ *             handler is used by systems like saveas which need to be
+ *             aware of data transfer start/end conditions without
+ *             interfering with the normal entry table.  This will not
+ *             normally concern applications however.
+ */
+
+extern routine save;
+
+/*----- The save handler --------------------------------------------------*/
+
+#define sEntry__save 0
+
+#define sEntry__send 4
+
+#define sEntry__success 8
+
+#define sEntry__failed 12
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/xfer/saveAs b/StraySrc/Libraries/Sapphire/csapph/h/xfer/saveAs
new file mode 100644 (file)
index 0000000..cbdeccd
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * saveAs.h
+ *
+ * [Generated from saveAs, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __saveAs_h
+#define __saveAs_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  saveAs
+ */
+
+/* --- saveAs --- *
+ *
+ * On entry:   R0 == estimated size of data
+ *             R1 == file type of the data
+ *             R2 == pointer to name of the file
+ *             R3 == pointer to handler block
+ *             R4 == value to pass to handlers in R10
+ *             R5 == value to pass to handlers in R12
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Displays a save as dialogue box for you to save some data.
+ */
+
+extern routine saveAs;
+
+/*----- The SaveAs handler block ------------------------------------------*
+ *
+ * The block begins with the message tag for the dialogue title, followed by
+ * an align to word boundary and then branch instructions or 0 for:
+ */
+
+#define saEntry__closed 0
+
+#define saEntry__save 4
+
+#define saEntry__send 8
+
+#define saEntry__success 12
+
+#define saEntry__failed 16
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/xfer/xload b/StraySrc/Libraries/Sapphire/csapph/h/xfer/xload
new file mode 100644 (file)
index 0000000..3318424
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * xload.h
+ *
+ * [Generated from xload, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __xload_h
+#define __xload_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  xload_file
+ *  xload_initBuf
+ *  xload_killBuf
+ *  xload_extend
+ *  xload_doneBuf
+ *  xload_done
+ *  xload_failed
+ *  xload_byte
+ *  xload_word
+ *  xload_block
+ */
+
+/* --- xload_file --- *
+ *
+ * On entry:   R0 == pointer to loader routine
+ *             R1 == R10 value to pass to loader
+ *             R2 == R12 value to pass to loader
+ *             R3 == pointer to leafname of file (passed to loader in R0)
+ *             R4 == pointer to filename to load from
+ *             R5 == whether the file is safe (passed to loader in R1)
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Calls a generalised loader routine to read data from a file.
+ */
+
+extern routine xload_file;
+
+/* --- xload_initBuf --- *
+ *
+ * On entry:   R0 == pointer to loader routine
+ *             R1 == R10 value to pass to loader
+ *             R2 == R12 value to pass to loader
+ *             R3 == pointer to leafname of file (passed to loader in R0)
+ *
+ * On exit:    R0 == pointer to load buffer
+ *             R1 == size of load buffer
+ *             May return an error
+ *
+ * Use:                Starts a RAM transfer and starts up a generalised load
+ *             routine.
+ */
+
+extern routine xload_initBuf;
+
+/* --- xload_killBuf --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Does a buffer destroy for a failed load operation.
+ */
+
+extern routine xload_killBuf;
+
+/* --- xload_extend --- *
+ *
+ * On entry:   R1 == size of last buffer used for receiving
+ *
+ * On exit:    R0 == pointer to new buffer
+ *             R1 == size of new buffer
+ *             May return an error
+ *
+ * Use:                Performs a buffer extent operation during an xload RAM
+ *             transfer.
+ */
+
+extern routine xload_extend;
+
+/* --- xload_doneBuf --- *
+ *
+ * On entry:   R1 == total size of data received
+ *
+ * On exit:    R0 corrupted
+ *             May return an error
+ *
+ * Use:                Handles the last bufferful of a RAM load.
+ */
+
+extern routine xload_doneBuf;
+
+/* --- xload_done --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Tidies up after a successful load job.
+ */
+
+extern routine xload_done;
+
+/* --- xload_failed --- *
+ *
+ * On entry:   R0 == pointer to error block
+ *
+ * On exit:    --
+ *
+ * Use:                Tidies up a RAM transfer after an error.
+ */
+
+extern routine xload_failed;
+
+/* --- xload_byte --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    CC if data read OK, and
+ *               R0 == byte read
+ *             else CC if end-of-file, and
+ *               R0 corrupted
+ *             May return an error
+ *
+ * Use:                Reads a byte from the current input.
+ */
+
+extern routine xload_byte;
+
+/* --- xload_word --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    CC if data read OK, and
+ *               R0 == word read
+ *             else CS if end-of-file and
+ *               R0 corrupted
+ *             May return an error
+ *
+ * Use:                Reads a word from the current input.
+ */
+
+extern routine xload_word;
+
+/* --- xload_block --- *
+ *
+ * On entry:   R0 == pointer to buffer to read
+ *             R1 == size of buffer to read
+ *
+ * On exit:    R0, R1 preserved
+ *             R2 == number of bytes read
+ *             CC if more data available, CS for end-of-file
+ *             May return an error
+ *
+ * Use:                Reads in a block of data.  Data is buffered, so this is
+ *             fairly quick for reading small objects.  Large data blocks
+ *             are read directly to avoid buffering overhead.
+ */
+
+extern routine xload_block;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/h/xfer/xsave b/StraySrc/Libraries/Sapphire/csapph/h/xfer/xsave
new file mode 100644 (file)
index 0000000..d2e6e2b
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * xsave.h
+ *
+ * [Generated from xsave, 08 November 1995]
+ */
+
+#pragma include_only_once
+#pragma force_top_level
+
+#ifndef __xsave_h
+#define __xsave_h
+
+/*----- Overview ----------------------------------------------------------*
+ *
+ * Functions provided:
+ *
+ *  xsave_save
+ *  xsave_send
+ *  xsave_done
+ *  xsave_failed
+ *  xsave_byte
+ *  xsave_word
+ *  xsave_string
+ *  xsave_block
+ */
+
+/* --- xsave_save --- *
+ *
+ * On entry:   R0 == pointer to saver routine
+ *             R1 == R10 value to pass to saver
+ *             R2 == R12 value to pass to saver
+ *             R3 == pointer to filename to save to
+ *             R4 == filetype of file to save
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Calls a generalised saver routine to write data to a file.
+ */
+
+extern routine xsave_save;
+
+/* --- xsave_send --- *
+ *
+ * On entry:   R0 == pointer to saver routine
+ *             R1 == R10 value to pass to saver
+ *             R2 == R12 value to pass to saver
+ *
+ * On exit:    R0 == pointer to block to send
+ *             R1 == size of block
+ *             CS if this is the last block, else CC
+ *             May return an error
+ *
+ * Use:                Calls a generalised saver routine to write data to another
+ *             application, using RAM transfer.  Note that you must call
+ *             this routine from your send entry point throughout the
+ *             save operation.
+ */
+
+extern routine xsave_send;
+
+/* --- xsave_done --- *
+ *
+ * On entry:   --
+ *
+ * On exit:    --
+ *
+ * Use:                Tidies up after a successful save job.
+ */
+
+extern routine xsave_done;
+
+/* --- xsave_failed --- *
+ *
+ * On entry:   R0 == pointer to error block
+ *
+ * On exit:    --
+ *
+ * Use:                Tidies up a RAM transfer after an error.
+ */
+
+extern routine xsave_failed;
+
+/* --- xsave_byte --- *
+ *
+ * On entry:   R0 == byte to write in lowest 8 bits
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Writes a single byte to the current output.
+ */
+
+extern routine xsave_byte;
+
+/* --- xsave_word --- *
+ *
+ * On entry:   R0 == word to write
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Writes a single word to the current output.
+ */
+
+extern routine xsave_word;
+
+/* --- xsave_string --- *
+ *
+ * On entry:   R0 == pointer to a control-terminated string
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Writes a control-terminated string to the current output.
+ *             The string is null terminated in the output file.
+ */
+
+extern routine xsave_string;
+
+/* --- xsave_block --- *
+ *
+ * On entry:   R0 == pointer to buffer to write
+ *             R1 == size of buffer to write
+ *
+ * On exit:    May return an error
+ *
+ * Use:                Writes out a block of data.  Data is buffered, so this is
+ *             fairly quick for reading small objects.  Large data blocks
+ *             are sent directly to avoid buffering overhead.
+ */
+
+extern routine xsave_block;
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Sapphire/csapph/s/cmath b/StraySrc/Libraries/Sapphire/csapph/s/cmath
new file mode 100644 (file)
index 0000000..3d30b7b
--- /dev/null
@@ -0,0 +1,292 @@
+;
+; cmath.s
+;
+; Standard maths routines for Sapphire
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+;              GET     libs:swis
+
+               GET     libs:stream
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         ONEARG
+               [       "$label"<>""
+               EXPORT  $label
+               ALIGN
+$label
+               ]
+               STMFD   R13!,{R0,R1}
+               LDFD    F0,[R13],#8
+               MEND
+
+               MACRO
+$label         TWOARG
+               [       "$label"<>""
+               EXPORT  $label
+               ALIGN
+$label
+               ]
+               STMFD   R13!,{R0-R3}
+               LDFD    F0,[R13],#8
+               LDFD    F1,[R13],#8
+               MEND
+
+               MACRO
+$label         UNOP    $op
+$label         ONEARG
+               $op.E   F0,F0
+               MOVS    PC,R14
+               MEND
+
+               MACRO
+               CTOP
+               MOV     R1,#0
+               RFS     R12
+               WFS     R1
+               MEND
+
+               MACRO
+               CBOT
+               RFS     R1
+               WFS     R12
+               TST     R1,#&0F
+               MOVEQS  PC,R14
+               B       cmath__error
+               MEND
+
+               MACRO
+               COP     $op
+               CTOP
+               $op
+               CBOT
+               MEND
+
+               MACRO
+$label         CUNOP   $op
+$label         ONEARG
+               COP     "$op.E F0,F0"
+               MEND
+
+               MACRO
+$label         CBINOP  $op
+$label         TWOARG
+               COP     "$op.E F0,F0,F1"
+               MEND
+
+               MACRO
+               WS      $addr,$reg,$tmp
+               IMPORT  |__sph_workoff|,WEAK
+               ALIGN
+               LDR     $reg,$addr
+               DCD     |__sph_workoff| + &E51B0004 + ($tmp<<12)
+               MEND
+
+;----- Error numbers --------------------------------------------------------
+
+               ^       1
+EDOM           #       1
+ERANGE         #       1
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+               ; --- Simple FP ops ---
+               ;
+               ; These map onto FP instructions in a simple way.  Some of
+               ; the simpler ops are actually inlined by the compiler
+               ; anyway.
+
+sin            UNOP    SIN
+cos            UNOP    COS
+atan           UNOP    ATN
+
+tan            CUNOP   TAN
+asin           CUNOP   ASN
+acos           CUNOP   ACS
+
+atan2          TWOARG
+               COP     "POLE F0,F1,F0"
+
+exp            CUNOP   EXP
+log            CUNOP   LGN
+log10          CUNOP   LOG
+
+|__sapph_sqrt| CUNOP   SQT
+pow            CBINOP  POW
+
+fabs           UNOP    ABS
+
+fmod           TWOARG
+               CTOP
+               DVFE    F2,F0,F1
+               RNDEZ   F2,F2
+               MUFE    F1,F2,F1
+               SUFE    F0,F0,F1
+               CBOT
+
+               ; --- Rounding functions ---
+
+ceil           ONEARG
+               RNDEP   F0,F0
+               MOVS    PC,R14
+
+floor          ONEARG
+               RNDEM   F0,F0
+               MOVS    PC,R14
+
+modf           ONEARG
+               RNDEZ   F1,F0
+               SUFE    F0,F0,F1
+               STFD    F1,[R2,#0]
+               MOVS    PC,R14
+
+               ; --- Hyperbolic functions ---
+
+sinh           ONEARG
+               CTOP
+               MNFE    F1,F0
+               EXPE    F0,F0
+               EXPE    F1,F1
+               SUFE    F0,F0,F1
+               DVFE    F0,F0,#2
+               CBOT
+
+cosh           ONEARG
+               CTOP
+               MNFE    F1,F0
+               EXPE    F0,F0
+               EXPE    F1,F1
+               ADFE    F0,F0,F1
+               DVFE    F0,F0,#2
+               CBOT
+
+tanh           ONEARG
+               CTOP
+               MNFE    F1,F0
+               EXPE    F0,F0
+               EXPE    F1,F1
+               ADFE    F2,F0,F1
+               SUFE    F0,F0,F1
+               DVFE    F0,F0,F2
+               CBOT
+
+               ; --- Horrific FP-number-building functions ---
+
+               EXPORT  frexp
+frexp          ROUT
+
+               MOVS    R3,R0,LSL #1
+               CMPEQ   R1,#0
+               MOVNE   R3,R0,LSR #20
+               BICNE   R3,R3,#&800
+               ADDNE   R3,R3,#2
+               SUBNE   R3,R3,#1024
+               BICNE   R0,R0,#&40000000
+               BICNE   R0,R0,#&00100000
+               ORRNE   R0,R0,#&3FC00000
+               ORRNE   R0,R0,#&00200000
+               STR     R3,[R2,#0]
+               ONEARG
+               NRME    F0,F0
+               MOVS    PC,R14
+
+               LTORG
+
+               EXPORT  ldexp
+ldexp          ROUT
+
+               ADD     R2,R2,#1024
+               SUB     R2,R2,#1
+               MOV     R2,R2,LSL #21
+               MOV     R2,R2,LSR #1
+               MOV     R3,#0
+               TWOARG
+               CTOP
+               MUFE    F0,F0,F1
+               CBOT
+
+               LTORG
+
+               ; --- Error handling ---
+
+; --- cmath__error ---
+;
+; On entry:    R1 == error status indicator
+;
+; On exit:     errno set up nicely
+;
+; Use:         Handles errors in maths routines.
+
+cmath__error   ROUT
+
+               TST     R1,#&3                  ;Check for IVO and DVZ
+               MOVNE   R0,#EDOM                ;Domain error
+               BNE     %50cmath__error         ;So return that then
+
+               TST     R1,#&8                  ;Check for UFL condition
+               MVFNEE  F0,#0                   ;Underflowed -- zero result
+               MOVNE   R0,#ERANGE              ;And return a range error
+               BNE     %50cmath__error         ;And return the result
+
+               CMFE    F0,#0                   ;Is result positive?
+               LDFGTD  F0,cmath__huge          ;Yes -- get positive huge
+               LDFLED  F0,cmath__nhuge         ;No -- get negative huge
+               MOV     R0,#ERANGE              ;And return a range error
+
+50cmath__error
+               WS      cmath__wSpace,R12,R3    ;Find workspace location
+               STR     R0,[R12,R3]             ;Store the error value
+               MOVS    PC,R14                  ;And return to caller
+
+               EXPORT  cmath__huge
+cmath__huge    DCD     &7FEFFFFF,-1
+cmath__nhuge   DCD     &FFEFFFFF,-1
+
+               LTORG
+
+; --- cmath_errno ---
+;
+; On entry:    --
+;
+; On exit:     R0 == address of `errno'
+;
+; Use:         Finds the address of the `errno' variable.
+
+               EXPORT  cmath_errno
+cmath_errno    ROUT
+
+               WS      cmath__wSpace,R12,R0
+               ADD     R0,R12,R0
+               MOVS    PC,R14
+
+               LTORG
+
+cmath__wSpace  DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+cmath__wStart  #       0
+
+cmath__errno   #       4                       ;Global `errno' variable
+
+cmath__wSize   EQU     {VAR}-cmath__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     cmath__wSize
+               DCD     cmath__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/csapph/s/crout b/StraySrc/Libraries/Sapphire/csapph/s/crout
new file mode 100644 (file)
index 0000000..023189b
--- /dev/null
@@ -0,0 +1,185 @@
+;
+; crout.s
+;
+; Some interfaces to standard Sapphire routines
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+;              GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:flex
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:string
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         PREAMBLE
+$label         STMFD   sp!,{R11,lr}
+               MOV     R11,sl
+               MEND
+
+               MACRO
+$label         POSTAMBLE
+$label         LDMFD   sp!,{R11,pc}^
+               MEND
+
+               MACRO
+$label         VENEER
+               EXPORT  __sapph_$label
+__sapph_$label PREAMBLE
+               BL      $label
+               POSTAMBLE
+               MEND
+
+               MACRO
+$label         FLEXVNR
+               EXPORT  __sapph_$label
+__sapph_$label PREAMBLE
+               BL      $label
+               MOVCS   a1,#0
+               LDRCC   a1,[a1,#0]
+               POSTAMBLE
+               MEND
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- __sapph_scratchpad ---
+
+               EXPORT  |__sapph_scratchpad|
+|__sapph_scratchpad|
+               MOV     a1,sl
+               MOVS    pc,lr
+
+; --- strsubst ---
+
+               EXPORT  strsubst
+strsubst       MOV     ip,sp
+               STMFD   sp!,{R4-R11,lr}
+               MOV     R11,sl
+               LDMIA   ip,{R4-R10}
+               BL      str_subst
+               LDMFD   sp!,{R4-R11,pc}^
+
+; --- strcmp ---
+; --- stricmp ---
+
+               EXPORT  strcmp
+               EXPORT  stricmp
+
+strcmp         MOV     ip,lr
+               BL      str_cmp
+               B       %10
+
+stricmp                MOV     ip,lr
+               BL      str_icmp
+
+10             MOVLT   a1,#-1
+               MOVEQ   a1,#0
+               MOVGT   a1,#1
+               MOVS    pc,ip
+
+               LTORG
+
+; --- strbuffer ---
+
+               EXPORT  strbuffer
+strbuffer      PREAMBLE
+               BL      str_buffer
+               MOV     a1,R1
+               POSTAMBLE
+
+; --- strerror ---
+
+               EXPORT  strerror
+strerror       MOV     ip,sp
+               STMFD   sp!,{R4-R11,lr}
+               MOV     R11,sl
+               LDMIA   ip,{R4-R10}
+               MOV     ip,a2
+               BL      str_buffer
+               STR     a1,[a2],#4
+               MOV     a1,ip
+               BL      str_subst
+               SUB     a1,a1,#4
+               LDMFD   sp!,{R4-R11,pc}^
+
+; --- msgs_lookup ---
+
+msgs_lookup    VENEER
+
+; --- msgs_error ---
+
+               EXPORT  |__sapph_msgs_error|
+|__sapph_msgs_error|
+               MOV     ip,sp
+               STMFD   sp!,{R4-R11,lr}
+               MOV     R11,sl
+               LDMIA   ip,{R4-R10}
+               MOV     ip,a2
+               BL      str_buffer
+               STR     a1,[a2],#4
+               MOV     a1,ip
+               BL      msgs_lookup
+               BL      str_subst
+               SUB     a1,a1,#4
+               LDMFD   sp!,{R4-R11,pc}^
+
+; --- malloc ---
+
+               EXPORT  malloc
+malloc         CMP     a1,#0
+               MOVEQS  pc,lr
+               PREAMBLE
+               BL      alloc
+               MOVCS   a1,#0
+               POSTAMBLE
+
+; --- free ---
+
+               EXPORT  |__sapph_free|
+|__sapph_free| CMP     a1,#0
+               MOVEQS  pc,lr
+               PREAMBLE
+               BL      free
+               POSTAMBLE
+
+; --- alloc_error ---
+
+alloc_error    VENEER
+
+; --- flex ---
+
+flex_alloc     FLEXVNR
+flex_free      VENEER
+flex_size      VENEER
+flex_extend    FLEXVNR
+flex_midExtend FLEXVNR
+
+               EXPORT  |__sapph_flex_save|
+|__sapph_flex_save|
+               PREAMBLE
+               FSAVE   R0
+               POSTAMBLE
+
+               EXPORT  |__sapph_flex_load|
+|__sapph_flex_load|
+               PREAMBLE
+               FLOAD   R0
+               POSTAMBLE
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/csapph/s/crts b/StraySrc/Libraries/Sapphire/csapph/s/crts
new file mode 100644 (file)
index 0000000..7058bdb
--- /dev/null
@@ -0,0 +1,158 @@
+;
+; crts.s
+;
+; C run-time support functions for Sapphire
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+;              GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:divide
+               IMPORT  div_byZero
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- __rt_udiv10 ---
+;
+; On entry:    R0 == value to divide
+;
+; On exit:     R0 == value / 10
+;              R1 == value % 10
+;
+; Use:         Divides an unsigned number by 10.
+
+               EXPORT  |__rt_udiv10|
+               EXPORT  |_kernel_udiv10|
+
+|__rt_udiv10|  ROUT
+|_kernel_udiv10|
+
+               MOV     R1,R0
+               ADD     R0,R0,R0,LSR #1
+               ADD     R0,R0,R0,LSR #4
+               ADD     R0,R0,R0,LSR #8
+               ADD     R0,R0,R0,LSR #16
+               MOV     R0,R0,LSR #4
+               ADD     R2,R0,R0,LSL #2
+               SUB     R1,R1,R2,LSL #1
+               SUBS    R1,R1,#10
+               ADDGE   R0,R0,#1
+               ADDLT   R1,R1,#10
+               MOVS    PC,R14
+
+               LTORG
+
+; --- __rt_sdiv10 ---
+;
+; On entry:    R0 == value to divide
+;
+; On exit:     R0 == value / 10
+;              R1 == value % 10
+;
+; Use:         Divides a signed number by 10.
+
+               EXPORT  |__rt_sdiv10|
+               EXPORT  |_kernel_sdiv10|
+
+|__rt_sdiv10|  ROUT
+|_kernel_sdiv10|
+
+               MOVS    R3,R0
+               RSBMI   R0,R0,#0
+               MOV     R1,R0
+               ADD     R0,R0,R0,LSR #1
+               ADD     R0,R0,R0,LSR #4
+               ADD     R0,R0,R0,LSR #8
+               ADD     R0,R0,R0,LSR #16
+               MOV     R0,R0,LSR #4
+               ADD     R2,R0,R0,LSL #2
+               SUB     R1,R1,R2,LSL #1
+               SUBS    R1,R1,#10
+               ADDGE   R0,R0,#1
+               ADDLT   R1,R1,#10
+               CMP     R3,#0
+               RSBMI   R0,R0,#0
+               RSBMI   R1,R1,#0
+               MOVS    PC,R14
+
+               LTORG
+
+; --- __rt_udiv ---
+;
+; On entry:    R0 == divisor
+;              R1 == dividend
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         Divides in an unsigned way.
+
+               EXPORT  |__rt_udiv|
+               EXPORT  |x$udivide|
+
+|__rt_udiv|    ROUT
+|x$udivide|
+
+               EOR     R0,R1,R0
+               EOR     R1,R1,R0
+               EOR     R0,R1,R0
+               B       div_unsigned
+
+               LTORG
+
+; --- __rt_sdiv ---
+;
+; On entry:    R0 == divisor
+;              R1 == dividend
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         Divides in a signed way.
+
+               EXPORT  |__rt_sdiv|
+               EXPORT  |x$divide|
+
+|__rt_sdiv|    ROUT
+|x$divide|
+
+               EOR     R0,R1,R0
+               EOR     R1,R1,R0
+               EOR     R0,R1,R0
+               B       divide
+
+               LTORG
+
+; --- __rt_divtest ---
+;
+; On entry:    R0 == a number
+;
+; On exit:     --
+;
+; Use:         If R0 is zero, a `divide by zero' error is raised.
+
+               EXPORT  |__rt_divtest|
+               EXPORT  |x$divtest|
+
+|__rt_divtest| ROUT
+|x$divtest|
+
+               CMP     R0,#0
+               MOVNES  PC,R14
+               B       div_byZero
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/csapph/s/csapph b/StraySrc/Libraries/Sapphire/csapph/s/csapph
new file mode 100644 (file)
index 0000000..37cacd3
--- /dev/null
@@ -0,0 +1,125 @@
+;
+; csapph.s
+;
+; C support for Sapphire programs
+;
+; © 1995 Straylight
+;
+
+;----- Notice ---------------------------------------------------------------
+;
+; We haven't lost our minds.  We aren't planning to move over to development
+; in C.  Nothing like that.  This will allow us to use C code from other
+; sources (a bit) in Sapphire programs, and maybe sort out algorithms before
+; committing to register allocations.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- __sapph_veneer ---
+;
+; On entry:    R0-R12 == argument registers
+;              R14 == routine to call
+;              Return address on stack
+;
+; On exit:     R0-R12 == returned values
+;              Flags may be altered by called routine
+;
+; Use:         Calls a C routine, passing it arguments, and getting results
+;              back.
+
+               EXPORT  |__sapph_veneer|
+|__sapph_veneer| ROUT
+
+               STMFD   R13!,{R0-R12,PC}        ;Save registers
+               MOV     sl,R11                  ;Look after env pointer
+               MOV     a1,R13                  ;Point to the regset
+               MOV     a2,R10                  ;Pass object pointer
+               MOV     a3,R12                  ;Pass workspace pointer
+               MOV     a4,R11                  ;And the scratchpad
+               MOV     fp,#0                   ;Terminate stack frame list
+
+               MOV     ip,R14                  ;Point to the routine
+               MOV     lr,pc                   ;Set up a return address
+               MOV     pc,ip                   ;And call the routine
+
+               LDR     ip,[R13,#52]            ;Load the flags word
+               AND     a2,a1,#&F0              ;Get the mask bits out
+               BIC     ip,ip,a2,LSL #24        ;Mask some flags out
+               TEQP    ip,a1,LSL #28           ;Toggle and set the flags
+               MOV     R0,R0                   ;No-op
+               LDMFD   R13!,{R0-R12,R14,PC}    ;And return to caller
+
+               LTORG
+
+; --- call ---
+;
+; On entry:    a1 == pointer to routine
+;              a2 == pointer to regset
+;
+; On exit:     a1 == 0, or pointer to error, as seems to be usual
+;
+; Use:         Calls a random routine in Sapphire, or anywhere else.  The
+;              Scratchpad pointer is forced into R11.
+
+               EXPORT  call
+call           ROUT
+
+               STMFD   sp!,{a1,a2,v1-v6,sl,fp,ip,lr} ;Save lots of registers
+               STR     sl,[a2,#44]             ;Store Scratchpad away
+               MOV     lr,pc                   ;Set up current flags
+               AND     lr,lr,#&0C000003        ;Leave important flags
+               TEQP    lr,#0                   ;Clear the others please
+               LDMIA   a2,{R0-R12}             ;Load lots of registers
+               MOV     lr,pc                   ;Set up return address
+               LDR     pc,[sp],#4              ;Call the routine
+               LDR     lr,[sp],#4              ;Load the base address back
+               STMIA   lr,{R0-R12,PC}          ;Store all the registers
+               MOVVC   R0,#0                   ;If no error, return 0
+               LDMFD   sp!,{v1-v6,sl,fp,ip,pc}^ ;And return to caller
+
+               LTORG
+
+; --- swi ---
+;
+; On entry:    R0 == SWI number
+;              R1 == pointer to regset
+;
+; On exit:     R0 == zero, or pointer to error
+;
+; Use:         Calls a SWI in a versatile, fast, and inconvenient way.
+
+               EXPORT  swi
+swi            ROUT
+
+               STMFD   R13!,{R4-R10,R14}       ;Save some registers
+               MOV     R10,R1                  ;Remember this pointer
+               ORR     R0,R0,#&EF000000        ;Make the SWI number
+               LDR     R14,=&E1A0F00C          ;Get the return instruction
+               STMFD   R13!,{R0,R14}           ;Save them on the stack
+               LDMIA   R10,{R0-R9}             ;Load registers to pass
+               MOV     R12,PC                  ;Set up return address
+               MOV     PC,R13                  ;Call the SWI instruction
+               STMIA   R10,{R0-R9}             ;Store the output registers
+               STR     PC,[R10,#52]            ;Store the output flags too
+               MOVVC   R0,#0                   ;If no error, return zero
+               ADD     R13,R13,#8              ;Restore stack pointer
+               LDMFD   R13!,{R4-R10,PC}^       ;And return to caller
+
+               LTORG
+
+               GBLL    OPT_CALL
+               GBLL    OPT_SAPPHIRE
+               GET     libs:s.xswi
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/csapph/s/csetjmp b/StraySrc/Libraries/Sapphire/csapph/s/csetjmp
new file mode 100644 (file)
index 0000000..cc9f43c
--- /dev/null
@@ -0,0 +1,71 @@
+;
+; csetjmp.s
+;
+; Support for setjmp and longjmp
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- setjmp ---
+;
+; On entry:    R0 == pointer to setjmp block
+;
+; On exit:     R0 == 0
+;
+; Use:         Fills a jmp_buf with useful information
+
+               EXPORT  setjmp
+setjmp         ROUT
+
+               SWI     XFPEmulator_Version     ;Do we have FP available?
+               MOVVS   R12,#0                  ;No -- remember this
+               STRVS   R12,[R0,#84]            ;Store the value away
+               STFVCE  F4,[R0],#12             ;Store FP registers
+               STFVCE  F5,[R0],#12
+               STFVCE  F6,[R0],#12
+               STFVCE  F7,[R0],#12
+               STMIA   R0,{R4-R11,R13,R14}     ;Store lots of stuff
+               MOV     R0,#0                   ;Return zero
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- longjmp ---
+;
+; On entry:    R0 == pointer to jmp_buf block
+;              R1 == return value
+;
+; On exit:     R0 == R1 on entry, or 1 if R1 was 0
+;
+; Use:         Returns to a setjmp position.
+
+               EXPORT  longjmp
+longjmp                ROUT
+
+               LDR     R14,[R0,#84]            ;Load the final word out
+               CMP     R14,#0                  ;Is it defined there?
+               LDFNEE  F4,[R0],#12             ;Load FP registers back
+               LDFNEE  F5,[R0],#12
+               LDFNEE  F6,[R0],#12
+               LDFNEE  F7,[R0],#12
+               LDMIA   R0,{R4-R14}             ;Restore old registers
+               MOVS    R0,R1                   ;Get the return value
+               MOVEQ   R0,#1                   ;If it was zero, fiddle it
+               MOVS    PC,R14                  ;And return to `caller'
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/csapph/s/cstart b/StraySrc/Libraries/Sapphire/csapph/s/cstart
new file mode 100644 (file)
index 0000000..6d55972
--- /dev/null
@@ -0,0 +1,39 @@
+;
+; cstart.s
+;
+; Starts up a Sapphire application written in C
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+;              GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:sapphire
+
+               IMPORT  sapph_main
+               IMPORT  appname
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |!!Start$$Code|,CODE,READONLY
+               ENTRY
+
+               LDR     R0,=appname
+               MOV     R1,#512
+               MOV     R2,#0
+               BL      sapphire_init
+               BL      sapph_main
+               SWI     &11                     ;OS_Exit
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/csapph/s/ctype b/StraySrc/Libraries/Sapphire/csapph/s/ctype
new file mode 100644 (file)
index 0000000..f706f54
--- /dev/null
@@ -0,0 +1,214 @@
+;
+; ctype.s
+;
+; A ctype implementation done the proper way
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- Character table format ---
+;
+; The table consists of halfword entries, which have the following format:
+;
+;   Bit                Meaning
+;    0         whitespace
+;    1         punctuation
+;    2         blank
+;    3         lower case
+;    4         upper case
+;    5         digit
+;    6         control character
+;    7         hex digit
+
+; --- ctype_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets up the character translation table.
+
+               EXPORT  ctype_init
+ctype_init     ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               ADR     R2,ctype__table         ;Point to the main table
+               ADR     R3,ctype__terrTrans     ;Point to territory decode
+
+10             LDRB    R1,[R3],#1              ;Load property number
+               CMP     R1,#255                 ;Is this the end?
+               BEQ     %f10                    ;Yes -- return then
+               MOV     R0,#-1                  ;Get the current territory
+               SWI     XTerritory_CharacterPropertyTable
+               BVS     %90ctype_init           ;If not there, quit now
+               LDRB    R1,[R3],#1              ;Load the bit number
+
+               MOV     R4,#0                   ;Initialise a counter
+00             TST     R4,#&1F000000           ;Run out of bits?
+               LDREQ   R5,[R0],#4              ;Yes -- load some more then
+               MOVS    R5,R5,LSR #1            ;Put a bit in carry
+               LDRB    R14,[R2,R4,LSR #24]     ;Load the byte
+               BICCC   R14,R14,R1              ;Maybe clear the bit
+               ORRCS   R14,R14,R1              ;Maybe set it
+               STRB    R14,[R2,R4,LSR #24]     ;Store the byte back
+               ADDS    R4,R4,#&01000000        ;Increment the counter
+               BCC     %b00                    ;And loop until done
+               B       %b10                    ;Skip back for next bit
+
+10             MOV     R0,#-1                  ;Use current territory
+               SWI     XTerritory_UpperCaseTable ;Find upper case table
+               MOVVC   R1,R0                   ;Remember this value
+               MOVVC   R0,#-1                  ;Current territory again
+               SWIVC   XTerritory_LowerCaseTable ;And get the lower table
+               BVS     %90ctype_init           ;If not there, quit now
+
+               MOV     R3,#0                   ;Get a counter going
+00             LDRB    R14,[R2],#1             ;Load the flags byte
+               MOVS    R14,R14,LSL #28         ;Put letter bits away
+               LDRCSB  R14,[R0,R3,LSR #24]     ;If uppercase, get lower
+               LDRMIB  R14,[R1,R3,LSR #24]     ;Otherwise get upper
+               STRB    R14,[R2,#255]           ;Store in the table nicely
+               ADDS    R3,R3,#&01000000        ;Move pointers on
+               BCC     %b00                    ;And keep going until done
+
+90ctype_init   LDMFD   R13!,{R0-R5,PC}^        ;Return when finished
+
+S              EQU     1
+P              EQU     2
+B              EQU     4
+L              EQU     8
+U              EQU     16
+D              EQU     32
+C              EQU     64
+X              EQU     128
+
+ctype__terrTrans DCB   0,C
+               DCB     1,U
+               DCB     2,L
+               DCB     4,P
+               DCB     5,S
+               DCB     6,D
+               DCB     7,X
+               DCB     255,255
+
+               DCD     0
+ctype__table   DCB     C,   C,   C,   C,       C,   C,   C,   C
+               DCB     C+S, C+S, C+S, C+S,     C+S, C+S, C,   C
+               DCB     C,   C,   C,   C,       C,   C,   C,   C
+               DCB     C,   C,   C,   C,       C,   C,   C,   C
+               DCB     B,   P,   P,   P,       P,   P,   P,   P
+               DCB     P,   P,   P,   P,       P,   P,   P,   P
+               DCB     D,   D,   D,   D,       D,   D,   D,   D
+               DCB     D,   D,   P,   P,       P,   P,   P,   P
+               DCB     P,   U+X, U+X, U+X,     U+X, U+X, U+X, U
+               DCB     U,   U,   U,   U,       U,   U,   U,   U
+               DCB     U,   U,   U,   U,       U,   U,   U,   U
+               DCB     U,   U,   U,   P,       P,   P,   P,   P
+               DCB     P,   L+X, L+X, L+X,     L+X, L+X, L+X, L
+               DCB     L,   L,   L,   L,       L,   L,   L,   L
+               DCB     L,   L,   L,   L,       L,   L,   L,   L
+               DCB     L,   L,   L,   P,       P,   P,   P,   C
+
+               DCB     P,   P,   P,   P,       P,   U,   L,   P
+               DCB     P,   P,   P,   P,       P,   P,   P,   P
+               DCB     P,   P,   P,   P,       P,   P,   P,   P
+               DCB     P,   P,   U,   L,       P,   P,   P,   P
+               DCB     P,   P,   P,   P,       P,   P,   P,   P
+               DCB     P,   P,   P,   P,       P,   P,   P,   P
+               DCB     P,   P,   P,   P,       P,   P,   P,   P
+               DCB     P,   P,   P,   P,       P,   P,   P,   P
+               DCB     U,   U,   U,   U,       U,   U,   U,   U
+               DCB     U,   U,   U,   U,       U,   U,   U,   U
+               DCB     U,   U,   U,   U,       U,   U,   U,   P
+               DCB     U,   U,   U,   U,       U,   U,   U,   L
+               DCB     L,   L,   L,   L,       L,   L,   L,   L
+               DCB     L,   L,   L,   L,       L,   L,   L,   L
+               DCB     L,   L,   L,   L,       L,   L,   L,   P
+               DCB     L,   L,   L,   L,       L,   L,   L,   L
+
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   'a', 'b', 'c',     'd', 'e', 'f', 'g'
+               DCB     'h', 'i', 'j', 'k',     'l', 'm', 'n', 'o'
+               DCB     'p', 'q', 'r', 's',     't', 'u', 'v', 'w'
+               DCB     'x', 'y', 'z', 0,       0,   0,   0,   0
+               DCB     0,   'A', 'B', 'C',     'D', 'E', 'F', 'G'
+               DCB     'H', 'I', 'J', 'K',     'L', 'M', 'N', 'O'
+               DCB     'P', 'Q', 'R', 'S',     'T', 'I', 'V', 'W'
+               DCB     'X', 'Y', 'Z', 0,       0,   0,   0,   0
+
+               DCB     0,   0,   0,   0,       0,   '\86', '\85',  0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   '\9b', '\9a',     0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     0,   0,   0,   0,       0,   0,   0,   0
+               DCB     'à', 'á', 'â', 'ã',     'ä', 'å', 'æ', 'ç'
+               DCB     'è', 'é', 'ê', 'ë',     'ì', 'í', 'î', 'ï'
+               DCB     'ð', 'ñ', 'ò', 'ó',     'ô', 'õ', 'ö', 0
+               DCB     'ø', 'ù', 'ú', 'û',     'ü', 'ý', 'þ', 'ß'
+               DCB     'À', 'Á', 'Â', 'Ã',     'Ä', 'Å', 'Æ', 'Ç'
+               DCB     'È', 'É', 'Ê', 'Ë',     'Ì', 'Í', 'Î', 'Ï'
+               DCB     'Ð', 'Ñ', 'Ò', 'Ó',     'Ô', 'Õ', 'Ö', 0
+               DCB     'Ø', 'Ù', 'Ú', 'Û',     'Ü', 'Ý', 'Þ', 'Y'
+
+               LTORG
+
+; --- ctype_findTable ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to table
+;
+; Use:         Finds the character table.
+
+               EXPORT  ctype_findTable
+ctype_findTable        ROUT
+
+               ADRL    R0,ctype__table
+               MOVS    PC,R14
+
+               LTORG
+
+; --- Other ctype routines ---
+
+               EXPORT  toupper
+toupper                ADRL    R1,ctype__table
+               LDRB    R2,[R1,R0]!
+               TST     R2,#L
+               LDRNEB  R0,[R1,#256]
+               MOVS    PC,R14
+
+               EXPORT  tolower
+tolower                ADRL    R1,ctype__table
+               LDRB    R2,[R1,R0]!
+               TST     R2,#U
+               LDRNEB  R0,[R1,#256]
+               MOVS    PC,R14
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/dbx/s/arrow b/StraySrc/Libraries/Sapphire/dbx/s/arrow
new file mode 100644 (file)
index 0000000..d7d284d
--- /dev/null
@@ -0,0 +1,140 @@
+;
+; dbx.arrow.s
+;
+; Implementation of arrow icons as dbx controls (MDW)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:repeater
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx._dbxMacs
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+arrow_event    EQU     &80000002               ;Click on an arrow button
+                                               ;R1 == icon handle
+                                               ;R2 == increment value or 0
+
+; --- arrow ---
+;
+; Control data:        +0 == increment when clicked with Select
+;              +4
+;
+; Workspace:   --
+;
+; Flags:       --
+;
+; Use:         Control type for an arrow button.
+
+               EXPORT  arrow
+arrow          ROUT
+
+               DBXWS   arrow__wSpace
+               DCD     dbxMask_click
+
+               TST     R2,#5                   ;Is this a bona fido click?
+               MOVEQS  PC,R14                  ;No -- then ignore it
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers away
+               STR     R1,arrow__icon          ;Save the icon handle
+
+               ; --- First, select the arrow button ---
+
+               MOV     R0,R10                  ;Get the dialogue handle
+               MOV     R2,#1                   ;Set icon's select state
+               BL      dbox_select             ;Show the button popped in
+
+               ; --- Calculate the increment to return ---
+
+               SUB     R13,R13,#20             ;Make some space for a block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetPointerInfo     ;Get the current mouse state
+               LDR     R14,[R1,#8]             ;Load the button status
+               LDR     R2,[R9,#0]              ;Get the arrow increment
+               CMP     R14,#1                  ;Is Adjust being clicked?
+               RSBEQ   R2,R2,#0                ;Yes -- negate the increment
+               STR     R2,arrow__inc           ;Save the increment
+               ADD     R13,R13,#20             ;Reclaim the stack space
+
+               ; --- Now set up the repeater ---
+
+               ADR     R0,arrow__repeat        ;Point to repeater routine
+               MOV     R1,R10                  ;Pass dialogue in R10
+               MOV     R2,R12                  ;And workspace in R12
+               BL      repeater                ;Set up the repeater
+
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller if all OK
+
+arrow__wSpace  DCD     0
+
+               LTORG
+
+; --- arrow__repeat ---
+;
+; On entry:    R0 == number of repeats, or 0 for end of job
+;
+; On exit:     --
+;
+; Use:         Handles autorepeating for the arrow button.
+
+arrow__repeat  ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               CMP     R0,#0                   ;Is this the end?
+               BEQ     %50arrow__repeat        ;Yes -- do different things
+
+               ; --- Send a normal continuation event ---
+               ;
+               ; To avoid `buffering' effect, remove the MUL R2,R0,R2
+               ; instruction.
+
+               LDMIA   R12,{R1,R2}             ;Load increment and icon
+               MUL     R2,R0,R2                ;Accumulate lots of ops
+               MOV     R0,#arrow_event         ;Get the event code
+               BL      dbx_sendEvent           ;Send the event along nicely
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               ; --- Send end-of-the-job event ---
+
+50arrow__repeat        MOV     R0,R10                  ;Yes -- get the dialogue
+               LDR     R1,arrow__icon          ;Load the icon handle
+               MOV     R2,#0                   ;Deselect the button
+               BL      dbox_select             ;And do the deselect op
+
+               MOV     R0,#arrow_event         ;Get the event code
+               BL      dbx_sendEvent           ;Send the event along nicely
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+arrow__wStart  #       0
+
+arrow__icon    #       4                       ;Icon handle of button
+arrow__inc     #       4                       ;Increment to return
+
+arrow__wSize   EQU     {VAR}-arrow__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     arrow__wSize
+               DCD     arrow__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/dbx/s/colourPot b/StraySrc/Libraries/Sapphire/dbx/s/colourPot
new file mode 100644 (file)
index 0000000..b92995d
--- /dev/null
@@ -0,0 +1,277 @@
+;
+; colourPot.s
+;
+; dbx control for selecting Wimp colours (MDW)
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:colourBox
+               GET     sapphire:dbox
+               GET     sapphire:errorBox
+               GET     sapphire:screen
+               GET     sapphire:winUtils
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx._dbxMacs
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- colourPot ---
+;
+; Control data:        +0 == null terminated title string, or empty for default
+;              +n
+;
+; Workspace:   +0 == current colour selected
+;              +1
+;
+; Flags:       bit 8 == allow transparent
+;
+; Use:         Provides a `colour button' which allows the user to choose
+;              a Wimp colour.
+
+               EXPORT  colourPot
+colourPot      ROUT
+
+               DBXWS   cp__wSpace
+               DCD     dbxMask_click + dbxMask_redraw
+
+               CMP     R0,#dbxEvent_click      ;Is this a click event?
+               BEQ     %50colourPot            ;Yes -- deal with that then
+
+               ; --- Redraw a colour pot ---
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDRB    R14,[R8,#0]             ;Load current colour
+               CMP     R14,#255                ;Is it transparent?
+               BEQ     %20colourPot            ;Yes -- deal with that then
+
+               ; --- Handle shading of icons ---
+               ;
+               ; We use the Wimp's shading algorithm from RISC OS 3.5 for
+               ; this -- clear a bunch of bits!  This is extremely odd,
+               ; since it doesn't take the lightness/darkness of the colour
+               ; into account, but it does appear to be standard...
+
+               STMFD   R13!,{R0-R3}            ;Save more registers
+               ORR     R2,R14,#&80             ;Set the `background' bit
+               MOV     R0,R10                  ;Get the dialogue handle
+               BL      dbox_window             ;Get the window handle
+               BL      winUtils_shaded         ;Is the icon shaded?
+               ANDCS   R2,R2,#&82              ;Yes -- oddly clear bits
+               MOV     R0,R2                   ;Get colour in R0
+               SWI     Wimp_SetColour          ;Set the colour up
+               SWI     OS_WriteI+16            ;Clear graphics window
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               ; --- Fill transparent with hatching ---
+
+20colourPot    STMFD   R13!,{R0-R7}            ;Save lots of registers
+               MOV     R6,R2                   ;Look after left x coord
+               MOV     R7,R3                   ;And the bottom y coord too
+
+               ; --- Work out a colour translation table ---
+               ;
+               ; We will shade the pattern sprite if we need to, by using
+               ; an alternate palette table.
+
+               MOV     R0,R10                  ;Get the dbox handle
+               BL      dbox_window             ;Translate to window handle
+               BL      winUtils_shaded         ;Is the icon shaded?
+               MOV     R0,#0                   ;My sprite is mode 0
+               ADRCC   R1,cp__hatchPal         ;Point to the palette
+               ADRCS   R1,cp__shadePal         ;Whichever is appropriate
+               MOV     R2,#-1                  ;Create for current mode
+               MOV     R3,#-1                  ;And the current palette
+               MOV     R4,R11                  ;Build it in the scratchpad
+               SWI     ColourTrans_SelectTable ;Build the translate table
+
+               ; --- Now set up a zoom block ---
+
+               BL      screen_getInfo          ;Read current screen info
+               ADD     R14,R0,#screen_dx       ;Find current pixel sizes
+               LDMIA   R14,{R2,R3}             ;Load these out as divisors
+               MOV     R0,#2                   ;Sprite x width is 2
+               MOV     R1,#4                   ;And the y height is 4
+               STMFD   R13!,{R0-R3}            ;Save these on the stack
+
+               ; --- Finally, plot the sprite ---
+
+               MOV     R0,#52                  ;Plot sprite scaled
+               ORR     R0,R0,#(1<<9)           ;We have a sprite pointer
+               MOV     R1,#&1000               ;Use a bogus sprite area
+               ADR     R2,cp__hatchSprite      ;Point to the sprite data
+               MOV     R3,R6                   ;Recover the x coordinate
+               MOV     R4,R7                   ;And the y coordinate
+               MOV     R5,#0                   ;Just plot the thing
+               MOV     R6,R13                  ;Point to zoom block
+               MOV     R7,R11                  ;And to the translate table
+               SWI     OS_SpriteOp             ;Plot the sprite
+               ADD     R13,R13,#16             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R7,PC}^        ;And return to caller
+
+               ; --- Sprite definition ---
+               ;
+               ; Here for compactness.
+
+cp__hatchPal   DCD     &FFFFFF00
+               DCD     &00000000
+
+cp__shadePal   DCD     &FFFFFF00
+               DCD     &BABABA00
+
+cp__hatchSprite        DCD     44+9*4
+               DCB     "hatchptn",0,0,0,0
+               DCD     0
+               DCD     8
+               DCD     0
+               DCD     17
+               DCD     44
+               DCD     44
+               DCD     0
+
+               DCD     &00030303
+               DCD     &0000cccc
+               DCD     &00003030
+               DCD     &0000cccc
+               DCD     &00030303
+               DCD     &0000cccc
+               DCD     &00003030
+               DCD     &0000cccc
+               DCD     &00030303
+
+               ; --- Handle a mouse click on the button ---
+
+50colourPot    TST     R2,#2                   ;Is this a menu click?
+               BNE     %70colourPot            ;Yes -- bring up the dialogue
+               TST     R2,#5                   ;Make sure it's not a drag
+               MOVEQS  PC,R14                  ;If it is, ignore it
+
+               ; --- Handle a SELECT or ADJUST click ---
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               LDRB    R0,[R8,#0]              ;Load the current colour
+               TST     R0,#&F0                 ;Any top bits set?
+               MOVNE   R0,#0                   ;Yes -- force a wraparound
+               BNE     %f00                    ;And skip on
+               TST     R2,#1                   ;Is this an adjust click?
+               RSBNE   R0,R0,#15               ;Invert the colour if reqd
+               MOV     R0,R0,LSL #28           ;Shift into top nibble
+               ADDS    R0,R0,#(1<<28)          ;Increment the colour
+               LDREQ   R14,[R9,#-12]           ;Load the flags word
+               EOREQ   R14,R14,#(1<<8)         ;Complement trans bit
+               TSTEQ   R14,#(1<<8)             ;Are we allowing transparent?
+               MOVEQ   R0,#255                 ;Yes -- do that then
+               MOVNE   R0,R0,LSR #28           ;Otherwise shift down again
+00             TSTNE   R2,#1                   ;Was it an adjust click?
+               RSBNE   R0,R0,#15               ;Yes -- uninvert the colour
+               STRB    R0,[R8,#0]              ;Save the colour back again
+               BL      cp__update              ;We've updated the colour
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               ; --- Handle MENU click --
+
+70colourPot    STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               STMIA   R12,{R1,R8,R10}         ;Save useful information
+               LDRB    R0,[R9,#0]              ;Load first byte of title
+               CMP     R0,#&20                 ;Is this string empty?
+               ADRCC   R0,cp__title            ;Yes -- use default string
+               MOVCS   R0,R9                   ;No -- point to user's title
+               LDRB    R1,[R8,#0]              ;Find the current colour
+               LDR     R14,[R9,#-12]           ;Load the control's flags
+               TST     R14,#(1<<8)             ;Does he allow transparent?
+               ORRNE   R1,R1,#(1<<8)           ;Yes -- then so shall we
+               ADR     R2,cp__handler          ;Point to my handler
+               MOV     R3,#0                   ;Don't care about R10
+               MOV     R4,R12                  ;Pass workspace in R12
+               BL      colourBox               ;Try to display the dialogue
+               MOVVS   R1,#1                   ;If it failed, display error
+               BLVS    errorBox                ;In a one-button errorbox
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+cp__title      DCB     "cpTITLE",0
+
+               LTORG
+
+; --- cp__handler ---
+;
+; On entry:    R0 == event code
+;              R1 == colour chosen
+;
+; On exit:     --
+;
+; Use:         Handles events for our colour box.
+
+cp__handler    ROUT
+
+               CMP     R0,#cbEvent_select      ;User made a selection?
+               MOVNES  PC,R14                  ;No -- don't care
+               STMFD   R13!,{R1,R8,R10,R14}    ;Save some registers
+               MOV     R14,R1                  ;Look after the colour
+               LDMIA   R12,{R1,R8,R10}         ;Load icon, data, and dbox
+               STRB    R14,[R8,#0]             ;Save the new colour
+               BL      cp__update              ;Tell client we've updated
+               LDMFD   R13!,{R1,R8,R10,PC}^    ;And return to caller
+
+               LTORG
+
+; --- cp__update ---
+;
+; On entry:    R1 == icon handle
+;              R8 == address of control data
+;              R10 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Updates the dialogue box and sends our owner an event.
+
+cp__update     ROUT
+
+               STMFD   R13!,{R0,R2,R14}        ;Save some registers
+               MOV     R0,R10                  ;Get the dialogue handle
+               BL      dbx_update              ;Redraw the control
+               MOV     R0,#colourPot_event     ;Get the event code
+               LDRB    R2,[R8,#0]              ;Load the current colour
+               BL      dbx_sendEvent           ;Send the event off
+               LDMFD   R13!,{R0,R2,PC}^        ;And return to caller
+
+               LTORG
+
+cp__wSpace     DCD     0
+
+;----- Magic constants ------------------------------------------------------
+
+colourPot_event        EQU     &80000006
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+cp__wStart     #       0
+
+cp__icon       #       4                       ;Current control's icon
+cp__addr       #       4                       ;Address of colour byte
+cp__dbox       #       4                       ;Current control's dialogue
+
+cp__wSize      EQU     {VAR}-cp__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     cp__wSize
+               DCD     cp__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/dbx/s/dbx b/StraySrc/Libraries/Sapphire/dbx/s/dbx
new file mode 100644 (file)
index 0000000..24346b0
--- /dev/null
@@ -0,0 +1,877 @@
+;
+; dbx.dbx.s
+;
+; Managing dialogue box control types (MDW)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:msgs
+               GET     sapphire:screen
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- dbx_declare ---
+;
+; On entry:    R0 == dialogue box handle from dbox
+;              R1 == pointer to dialogue box definition block
+;
+; On exit:     --
+;
+; Use:         Declares a dialogue box to be dbx-managed, and declares the
+;              control types of all its controls.
+
+               EXPORT  dbx_declare
+dbx_declare    ROUT
+
+               STMFD   R13!,{R0-R2,R10,R14}    ;Save some registers
+               MOV     R10,R0                  ;Get dialogue handle
+
+               ; --- Sort out what needs doing ---
+
+               LDR     R14,[R10,#dbx__defn]    ;Is there a dbx definition?
+               CMP     R14,#0                  ;If so, this isn't zero
+               BEQ     %10dbx_declare          ;No -- skip onwards
+
+               ; --- Shut down the existing controls ---
+
+               MOV     R2,R1                   ;Keep the control block
+               MOV     R0,#dbxEvent_lifeCycle  ;Get the lifecycle code
+               LDR     R14,[R10,#dbox__flags]  ;Load the flags word
+               TST     R14,#dbFlag__open       ;Is the box open right now?
+               MOVNE   R1,#dblc_close          ;Tell controls it's closed
+               BLNE    dbx__broadcast          ;Send the message
+               MOV     R1,#dblc_destroy        ;Tell controls to shut down
+               BL      dbx__broadcast          ;Send the message
+               STR     R2,[R10,#dbx__defn]     ;Save the new control block
+               B       %50dbx_declare          ;And skip ahead
+
+               ; --- Set up first dbx controls ---
+
+10dbx_declare  STR     R1,[R10,#dbx__defn]     ;Store the definition pointer
+               ADD     R14,R10,#dbox__proc     ;Point to the event proc
+               LDMIA   R14,{R0-R2}             ;Load all the information
+               ADD     R14,R10,#dbx__proc      ;Point to my bit of data
+               STMIA   R14,{R0-R2}             ;Save the old handler away
+
+               ; --- Now set up the dbx handler ---
+
+               ADR     R14,dbx__events         ;Point to my event handler
+               STR     R14,[R0,#dbox__proc]    ;Save this as the new proc
+               STR     R10,[R0,#dbox__R10]     ;Pass dbox handle in R10
+
+               ; --- Send initialise messages ---
+
+50dbx_declare  MOV     R0,#dbxEvent_lifeCycle  ;Get the event code
+               MOV     R1,#dblc_create         ;Send creation notice
+               BL      dbx__broadcast          ;Send the message
+               LDR     R14,[R10,#dbox__flags]  ;Load the flags word
+               TST     R14,#dbFlag__open       ;Is the dialogue open?
+               MOVNE   R1,#dblc_open           ;Inform controls it's open
+               BLNE    dbx__broadcast          ;And send the message
+
+               ; --- Done (at last) ---
+
+               LDMFD   R13!,{R0-R2,R10,PC}^    ;Return to caller
+
+               LTORG
+
+; --- dbx_sendEvent ---
+;
+; On entry:    R0 == event code to send
+;              R1-R7 == depend on the event code
+;              R10 == dialogue box handle
+;
+; On exit:     C flag as set by event handler
+;
+; Use:         Sends an event to the specified dialogue box.  This is
+;              intended to be used by control handlers, hence the unusual
+;              placing of the dialogue handle in R10.
+
+               EXPORT  dbx_sendEvent
+dbx_sendEvent  ROUT
+
+               STMFD   R13!,{R8-R10,R12,R14}   ;Save some registers
+               MOV     R9,R10                  ;Pass dialogue handle in R9
+               LDR     R14,[R10,#dbx__defn]    ;Is this dialogue box dbx'ed?
+               CMP     R14,#0                  ;Yes -- then this isn't 0
+               ADDEQ   R14,R10,#dbox__proc     ;No -- point to real proc
+               ADDNE   R14,R10,#dbx__proc      ;Yes -- point to saved proc
+               LDMIA   R14,{R8,R10,R12}        ;Load the proc bitties
+               ADDS    R0,R0,#0                ;Clear the carry flag
+               TEQ     R8,#0                   ;Is there a handler?
+               MOV     R14,PC                  ;Set up return address
+               MOVNE   PC,R8                   ;Call the handler then
+               LDMFD   R13!,{R8-R10,R12,R14}   ;Load the registers I saved
+               ORRCSS  PC,R14,#C_flag          ;If C set, set C on exit
+               BICCCS  PC,R14,#C_flag          ;If C clear, clear C on exit
+
+               LTORG
+
+; --- dbx__events ---
+;
+; On entry:    R0 == event code
+;              R1-R7 == depend on event type
+;              R10 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Handles events for a dbx-managed dialogue box.
+
+dbx__events    ROUT
+
+               ; --- Make sure it's an interesting event ---
+
+               CMP     R0,#dbEvent_redraw      ;Is it a redraw event?
+               BEQ     dbx__redraw             ;Handle redraws specially
+
+               CMP     R0,#0                   ;Is icon handle in R0?
+               BGE     %10dbx__events          ;Yes -- handle cleverly
+
+               CMP     R0,#dbEvent_help        ;Test events with icon in R1
+               CMPNE   R0,#dbEvent_save
+               CMPNE   R0,#dbEvent_load
+               CMPNE   R0,#dbEvent_menu
+               BEQ     %20dbx__events          ;If any of them, handle it
+
+               CMP     R0,#dbEvent_drag        ;And now ones with icon in R2
+               CMPNE   R0,#dbEvent_key
+               BEQ     %30dbx__events
+
+               CMP     R0,#dbEvent_lifeCycle   ;Is it a lifecycle broadcast?
+               BEQ     %40dbx__events
+
+               ; --- Don't recognise the event ---
+               ;
+               ; So we'd better pass it to the original dbox handle
+
+               B       dbx_sendEvent           ;This handles everything!
+
+               ; --- Handle mouse click events ---
+
+10dbx__events  STMFD   R13!,{R0-R2,R14}        ;Save some registers away
+               MOV     R2,R1                   ;Get mouse button state
+               MOV     R1,R0                   ;Get the icon clicked
+               MOV     R0,#dbxEvent_click      ;Give control a click event
+               BL      dbx__ctrlEvent          ;Send it to the control
+               LDMFD   R13!,{R0-R2,R14}        ;Restore all the registers
+               B       %80dbx__events          ;Tidy up things with C flag
+
+               ; --- Handle events with icon handle in R1 ---
+
+20dbx__events  STMFD   R13!,{R0-R5,R14}        ;Save a load of registers
+               CMP     R0,#dbEvent_menu        ;Is this a menu click event?
+               MOVEQ   R0,#dbxEvent_click      ;Yes -- then give a click
+               MOVEQ   R2,#2                   ;And set the `menu' bit
+
+               MOV     R5,#dbxDrop_load        ;Assume event is a load
+               CMP     R0,#dbEvent_save        ;Is this a save event?
+               MOVEQ   R5,#dbxDrop_save        ;Yes -- it's a save instead
+               CMPNE   R0,#dbEvent_load        ;Or maybe it's a load event
+               MOVEQ   R0,#dbxEvent_drop       ;It's a file dropped event
+
+               CMP     R0,#dbEvent_help        ;In that case, it's a help?
+               MOVEQ   R0,#dbxEvent_help       ;Yes -- set up that event
+
+               BL      dbx__ctrlEvent          ;Send it to the control
+               LDMFD   R13!,{R0-R5,R14}        ;Restore a load of registers
+               B       %80dbx__events          ;And tidy everything up
+
+               ; --- And now handle the oddities with handles in R2 ---
+               ;
+               ; Both of these work just the same -- swap R2 and R1 over,
+               ; load event code into R0 and dispatch the event
+
+30dbx__events  STMFD   R13!,{R0-R2,R14}        ;Save some registers away
+               EOR     R1,R1,R2                ;The standard swap-in-three
+               EOR     R2,R1,R2                ;R2 == old_R1 now
+               EOR     R1,R1,R2                ;R1 == old_R2 now.  Done!
+               CMP     R0,#dbEvent_drag        ;Was it a drag event?
+               MOVEQ   R0,#dbxEvent_click      ;Yes -- deliver a click
+               MOVNE   R0,#dbxEvent_key        ;No -- deliver a keypress
+               BL      dbx__ctrlEvent          ;Send it to the control
+               LDMFD   R13!,{R0-R2,R14}        ;Restore the registers
+               B       %80dbx__events          ;And tidy everything up
+
+               ; --- Handle lifecycle changes ---
+
+40dbx__events  STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,#dbxEvent_lifeCycle  ;Get the event code
+               BL      dbx__broadcast          ;Send the message out
+               LDMFD   R13!,{R0,R14}           ;Restore registers
+               B       %80dbx__events          ;And tidy everything up
+
+               ; --- Now handle the standard aftermath ---
+               ;
+               ; If the control didn't like it, we pass the whole event on
+               ; to the user dialogue box handler.
+
+80dbx__events  BCC     dbx_sendEvent           ;Send event to user if nec.
+               ORRS    PC,R14,#C_flag          ;Otherwise, we claim it
+
+               LTORG
+
+; --- dbx_findData ---
+;
+; On entry:    R0 == icon handle
+;              R10 == dialogue box handle
+;
+; On exit:     If found, CS and
+;                R8 == pointer to writable control data
+;                R9 == pointer to static control data
+;              else CC and
+;                R8, R9 corrupted
+;
+; Use:         Allows a control to find its data when called by client
+;              code.
+
+               EXPORT  dbx_findData
+dbx_findData   ROUT
+
+               STMFD   R13!,{R4-R7,R14}        ;Save some registers
+               LDR     R9,[R10,#dbx__defn]     ;Find the dialogue def block
+10dbx_findData LDMIA   R9,{R4-R8}              ;Load all the information
+               CMP     R4,#-1                  ;Is the icon handle -1?
+               BEQ     %80dbx_findData         ;Yes -- icon handle not found
+               CMP     R1,R4                   ;Is this a match we have?
+               ADDNE   R9,R9,R7                ;No -- add in the block size
+               BNE     %10dbx_findData         ;And loop around again
+
+               ; --- Find control's workspace if necessary ---
+               ;
+               ; If the user has not supplied control writable data and
+               ; it wants some, an address exception is created.
+
+               ADD     R9,R9,#16               ;Point past this block header
+               TST     R6,#dbxFlag_dataR10 :OR: dbxFlag_dataR12
+               MOVEQ   R8,#&80000000           ;Address exception if wanted
+               BEQ     %15dbx_findData         ;No data -- skip onwards
+
+               ADD     R9,R9,#4                ;Skip past data offset word
+               TST     R6,#dbxFlag_dataR10     ;Does he want R10-relative?
+               LDRNE   R14,[R10,#dbx__R10]     ;Yes -- load user's R10 value
+               LDREQ   R14,[R10,#dbx__R12]     ;No -- load user's R12 value
+               ADD     R8,R14,R8               ;Add in loaded offset nicely
+
+15dbx_findData LDMFD   R13!,{R4-R7,R14}        ;Unstack registers
+               ORRS    PC,R14,#C_flag          ;Say we found it OK
+
+80dbx_findData LDMFD   R13!,{R4-R7,R14}        ;Unstack registers
+               BICS    PC,R14,#C_flag          ;Say we couldn't find it
+
+               LTORG
+
+; --- dbx__ctrlEvent ---
+;
+; On entry:    R0 == dbx event code type
+;              R1 == icon handle to dispatch to
+;              R2-R7 == depend on the event code
+;              R10 == dialogue box handle
+;
+; On exit:     Registers preserved, C set if control claimed the event
+;
+; Use:         Sends an event to a control, setting up all the registers
+;              etc. appropriately.
+
+dbx__ctrlEvent ROUT
+
+               STMFD   R13!,{R4-R9,R14}        ;Save masses of registers
+               LDR     R9,[R10,#dbx__defn]     ;Find the dialogue def block
+               MOV     R4,R13                  ;Point to stacked registers
+00             LDMIA   R9,{R4-R8}              ;Load all the information
+               CMP     R4,#-1                  ;Is the icon handle -1?
+               BEQ     %80dbx__ctrlEvent       ;Yes -- icon handle not found
+               CMP     R1,R4                   ;Is this a match we have?
+               ADDNE   R9,R9,R7                ;No -- add in the block size
+               BNE     %b00                    ;And loop around again
+               BL      dbx__deliver            ;Deliver the event
+               LDMFD   R13!,{R4-R9,R14}        ;Unstack registers
+               ORRCSS  PC,R14,#C_flag          ;And return with C set
+               BICCCS  PC,R14,#C_flag          ;Or not, appropriately
+
+80             LDMFD   R13!,{R4-R9,R14}        ;Unstack registers
+               BICS    PC,R14,#C_flag          ;Event was not claimed
+
+               LTORG
+
+; --- dbx__deliver ---
+;
+; On entry:    R0 == dbx event code to deliver
+;              R1-R3 == arguments specific to the event
+;              R4 == pointer to more arguments for event (R4-R7)
+;              R5 == (untransformed) pointer to event code
+;              R6 == dbx control flags
+;              R7 == size of control block
+;              R8 == pointer to control writable data
+;              R9 == address of control information
+;              R10 == dialogue handle
+;
+; On exit:     Registers preserved, C set if control claimed the event
+;
+; Use:         Delivers an event to a control.
+
+dbx__deliver   ROUT
+
+               STMFD   R13!,{R4-R9,R12,R14}    ;Save some registers
+
+               ; --- Check that the control is interested ---
+
+               BL      dbx__xform              ;Translate R5 nicely
+               LDMIA   R5,{R7,R12,R14}         ;Load control R12 and flags
+               CMP     R7,#0                   ;Is there an address?
+               LDRNE   R7,[R7,#0]              ;Load workspace offset
+               LDRNE   R12,[R11,-R12]          ;Load workspace base address
+               ADDNE   R12,R12,R7              ;And work out workspace
+               MOV     R7,#1                   ;To shift the bit around
+               TST     R14,R7,LSL R0           ;Check event's mask bit
+               BEQ     %80dbx__deliver         ;Bit is clear -- ignore event
+
+               ; --- Find control's workspace if necessary ---
+               ;
+               ; If the user has not supplied control writable data and
+               ; it wants some, an address exception is created.
+
+               ADD     R9,R9,#16               ;Point past this block header
+               TST     R6,#dbxFlag_dataR10 :OR: dbxFlag_dataR12
+               MOVEQ   R8,#&80000000           ;Address exception if wanted
+               BEQ     %15dbx__deliver         ;No data -- skip onwards
+
+               ADD     R9,R9,#4                ;Skip past data offset word
+               TST     R6,#dbxFlag_dataR10     ;Does he want R10-relative?
+               LDRNE   R14,[R10,#dbx__R10]     ;Yes -- load user's R10 value
+               LDREQ   R14,[R10,#dbx__R12]     ;No -- load user's R12 value
+               ADD     R8,R14,R8               ;Add in loaded offset nicely
+
+               ; --- Writable data pointer is set up then ---
+
+15dbx__deliver LDMIA   R4,{R4-R7}              ;Fetch saved registers
+               MOV     R14,PC                  ;Set up return address nicely
+               ADD     PC,R5,#12               ;Call the control's code
+
+               LDMFD   R13!,{R4-R9,R12,R14}    ;Restore all the registers
+               ORRCSS  PC,R14,#C_flag          ;If C set, set C on return
+               BICCCS  PC,R14,#C_flag          ;Otherwise clear C on return
+
+               ; --- We couldn't find a suitable control ---
+
+80dbx__deliver LDMFD   R13!,{R4-R9,R12,R14}    ;Restore all the registers
+               BICS    PC,R14,#C_flag          ;Clear C -- event ignored
+
+               LTORG
+
+
+; --- dbx__broadcast ---
+;
+; On entry:    R0 == dbx event code
+;              R1-R7 depend on the event code
+;              R10 == dialogue box handle
+;
+; On exit:     ---
+;
+; Use:         Sends an event to all controls in a dialogue box.
+
+dbx__broadcast ROUT
+
+               STMFD   R13!,{R4-R9,R14}        ;Save some registers
+               LDR     R9,[R10,#dbx__defn]     ;Find the control definition
+               MOV     R4,R13                  ;Point to stacked arguments
+00             LDMIA   R9,{R4-R8}              ;Load information from block
+               CMP     R4,#-1                  ;Is icon number bogus?
+               LDMEQFD R13!,{R4-R9,PC}^        ;Yes -- then return
+               BL      dbx__deliver            ;Deliver the event
+               ADD     R9,R9,R7                ;Move on to next event
+               B       %b00                    ;And keep on looping
+
+               LTORG
+
+; --- dbx__xform ---
+;
+; On entry:    R5 == pointer to a dbx control
+;
+; On exit:     R5 possibly modified
+;
+; Use:         Translates R5 to point to a dbx control block.  The problem
+;              is dynamic linking: R5 might actually point to a branch
+;              to the real control.  So we spot that here and hack around
+;              the problem.
+
+dbx__xform     ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,[R5,#0]             ;Load the pointer out
+               CMP     R14,#&80000000          ;Is the pointer out of range?
+               BICCS   R14,R14,#&FF000000      ;Clear instruction bits
+               ADDCS   R14,R14,#2              ;Account for pipeline
+               ADDCS   R5,R5,R14,LSL #2        ;And work out the address
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- dbx__redraw ---
+;
+; On entry:    R0 == dbEvent_redraw
+;              R1 == pointer to redraw rectangle block
+;              R2 == x coordinate of window origin on screen
+;              R3 == y coordinate of window origin on screen
+;              R10 == dialogue box handle
+;
+; On exit:     Registers preserved, C clear on exit unless user claimed
+;              the redraw event.
+;
+; Use:         Handles a redraw event for a dbx-controlled dialogue box.
+;              We go through all the controls in the block and test which
+;              ones want redraw events.  For each one, we set the graphics
+;              rectangle to the intersection of the icon bounding box and
+;              the redraw rectangle, load the screen position of the icon
+;              and pass the control handler a redraw event.
+
+dbx__redraw    ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+               BL      dbx_sendEvent           ;Let the user do some redraw
+               LDMCSFD R13!,{PC}               ;If it was claimed, return
+               STMFD   R13!,{R0-R9,R12}        ;Save some more registers
+
+               ; --- Set up some standard registers ---
+
+               MOV     R6,R2                   ;Look after the origin coords
+               MOV     R7,R3                   ;Both x and y -- we need 'em
+               ADD     R5,R1,#28               ;Point to redraw rectangle
+
+               LDR     R0,[R10,#dbx__defn]     ;Find the control definitions
+
+               ; --- Now loop through the controls ---
+
+10dbx__redraw  LDMIA   R0,{R1-R4,R8}           ;Load the control information
+               CMP     R1,#-1                  ;Is this the end of the list?
+               BEQ     %90dbx__redraw          ;Yes -- return to caller
+
+               ; --- Check if the control likes redraw events ---
+
+               LDR     R14,[R2,#0]             ;Load the value out
+               CMP     R14,#&80000000          ;Is it out of range?
+               BICCS   R14,R14,#&ff000000      ;Yes -- clear instruction
+               ADDCS   R14,R14,#2              ;Compensate for pipeline
+               ADDCS   R2,R2,R14,LSL #2        ;And work out real address
+               LDMIA   R2,{R9,R12,R14}         ;Load control R12 and flags
+               CMP     R9,#0                   ;Is there an address?
+               LDRNE   R9,[R9,#0]              ;Load workspace offset
+               LDRNE   R12,[R11,-R12]          ;Load workspace base
+               ADDNE   R12,R12,R9              ;Work out workspace address
+               TST     R14,#1<<dbxEvent_redraw ;Is the mask bit set for 'em?
+               ADDEQ   R0,R0,R4                ;No -- move to next one
+               BEQ     %10dbx__redraw          ;And loop back round again
+
+               ; --- It does -- spring into action then ---
+
+               ADD     R9,R0,#16               ;Point past this block header
+               TST     R3,#dbxFlag_dataR10 :OR: dbxFlag_dataR12
+               MOVEQ   R8,#&80000000           ;Address exception if wanted
+               BEQ     %15dbx__redraw          ;No data -- skip onwards
+
+               ADD     R9,R9,#4                ;Skip past data offset word
+               TST     R3,#dbxFlag_dataR10     ;Does he want R10-relative?
+               LDRNE   R14,[R10,#dbx__R10]     ;Yes -- load user's R10 value
+               LDREQ   R14,[R10,#dbx__R12]     ;No -- load user's R12 value
+               ADD     R8,R14,R8               ;Add in loaded offset nicely
+
+               ; --- Registers R8 onwards are all set up then ---
+
+15dbx__redraw  STMFD   R13!,{R0,R2-R5}         ;Save some more registers
+               LDR     R0,[R10,#dbox__defn]    ;Load the window def pointer
+               ADD     R0,R0,#88               ;Point to the first icon
+               ADD     R0,R0,R1,LSL #5         ;Point to R1th icon
+               LDMIA   R0,{R2-R5,R14}          ;Load icon coordinates
+               ADD     R2,R2,R6                ;Convert them to screen ones
+               ADD     R3,R3,R7
+               ADD     R4,R4,R6
+               ADD     R5,R5,R7
+
+               ; --- Trim icon so all coords are inclusive ---
+
+               STMFD   R13!,{R6-R10}           ;Save some temp regs too
+               TST     R14,#4                  ;Does icon have a border?
+               BL      screen_getInfo          ;Get the current screen info
+               ADD     R0,R0,#screen_dx        ;Point to the pixel sizes
+               LDMIA   R0,{R10,R14}            ;Load the pixel sizes out
+               SUB     R4,R4,R10               ;Chop off the extra x pixel
+               SUB     R5,R5,R14               ;Chop off the y one too
+               SUBNE   R4,R4,R10               ;If border, take off an...
+               SUBNE   R5,R5,R14               ;... extra pixel all the...
+               ADDNE   R2,R2,R10               ;... way round to stop...
+               ADDNE   R3,R3,R14               ;... nasty flickery effects
+
+               ; --- Now load the graphics window and compare ---
+
+               LDR     R6,[R13,#36]            ;Load the rectangle pointer
+               LDMIA   R6,{R6-R9}              ;Load the rectangle coords
+               SUB     R8,R8,R10               ;Trim these coordinates too
+               SUB     R9,R9,R14
+               CMP     R2,R8                   ;Check they overlap
+               CMPLE   R3,R9
+               CMPLE   R6,R4
+               CMPLE   R7,R5
+               BGT     %70dbx__redraw          ;And skip to the end
+
+               ; --- Now construct the intersection rectangle ---
+
+               STMFD   R13!,{R6-R9}            ;Save these coordinates away
+               CMP     R6,R2
+               MOVLT   R6,R2
+               CMP     R7,R3
+               MOVLT   R7,R3
+               CMP     R8,R4
+               MOVGT   R8,R4
+               CMP     R9,R5
+               MOVGT   R9,R5
+
+               ; --- Set this as the graphics rectangle ---
+
+               MOV     R6,R6,LSL #8            ;Shift x0 up one byte
+               ORR     R6,R6,#24               ;Set graphics rectangle code
+               ORR     R6,R6,R7,LSL #24        ;Move in bottom byte of y0
+               MOV     R7,R7,LSR #8            ;Get top byte of y0
+               ORR     R7,R7,R8,LSL #8         ;Move in both bytes of x1
+               ORR     R7,R7,R9,LSL #24        ;Move in bottom byte of y1
+               MOV     R8,R9,LSR #8            ;Get top byte of y1
+               STMFD   R13!,{R1,R6-R8}         ;Save that lot on the stack
+               ADD     R0,R13,#4               ;Point to VDU sequence
+               MOV     R1,#9                   ;Length of the sequence
+               SWI     OS_WriteN               ;Write them to the VDU
+               LDMFD   R13!,{R1}               ;Restore R1 from the stack
+               ADD     R13,R13,#12             ;Reclaim stack from VDU op
+
+               ; --- Now call the control's event handler ---
+
+               ADD     R14,R13,#24             ;Point to old saved registers
+               LDMIA   R14!,{R8-R10}           ;Restore arguments for event
+               LDR     R6,[R13,#52]            ;Load graphics window pointer
+               LDR     R0,[R14,#4]             ;Get the control handler ptr
+               ADD     R0,R0,#12               ;Point to the handler code
+               STMFD   R13!,{R0}               ;Save it on the stack
+               MOV     R0,#dbxEvent_redraw     ;Give it a redraw event code
+               MOV     R14,PC                  ;Set up the return address
+               LDMFD   R13!,{PC}               ;Call the routine nicely
+
+               ; --- Tidy everything up once more ---
+
+               LDMFD   R13!,{R6-R9}            ;Get the old graphics window
+               MOV     R6,R6,LSL #8            ;Shift x0 up one byte
+               ORR     R6,R6,#24               ;Set graphics rectangle code
+               ORR     R6,R6,R7,LSL #24        ;Move in bottom byte of y0
+               MOV     R7,R7,LSR #8            ;Get top byte of y0
+               ORR     R7,R7,R8,LSL #8         ;Move in both bytes of x1
+               ORR     R7,R7,R9,LSL #24        ;Move in bottom byte of y1
+               MOV     R8,R9,LSR #8            ;Get top byte of y1
+               STMFD   R13!,{R6-R8}            ;Save that lot on the stack
+               MOV     R0,R13                  ;Point to VDU sequence
+               MOV     R1,#9                   ;Length of the sequence
+               SWI     OS_WriteN               ;Restore graphics window
+               ADD     R13,R13,#12             ;Reclaim stack from VDU op
+
+70dbx__redraw  LDMFD   R13!,{R6-R10}           ;Restore main code's R6-R10
+               LDMFD   R13!,{R0,R2-R5}         ;Restore variables for loop
+               ADD     R0,R0,R4                ;Move on to the next block
+               B       %10dbx__redraw          ;Go back to the main loop
+
+               ; --- Return to the caller ---
+
+90dbx__redraw  LDMFD   R13!,{R0-R9,R12,R14}    ;Restore a load of registers
+               BICS    PC,R14,#C_flag          ;Return without claiming
+
+               LTORG
+
+; --- dbx_controlBBox ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == control icon number
+;
+; On exit:     R0,R1 preserved
+;              R2-R5 == inclusive screen coordinates of icon bounding box
+;
+; Use:         Calculates the position *on the screen* of the given control
+;              icon, and returns it to you as a set of four inclusive
+;              coordinates (*not* inclusive-exclusve as the WIMP tends to
+;              return to you)
+
+               EXPORT  dbx_controlBBox
+dbx_controlBBox        ROUT
+
+               STMFD   R13!,{R0,R1,R6,R7,R14}  ;Save a load of registers
+               MOV     R7,R0                   ;Look after the dbox handle
+               LDR     R0,[R0,#dbox__defn]     ;Find the window definition
+               ADD     R0,R0,#88               ;Find the first icon defn
+               ADD     R0,R0,R1,LSL #5         ;Find the correct icon defn
+               LDMIA   R0,{R2-R6}              ;Load coordinates and flags
+               TST     R6,#4                   ;Does the icon have a border?
+
+               BL      screen_getInfo          ;Find info about the screen
+               ADD     R0,R0,#screen_dx        ;Point to the pixel sizes
+               LDMIA   R0,{R0,R1}              ;Load the pixel sizes
+
+               SUB     R4,R4,R0                ;Get the inclusive coords
+               SUB     R5,R5,R1
+               SUBNE   R4,R4,R0                ;If border, move inwards
+               SUBNE   R5,R5,R1
+               ADDNE   R2,R2,R0
+               ADDNE   R3,R3,R1
+
+               LDR     R0,[R7,#dbox__window]   ;Get the dbox's window handle
+               SUB     R13,R13,#36             ;Make way for icon state blk
+               STR     R0,[R13,#0]             ;Save the window handle in it
+               MOV     R1,R13                  ;Point at the block
+               SWI     Wimp_GetWindowState     ;Get all the window info
+
+               LDR     R6,[R1,#4]              ;Get the min x coordinate
+               ADD     R1,R1,#16               ;Point to the max y coord
+               LDMIA   R1,{R0,R7,R14}          ;Load the other coords I want
+               SUB     R6,R6,R7                ;Get the x origin position
+               SUB     R7,R0,R14               ;Get the y origin position
+
+               ADD     R2,R2,R6                ;Convert icon posn to screen
+               ADD     R3,R3,R7
+               ADD     R4,R4,R6
+               ADD     R5,R5,R7
+
+               ADD     R13,R13,#36             ;Reclaim that stack I used
+               LDMFD   R13!,{R0,R1,R6,R7,PC}^  ;Return to caller happy
+
+               LTORG
+
+; --- dbx_update ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number of control to update
+;
+; On exit:     --
+;
+; Use:         Redraws the specified control immediately.  If the control
+;              does not redraw itself, this call does nothing.
+
+               EXPORT  dbx_update
+dbx_update     ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,#dbxEvent_redraw     ;Send a redraw event
+               BL      dbx__update             ;Perform the redraw
+               LDMFD   R13!,{R2,PC}^           ;And return to caller
+
+               LTORG
+
+; --- dbx_qUpdate ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number of control to update
+;
+; On exit:     --
+;
+; Use:         Makes a control quickly update itself in whichever way it
+;              needs to in order to be perfect again.  It is anticipated
+;              that this is used to update EORed areas of the control.
+
+               EXPORT  dbx_qUpdate
+dbx_qUpdate    ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,#dbxEvent_update     ;Send an update event
+               BL      dbx__update             ;Perform the redraw
+               LDMFD   R13!,{R2,PC}^           ;And return to caller
+
+               LTORG
+
+; --- dbx__update ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number of control to update
+;              R2 == event to send to control
+;
+; On exit:     --
+;
+; Use:         Sends events to a control to perform an update.  This is used
+;              for dbx_update and for dbx_qUpdate.
+
+dbx__update    ROUT
+
+               STMFD   R13!,{R0-R10,R12,R14}   ;Save a large number of regs
+               MOV     R10,R0                  ;Look after the dbox handle
+
+               ; --- Try to find the control ---
+
+               LDR     R9,[R10,#dbx__defn]     ;Find the dialogue def block
+10dbx__update  LDMIA   R9,{R4-R8}              ;Load all the information
+               CMP     R4,#-1                  ;Is the icon handle -1?
+               BEQ     %80dbx__update          ;Yes -- icon handle not found
+               CMP     R1,R4                   ;Is this a match we have?
+               ADDNE   R9,R9,R7                ;No -- add in the block size
+               BNE     %10dbx__update          ;And loop around again
+
+               ; --- We have found the control ---
+               ;
+               ; Check that it supports redraw events.
+
+               BL      dbx__xform              ;Translate the pointer
+               LDMIA   R5,{R4,R12,R14}         ;Load control R12 and flags
+               CMP     R4,#0                   ;Is there any workspace?
+               LDRNE   R4,[R4,#0]              ;Load workspace offset
+               LDRNE   R12,[R11,-R12]          ;Load workspace base
+               ADDNE   R12,R12,R4              ;And work out workspace
+               MOV     R4,#1                   ;A value to shift with
+               TST     R14,R4,LSL R2           ;Check it wants the event
+               BEQ     %80dbx__update          ;No -- skip to the end
+
+               ; --- Now find the control's workspace ---
+
+               ADD     R9,R9,#16               ;Point past this block header
+               TST     R6,#dbxFlag_dataR10 :OR: dbxFlag_dataR12
+               MOVEQ   R8,#&80000000           ;Address exception if wanted
+               BEQ     %15dbx__update          ;No data -- skip onwards
+
+               ADD     R9,R9,#4                ;Skip past data offset word
+               TST     R6,#dbxFlag_dataR10     ;Does he want R10-relative?
+               LDRNE   R14,[R10,#dbx__R10]     ;Yes -- load user's R10 value
+               LDREQ   R14,[R10,#dbx__R12]     ;No -- load user's R12 value
+               ADD     R8,R14,R8               ;Add in loaded offset nicely
+
+               ; --- Now we need to find the icon definition ---
+
+15dbx__update  ADD     R5,R5,#12               ;Point to the control handler
+               STMFD   R13!,{R5}               ;Save control handler ptr
+               LDR     R0,[R10,#dbox__defn]    ;Load the window def pointer
+               ADD     R0,R0,#88               ;Point to the first icon
+               ADD     R0,R0,R1,LSL #5         ;Point to R1th icon
+               LDMIA   R0,{R2-R6}              ;Load icon coordinates
+               SUB     R13,R13,#44             ;Make way for a redraw blk
+               LDR     R14,[R10,#dbox__window] ;Get the dialogue's window
+               STR     R14,[R13,#0]            ;Store it in the block
+               STMIB   R13,{R2-R5}             ;Store icon coordinates too
+
+               ; --- Start the window update ---
+
+               MOV     R1,R13                  ;Point to the update block
+               SWI     Wimp_UpdateWindow       ;Give me a first rectangle
+               CMP     R0,#0                   ;Is there anything to do?
+               BEQ     %70dbx__update          ;No -- skip to loop bottom
+
+               ; --- Fix the icon bounding box to be inclusive ---
+
+               TST     R6,#4                   ;Does icon have a border?
+               BL      screen_getInfo          ;Get the screen information
+               ADD     R0,R0,#screen_dx        ;Point to the pixel sizes
+               LDMIA   R0,{R6,R7}              ;Get the pixel sizes
+               SUB     R4,R4,R6                ;Chop off the extra x pixel
+               SUB     R5,R5,R7                ;Chop off the y one too
+               SUBNE   R4,R4,R6                ;If border, take off an...
+               SUBNE   R5,R5,R7                ;... extra pixel all the...
+               ADDNE   R2,R2,R6                ;... way round to stop...
+               ADDNE   R3,R3,R7                ;... nasty flickery effects
+
+               ; --- Now translate the whole thing to window coords ---
+
+               LDR     R6,[R1,#4]              ;Get the window left position
+               ADD     R0,R1,#16               ;Point to the top position
+               LDMIA   R0,{R0,R7,R14}          ;Load top, and scroll posns
+               SUB     R6,R6,R7                ;Convert to find origin x
+               SUB     R7,R0,R14               ;Convert to find origin y
+               ADD     R2,R2,R6                ;Convert rectangle now
+               ADD     R3,R3,R7
+               ADD     R4,R4,R6
+               ADD     R5,R5,R7
+               ADD     R6,R13,#28              ;Load graphic window pointer
+
+               ; --- Now do the main update loop ---
+
+20dbx__update  LDR     R1,[R13,#52]            ;Load control's icon handle
+               LDR     R0,[R13,#56]            ;And the event which we send
+               MOV     R14,PC                  ;Set up the return address
+               LDR     PC,[R13,#44]            ;Call the control routine
+               MOV     R1,R13                  ;Point to the update block
+               SWI     Wimp_GetRectangle       ;Get the next rectangle
+               CMP     R0,#0                   ;Are there any more left?
+               BNE     %20dbx__update          ;Yes -- loop round again
+
+               ; --- Tidy up the stack and registers ---
+
+70dbx__update  ADD     R13,R13,#48             ;Restore all the stack
+
+               ; --- Return to caller ---
+
+80dbx__update  LDMFD   R13!,{R0-R10,R12,PC}^   ;Return to caller at last
+
+               LTORG
+
+;----- Dialogue box blocks --------------------------------------------------
+
+               ^       0
+
+; --- Information for dbox ---
+
+dbox__window   #       4                       ;The real window handle
+dbox__proc     #       4                       ;Pointer to event handler
+dbox__R10      #       4                       ;Magic handle for event proc
+dbox__R12      #       4                       ;Workspace for event proc
+dbox__oldCaret #       24                      ;Caret position to restore
+dbox__defn     #       4                       ;Pointer to window template
+dbox__template #       4                       ;Pointer to original template
+dbox__title    #       4                       ;Embedded title icon number
+dbox__flags    #       4                       ;Various interesting flags
+
+; --- Information for dbx ---
+
+dbx__proc      #       4                       ;Pointer to user event proc
+dbx__R10       #       4                       ;Object pointer for user proc
+dbx__R12       #       4                       ;Workspace for user proc
+dbx__defn      #       4                       ;Pointer to control def block
+
+dbox__blockSize        #       0                       ;Size of the above block
+
+; --- Flags ---
+
+dbFlag__open   EQU     (1<<0)                  ;Borrowed from dbox
+
+;----- dbx dialogue definition ----------------------------------------------
+
+               ^       0
+dbx__icon      #       4                       ;Icon number of this control
+dbx__control   #       4                       ;Pointer to control type
+dbx__dbFlags   #       4                       ;Flags for the control
+dbx__size      #       4                       ;Size of this control info
+dbx__data      #       4                       ;(Optional) offset to data
+
+dbxFlag_dataR10        EQU     (1<<0)                  ;Has R10-relative data
+dbxFlag_dataR12        EQU     (1<<1)                  ;Has R12-relative data
+
+;----- dbx control definition -----------------------------------------------
+
+               ^       0
+dbx__ctrlR12   #       4                       ;Workspace for control
+dbx__ctrlFlags #       4                       ;Flags mask for the control
+dbx__handler   #       4                       ;The actual handler code
+
+;----- dbx event codes ------------------------------------------------------
+
+               ^       0
+dbxEvent_click #       1
+dbxEvent_redraw        #       1
+dbxEvent_key   #       1
+dbxEvent_drop  #       1
+dbxEvent_help  #       1
+dbxEvent_update        #       1
+dbxEvent_lifeCycle #   1
+
+               ^       0
+dbxDrop_load   #       1
+dbxDrop_save   #       1
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/dbx/s/fileIcon b/StraySrc/Libraries/Sapphire/dbx/s/fileIcon
new file mode 100644 (file)
index 0000000..20a9e8f
--- /dev/null
@@ -0,0 +1,390 @@
+;
+; dbx.fileIcon.s
+;
+; Draggable file icons as dbx controls (MDW)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+               GET     sapphire:string
+               GET     sapphire:win
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx._dbxMacs
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- fileIcon_sprName ---
+;
+; On entry:    R0 == filetype
+;              R1 == pointer to filename
+;
+; On exit:     R0 == pointer to sprite name to use
+;
+; Use:         Works out the sprite name to use for the given filetype and
+;              name pair.
+
+               EXPORT  fileIcon_sprName
+fileIcon_sprName ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Save some registers
+
+               ; --- Get some easy cases out the way ---
+
+               CMP     R0,#&3000               ;Is it untyped?
+               ADREQ   R0,fi__xxx              ;Yes -- point to the default
+               BEQ     %90fileIcon_sprName     ;And skip to the end
+               CMP     R0,#&1000               ;Is it a directory?
+               ADREQ   R0,fi__dir              ;Point to the sprite name
+               BEQ     %90fileIcon_sprName     ;And skip to the end
+               CMP     R0,#&2000               ;Is this an application?
+               BEQ     %50fileIcon_sprName     ;Yes -- handle that nicely
+
+               ; --- It's just a simple file ---
+
+               MOV     R3,R0                   ;Look after the filetype
+               MOV     R0,R11                  ;Use scratchpad for name
+               ADR     R1,fi__file             ;Point to sprite name prefix
+               BL      str_cpy                 ;Copy the string over
+               MOV     R2,#2                   ;Three characters to write
+
+               ; --- Write the hex number on the end ---
+
+00             AND     R14,R3,#&F              ;Get the bottom nibble
+               MOV     R3,R3,LSR #4            ;And shift down the type
+               ADD     R14,R14,#'0'            ;Convert to a digit
+               CMP     R14,#'9'                ;Is it a letter, really?
+               ADDGT   R14,R14,#'a'-'9'-1      ;Yes -- make it so
+               STRB    R14,[R0,R2]             ;Store the letter then
+               SUBS    R2,R2,#1                ;Do the next character
+               BGE     %00fileIcon_sprName     ;If more -- do them
+               MOV     R2,#0                   ;A NULL byte
+               STRB    R2,[R0,#3]              ;Terminate the string
+               MOV     R0,R11                  ;Point to the string
+               BL      fi__sExist              ;Does it exist?
+               ADRCC   R0,fi__xxx              ;No -- use default sprite
+               B       %90fileIcon_sprName     ;And return to caller
+
+               ; --- The thingy is an application ---
+
+50             MOV     R0,R1                   ;Point to start of filename
+51             LDRB    R14,[R1],#1             ;Get a character
+               CMP     R14,#'.'                ;Is it a dot?
+               MOVEQ   R0,R1                   ;Yes -- remember position
+               CMP     R14,#32                 ;Is it a control char?
+               BGE     %51fileIcon_sprName     ;No -- keep looping
+               BL      fi__sExist              ;Does it exist?
+               ADRCC   R0,fi__app              ;No -- use default sprite
+
+90             LDMFD   R13!,{R1-R3,PC}^        ;Return to caller
+
+fi__xxx                DCB     "file_xxx",0
+fi__app                DCB     "application",0
+fi__file       DCB     "file_",0
+fi__dir                DCB     "directory",0
+
+               LTORG
+
+; --- fi__sExist ---
+;
+; On entry:    R0 == pointer to sprite name
+;
+; On exit:     CS if the sprite exists, CC if it doesn't
+;
+; Use:         Informs you whether a sprite exists
+
+fi__sExist     ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Save some registers
+               MOV     R2,R0                   ;Point to the sprite name
+               MOV     R0,#40                  ;Read sprite information
+               SWI     XWimp_SpriteOp          ;Get the information
+               LDMFD   R13!,{R0-R6,R14}        ;Restore registers
+               ORRVCS  PC,R14,#C_flag          ;If it exists, set C
+               BICVSS  PC,R14,#C_flag          ;Otherwise clear C
+
+               LTORG
+
+; --- fileIcon ---
+;
+; Control data:        +0
+;
+; Workspace:   +0 == filetype of object to display
+;              +4 == address of filename
+;              +8
+;
+; Flags:       --
+;
+; Use:         Control which displays a filetype icon, and allows it to
+;              be dragged.
+
+               EXPORT  fileIcon
+fileIcon       ROUT
+
+               DBXWS   fi__wSpace
+               DCD     dbxMask_click+dbxMask_redraw
+
+               CMP     R0,#dbxEvent_click      ;Is it a click event?
+               BEQ     %50fileIcon             ;Yes -- deal with it
+
+               ; --- We must have a redraw event then ---
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+
+               ; --- Find out if it should be invisible ---
+
+               LDMIA   R12,{R0,R14}            ;Get vanished dbox,icon
+               CMP     R0,R10                  ;Check dialogues match
+               CMPEQ   R1,R14                  ;And the icon handles
+               LDMEQFD R13!,{R0-R3,PC}^        ;Yes -- leave icon blank
+
+               ; --- Just fill in the sprite ---
+
+               SUB     R13,R13,#40             ;Get me a block, please
+               MOV     R0,R10                  ;The dialogue box
+               BL      dbox_window             ;Get the window handle
+               STMIA   R13,{R0,R1}             ;Store window, icon handle
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetIconState       ;Get the icon state
+               LDMIA   R8,{R0,R1}              ;Load filetype/name
+               BL      fileIcon_sprName        ;Get the sprite name
+               MOV     R1,R0                   ;Put spritename in R1
+               MOV     R0,#&1A                 ;The icon flags
+               ORR     R0,R0,#&100             ;...continued
+               LDR     R14,[R13,#24]           ;Load the icon flags word
+               EOR     R14,R14,#&005F0000      ;Toggle ESG and shaded bits
+               TST     R14,#&00400000          ;Is the shaded bit set?
+               TSTNE   R14,#&001F0000          ;No -- check the ESG then
+               ORREQ   R0,R0,#&00400000        ;Yes -- set the shaded bit
+               MOV     R2,#1                   ;Use Wimp sprite area
+               MOV     R3,#12                  ;Size of indirected buffer
+               ADD     R14,R13,#24             ;Point into the block
+               STMIA   R14,{R0-R3}             ;Store into the block
+               ADD     R1,R13,#8               ;For use with PlotIcon
+               SWI     Wimp_PlotIcon           ;Plot the icon
+               ADD     R13,R13,#40             ;Reclaim the block
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to the caller
+
+               ; --- We have been given a click event ---
+
+50             TST     R2,#&F0                 ;Was it a drag event?
+               MOVEQS  PC,R14                  ;No -- return
+
+               STMFD   R13!,{R0-R7,R14}        ;Save some registers away
+
+               ; --- Find out if we can use DragAYum ---
+
+               MOV     R0,#161                 ;Read CMOS locations
+               MOV     R1,#28                  ;Various strange status flags
+               SWI     OS_Byte                 ;Get the CMOS value there
+               TST     R2,#2                   ;Is the bit set?
+               BEQ     %60fileIcon             ;No -- use normal drag box
+
+               ; --- Set things up for DragALuvvley ---
+
+               MOV     R0,R10                  ;Get the dialogue box handle
+               LDR     R1,[R13,#4]             ;Get the icon handle to use
+               BL      dbx_controlBBox         ;Get the icon bounding box
+               BL      screen_getInfo          ;Get some screen information
+               ADD     R0,R0,#screen_dx        ;Point to the pixel sizes
+               LDMIA   R0,{R0,R1}              ;Get the pixel sizes
+               ADD     R4,R4,R0                ;Make the coordinates...
+               ADD     R5,R5,R1                ;... inclusive again
+               STMFD   R13!,{R2-R5}            ;Store these on the stack
+               LDMIA   R8,{R0,R1}              ;Get the filetype and name
+               BL      fileIcon_sprName        ;Convert into a sprite name
+               MOV     R2,R0                   ;Point to it in R2
+               MOV     R3,R13                  ;Point to my coords block
+               MOV     R1,#1                   ;Sprite area containing icon
+               MOV     R0,#&C5                 ;Various gadgetty flags
+               SWI     XDragASprite_Start      ;Start the drag up
+               ADD     R13,R13,#16             ;Clear up the coords block
+               BVS     %60fileIcon             ;If it failed, use normal box
+
+               ; --- Make the file icon `vanish' ---
+
+               MOV     R0,R10                  ;Get the dialogue handle
+               LDR     R1,[R13,#4]             ;Get the icon handle too
+               STMIA   R12,{R0,R1}             ;Save them as having vanished
+               BL      dbox_window             ;Get the dialogue handle
+               MOV     R2,#0                   ;Don't fiddle the flags
+               MOV     R3,#0                   ;Really don't do this
+               STMFD   R13!,{R0-R3}            ;Save them on the stack
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetIconState       ;Prod icon into redrawing
+               ADD     R13,R13,#16             ;Recover the stack space
+               B       %80fileIcon             ;Skip to setting up unknowns
+
+               ; --- Use an old-fashioned type drag box ---
+
+60             SUB     R13,R13,#56             ;Make way for a drag block
+               MOV     R0,R10                  ;Get the dialogue handle
+               LDR     R1,[R13,#60]            ;Get the icon handle to use
+               BL      dbx_controlBBox         ;Get the icon bounding box
+               BL      screen_getInfo          ;Get some screen information
+               ADD     R14,R0,#screen_width    ;Point to screen dimensions
+               LDMIA   R14,{R6,R7}             ;Load them out of the block
+
+               ; --- Convert the coordinates ---
+
+               LDMIA   R0,{R0,R1}              ;Get the eigen factors
+               MOV     R14,#1                  ;For shifting about a bit
+               MOV     R0,R14,LSL R0           ;Get the x pixel size
+               MOV     R1,R14,LSL R1           ;And the y pixel size
+               ADD     R4,R4,R0                ;Convert back to exclusive...
+               ADD     R5,R5,R1                ;... coordinates (grr...)
+
+               ; --- Now build the main drag block ---
+
+               MOV     R0,R10                  ;Get the dialogue handle
+               BL      dbox_window             ;Convert to a window handle
+               MOV     R1,#5                   ;Fixed-size drag box
+               MOV     R14,R13                 ;Point to the block
+               STMIA   R14!,{R0-R5}            ;Save window, type and box
+               MOV     R4,#0                   ;Set boundaries to the...
+               MOV     R5,#0                   ;... whole screen
+               STMIA   R14!,{R4-R7}            ;Save the boundaries too
+               MOV     R1,R13                  ;Point to the drag block
+               SWI     Wimp_DragBox            ;Start up the drag
+               ADD     R13,R13,#56             ;Restore the stack again
+
+               ; --- Set up the unknown handler and return ---
+
+80             ADR     R0,fi__unknown          ;Point to my handler proc
+               LDR     R1,[R13,#4]             ;Pass icon handle in R4
+                                               ;See, it does have use!
+               MOV     R2,R10                  ;Pass dialogue handle in R10
+               MOV     R3,R12                  ;And my workspace in R12
+               BL      win_unknownHandler      ;Register the magic handler
+               LDMFD   R13!,{R0-R7,R14}        ;Unstack a load of registers
+               ORRS    PC,R14,#C_flag          ;Return and claim the click
+
+fi__wSpace     DCD     0
+
+               LTORG
+
+; --- fi__unknown ---
+;
+; On entry:    R0 == an event code
+;              R1 == pointer to any associated event data
+;
+; On exit:     CS if I handled it
+;
+; Use:         Stops the drag and sends a drag finished event to the
+;              dialogue box.
+
+fi__unknown    ROUT
+
+               CMP     R0,#7                   ;Is this a drag finished?
+               MOVNES  PC,R14                  ;No -- not interested then
+
+               ; --- Send the mouse position to the dialogue ---
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers away
+               SWI     XDragASprite_Stop       ;Stop thy silly dragging
+               SUB     R13,R13,#24             ;Make some space
+               MOV     R1,R13                  ;Point to the block created
+               SWI     Wimp_GetPointerInfo     ;Get the current position
+               MOV     R0,#fIcon_event         ;Get the event code
+               MOV     R1,R4                   ;Send to the correct icon
+               ADD     R14,R13,#12             ;Get window and icon handles
+               LDMIA   R14,{R2,R3}             ;Load them from the block
+               ADD     R13,R13,#24             ;Restore the stack pointer
+               BL      dbx_sendEvent           ;Deliver the event then
+
+               ; --- Now disable the unknown handler ---
+
+               ADR     R0,fi__unknown          ;Point to my handler proc
+               MOV     R1,R4                   ;Pass icon handle in R4
+               MOV     R2,R10                  ;Pass dialogue handle in R10
+               MOV     R3,R12                  ;And my workspace in R12
+               BL      win_removeUnknownHandler ;Deregister the handler
+               LDMFD   R13!,{R0-R3,R14}        ;Unstack a load of registers
+               ORRS    PC,R14,#C_flag          ;Return and claim the click
+
+               LTORG
+
+; --- fileIcon_reAppear ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Makes the currently vanished file icon reappear.
+
+               EXPORT  fileIcon_reAppear
+fileIcon_reAppear
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Save some registers
+               WSPACE  fi__wSpace              ;Locate my workspace
+               LDMIA   R12,{R0,R1}             ;Get the vanished dbox/icon
+               CMP     R0,#0                   ;Is the dialogue null?
+               LDMEQFD R13!,{R0-R3,R12,PC}^    ;Yes -- ignore this call
+               MOV     R14,#0                  ;Zero out the vanished dbox
+               STR     R14,fi__dbox            ;Save it over the old one
+               BL      dbox_window             ;Get the dialogue handle
+               MOV     R2,#0                   ;Don't fiddle the flags
+               MOV     R3,#0                   ;Really don't do this
+               STMFD   R13!,{R0-R3}            ;Save them on the stack
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetIconState       ;Prod icon into redrawing
+               ADD     R13,R13,#16             ;Recover the stack space
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- fileIcon_closed ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Informs fileIcon that the specified dialogue box has closed.
+
+               EXPORT  fileIcon_closed
+fileIcon_closed        ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  fi__wSpace              ;Find my workspace pointer
+               LDR     R14,fi__dbox            ;Load the current dbox handle
+               CMP     R14,R0                  ;Is it a match?
+               MOVEQ   R14,#0                  ;Yes -- get a dummy handle
+               STREQ   R14,fi__dbox            ;And store in its place
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+fIcon_event    EQU     &80000003
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+fi__wStart     #       0
+
+fi__dbox       #       4                       ;Dbox with vanished icon
+fi__icon       #       4                       ;The vanished icon
+
+fi__wSize      EQU     {VAR}-fi__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     fi__wSize
+               DCD     fi__wSpace
+               DCD     16
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/dbx/s/numWrite b/StraySrc/Libraries/Sapphire/dbx/s/numWrite
new file mode 100644 (file)
index 0000000..1495b2f
--- /dev/null
@@ -0,0 +1,337 @@
+;
+; dbx.numWrite.s
+;
+; Numeric writable icons (MDW)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:keyMap
+               GET     sapphire:string
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx._dbxMacs
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- numWrite ---
+;
+; Control data:        +0 == minimum value
+;              +4 == maximum value
+;              +8
+;
+; Workspace:   +0
+;
+; Flags:       --
+;
+; Use:         Control type for numeric writable icons.
+
+               EXPORT  numWrite
+numWrite       ROUT
+
+               DBXWS   0                       ;No need for workspace
+               DCD     dbxMask_key             ;Interested in keypresses
+
+               STMFD   R13!,{R0-R7,R14}        ;Save lots of registers
+               MOV     R6,R2                   ;Keep the new character safe
+
+               MOV     R0,R10                  ;And the dialogue box handle
+               BL      dbox_getField           ;Read the current contents
+               MOV     R7,R2                   ;Keep this pointer
+
+               ; --- Find out where the caret is ---
+
+               SUB     R13,R13,#24             ;Make space for caret block
+               MOV     R1,R13                  ;Point at this block
+               SWI     Wimp_GetCaretPosition   ;Find where the caret is
+               LDR     R5,[R13,#20]            ;Load the icon index
+
+               ; --- Find out if this keypress is interesting ---
+
+               CMP     R5,#0                   ;Is the cursor at the start?
+               LDREQB  R14,[R7,#0]             ;Yes -- get the first byte
+               CMPEQ   R14,#'-'                ;Is it a minus sign?
+               BEQ     %50numWrite             ;Yes -- disallow it then
+
+               SUB     R14,R6,#'0'             ;Convert keypress to digit
+               CMP     R14,#10                 ;Is it a proper digit?
+               BCC     %10numWrite             ;Yes -- deal with it then
+               SUB     R14,R6,#key_k0          ;Try again with keypad
+               CMP     R14,#10                 ;Is it a proper digit?
+               SUBCC   R6,R6,#key_k0-'0'       ;Yes -- convert to ASCII
+               BCC     %10numWrite             ;Yes -- deal with it then
+               CMP     R6,#'-'                 ;Is is a `-' sign?
+               CMPNE   R6,#key_kMinus          ;Or the one on the keypad?
+               MOVEQ   R6,#'-'                 ;Either -- make it a `-'
+               BNE     %50numWrite             ;No -- ignore it then
+               LDR     R3,[R9,#0]              ;Load the minimum value
+               CMP     R3,#0                   ;Does it allow negative nos?
+               BGE     %50numWrite             ;No -- ignore it then
+               CMP     R5,#0                   ;Is the cursor at the start?
+               BNE     %50numWrite             ;No -- ignore it then
+
+               ; --- We've got a character to insert ---
+
+10numWrite     MOV     R2,R7                   ;Point at the icon's text
+               MOV     R7,#0                   ;An initial index
+20numWrite     CMP     R7,R5                   ;Is this the caret position?
+               MOVEQ   R14,R6                  ;Yes -- insert my char
+               LDRNEB  R14,[R2],#1             ;Otherwise load from icon
+               STRB    R14,[R11,R7]            ;Save in position
+               CMP     R14,#32                 ;Is there more to go?
+               ADDGE   R7,R7,#1                ;Increment the index
+               BGE     %20numWrite             ;Yes -- go round again
+               SUB     R7,R7,#1                ;This is the original length
+
+               ; --- Fill the icon in nicely ---
+
+               MOV     R2,R11                  ;Point to my nice new string
+               BL      numWrite__read          ;Convert it to an integer
+               MOV     R6,R2                   ;Take a copy of this value
+               LDR     R1,[R13,#28]            ;Load the icon number
+               LDMIA   R9,{R3,R4}              ;Load the boundary values
+               SUB     R4,R4,R3                ;Get the range size
+               SUB     R14,R2,R3               ;Subtract the bottom end
+               CMP     R14,R4                  ;Is the value in range?
+               MOVLS   R0,R10                  ;Yes -- get dialogue handle
+               MOVLS   R2,R11                  ;Point at the string I made
+               BLLS    dbox_setField           ;And just write the string
+               BLHI    numWrite__set           ;Otherwise set the value
+               MOVHI   R6,R2                   ;If changed, copy value
+               BL      dbx_sendEvent           ;Send the user an event
+
+               ; --- Move the caret on ---
+
+               MOV     R0,R10                  ;Get the dialogue handle
+               BL      dbox_getField           ;Find the text address
+               MOV     R0,R2                   ;Point to the buffer
+               BL      str_len                 ;Find the string length
+               SUBS    R14,R0,R7               ;Find the length difference
+               BEQ     %40numWrite             ;No movement -- forget it
+               ADD     R5,R5,R14               ;Move caret position on 1
+               CMP     R5,R0                   ;Is the caret in range?
+               LDMLSIA R13,{R0-R4}             ;Load rest of caret state
+               SWILS   Wimp_SetCaretPosition   ;Set this as the new pos
+
+               ; --- Pass an event to the user ---
+
+               MOV     R0,#numWrite_event      ;Get the event number
+               MOV     R2,#numWrite_change     ;The value has been changed
+               MOV     R3,R6                   ;Pass the value in R3
+               BL      dbx_sendEvent           ;Pass the event on
+
+40numWrite     ADD     R13,R13,#24             ;Restore the stack now
+               LDMFD   R13!,{R0-R7,R14}        ;Unstack the registers
+               ORRS    PC,R14,#C_flag          ;I used the character
+
+               ; --- Handle a weird character ---
+
+50numWrite     ADD     R13,R13,#24             ;Restore the stack
+
+               ; --- Make sure it's an arrow key ---
+
+               TST     R6,#&100                ;Is the top bit set?
+               BEQ     %90numWrite             ;No -- just return then
+               BIC     R6,R6,#&130             ;Ignore modifier bits
+               CMP     R6,#key_Tab-&100        ;Is it tab?
+               CMPNE   R6,#key_sTab-&100       ;Or is it shift-tab?
+               CMPNE   R6,#key_Up-&100         ;Or any of the cursor keys?
+               CMPNE   R6,#key_Down-&100
+               CMPNE   R6,#key_cUp-&100        ;Or maybe with control
+               CMPNE   R6,#key_cDown-&100
+               BNE     %90numWrite             ;No -- just return then
+
+               LDR     R1,[R13,#4]             ;Load the icon number
+               MOV     R0,R10                  ;Get my dialogue handle
+               BL      numWrite_read           ;Read the current value
+               BL      numWrite__set           ;Set this as the new value
+               MOV     R0,#numWrite_event      ;Get my event code
+               MOV     R3,R2                   ;Pass value in R3
+               MOV     R2,#numWrite_move       ;The cursor has moved
+               BL      dbx_sendEvent           ;Send the user an event
+
+90numWrite     LDMFD   R13!,{R0-R7,R14}        ;Unstack the registers
+               BICS    PC,R14,#C_flag          ;Let someone else have it
+
+               LTORG
+
+; --- numWrite_set ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number within dialogue
+;              R2 == value to set in the icon
+;
+; On exit:     R2 == value actually set
+;
+; Use:         Writes the specified numeric value into the given writable
+;              icon.  The icon must be a dbx control with numWrite type
+;              for this to work.
+
+               EXPORT  numWrite_set
+numWrite_set   ROUT
+
+               STMFD   R13!,{R0,R1,R8-R10,R14} ;Save some registers
+               MOV     R10,R0                  ;Keep the dialogue handle
+               BL      dbx_findData            ;Look up all the dbx info
+               BL      numWrite__set           ;Do the actual work
+               LDMFD   R13!,{R0,R1,R8-R10,PC}^ ;Return to caller
+
+               LTORG
+
+; --- numWrite__set ---
+;
+; On entry:    R1 == icon handle to set it in
+;              R2 == value to set
+;              R9 == pointer to minimum and maximum values
+;              R10 == dialogue box handle
+;
+; On exit:     R2 == actual value set
+;
+; Use:         Forces the given value between the limits for the icon
+;              and writes it into the specified icon.
+
+numWrite__set  STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Force the value in range ---
+
+               LDMIA   R9,{R0,R1}              ;Load min and max values
+               CMP     R2,R0                   ;Is it big enough?
+               MOVLT   R2,R0                   ;No -- make it bigger then
+               CMP     R2,R1                   ;Is it small enough?
+               MOVGT   R2,R1                   ;No -- make it smaller then
+               STR     R2,[R13,#8]             ;Return this modified value
+
+               ; --- Translate it into a string ---
+
+               MOV     R0,R2                   ;Get value in R0 now
+               MOV     R1,R11                  ;Build string in scratchpad
+               MOV     R2,#256                 ;Specify the scratchpad size
+               SWI     OS_ConvertInteger4      ;Convert it to a string
+
+               ; --- Write it into the icon ---
+
+               MOV     R2,R0                   ;Point at my nice new string
+               LDR     R1,[R13,#4]             ;Load the icon handle back
+               MOV     R0,R10                  ;Get the dialogue handle
+               BL      dbox_setField           ;And write it into the icon
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- numWrite_read ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon handle
+;
+; On exit:     CC if icon contains a valid integer, and
+;                R2 == value shown in the icon
+;              else CS and
+;                R2 == 0
+;
+; Use:         Reads the numeric value within the icon specifed.
+
+               EXPORT  numWrite_read
+numWrite_read  ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+               BL      dbox_getField           ;Find the icon string
+               BL      numWrite__read          ;Convert it to an integer
+               LDMFD   R13!,{PC}               ;Return it and the flags
+
+               LTORG
+
+; --- numWrite__read ---
+;
+; On entry:    R2 == pointer to a string
+;
+; On exit:     R2 == integer represented by string and CC or 0 and CS
+;
+; Use:         Converts a string showing a decimal integer to the value
+;              it represents.
+
+numWrite__read ROUT
+
+               STMFD   R13!,{R0,R1,R14}
+
+               ; --- Set up some initial values ---
+
+               MOV     R0,R2                   ;Point to the string start
+               MOV     R1,#0                   ;Not found any digits yet
+               MOV     R2,#0                   ;A good accumulator
+
+               ; --- Check for a leading sign ---
+
+               LDRB    R14,[R0],#1             ;Load a byte from the string
+               CMP     R14,#'-'                ;Is it a `-' sign?
+               ORREQ   R1,R1,#1                ;Set the `negative' bit
+               LDREQB  R14,[R0],#1             ;Yes -- load another byte
+
+               ; --- Now read bytes from the string ---
+               ;
+               ; We stop as soon as we find a character which isn't a
+               ; digit.
+
+10             SUB     R14,R14,#'0'            ;Convert to an integer
+               CMP     R14,#10                 ;Is it in range?
+               BCS     %20numWrite__read       ;No -- that's it then
+               TST     R1,#1                   ;Is the number negative?
+               ADD     R2,R2,R2,LSL #2         ;Multiply by 5
+               ADDEQ   R2,R14,R2,LSL #1        ;If +ve, double and add new
+               RSBNE   R2,R14,R2,LSL #1        ;Otherwise, subtract it
+               ORR     R1,R1,#2                ;Say we read something good
+               LDRB    R14,[R0],#1             ;Load a new byte
+               B       %10numWrite__read       ;Go round the loop again
+
+               ; --- Return the value ---
+
+20             TST     R1,#2                   ;Was the number valid?
+               LDMFD   R13!,{R0,R1,R14}        ;Restore the registers
+               ORREQS  PC,R14,#C_flag          ;No -- set C as error warning
+               BICNES  PC,R14,#C_flag          ;Otherwise clear it
+
+               LTORG
+
+; --- numWrite_bump ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon handle
+;              R2 == increment to apply to it
+;
+; On exit:     R2 == updated value in the icon
+;
+; Use:         Adjusts the value in a writable icon by a given increment.
+
+               EXPORT  numWrite_bump
+numWrite_bump  ROUT
+
+               STMFD   R13!,{R0,R1,R3,R14}     ;Save some registers
+               MOV     R3,R2                   ;Look after the increment
+               BL      numWrite_read           ;Read the current value
+               ADDCC   R2,R2,R3                ;If valid, apply increment
+               BL      numWrite_set            ;And write the value back
+               LDMFD   R13!,{R0,R1,R3,PC}^     ;Return to caller
+
+               LTORG
+
+;----- Constants ------------------------------------------------------------
+
+numWrite_event EQU     &80000004               ;R1 == icon number changed
+                                               ;R2 == subreason code
+                                               ;R3 == new value of icon
+
+numWrite_change        EQU     0                       ;Subreason -- number changed
+numWrite_move  EQU     1                       ;Subreason -- cursor moved
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/dbx/s/slider b/StraySrc/Libraries/Sapphire/dbx/s/slider
new file mode 100644 (file)
index 0000000..8a466c3
--- /dev/null
@@ -0,0 +1,395 @@
+;
+; dbx.slider.s
+;
+; Implementation of sliders as a dbx control
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:divide
+               GET     sapphire:idle
+               GET     sapphire:win
+               GET     sapphire:msgs
+               GET     sapphire:screen
+               GET     sapphire:winUtils
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx._dbxMacs
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+slFlag_vertical        EQU     (1<<8)
+slFlag_horizontal EQU  0
+slFlag_colData EQU     (1<<9)
+
+; --- slider ---
+;
+; Control data:        +0 == slider colour (if flags bit 9 clear)
+;              +1 == background colour
+;              +2 == separator colour
+;              +3 == reserved
+;              +4 == maximum slider value
+;              +8
+;
+; Workspace:   +0 == current slider value
+;              +4 == slider colour (if flags bit 9 set)
+;              +5 == reserved, must be 0
+;              +8
+;
+; Flags:       Bit 8 == slider is horizontal if clear, vertical is set
+;
+; Use:         Control type for a slider.
+
+               EXPORT  slider
+slider         ROUT
+
+               DBXWS   slider__wSpace
+               DCD     dbxMask_click + dbxMask_redraw
+
+               CMP     R0,#0                   ;Is this a click event?
+               BEQ     %50slider               ;Yes -- handle it
+
+               ; --- Handle a whole slider redraw operation ---
+
+               STMFD   R13!,{R0-R2,R6-R8,R10,R14}
+
+               ; --- Get a colour mask ---
+               ;
+               ; We use RISC OS 3.5's peculiar shading algorithm -- clear
+               ; all the colour bits except 1!  This is easy -- we just
+               ; set up an AND mask in R10 at the start.
+
+               MOV     R0,R10                  ;Get the dialogue box handle
+               BL      dbox_window             ;Translate to window handle
+               BL      winUtils_shaded         ;Is the icon shaded, please?
+               MOVCS   R10,#2                  ;Yes -- leave only bit 1
+               MOVCC   R10,#&FF                ;Otherwise leave colour alone
+
+               ; --- Sort out what needs doing ---
+
+               LDR     R6,[R9,#-12]            ;Locate the flags word
+               TST     R6,#slFlag_vertical     ;Is the slider vertical?
+               SUBNE   R7,R5,R3                ;Yes -- calculate the height
+               SUBEQ   R7,R4,R2                ;No -- calculate the width
+
+               ; --- Work out the length to draw out ---
+
+               LDR     R0,[R8,#0]              ;Load the slider value
+               MUL     R0,R7,R0                ;Multiply the value up
+               LDR     R1,[R9,#4]              ;Get the slider maximum val
+               BL      div_round               ;Calculate correct length
+               MOV     R6,R0                   ;Look after the quotient
+               MOV     R7,R2                   ;Keep the left hand edge
+               BEQ     %10slider               ;If slider not vert, skip
+
+               ; --- Now draw a vertical slider ---
+
+               LDR     R14,[R9,#-12]           ;Locate the flags word
+               TST     R14,#slFlag_colData     ;Is the colour writable?
+               LDREQB  R0,[R9,#0]              ;Get the slider colour...
+               LDRNEB  R0,[R8,#4]              ;... from wherever it is
+               AND     R0,R0,R10               ;Mask colour for shading
+               SWI     Wimp_SetColour          ;Start in this colour
+
+               BL      screen_getInfo          ;Get some screen information
+               LDR     R8,[R0,#screen_dy]      ;Load the y pixel size
+
+               MOV     R0,#4                   ;Move absolute coordinates
+               MOV     R1,R7                   ;Left hand side of control
+               MOV     R2,R3                   ;Bottom edge of control
+               SWI     OS_Plot                 ;Move graphics cursor there
+               MOV     R0,#&65                 ;Rectangle fill absolute
+               MOV     R1,R4                   ;Right hand side of control
+               ADD     R2,R3,R6                ;Top of the slider bar
+               SUB     R2,R2,R8                ;Allow a bit for the crossbar
+               CMP     R2,R3                   ;Is there any slider bar?
+               SWIGE   OS_Plot                 ;Fill in the slider bar
+
+               LDRB    R0,[R9,#2]              ;Get the separator colour
+               AND     R0,R0,R10               ;Mask colour for shading
+               SWI     Wimp_SetColour          ;Use this colour now
+               MOV     R0,#4                   ;Move cursor absolute
+               ADD     R2,R2,R8                ;Top edge of slider bar
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#5                   ;Draw line absolute
+               MOV     R1,R7                   ;Left hand side of control
+               SWI     OS_Plot                 ;Fill in the middle bit
+
+               LDRB    R0,[R9,#1]              ;Get the background colour
+               AND     R0,R0,R10               ;Mask colour for shading
+               SWI     Wimp_SetColour          ;Use this colour now
+               MOV     R0,#4                   ;Move cursor absolute
+               ADD     R2,R2,R8                ;Top edge of slider bar
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#&65                 ;Rectangle fill absolute
+               MOV     R1,R4                   ;Left hand side of control
+               CMP     R2,R5                   ;Is there anything to draw?
+               MOV     R2,R5                   ;Top of the control
+               SWILE   OS_Plot                 ;Fill in the background bit
+
+               B       %90slider               ;Skip to the end now
+
+               ; --- Now draw a horizontal slider ---
+
+10slider       LDR     R14,[R9,#-12]           ;Locate the flags word
+               TST     R14,#slFlag_colData     ;Is the colour writable?
+               LDREQB  R0,[R9,#0]              ;Get the slider colour...
+               LDRNEB  R0,[R8,#4]              ;... from wherever it is
+               AND     R0,R0,R10               ;Mask colour for shading
+               SWI     Wimp_SetColour          ;Start in this colour
+
+               BL      screen_getInfo          ;Get some screen information
+               LDR     R8,[R0,#screen_dx]      ;Load the x pixel size
+
+               MOV     R0,#4                   ;Move absolute coordinates
+               MOV     R1,R7                   ;Left hand side of control
+               MOV     R2,R3                   ;Bottom edge of control
+               SWI     OS_Plot                 ;Move graphics cursor there
+               MOV     R0,#&65                 ;Rectangle fill absolute
+               ADD     R1,R7,R6                ;Right of the slider bar
+               SUB     R1,R1,R8                ;Allow for the crossbar
+               MOV     R2,R5                   ;Top edge of the control
+               CMP     R1,R7                   ;Is there anything to draw?
+               SWIGE   OS_Plot                 ;Fill in the slider bar
+
+               LDRB    R0,[R9,#2]              ;Get the separator colour
+               AND     R0,R0,R10               ;Mask colour for shading
+               SWI     Wimp_SetColour          ;Use this colour now
+               MOV     R0,#4                   ;Move cursor absolute
+               ADD     R1,R1,R8                ;Top edge of slider bar
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#5                   ;Draw line absolute
+               MOV     R2,R3                   ;Bottom edge of the control
+               SWI     OS_Plot                 ;Fill in the middle bit
+
+               LDRB    R0,[R9,#1]              ;Get the background colour
+               AND     R0,R0,R10               ;Mask colour for shading
+               SWI     Wimp_SetColour          ;Use this colour now
+               MOV     R0,#4                   ;Move cursor absolute
+               ADD     R1,R1,R8                ;Top edge of slider bar
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#&65                 ;Rectangle fill absolute
+               CMP     R1,R4                   ;Is there anything to draw?
+               MOV     R1,R4                   ;Right hand side of control
+               MOV     R2,R5                   ;Top of the control
+               SWILE   OS_Plot                 ;Fill in the background bit
+
+90slider       LDMFD   R13!,{R0-R2,R6-R8,R10,PC}^
+
+               ; --- Handle a mouse click event ---
+               ;
+               ; We start a slider drag operation
+
+50slider       TST     R2,#5                   ;Is this a real mouse click?
+               MOVEQS  PC,R14                  ;No -- then ignore it
+               STMFD   R13!,{R0-R3,R14}        ;Save a few registers
+
+               ; --- Save the slider information away ---
+
+               MOV     R0,R10                  ;Get dialogue handle in R0
+               BL      dbx_controlBBox         ;Get the control position
+               STMIA   R12,{R1-R5,R8,R9}       ;Save the state in workspace
+
+               ; --- Start a drag operation ---
+
+               SUB     R13,R13,#56             ;Make way for a drag block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetPointerInfo     ;Get the pointer position
+               LDR     R7,[R9,#-12]            ;Get the control flags
+               TST     R7,#slFlag_vertical     ;Is the slider vertical?
+               LDRNE   R0,[R13,#0]             ;Yes -- read mouse x position
+               LDREQ   R0,[R13,#4]             ;No -- read mouse y position
+
+               MOVNE   R2,R0                   ;Force mouse to straight line
+               MOVNE   R4,R0
+               MOVEQ   R3,R0
+               MOVEQ   R5,R0
+
+               MOV     R0,R10                  ;Get the dialogue handle
+               BL      dbox_window             ;Get the dbox's window handle
+               MOV     R1,#7                   ;Drag type is user-defined
+               STMIA   R13,{R0,R1}             ;Store them in the block
+               ADD     R14,R13,#24             ;Point to parent box posn
+               STMIA   R14,{R2-R5}             ;Save them in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_DragBox            ;Start a drag operation
+               ADD     R13,R13,#56             ;Reclaim all that stack space
+
+               ADR     R0,sl__ukEvents         ;Point to unknown handler
+               MOV     R1,#0                   ;Don't care about R4
+               MOV     R2,R10                  ;Pass dialogue box in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_unknownHandler      ;Add the handler
+               MOVVC   R0,#2                   ;Call me every TV frame
+               ADRVC   R1,sl__idles            ;Point to idle handler
+               BLVC    idle_handler            ;Add in the idle handler
+               BL      sl__idles               ;Do one now for luck
+
+60slider       LDMIA   R13!,{R0-R3,R14}        ;Load the registers back
+               ORRS    PC,R14,#C_flag          ;Claim this event
+
+slider__wSpace DCD     0
+
+               LTORG
+
+; --- sl__idles ---
+;
+; On entry:    R10 == dialogue box handle for dbox
+;              R12 == my workspace
+;
+; On exit:     --
+;
+; Use:         Handles idle events during a slider drag
+
+sl__idles      ROUT
+
+               STMFD   R13!,{R0-R5,R8,R9,R14}  ;Save a barrelload of regs
+               LDMIB   R12,{R2-R5,R8,R9}       ;Load registers for readVal
+               MOV     R0,#slider_event        ;My very own event code
+               MOV     R1,#slider_sliding      ;Indicate it's still going
+               BL      sl__readVal             ;Perform the update
+               BLCS    dbx_sendEvent           ;Send the event if it changed
+               LDMFD   R13!,{R0-R5,R8,R9,PC}^  ;Return to caller
+
+               LTORG
+
+; --- sl__ukEvents ---
+;
+; On entry:    R0 == event code
+;              R1 == pointer to event data
+;              R4 == 0!
+;              R10 == dialogue box handle
+;              R12 == my workspace
+;
+; On exit:     If R0 == 7 on entry, C set, otherwise all preserved
+;
+; Use:         Handles unknown events for sliders.
+
+sl__ukEvents   ROUT
+
+               CMP     R0,#7                   ;Is this a drag event?
+               MOVNES  PC,R14                  ;No -- not interested then
+               STMFD   R13!,{R0-R5,R8,R9,R14}  ;Save a bucketload of regs
+
+               ; --- Update the slider one last time ---
+
+               LDMIB   R12,{R2-R5,R8,R9}       ;Load registers for readVal
+               MOV     R0,#slider_event        ;My very own event code
+               MOV     R1,#slider_slid         ;Indicate it's over now
+               BL      sl__readVal             ;Perform the update
+               BL      dbx_sendEvent           ;Send the event regardless
+
+               ; --- Close down the idle and unknown handlers ---
+
+               ADR     R0,sl__ukEvents         ;Point to unknown handler
+               MOV     R1,#0                   ;Don't care about R4
+               MOV     R2,R10                  ;Pass dialogue box in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_removeUnknownHandler;Add the handler
+               MOV     R0,#2                   ;Call me every TV frame
+               ADR     R1,sl__idles            ;Point to idle handler
+               BL      idle_removeHandler      ;Add in the idle handler
+
+               LDMFD   R13!,{R0-R5,R8,R9,PC}^  ;Return to caller at last
+
+               LTORG
+
+; --- sl__readVal ---
+;
+; On entry:    R0 == event code for dialogue box (slider_event)
+;              R1 == subreason code to send (slider_sliding or slider_slid)
+;              R2-R5 == position of icon on screen
+;              R8 == pointer to control workspace
+;              R9 == pointer to control definition
+;              R10 == dialogue box handle
+;
+; On exit:     R2,R3 set up for slider event
+;              CS if the slider position has changed
+;
+; Use:         Reads a slider value from mouse position, and sends the
+;              dialogue box an event
+
+sl__readVal    ROUT
+
+               STMFD   R13!,{R0,R1,R6,R14}     ;Save some registers
+
+               ; --- Read the mouse position ---
+
+               SUB     R13,R13,#20             ;Make space for a mouse blk
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetPointerInfo     ;Get the pointer position
+               LDR     R14,[R9,#-12]           ;Load the control flags
+               TST     R14,#slFlag_vertical    ;Is the control vertical?
+               LDRNE   R0,[R1,#4]              ;Yes -- get the y coordinate
+               SUBNE   R0,R0,R3                ;And chop off bottom posn
+               LDREQ   R0,[R1,#0]              ;No -- get the x coordinate
+               SUBEQ   R0,R0,R2                ;And chop of the left posn
+               ADD     R13,R13,#20             ;Reclaimt the stack now
+
+               ; --- Scale this value to user's units ---
+
+               LDR     R6,[R9,#4]              ;Get user's maximum value
+               MUL     R0,R6,R0                ;Multiply position up nicely
+               SUBNE   R1,R5,R3                ;Vertical -- get height
+               SUBEQ   R1,R4,R2                ;Horizontal -- get width
+               BL      div_round               ;Divide and round to nearest
+               CMP     R0,R6                   ;Is the value too large?
+               MOVGT   R0,R6                   ;Yes -- force it down then
+               CMP     R0,#0                   ;Is it too small?
+               MOVLT   R0,#0                   ;Yes -- force it up then
+               LDR     R3,[R8,#0]              ;Get the old slider value
+               CMP     R0,R3                   ;Is this the same as then?
+               STRNE   R0,[R8,#0]              ;No -- Store the new value
+               MOVNE   R3,R0                   ;Keep a copy for later
+
+               ; --- Update the picture of the slider ---
+
+               MOV     R0,R10                  ;Get the dialogue handle
+               LDR     R1,slider__icon         ;Get the icon handle
+               BLNE    dbx_update              ;Update the slider display
+
+               MOV     R2,R1                   ;Get icon handle in R2
+               LDMFD   R13!,{R0,R1,R6,R14}     ;Restore registers
+               ORRNES  PC,R14,#C_flag          ;If new value, set C on exit
+               BICEQS  PC,R14,#C_flag          ;Otherwise clear it
+
+               LTORG
+
+;----- Slider event codes ---------------------------------------------------
+
+slider_event   EQU     &80000001
+slider_sliding EQU     0
+slider_slid    EQU     1
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+slider__wStart #       0
+
+slider__icon   #       4                       ;Icon handle for slider
+slider__iconPos        #       16                      ;Icon coordinates on screen
+slider__work   #       4                       ;Pointer to user's workarea
+slider__defn   #       4                       ;Pointer to slider definition
+
+slider__wSize  EQU     {VAR}-slider__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     slider__wSize
+               DCD     slider__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/dbx/s/stringSet b/StraySrc/Libraries/Sapphire/dbx/s/stringSet
new file mode 100644 (file)
index 0000000..7052c05
--- /dev/null
@@ -0,0 +1,157 @@
+;
+; stringSet.s
+;
+; String set dialogue box control
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:menu
+               GET     sapphire:menuDefs
+               GET     sapphire:msgs
+               GET     sapphire:string
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx._dbxMacs
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- stringSet ---
+;
+; Control data:        +0 == address of menu definition
+;              +4 == address of string table
+;              +8 == icon number in which to write string
+;              +12
+;
+; Workspace:   +0 == current value of radio selection
+;              +4
+;
+; Flags:       --
+;
+; Use:         Provides handling for a `menu button' -- when clicked, a
+;              menu of possible values appears, from which the user may
+;              choose an entry.  The chosen string is copied to the icon.
+
+               EXPORT  stringSet
+stringSet      ROUT
+
+               DBXWS   strs__wSpace
+               DCD     dbxMask_click
+
+               TST     R2,#7                   ;Ensure it's a mouse click
+               MOVEQS  PC,R14                  ;No -- then return right now
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               LDR     R14,[R9,#8]             ;Load destination icon
+               STMIA   R12,{R10,R14}           ;Save icon and dbox away
+               MOV     R0,R10                  ;Get dialogue in R0
+               BL      dbox_slab               ;Slab the button he clicked
+               LDR     R0,[R9,#0]              ;Load the menu address
+               ADR     R1,strs__menu           ;Point to my menu handler
+               MOV     R2,R8                   ;Point to radio selector
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      menu_create             ;Display the menu nicely
+               BL      dbox_unslab             ;Now unslab the icon again
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+; --- strs__menu ---
+;
+; On entry:    R0 == menu event code
+;              R1 == index of item chosen
+;
+; On exit:     --
+;
+; Use:         Handles a selection from a string set menu.
+
+strs__menu     ROUT
+
+               CMP     R0,#mEvent_select       ;Is this a menu selection?
+               MOVNES  PC,R14                  ;No -- then return to caller
+               STMFD   R13!,{R0-R2,R10,R14}    ;Save some registers
+               LDR     R14,[R10,#0]            ;Load the old value out
+               CMP     R14,R1                  ;Do they match up?
+               LDMEQFD R13!,{R0-R2,R10,PC}^    ;Yes -- ignore the select
+               STR     R1,[R10,#0]             ;Store new radio button value
+               MOV     R2,R1                   ;Look after this value now
+               LDMIA   R12,{R0,R1}             ;Load saved icon and dialogue
+               MOV     R10,R0                  ;Put dialogue in R10 nicely
+               BL      stringSet_setValue      ;Set up the icon string
+               MOV     R0,#stringSet_event     ;Put event code in R0
+               BL      dbx_sendEvent           ;Inform client of change
+               LDMFD   R13!,{R0-R2,R10,PC}^    ;And return to caller
+
+               LTORG
+
+; --- stringSet_setValue ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon handle
+;
+; On exit:     --
+;
+; Use:         Sets the contents of the display area attached to a string
+;              set control from the current state of the control.
+
+               EXPORT  stringSet_setValue
+stringSet_setValue ROUT
+
+               STMFD   R13!,{R0-R2,R8-R10,R14} ;Save some registers
+               MOV     R10,R0                  ;Put dialogue handle in R10
+               MOV     R0,R1                   ;Get control icon in R0
+               BL      dbx_findData            ;Find my control data
+               LDMCCFD R13!,{R0-R2,R8-R10,PC}^ ;If failed, ignore this
+
+               ; --- Now look up the correct string ---
+
+               LDR     R1,[R8,#0]              ;Load the current value
+               LDR     R0,[R9,#4]              ;Load string table base
+               BL      str_index               ;Find the correct one
+
+               ; --- Fill in the icon number ---
+
+10             BL      msgs_lookup             ;Translate the string
+               MOV     R2,R0                   ;Point to the result
+               LDR     R1,[R9,#8]              ;Load the display icon handle
+               MOV     R0,R10                  ;Get the dialogue box handle
+               BL      dbox_setField           ;Write the string in
+               LDMFD   R13!,{R0-R2,R8-R10,PC}^ ;And return to caller
+
+               LTORG
+
+strs__wSpace   DCD     0
+
+stringSet_event        EQU     &80000005
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+strs__wStart   #       0
+
+strs__dbox     #       4                       ;Dbox of current stringset
+strs__icon     #       4                       ;Icon of current stringset
+
+strs__wSize    EQU     {VAR}-strs__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     strs__wSize
+               DCD     strs__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/def/csapph b/StraySrc/Libraries/Sapphire/def/csapph
new file mode 100644 (file)
index 0000000..37f7ded
--- /dev/null
@@ -0,0 +1,99 @@
+;
+; cdll definition file for Sapphire C support section
+;
+
+name "Sapphire.CSapph"
+  version 1.00
+  author "© %ce%yr Straylight (%zdy %mo %ce%yr)"
+  nonAPCS
+
+;----- Exported symbols -----------------------------------------------------
+
+exports {                      ; Next = 60
+
+  __csapph_stub                        = 0
+
+  ; --- Run-time support ---
+
+  __rt_udiv10                  = 1
+  __rt_sdiv10                  = 2
+  __rt_udiv                    = 3
+  __rt_sdiv                    = 4
+  __rt_divtest                 = 5
+
+  ; --- Sapphire/C veneer ---
+
+  __sapph_veneer               = 6
+  call                         = 7
+  swi                          = 8
+  _call                                = 9
+  _callx                       = 10
+  _swi                         = 11
+  _swix                                = 12
+
+  ; --- Specific Sapphire routine veneers ---
+
+  __sapph_scratchpad           = 13
+  strsubst                     = 14
+  strcmp                       = 15
+  stricmp                      = 16
+  strbuffer                    = 17
+  strerror                     = 18
+  __sapph_msgs_lookup          = 19
+  __sapph_msgs_error           = 20
+  malloc                       = 21
+  __sapph_free                 = 22
+  __sapph_alloc_error          = 23
+  __sapph_flex_alloc           = 24
+  __sapph_flex_free            = 25
+  __sapph_flex_size            = 26
+  __sapph_flex_extend          = 27
+  __sapph_flex_midExtend       = 28
+  __sapph_flex_save            = 29
+  __sapph_flex_load            = 30
+
+  ; --- Maths routines from the C library ---
+
+  sin                          = 31
+  cos                          = 32
+  atan                         = 33
+  tan                          = 34
+  asin                         = 35
+  acos                         = 36
+  atan2                                = 37
+  exp                          = 38
+  log                          = 39
+  log10                                = 40
+  __sapph_sqrt                 = 41
+  pow                          = 42
+  fabs                         = 43
+  fmod                         = 44
+  ceil                         = 45
+  floor                                = 46
+  modf                         = 47
+  sinh                         = 48
+  cosh                         = 49
+  tanh                         = 50
+  frexp                                = 51
+  ldexp                                = 52
+  cmath_errno                  = 53
+
+  ; --- ctype routines from the C library ---
+
+  ctype_init                   = 54
+  ctype_findTable              = 55
+  toupper                      = 56
+  tolower                      = 57
+
+  ; --- setjmp and longjmp ---
+
+  setjmp                       = 58
+  longjmp                      = 59
+}
+
+;----- Object files ---------------------------------------------------------
+
+objects {
+  lib.sapphire
+  dl.csapph
+}
diff --git a/StraySrc/Libraries/Sapphire/def/list b/StraySrc/Libraries/Sapphire/def/list
new file mode 100644 (file)
index 0000000..4c40434
--- /dev/null
@@ -0,0 +1,80 @@
+;
+; cdll definition file for Sapphire List section
+;
+
+name "Sapphire.List"
+  version 1.00
+  author "© %ce%yr Straylight (%zdy %mo %ce%yr)"
+  nonAPCS
+
+;----- Exported symbols -----------------------------------------------------
+
+exports                                ; Next = 47
+{
+  __list_stub                  = 0
+
+  ; --- gallery ---
+
+  gallery_drawBox              = 1
+  gallery_eventHandler         = 2
+  gallery_removeBox            = 3
+  gallery_reset                        = 4
+
+  ; --- listBox ---
+
+  lb_clearSelection            = 5
+  lb_clickM                    = 6
+  lb_clickS                    = 7
+  lb_create                    = 8
+  lb_destroy                   = 9
+  lb_drag                      = 10
+  lb_eventHandler              = 11
+  lb_init                      = 12
+  lb_inserted                  = 13
+  lb_isSelected                        = 14
+  lb_plotString                        = 15
+  lb_removed                   = 16
+  lb_select                    = 17
+  lb_update                    = 18
+  lb_updateItem                        = 19
+  lb_window                    = 20
+
+  ; --- llistMan ---
+
+  llist_addItem                        = 21
+  llist_create                 = 22
+  llist_destroy                        = 23
+  llist_enumerate              = 24
+  llist_indexToItem            = 25
+  llist_init                   = 26
+  llist_itemToIndex            = 27
+  llist_items                  = 28
+  llist_registerSort           = 29
+  llist_reinsert               = 30
+  llist_removeItem             = 31
+  llist_setFlags               = 32
+
+  ; --- viewer ---
+
+  viewer_click                 = 33
+  viewer_close                 = 34
+  viewer_create                        = 35
+  viewer_destroy               = 36
+  viewer_dragSelection         = 37
+  viewer_eventHandler          = 38
+  viewer_isSelected            = 39
+  viewer_open                  = 40
+  viewer_rescan                        = 41
+  viewer_select                        = 42
+  viewer_selectAll             = 43
+  viewer_setTitle              = 44
+  viewer_update                        = 45
+  viewer_window                        = 46
+}
+
+;----- Object files ---------------------------------------------------------
+
+objects {
+  lib.sapphire
+  dl.list
+}
diff --git a/StraySrc/Libraries/Sapphire/def/resources b/StraySrc/Libraries/Sapphire/def/resources
new file mode 100644 (file)
index 0000000..114315a
--- /dev/null
@@ -0,0 +1,19 @@
+;
+; sapphRes DLL definition
+;
+; © 1995 Straylight
+;
+
+name "Sapphire.Resources"
+  author "© %ce%yr Straylight (%zdy %mo %ce%yr) [UK version]"
+  version 1.00
+  nonAPCS
+
+exports {
+  sapphRes_find
+}
+
+objects {
+  o.sapphRes
+  o.resources
+}
diff --git a/StraySrc/Libraries/Sapphire/def/tearoff b/StraySrc/Libraries/Sapphire/def/tearoff
new file mode 100644 (file)
index 0000000..6a2be32
--- /dev/null
@@ -0,0 +1,29 @@
+;
+; cdll definition file for Sapphire TMS section
+;
+
+name "Sapphire.Tearoff"
+  version 1.00
+  author "© %ce%yr Straylight (%zdy %mo %ce%yr)"
+  nonAPCS
+
+;----- Exported symbols -----------------------------------------------------
+
+exports {                      ; Next = 5
+
+  __tearoff_stub               = 0
+
+  ; --- tms ---
+
+  tms_create                   = 1
+  tms_help                     = 2
+  tms_init                     = 3
+  tms_recreate                 = 4
+}
+
+;----- Object files ---------------------------------------------------------
+
+objects {
+  lib.sapphire
+  dl.tearoff
+}
diff --git a/StraySrc/Libraries/Sapphire/def/thread b/StraySrc/Libraries/Sapphire/def/thread
new file mode 100644 (file)
index 0000000..fd9a8bb
--- /dev/null
@@ -0,0 +1,41 @@
+;
+; cdll definition file for Sapphire PMT section
+;
+
+name "Sapphire.Thread"
+  version 0.00
+  author "© %ce%yr Straylight (%zdy %mo %ce%yr) [development version]"
+  nonAPCS
+
+;----- Exported symbols -----------------------------------------------------
+
+exports {                      ; Next = 17
+
+  __thread_stub                        = 0
+
+  ; --- thread ---
+
+  thread_create                        = 1
+  thread_createSem             = 2
+  thread_destroy               = 3
+  thread_destroySem            = 4
+  thread_enterCrit             = 5
+  thread_errorHandler          = 6
+  thread_init                  = 7
+  thread_leaveCrit             = 8
+  thread_resume                        = 9
+  thread_setPriority           = 10
+  thread_setTimeSlice          = 11
+  thread_signal                        = 12
+  thread_suspend               = 13
+  thread_threaded              = 14
+  thread_wait                  = 15
+  thread_yield                 = 16
+}
+
+;----- Object files ---------------------------------------------------------
+
+objects {
+  lib.sapphire
+  dl.thread
+}
diff --git a/StraySrc/Libraries/Sapphire/rsc/ColourSel,fec b/StraySrc/Libraries/Sapphire/rsc/ColourSel,fec
new file mode 100644 (file)
index 0000000..18bfabd
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/rsc/ColourSel,fec differ
diff --git a/StraySrc/Libraries/Sapphire/rsc/Messages b/StraySrc/Libraries/Sapphire/rsc/Messages
new file mode 100644 (file)
index 0000000..388d07d
--- /dev/null
@@ -0,0 +1,105 @@
+;
+; Sapphire messages
+;
+; © 1994 Straylight
+;
+
+; --- Note ---
+;
+; This file contains the actual message strings for all Sapphire message
+; tags.  The idea is that you can just dump the ones you really want into
+; your messages file and have done with it.
+
+;----- Miscellaneous strings ------------------------------------------------
+
+; --- Memory allocation ---
+
+allocNOMEM:Not enough memory
+hpNEMI:Not enough memory to intialise heap
+
+; --- Dialogue box handling ---
+
+dboxCRTERR:Couldn't create dialogue box: %0
+dboxNIND:Can't set text in non-indirected icon
+dbxDECLTWICE:Dialogue box already known to dbx
+ok:OK
+can:Cancel
+
+; --- Draw file handling ---
+
+drawTOONEW:This drawfile has an unrecognised format and cannot be rendered.
+drawBADFILE:This is not a drawfile.
+
+; --- Various standard dialogue boxes ---
+
+ebERRFRM:Error from %0
+noteFROM:Note from %0
+warnFROM:Warning from %0
+
+piHELP:This window shows you information about this version of the application.
+
+saDRAGICN:To save, drag the file icon to a directory viewer.
+sahDB:This is the save dialogue box.
+sahFICN:Drag this icon to a directory viewer or another application to save the file.
+sahWRT:Type a filename for the file here.
+sahOK:Click here to save the file under the name shown.
+
+; --- Menus ---
+
+mSOVF:Not enough memory to create menu -- increase menu_stackSize
+
+; --- Dealing with help messages ---
+
+helpOFLOW:Help message overflow
+
+; --- Key translation ---
+
+kstrF:F%i2
+kstrPRT:Print
+kstrTAB:Tab
+kstrCOPY:Copy
+kstrLEFT:Left
+kstrRIGHT:Right
+kstrDOWN:Down
+kstrUP:Up
+kstrINS:Insert
+kstrPDN:PageDown
+kstrPUP:PageUp
+kstrENTER:Enter
+kstrDEL:Delete
+kstrSPC:Space
+kstrESC:Esc
+kstrBSP:Backspace
+kstrRET:Return
+kstrHOME:Home
+kstrSH:Shift
+kstrCTL:Ctrl
+kstrKPD:Keypad
+
+; --- Loading resources ---
+
+msgsMLE:Error loading messages: %0
+rsprSLE:Error loading sprites: %0
+tplTNF:Template '%0' not found
+tplTLE:Error loading templates: %0
+
+; --- Handling errors ---
+
+sehNOHND:Fatal internal error: Uncaught exception thrown (type &%x0)
+rptERR:Internal error: '%1'.  Click Continue to try to resume, or Quit to stop %0.
+rptCONF:Are you sure you want to quit %0?  Click Continue to try to resume, or Quit to quit.
+rptUKEXC:Unknown exception (type &%x0)
+rptCONT:Continue
+rptQUIT:Quit
+
+; --- Data transfer ---
+
+saveDTDEAD:Data transfer failed, receiver dead
+
+; --- Handling background jobs ---
+
+thrNOCRT:Couldn't start background job: %0
+thrNOSEMCRT:Couldn't create semaphore: %0
+thrSEMINUSE:Can't destroy a semaphore while threads are waiting for it
+thrNOWAITSEM:Couldn't wait on semaphore: %0
+thrNOTATHRD:Only threads can wait on semaphores
diff --git a/StraySrc/Libraries/Sapphire/rsc/Sprites,ff9 b/StraySrc/Libraries/Sapphire/rsc/Sprites,ff9
new file mode 100644 (file)
index 0000000..885bc67
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/rsc/Sprites,ff9 differ
diff --git a/StraySrc/Libraries/Sapphire/rsc/Templates,fec b/StraySrc/Libraries/Sapphire/rsc/Templates,fec
new file mode 100644 (file)
index 0000000..9f1136e
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/rsc/Templates,fec differ
diff --git a/StraySrc/Libraries/Sapphire/s/akbd b/StraySrc/Libraries/Sapphire/s/akbd
new file mode 100644 (file)
index 0000000..e160d1d
--- /dev/null
@@ -0,0 +1,444 @@
+;
+; akbd.s
+;
+; Keyboard handling (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:keyMap
+               GET     sapphire:intKeys
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         KEYCMP  $reg,$key
+
+ [ $key > &100
+               CMP     $reg,# ( $key - &100 ) << 8
+ |
+               CMP     $reg,# $key
+ ]
+
+               MEND
+
+               MACRO
+$label         KEYRNG  $reg,$low,$high
+
+ [ $low > &100
+               SUB     R14,$reg,# ( $low - &100 ) << 8
+               CMP     R14,# ( $high - $low - &100 ) << 8
+ |
+               SUB     R14,$reg,# $low
+               CMP     R14,# $high-$low
+ ]
+
+               MEND
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- akbd_test ---
+;
+; On entry:    R0 == internal key number to test
+;
+; On exit:     CS if key was pressed, CC otherwise
+;
+; Use:         Informs you whether a given key is currently being pressed.
+
+               EXPORT  akbd_test
+akbd_test      ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R2,#&FF                 ;Test internal key number
+               EOR     R1,R0,#&FF              ;Wierd translation for key
+               MOV     R0,#&81                 ;Test for key pressed
+               SWI     OS_Byte                 ;Do the test nicely
+               CMP     R1,#0                   ;Is it pressed down?
+               LDMFD   R13!,{R0-R2,R14}        ;Restore registers anyhow
+               ORRNES  PC,R14,#C_flag          ;Yes -- set C on exit
+               BICEQS  PC,R14,#C_flag          ;No -- clear C on exit
+
+               LTORG
+
+; --- akbd_translate ---
+;
+; On entry:    R0 == Wimp key number
+;
+; On exit:     R0 == Straylight extended keyset key number
+;
+; Use:         Translates a Wimp key number into one of the more specific
+;              Straylight key numbers.
+
+akbd__s                EQU     (1<<0)
+akbd__c                EQU     (1<<1)
+
+               EXPORT  akbd_translate
+akbd_translate ROUT
+
+               ; --- Deep magic warning ---
+               ;
+               ; This routine is really not very pleasant.  If you can,
+               ; avoid messing about with it.  It contains several `clever'
+               ; tricks to try and reduce the code size and time taken,
+               ; which will probably end up being utterly incomprehensible.
+
+               STMFD   R13!,{R6-R10,R14}       ;Save some registers away
+               MOV     R10,R0                  ;Look after the keynumber
+               MOV     R9,R10                  ;Keep another copy
+
+               ; --- Do a clever translation on the Wimp key ---
+               ;
+               ; The idea is that instead of distinguishing the two keymap
+               ; halves by whether but 8 is set, we distinuguish by which
+               ; byte the value is in -- byte 0 for bottom-half values and
+               ; byte 1 for top-half values.  This has an advantage in that
+               ; *all* key values are now available as immediate constants.
+               ;
+               ; There is in fact a slight problem with this: &100 and &000
+               ; become indistinguishable.  This is OK, though, since the
+               ; value &100 cannot be returned by the Wimp.
+
+               CMP     R10,#&100               ;Is it in the top half?
+               MOVGE   R10,R10,LSL #8          ;Yes -- move it into byte 2
+               ANDGE   R10,R10,#&FF00          ;And clear the top bit
+
+               ; --- Handle PageUp/PageDown nicely ---
+
+               BIC     R14,R10,#&3100          ;Clear Shift and Control bits
+               CMP     R14,#&8E00              ;Is it PageUp/PageDown?
+               BEQ     %50                     ;Yes -- handle it specially
+
+               ; --- Remove some immediate no-hopers ---
+
+               KEYCMP  R10,&180                ;Is it really big?
+               BGE     %99                     ;Yes -- skip everything
+               KEYRNG  R10,'a','z'             ;Is it a simple character?
+               BLS     %99                     ;Yes -- skip everything
+               KEYRNG  R10,'A','Z'             ;Check upper case too
+               BLS     %99                     ;Yes -- skip everything
+               KEYRNG  R10,'[',']'             ;Go for the brackets too
+               BLS     %99                     ;Skip if in there
+
+               ; --- Work out the modifiers now ---
+
+               MOV     R8,#0                   ;No modifiers found yet
+               MOV     R0,#intk_Shift          ;Check for shift held down
+               BL      akbd_test               ;Is Shift being pressed?
+               ORRCS   R8,R8,#akbd__s          ;Yes -- set the bit then
+               MOV     R0,#intk_Ctrl           ;Check for ctrl too
+               BL      akbd_test               ;Is Ctrl being pressed?
+               ORRCS   R8,R8,#akbd__c          ;Yes -- set that bit
+
+               ; --- Various key checks ---
+
+               KEYCMP  R10,key_Delete          ;Check for Delete key
+               BEQ     akbd__del               ;Yes -- handle it
+
+               KEYCMP  R10,' '                 ;Check for Space key
+               BEQ     akbd__space             ;Yes -- handle it
+
+               ; --- Handle the mappings to `Return' ---
+
+               KEYCMP  R10,&0D                 ;Check for Return key
+               BNE     %10                     ;No -- skip ahead a little
+               MOV     R0,#intk_kEnter         ;Check for Enter key
+               BL      akbd_test               ;Scan the keyboard again
+               BCS     akbd__enter             ;Yes -- handle it
+               MOV     R0,#intk_M              ;Check for the M key
+               BL      akbd_test               ;Scan the keyboard again
+               BCS     %10                     ;If so, skip to ctrl keys
+
+               ADD     R9,PC,#0                ;Point to the table
+               B       %90                     ;And sort that out nicely
+               DCW     key_Return,key_sReturn
+               DCW     key_cReturn,key_scReturn
+
+akbd__enter    ADD     R9,PC,#0                ;Point to the table
+               B       %90                     ;And sort that out nicely
+               DCW     key_kEnter,key_skEnter
+               DCW     key_ckEnter,key_sckEnter
+
+akbd__space    ADD     R9,PC,#0                ;Point to the table
+               B       %90                     ;And sort that out nicely
+               DCW     key_Space,key_sSpace
+               DCW     key_cSpace,key_scSpace
+
+akbd__del      ADD     R9,PC,#0                ;Point to the table
+               B       %90                     ;And sort that out nicely
+               DCW     key_Delete,key_sDelete
+               DCW     key_cDelete,key_scDelete
+
+               ; --- Handle control keys now (at last!) ---
+
+10             CMP     R10,#&1B                ;Is it a control key?
+               BGE     %20                     ;No -- skip forwards then
+
+               MOV     R14,#&00BB              ;Part of the weird key mask
+               ORR     R14,R14,#&0300          ;Rest of the mask
+               MOV     R7,#1                   ;Will be shifted about
+               TST     R14,R7,LSL R10          ;Check the weirdness bit then
+               BEQ     %15                     ;If not *very* strange, skip
+
+               CMP     R10,#8                  ;Is it a backspace?
+               BNE     %11                     ;No -- skip ahead
+               MOV     R0,#intk_H              ;Could be a ctrl-H
+               BL      akbd_test               ;So check for that then
+               MOVCC   R0,#intk_8              ;Or a ctrl-8
+               BLCC    akbd_test               ;So check for that too
+               BCS     %11                     ;Either -- skip ahead
+
+               ADD     R9,PC,#0                ;Point to table
+               B       %90                     ;Handle table nicely
+               DCW     key_Backspace,key_sBackspace
+               DCW     key_cBackspace,key_scBackspace
+
+               ; --- Now handle keys which could be numbers ---
+
+akbd__numKeys  DCB     0,intk_1,0,intk_3,intk_4
+               DCB     intk_5,0,intk_7,intk_8,intk_9
+
+11             CMP     R10,#0                  ;Is it a null code?
+               BEQ     %13                     ;Yes -- it could be anything!
+
+               ADR     R14,akbd__numKeys       ;Point to internal key table
+               LDRB    R0,[R14,R10]            ;Load the correct number
+               BL      akbd_test               ;Test the key's state
+               BCC     %15                     ;It's not that weird then
+12             TST     R8,#akbd__s             ;Was Shift being pressed?
+               ADDNE   R9,R9,#&150             ;Yes -- add in offset
+               ADDEQ   R9,R9,#&130             ;No -- add different offset
+               B       %99                     ;And come right out of this
+
+               ; --- Handle a 0 key number ---
+
+13             MOV     R0,#intk_0              ;Is it control-0?
+               BL      akbd_test               ;Check the keyboard
+               MOVCC   R9,#2                   ;No -- then it's really 2
+               B       %12                     ;Now handle Shift status
+
+               ; --- It's a sensible control key ---
+
+15             TST     R8,#akbd__s             ;Is shift held down?
+               ADDNE   R9,R9,#&100             ;Yes -- add the offset nicely
+               B       %99                     ;And return the key number
+
+               ; --- Try to handle number key presses ---
+
+akbd__padTab   DCB     intk_k0,intk_k1,intk_k2,intk_k3,intk_k4
+               DCB     intk_k5,intk_k6,intk_k7,intk_k8,intk_k9
+
+20             SUB     R0,R10,#'0'             ;Chop off bottom limit
+               CMP     R0,#9                   ;Is it a numeric key?
+               BHI     %30                     ;No -- skip ahead then
+               ADR     R14,akbd__padTab        ;Point to key number table
+               LDRB    R0,[R14,R0]             ;Load the correct key number
+               BL      akbd_test               ;Check the key number nicely
+               ADDCS   R9,R9,#&1C0 - '0'       ;If on keypad, add offset
+               ADDCS   R9,R9,R8,LSL #4         ;And add in the modifiers
+               B       %99                     ;Return this value to caller
+
+               ; --- Handle other keypad bits ---
+               ;
+               ; This is somewhat clever in places, so watch out.  Rather
+               ; than branching on a match, or having an unconditional
+               ; CMP for each case, and a further CMP at the end, we
+               ; drop through to *all* subsequent comparisons, and take
+               ; this into account.
+               ;
+               ; Skeptics may say that this actually wastes an instruction.
+               ; Not true -- the setting up requires one value to be
+               ; initialised to an invalid value spotted at the end anyway,
+               ; and the base values are not valid immediate constants
+               ; anyway.  Oddly enough, &168 == &5A >> 2, which is valid!
+
+30             MOV     R7,#&168                ;Initial value for base
+               MOV     R0,#0                   ;Initial value for icode
+
+               CMP     R10,#'/'
+               SUBEQ   R7,R7,#1
+               ADDEQ   R0,R0,#intk_kSlash-intk_kStar
+               CMPNE   R10,#'*'
+               SUBEQ   R7,R7,#1
+               ADDEQ   R0,R0,#intk_kStar-intk_kHash
+               CMPNE   R10,#'#'
+               SUBEQ   R7,R7,#1
+               ADDEQ   R0,R0,#intk_kHash-intk_kMinus
+               CMPNE   R10,#'-'
+               SUBEQ   R7,R7,#1
+               ADDEQ   R0,R0,#intk_kMinus-intk_kPlus
+               CMPNE   R10,#'+'
+               SUBEQ   R7,R7,#2
+               ADDEQ   R0,R0,#intk_kPlus-intk_kDot
+               CMPNE   R10,#'.'
+               SUBEQ   R7,R7,#1
+               ADDEQ   R0,R0,#intk_kDot
+
+               BNE     %40                     ;If no match above, skip
+
+               BL      akbd_test               ;Test the key's state
+               BCC     %40                     ;If not pressed, skip
+
+               ; --- Now return the correct value ---
+               ;
+               ; We use the barrel shifter to copy the modifier key states
+               ; to the ARM flags.
+
+               MOV     R9,R7
+               MOVS    R14,R8,LSR #1           ;Copy ctrl to !Z, sh to C
+               SUBNE   R9,R9,#64               ;If ctrl, subtract 64
+               ADDCS   R9,R9,#16               ;If shift, add 16
+               ADDHI   R9,R9,#16               ;If both, subtract only 32
+               B       %99                     ;Return this value
+
+               ; --- Now tidy up any other weirdnesses ---
+
+40             CMP     R10,#&01E               ;Is it a home lookalike?
+               BEQ     akbd__home              ;Yes -- handle it nicely
+               CMP     R10,#&01B               ;Is it an escape press?
+               BEQ     akbd__esc               ;Yes -- handle that
+               KEYRNG  R10,&1C,&1F             ;Is it one of the others?
+               BHI     %99                     ;No -- nothing else for it
+
+               TST     R8,#akbd__s             ;Is Shift being pressed?
+               ADDNE   R9,R9,#&130             ;Yes -- offset correctly
+               ADDEQ   R9,R9,#&110             ;No -- use different offset
+               B       %99                     ;Return this value
+
+akbd__home     MOV     R0,#intk_6              ;It could be control-6
+               BL      akbd_test               ;Check this possibility
+               ADRCC   R9,akbd__homeMods       ;No -- point to home table
+               BCC     %90                     ;And process it as normal
+               TST     R8,#akbd__s             ;Is Shift being pressed?
+               ADDNE   R9,R9,#key_sc6-&1E      ;Yes -- handle this nicely
+               ADDEQ   R9,R9,#key_c6-&1E       ;No -- return other value
+               B       %99                     ;And return to caller
+
+akbd__homeMods DCW     key_Home,key_sHome
+               DCW     key_cHome,key_scHome
+
+akbd__esc      MOV     R0,#intk_LSquare        ;It could be control-[
+               BL      akbd_test               ;Check this possibility
+               ADRCC   R9,akbd__escMods        ;No -- point to escape table
+               BCC     %90                     ;And process it as normal
+               TST     R8,#akbd__s             ;Is Shift being pressed?
+               ADDNE   R9,R9,#key_scLSquare-&1B ;Yes -- handle this nicely
+               ADDEQ   R9,R9,#key_cLSquare-&1B ;No -- return other value
+               B       %99                     ;And return to caller
+
+akbd__escMods  DCW     key_Esc,key_sEsc
+               DCW     key_cEsc,key_scEsc
+
+               ; --- Distinguish Page keys from Shift+Up/Down ---
+
+50             TST     R10,#&0100              ;Is it up or down?
+               MOVNE   R0,#intk_PageUp         ;If up, check PageUp key
+               MOVEQ   R0,#intk_PageDown       ;Otherwise, check PageDown
+               BL      akbd_test               ;Check the key's pressedness
+               MOVNE   R0,#intk_k9             ;Can use keypad with NumLock!
+               MOVEQ   R0,#intk_k3             ;So check for this as well
+               BLCC    akbd_test               ;Check the key's pressedness
+               EORCS   R9,R9,#&050             ;If it is, mangle correctly
+               B       %99                     ;Return this value to caller
+
+               ; --- R9 points to a modifier table ---
+               ;
+               ; Entries in the table are held in halfwords, to save space
+
+90             TST     R8,#akbd__s             ;Is shift set?
+               BIC     R8,R8,#akbd__s          ;Clear shift bit anyway
+               LDR     R9,[R9,R8,LSL #1]       ;Load word from address
+               MOVNE   R9,R9,LSR #16           ;If set, shift word down
+               BIC     R9,R9,#&ff000000        ;Clear top byte of key value
+               BIC     R9,R9,#&00ff0000        ;Clear next byte of key too
+
+               ; --- Standard return-to-caller code ---
+
+99             MOV     R0,R9                   ;Return the key number
+               LDMFD   R13!,{R6-R10,PC}^       ;Return all registers
+
+               LTORG
+
+; --- akbd_pollKey ---
+;
+; On entry:    --
+;
+; On exit:     CC if a key was in the buffer and
+;                R0 == wimp translated key code
+;              else CS and
+;                R0 corrupted
+;
+; Use:         Reports whether the user has typed ahead, and if so what the ;          keypress. Note that the keypresses returned are WIMP-type,
+;              not Straylight extended ones so you will have to use
+;              akbd_translate if you need the extended type.
+;
+;              This call could be used to allow buffering of keypresses:
+;              on a Key_Pressed event you would call this routine until
+;              it returns FALSE and store the codes it returns in a buffer
+;              along with the code from the event.
+
+               EXPORT  akbd_pollKey
+akbd_pollKey   ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stack some registers
+               
+               ; --- Find out if there is a key waiting ---
+               
+               MOV     R0,#129                 ;Scan for a key
+               MOV     R1,#0                   ;No time limit
+               MOV     R2,#0
+               SWI     OS_Byte                 ;Read it then
+               CMP     R2,#&FF                 ;Was there a time out
+               BEQ     %95akbd_pollKey         ;Yes -- return
+               
+               ; --- Check for extended key codes ---
+               
+               CMP     R1,#0                   ;Was 0 returned?
+               BNE     %90akbd_pollKey         ;No -- return happily
+                       
+               MOV     R0,#129                 ;Scan for a key
+               MOV     R1,#0                   ;No time limit
+               MOV     R2,#0
+               SWI     OS_Byte                 ;Read it then
+               
+               CMP     R1,#0                   ;Is it still 0?
+               ADDNE   R1,R1,#&100             ;No -- return extended no.
+               
+90akbd_pollKey MOV     R0,R1                   ;No -- get the character code
+               LDMFD   R13!,{R1,R2,R14}        ;Load back registers
+               BICS    PC,R14,#C_flag          ;Return with C clear
+
+95akbd_pollKey LDMFD   R13!,{R1,R2,R14}        ;Load back registers
+               ORRS    PC,R14,#C_flag          ;Return with C set
+               
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/alloc b/StraySrc/Libraries/Sapphire/s/alloc
new file mode 100644 (file)
index 0000000..3003055
--- /dev/null
@@ -0,0 +1,326 @@
+;
+; alloc.s
+;
+; Redirectable memory allocation (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:subAlloc
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- alloc__halloc ---
+;
+; On entry:    R0 == size of block to find
+;
+; On exit:     CC and R0 == pointer to block, if possible
+;              CS if not enough memory
+;
+; Use:         Allocates memory from the OS_Heap area.  This is mainly
+;              useful for registering the OS_Heap heap as the current
+;              allocator.
+
+alloc__halloc  ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Save some registers away
+               MOV     R3,R0                   ;Move the size away
+               MOV     R1,R12                  ;Locate the heap address
+               MOV     R0,#2                   ;Allocate memory
+               SWI     XOS_Heap                ;Call the OS to allocate
+               BVS     %99alloc__halloc        ;If it failed, skip ahead
+               MOV     R0,R2                   ;Point at block it returned
+               LDMFD   R13!,{R1-R3,R14}        ;Find all the registers again
+               BICS    PC,R14,#C_flag          ;If successful, return CC
+
+99alloc__halloc        LDR     R1,[R0,#0]              ;Get the error number out
+               MOV     R2,#&084                ;&184 is `Not enough memory'
+               ORR     R2,R2,#&100             ;Complete the error number
+               CMP     R1,R2                   ;Is this right?
+               SWINE   OS_GenerateError        ;No -- something's screwed
+               LDMFD   R13!,{R1-R3,R14}        ;Find all the registers again
+               ORRS    PC,R14,#C_flag          ;No memory -- return CS
+
+               LTORG
+
+; --- alloc__hfree ---
+;
+; On entry:    R0 == pointer to a block allocated by alloc_halloc
+;
+; On exit:     --
+;
+; Use:         Frees a block allocated by alloc_halloc, or indeed by
+;              OS_Heap in the Sapphire fixed-size area.  If anything goes
+;              badly amiss, an error is generated.
+
+alloc__hfree   ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R2,R0                   ;Move the pointer away
+               MOV     R1,R12                  ;Locate the heap address
+               MOV     R0,#3                   ;Free memory
+               SWI     OS_Heap                 ;Free it, generating errors
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- alloc_register ---
+;
+; On entry:    R0 == pointer to allocator function
+;              R1 == pointer to free function
+;              R2 == workspace pointer to pass to them in R12
+;
+; On exit:     --
+;
+; Use:         Registers two functions to be used as a heap manager by
+;              alloc and free.
+;
+;              The allocator is entered with R0 as the size of block
+;              required, and should exit with CC and R0 == pointer to the
+;              block allocated if successful, CS if there wasn't enough
+;              memory and generate any other errors that occur.  Registers
+;              other than R0 must be preserved.
+;
+;              The freer is entered with R0 == pointer to block to free.
+;              It should exit with all registers preserved.  If anything
+;              goes wrong, it should generate an error.
+
+               EXPORT  alloc_register
+alloc_register ROUT
+
+               STMFD   R13!,{R0-R5,R12,R14}    ;Save some registers away
+               WSPACE  alloc__wSpace           ;Find my workspace
+
+               ; --- Search the list first ---
+
+10             LDMIA   R12,{R3-R5,R14}         ;Load the values out
+               CMP     R0,R4                   ;Do they match up nicely?
+               CMPEQ   R1,R5
+               CMPEQ   R2,R14
+               LDMEQFD R13!,{R0-R5,R12,PC}^    ;Yes -- then return now
+               CMP     R3,#0                   ;End of the list?
+               MOVNE   R12,R3                  ;Yes -- get a copy the
+               BNE     %10alloc_register       ;And go back round again
+
+20             MOV     R4,R2                   ;Keep the R12 value safe
+               MOV     R3,R1                   ;And the free routine ptr
+               MOV     R2,R0                   ;And the alloc routine ptr
+               MOV     R1,#0
+
+               MOV     R0,#alloc__nodeSize     ;Find size of a node block
+               BL      sub_alloc               ;Try to allocate memory
+               SWIVS   OS_GenerateError        ;This is a major problem
+
+               STMIA   R0,{R1-R4}              ;Save values into block
+               STR     R0,[R12,#0]             ;And link this block in
+
+               LDMFD   R13!,{R0-R5,R12,PC}^    ;Return to caller
+
+; --- alloc_useOSHeap ---
+;
+; On entry:    R1 == pointer to OS_Heap-managed heap to use
+;
+; On exit:     --
+;
+; Use:         Registers an OS_Heap heap to use to allocate memory when
+;              alloc is called.
+
+               EXPORT  alloc_useOSHeap
+alloc_useOSHeap        ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R2,R1                   ;Move into workspace pointer
+               ADR     R0,alloc__halloc        ;Point to OS_Heap allocator
+               ADR     R1,alloc__hfree         ;Point to OS_Heap freer
+               BL      alloc_register          ;Register them nicely
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+; --- alloc ---
+;
+; On entry:    R0 == size of block to allocate from current heap
+;
+; On exit:     R0 == pointer to block and CC if it all worked
+;              CS if there wasn't enough memory (R0 corrupted)
+;
+; Use:         Allocates R0 bytes from a heap manager.  This routine will
+;              attempt to allocate memory from the current heaps in order
+;              of registration (i.e. the Sapphire OS_Heap first etc.) until
+;              either one which can service the request is found, or all
+;              the heaps have been tried.
+
+               EXPORT  alloc
+alloc          ROUT
+
+               STMFD   R13!,{R1-R5,R12,R14}    ;Save some registers
+               WSPACE  alloc__wSpace           ;Find my workspace
+               ADD     R5,R0,#4                ;Add in the overhead
+
+               ADR     R1,alloc__list          ;Find the list head item
+10alloc                CMP     R1,#0                   ;Have we reached the end?
+               BEQ     %20alloc                ;Yes -- couldn't do it then
+               LDMIA   R1,{R2-R4,R12}          ;Load values from block
+               MOV     R0,R5                   ;Get block size wanted
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R3                   ;Call the allocator
+               MOVCS   R1,R2                   ;If it failed, move on
+               BCS     %10alloc                ;And try the next heap
+
+               STR     R1,[R0],#4              ;Save the node pointer
+               LDMFD   R13!,{R1-R5,R12,R14}    ;Return to caller with ptr
+               BICS    PC,R14,#C_flag          ;With C flag clear
+
+20alloc                LDMFD   R13!,{R1-R5,R12,R14}    ;Return to caller
+               ORRS    PC,R14,#C_flag          ;With no memory warning
+
+               LTORG
+
+; --- free ---
+;
+; On entry:    R0 == pointer to block allocated by alloc
+;
+; On exit:     --
+;
+; Use:         Frees a block allocated by alloc, regardless of which heap
+;              it came from.
+
+               EXPORT  free
+free           ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers
+               LDR     R1,[R0,#-4]!            ;Load node pointer from block
+               ADD     R1,R1,#alloc__free      ;Find free and workspace ptr
+               LDMIA   R1,{R1,R12}             ;Load them out
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R1                   ;And call the routine
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to caller done
+
+               LTORG
+
+; --- alloc_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the alloc system, and sets it up to use the
+;              kernel-provided OS_Heap area.
+
+               EXPORT  alloc_init
+alloc_init     ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Save some registers
+               WSPACE  alloc__wSpace           ;Find the workspace
+               LDR     R14,alloc__list         ;Find the list head pointer
+               CMP     R14,#0                  ;Is it null?
+               LDMNEFD R13!,{R0-R3,R12,PC}^    ;Yes -- return then
+
+               ; --- Initialise allocator list ---
+               ;
+               ; This is essential -- both msgs and suballoc need to be
+               ; able to allocate memory immediately.  We have to build the
+               ; whole link here, because we normally use suballoc to create
+               ; the link blocks!
+
+               MOV     R0,#0                   ;No next pointer yet
+               ADR     R1,alloc__halloc        ;Point to allocator
+               ADR     R2,alloc__hfree         ;And freer
+               LDR     R3,sapph_heapBase       ;Find the heap address
+               STMIA   R12,{R0-R3}             ;Save them all away
+
+               ; --- Set up other required things ---
+
+               BL      sub_init                ;Initialise suballocator
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+alloc__wSpace  DCD     0
+
+; --- alloc_error ---
+;
+; On entry:    --
+;
+; On exit:     V set and R0 == pointer to an error about not having enough
+;              memory.
+;
+; Use:         Returns an error suitable for displaying to a user if there
+;              isn't enough memory left.
+
+               EXPORT  alloc_error
+alloc_error    ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               ADR     R0,alloc__noMem         ;Point to the error block
+               BL      msgs_error              ;Translate the error message
+               LDMFD   R13!,{R1,R14}           ;Unstack the registers
+               ORRS    PC,R14,#V_flag          ;Return with the error nicely
+
+               ; --- The message ---
+               ;
+               ; Note that we supply a default, since it may be msgs which
+               ; is saying that it's out of memory!
+
+alloc__noMem   DCD     1
+               DCB     "allocNOMEM:Not enough memory",0
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+; --- Allocator list ---
+
+               ^       0
+alloc__next    #       4                       ;Address of next node
+alloc__alloc   #       4                       ;The allocator for blocks
+alloc__free    #       4                       ;The freer for blocks
+alloc__R12     #       4                       ;Workspace for allocator
+alloc__nodeSize        #       0                       ;Size of this block
+
+; --- Workspace ---
+
+               ^       0,R12
+alloc__wStart  #       0
+
+alloc__list    #       alloc__nodeSize         ;List of current allocators
+
+alloc__wSize   EQU     {VAR}-alloc__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     alloc__wSize
+               DCD     alloc__wSpace
+               DCD     0
+               DCD     alloc_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/banner b/StraySrc/Libraries/Sapphire/s/banner
new file mode 100644 (file)
index 0000000..efc10a8
--- /dev/null
@@ -0,0 +1,485 @@
+;
+; banner.s
+;
+; A startup banner window
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:dbox
+               GET     sapphire:divide
+               GET     sapphire:event
+               GET     sapphire:flex
+               GET     sapphire:heap
+               GET     sapphire:hour
+               GET     sapphire:nopoll
+               GET     sapphire:res
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+               GET     sapphire:wimp
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx.slider
+
+               [       :LNOT::DEF: bnr__dynaLink
+
+               IMPORT  |Image$$RW$$Base|,WEAK
+               IMPORT  |Image$$RW$$Limit|,WEAK
+               IMPORT  |Sapphire$$ClientData$$Base|,WEAK
+               IMPORT  |Sapphire$$ClientData$$Limit|,WEAK
+               IMPORT  |Sapphire$$ExtTable$$Base|,WEAK
+               IMPORT  |Sapphire$$ExtTable$$Limit|,WEAK
+
+               ]
+
+               IMPORT  |Sapphire$$LibData$$Base|,WEAK
+               IMPORT  |Sapphire$$LibData$$Limit|,WEAK
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+               [       :LNOT::DEF: bnr__dynaLink
+
+; --- banner ---
+;
+; On entry:    R0 == pointer to definition block, or 0
+;              R1 == R12 value to pass to setup routine, if present
+;
+; On exit:     --
+;
+; Use:         Displays a startup banner and initialises the library and
+;              client.  This call should be used as a replacement for
+;              sapphire_libInit.
+;
+;              If R0 is 0 on entry, no banner window is used; instead
+;              an hourglass percentage is displayed to indicate the
+;              amount of initialisation performed so far.
+;
+;              Alternatively, it should point to a table consisting of
+;              a flags word and optional arguments specified by the flags
+;              in order.  The options you can specify are a slider and
+;              percentage count icon (used to display current progress),
+;              a setup routine, and the leafname of a sprites file to
+;              attach to the banner window.
+;
+;              The setup routine is passed the banner dialogue handle in
+;              R0.  It should fill in parts of the banner window, such as
+;              the licencee name and serial number that can't be determined
+;              until runtime (for safeness), and maybe version information
+;              too.
+
+               EXPORT  banner
+banner         ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               ADR     R2,bnr__initList        ;Point to the list
+               BL      bnr_doBanner            ;Do the job
+               LDMFD   R13!,{R2,PC}^           ;And return to caller
+
+bnr__initList  DCD     |Image$$RW$$Limit|
+               DCD     |Sapphire$$ClientData$$Base|
+               DCD     |Sapphire$$ClientData$$Limit|
+               DCD     -1
+               DCD     |Sapphire$$ExtTable$$Base|
+               DCD     |Sapphire$$ExtTable$$Limit|
+
+               LTORG
+
+               ]
+
+; --- bnr_doBanner ---
+;
+; On entry:    R0 == pointer to definition block, or 0
+;              R1 == R12 value to pass to setup routine, if present
+;              R2 == pointer to library initialisation table
+;
+; On exit:     --
+;
+; Use:         Displays a startup banner and initialises the library and
+;              client.
+
+               EXPORT  bnr_doBanner
+bnr_doBanner   ROUT
+
+               STMFD   R13!,{R0-R10,R12,R14}   ;Save some registers
+
+               ; --- Initialise required parts of library ---
+
+               LDR     R0,sapph_appName        ;Find the application name
+               BL      hour_init               ;Initialise hourglass
+               BL      hour_on                 ;Turn on the hourglass
+               BL      alloc_init              ;Initialise heap functions
+               BL      wimp_init               ;Initialise WindowManager
+               BL      screen_init             ;Initialise screen info
+               BL      res_init                ;Find our resources
+               BL      nopoll_init             ;We need nonpolling dialogues
+               BL      dbox_init               ;Initialise dialogue boxes
+               BL      flex_init               ;Initialise nemory manager
+               BL      heap_init               ;And the heap manager too
+
+               ; --- Unpack the definition block ---
+
+               SUB     R13,R13,#36             ;Make a bit of workspace
+               MOV     R1,#0                   ;Clear two words
+               MOV     R2,#0
+               STMFD   R13!,{R1,R2}            ;Make two flex anchors
+               STR     R1,[R13,#40]            ;Initial percentage is 0
+               MOV     R10,#0                  ;Not created the block yet
+               LDR     R9,[R13,#44]            ;Load the block pointer
+               CMP     R9,#0                   ;Is there a block?
+               BEQ     %05bnr_doBanner         ;No -- don't bother then
+
+               ; --- Load the template file ---
+
+               MOV     R0,R13                  ;Point to this anchor
+               MOV     R1,#2048                ;Guess the size of the file
+               BL      flex_alloc              ;Try to allocate
+               BCS     %05bnr_doBanner         ;If it failed, ignore window
+
+               ADRL    R0,bnr__tfile           ;Point to template file name
+               MOV     R1,R11                  ;Build name in scratchpad
+               BL      res_find                ;Try to find the file
+               BCC     %05bnr_doBanner         ;If it failed, ignore window
+               MOV     R1,R0                   ;Point to the name
+               SWI     XWimp_OpenTemplate      ;Try to open the file
+               LDRVC   R1,[R13,#0]             ;Load the base of this block
+               ADDVC   R2,R1,#1024             ;Indirected data in 2nd K
+               ADDVC   R3,R1,#2048             ;And stop at the end please
+               MOVVC   R4,#-1                  ;Pray there's no fonts
+               ADRVCL  R5,bnr__template        ;Point to the template name
+               LDMVCIA R5,{R6-R8}              ;Load 3 words of data
+               ADDVC   R14,R13,#8              ;Point to some free space
+               STMVCIA R14,{R6-R8}             ;It writes back the name!
+               MOVVC   R5,R14                  ;So point to a copy
+               MOVVC   R6,#0                   ;Start from beginning
+               SWIVC   XWimp_LoadTemplate      ;Try to load the template
+               MOVVS   R7,R0                   ;If error, remember pointer
+               MOVVC   R7,#0                   ;Otherwise clear this
+               SWI     Wimp_CloseTemplate      ;Close the template file
+               MOVS    R0,R7                   ;Get the error back
+               BNE     %05bnr_doBanner         ;And go off somewhere else
+
+               ; --- Now load options from the block ---
+
+               MOV     R1,R9                   ;Move this around a bit
+               LDR     R0,[R1],#4              ;Load the flags word
+
+               TST     R0,#bFlag_slider        ;Does he want a slider?
+               LDRNE   R9,[R1],#4              ;Yes -- load the icon number
+               MOVEQ   R9,#-1                  ;Otherwise remember this
+
+               TST     R0,#bFlag_counter       ;Does he have a counter?
+               LDRNE   R8,[R1],#4              ;Yes -- load the icon number
+               MOVEQ   R8,#-1                  ;Otherwise remember this
+
+               TST     R0,#bFlag_setup         ;Does he have a setup routine
+               LDRNE   R7,[R1],#4              ;Yes -- load the address
+               MOVEQ   R7,#0                   ;Otherwise remember this
+
+               TST     R0,#bFlag_sprites       ;Does he have a sprite file
+               BEQ     %03bnr_doBanner         ;No -- don't load it then
+
+               ; --- Load the sprite file ---
+
+               MOV     R0,R1                   ;Point to the leafname
+               MOV     R1,R11                  ;Build name in scratchpad
+               BL      res_find                ;Try to get a good name
+               BCC     %03bnr_doBanner         ;If not there, don't worry
+               MOV     R1,R0                   ;Put name in right register
+               MOV     R0,#17                  ;Read information on file
+               SWI     XOS_File                ;Try to get the information
+               BVS     %03bnr_doBanner         ;Failed -- don't bother then
+               TST     R0,#1                   ;Is this a file?
+               BEQ     %03bnr_doBanner         ;No -- ignore it then
+               ADD     R0,R13,#4               ;Point to other anchor
+               ADD     R1,R4,#8                ;Get the file size
+               BL      flex_alloc              ;Allocate the memory
+               BCS     %03bnr_doBanner         ;Failed -- ignore it then
+               MOV     R0,#16                  ;Load the file
+               MOV     R1,R11                  ;Point to the filename
+               LDR     R2,[R13,#4]             ;Load the block address
+               ADD     R14,R4,#8               ;Get this block size
+               STR     R14,[R2],#4             ;Save it in the block
+               MOV     R3,#0                   ;Load where I said to load it
+               SWI     OS_File                 ;Load the file then
+
+               LDMIA   R13,{R0,R1}             ;Load the two anchors
+               STR     R1,[R0,#64]             ;Save the sprite pointer
+
+               ; --- Now create a dialogue box ---
+
+03bnr_doBanner LDR     R0,[R13,#0]             ;Load the window base address
+               BL      dbox_fromDefn           ;Try to create a dialogue
+               BVS     %05bnr_doBanner         ;If we couldn't, don't care
+               MOV     R10,R0                  ;Get the dialogue handle
+
+               ; --- If we need to, build a dbx block ---
+
+               CMP     R9,#-1                  ;Do we have a slider icon?
+               ADRNE   R14,bnr__dbx            ;Yes -- point to dbx skeleton
+               ADDNE   R1,R13,#8               ;Point to some spare memory
+               LDMNEIA R14!,{R3-R5}            ;Load some values out
+               MOVNE   R2,R9                   ;Get the icon handle
+               STMNEIA R1!,{R2-R5}             ;Store them away
+               LDMNEIA R14!,{R2-R5}            ;Load some more values
+               STMNEIA R1!,{R2-R5}             ;Save them away too
+               ADDNE   R1,R13,#8               ;Point to the dbx block
+               BLNE    dbx_declare             ;And attach the definition
+
+               ; --- Set up an event handler ---
+
+               MOV     R1,#0                   ;I don't have a handler
+               ADD     R2,R13,#40              ;Point to spare word
+               MOV     R3,#0                   ;Don't care about R12
+               BL      dbox_eventHandler       ;Set up the event handler
+
+               ; --- Now set up the dialogue box ---
+
+               CMP     R7,#0                   ;Does he have a setup routine
+               LDRNE   R12,[R13,#48]           ;Load caller's R12 value
+               MOVNE   R14,PC                  ;Set up return address
+               MOVNE   PC,R7                   ;And call his routine
+
+               ADD     R7,R13,#40              ;Point to count word
+               BL      bnr__count              ;Update the counter
+
+               ; --- Display the dialogue box ---
+               ;
+               ; This is a horrible hack, but I don't care.
+
+               MOV     R1,#dbOpen_centre+dbOpen_persist+dbOpen_nonSub
+               BL      dbox_open               ;Set up the position nicely
+               BL      dbox_window             ;Get the window handle
+               ORR     R0,R0,#1<<31            ;Don't constrain the mouse
+               BL      nopoll_open             ;Set up a fake redraw request
+               MOV     R1,R11                  ;Do this in the scratchpad
+               MOV     R0,#1                   ;Don't care about event mask
+               BL      event_poll              ;Send that fake event
+               BL      nopoll_close            ;Shut nopoll up now
+
+               ; --- Now we need to count the things to initialise ---
+
+05bnr_doBanner ADD     R7,R13,#40              ;Point to count word (again)
+               LDR     R5,[R13,#52]            ;Load the lib init block
+               ADD     R5,R5,#4                ;Skip past program end
+
+               ADR     R0,bnr__ownTable        ;Point to our own init table
+               LDMIA   R0,{R0,R1}              ;Load the base and limit
+               SUB     R0,R1,R0                ;Find the table size
+               MOV     R6,R0,LSR #4            ;Divide by size of entry
+
+               MOV     R2,R5                   ;Get a copy of his table
+10bnr_doBanner LDMIA   R2!,{R0,R1}             ;Load the base and limit
+               CMP     R0,#-1                  ;Is this the end yet?
+               SUBNE   R0,R1,R0                ;Find the table size
+               ADDNE   R6,R6,R0,LSR #4         ;Add on number in this table
+               BNE     %10bnr_doBanner         ;And carry on going
+
+               SUB     R2,R2,#4                ;We overshot a bit
+               LDMIA   R2,{R3,R4}              ;Load extension table values
+12bnr_doBanner CMP     R3,R4                   ;Reached the end yet?
+               BCS     %15bnr_doBanner         ;Yes -- phew!
+               MOV     R14,PC                  ;Set up return address
+               LDR     PC,[R3],#4              ;Call finding routine
+               SUB     R0,R1,R0                ;Find the table size
+               ADD     R6,R6,R0,LSR #4         ;Add on number in this table
+               B       %12bnr_doBanner         ;And carry on going
+
+               ; --- Now actually initialise things ---
+
+
+15bnr_doBanner MOV     R4,#0                   ;Nothing initialised yet
+               LDR     R2,sapph_workspace      ;Load the main workspace base
+               ADR     R0,bnr__ownTable        ;Point to our own init table
+               LDMIA   R0,{R0,R1}              ;Load the base and limit
+               BL      bnr__init               ;Initialise these bits
+
+20bnr_doBanner LDMIA   R5!,{R0,R1}             ;Load base and limit from tbl
+               CMP     R0,#-1                  ;Is this the end yet?
+               BLNE    bnr__init               ;No -- initialise from here
+               BNE     %20bnr_doBanner         ;And carry on going
+
+               SUB     R5,R5,#4                ;We went a little too far
+               LDMIA   R5,{R3,R5}              ;Find the extension table
+25bnr_doBanner CMP     R3,R5                   ;Have we finished yet?
+               BCS     %30bnr_doBanner         ;Yes -- better stop then
+               MOV     R14,PC                  ;Set up return address
+               LDR     PC,[R3],#4              ;Call this routine
+               LDR     R2,[R11,-R2]            ;Load the workspace base
+               BL      bnr__init               ;Do some initialisation
+               B       %25bnr_doBanner         ;And keep on going
+
+               ; --- Ahhh -- finished ---
+
+               CMP     R10,#0                  ;Do we have a dialogue box?
+               BEQ     %32bnr_doBanner         ;No -- don't wait then
+30bnr_doBanner SWI     OS_ReadMonotonicTime    ;What's the time, Mr Computer
+               ADD     R1,R0,#50               ;Wait for a second
+31bnr_doBanner SWI     OS_ReadMonotonicTime    ;What's the time, Mr Computer
+               CMP     R0,R1                   ;Waited long enough?
+               BMI     %31bnr_doBanner         ;No -- keep waiting then
+
+32bnr_doBanner MOVS    R0,R10                  ;Get the dialogue handle
+               BLNE    dbox_destroy            ;Trash it if I created it
+               LDR     R14,[R13,#0]            ;Load the dialogue anchor
+               CMP     R14,#0                  ;Did I create it?
+               ADDNE   R0,R13,#0               ;Yes -- point to the anchor
+               BLNE    flex_free               ;And free the block
+               LDR     R14,[R13,#4]            ;Load the sprite anchor
+               CMP     R14,#0                  ;Did I create it?
+               ADDNE   R0,R13,#4               ;Yes -- point to the anchor
+               BLNE    flex_free               ;And free the block
+
+               BL      hour_off                ;Turn off the hourglass now
+
+               ADD     R13,R13,#44             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R10,R12,PC}^   ;And return to caller
+
+bnr__template  DCB     "banner",0
+bnr__tfile     DCB     "Templates",0
+
+bnr__dbx       DCD     slider
+               DCD     dbxFlag_dataR10+slFlag_horizontal
+               DCD     28
+               DCD     0
+               DCB     8,1,1,0
+               DCD     100
+               DCD     -1
+
+bnr__ownTable  DCD     |Sapphire$$LibData$$Base|
+               DCD     |Sapphire$$LibData$$Limit|
+
+               LTORG
+
+; --- bnr__init ---
+;
+; On entry:    R0 == base of initialisation table
+;              R1 == limit of initialisation table
+;              R2 == pointer to workspace base
+;              R4 == number of units initialised so far
+;              R6 == number of items to initialise
+;              R7 == address of count word
+;              R8 == counter icon number
+;              R9 == slider icon number
+;              R10 == banner dialogue handle
+;
+; On exit:     --
+;
+; Use:         Initialises a load of library units.
+
+bnr__init      ROUT
+
+               STMFD   R13!,{R0-R3,R5,R14}     ;Save some registers
+               MOV     R3,R0                   ;Look after this pointer
+               LDR     R0,sapph_appName        ;Find application's name
+00bnr__init    CMP     R3,R1                   ;Have we finished yet?
+               LDMCSFD R13!,{R0-R3,R5,PC}^     ;Yes -- then return
+               LDR     R5,[R3,#12]             ;Load the init routine addr
+               ADD     R3,R3,#16               ;Move the pointer on a bit
+               CMP     R5,#0                   ;Is there an init routine?
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               MOVNE   PC,R5                   ;And call the routine
+
+               STMFD   R13!,{R0,R1}            ;Save some registers
+               ADD     R4,R4,#100              ;Initialised another one
+               MOV     R0,R4                   ;Get the value in R0
+               MOV     R1,R6                   ;How many there actually are
+               BL      div_round               ;Work out the percentage
+               STR     R0,[R7,#0]              ;Save the count word away
+               BL      bnr__count              ;Update the counter
+               LDMFD   R13!,{R0,R1}            ;And restore the registers
+
+               B       %00bnr__init            ;And go round again
+
+               LTORG
+
+; --- bnr__count ---
+;
+; On entry:    R7 == address of current percentage
+;              R8 == count icon number
+;              R9 == slider icon number
+;              R10 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Displays the count of how much we've done in some cunning
+;              way.
+
+bnr__count     ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               CMP     R10,#0                  ;Do we have a dialogue box?
+               BEQ     %50bnr__count           ;Yes -- handle that then
+
+               CMP     R9,#-1                  ;Do we have a slider?
+               MOVNE   R0,R10                  ;Yes -- get the dialogue
+               MOVNE   R1,R9                   ;And the icon handle
+               BLNE    dbx_update              ;And redraw the slider
+
+               CMP     R8,#-1                  ;Do we have a count icon?
+               LDRNE   R0,[R7,#0]              ;Yes -- get the current value
+               MOVNE   R1,R11                  ;Point to the scratchpad
+               MOVNE   R2,#256                 ;Give the size of the buffer
+               SWINE   OS_ConvertInteger4      ;Convert it to an integer
+               MOVNE   R2,R0                   ;Point to this text
+               MOVNE   R0,R10                  ;Get the dialogue handle
+               MOVNE   R1,R8                   ;And the icon handle
+               BLNE    dbox_setField           ;And write in the data
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+50bnr__count   LDR     R0,[R7,#0]              ;Get the current value
+               SWI     Hourglass_Percentage    ;Put it in the hourglass
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+; --- Flags ---
+
+bFlag_slider   EQU     (1<<0)                  ;Has a progress slider
+                                               ;+0 icon number for slider
+                                               ;+4
+
+bFlag_counter  EQU     (1<<1)                  ;Has a percentage indicator
+                                               ;+0 icon number for indicator
+                                               ;+4
+
+bFlag_setup    EQU     (1<<2)                  ;Needs a setup routine
+                                               ;+0 == address of routine
+                                               ;+4
+
+bFlag_sprites  EQU     (1<<3)                  ;Load a sprite file
+                                               ;+0 == name of sprite file
+                                               ;+n
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/bnrStub b/StraySrc/Libraries/Sapphire/s/bnrStub
new file mode 100644 (file)
index 0000000..febdaa0
--- /dev/null
@@ -0,0 +1,72 @@
+;
+; bnrStub.s
+;
+; Stub for banner
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  bnr_doBanner
+
+               IMPORT  |Image$$RW$$Limit|,WEAK
+
+               IMPORT  |Sapphire$$LibData$$Base|,WEAK
+               IMPORT  |Sapphire$$LibData$$Limit|,WEAK
+               IMPORT  |Sapphire$$ClientData$$Base|,WEAK
+               IMPORT  |Sapphire$$ClientData$$Limit|,WEAK
+               IMPORT  |Sapphire$$ExtTable$$Base|,WEAK
+               IMPORT  |Sapphire$$ExtTable$$Limit|,WEAK
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+               EXPORT  banner
+banner         ROUT
+
+               STMFD   R13!,{R2,R14}
+               ADR     R2,bnr__initTable
+               BL      bnr_doBanner
+               LDMFD   R13!,{R2,PC}^
+
+bnr__initTable DCD     |Image$$RW$$Limit|
+               DCD     |Sapphire$$LibData$$Base|
+               DCD     |Sapphire$$LibData$$Limit|
+               DCD     |Sapphire$$ClientData$$Base|
+               DCD     |Sapphire$$ClientData$$Limit|
+               DCD     -1
+               DCD     |Sapphire$$ExtTable$$Base|
+               DCD     |Sapphire$$ExtTable$$Limit|
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/buttons b/StraySrc/Libraries/Sapphire/s/buttons
new file mode 100644 (file)
index 0000000..d298250
--- /dev/null
@@ -0,0 +1,155 @@
+;
+; buttons.s
+;
+; Handle buttons definitions
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:msgs
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- buttons_setup ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to buttons block
+;              R2 == buttons base icon
+;              R3 == number of buttons to allow
+;
+; On exit:     R2 == buttons flag mask
+;              R3 == cancel button icon, or -1
+;
+; Use:         Sets up a dialogue box's buttons according to a buttons
+;              block.
+
+               EXPORT  buttons_setup
+buttons_setup  ROUT
+
+               STMFD   R13!,{R0,R1,R4-R9,R14}  ;Save some registers
+               MOV     R9,R1                   ;Look after the button table
+               ADD     R8,R2,R3                ;Get the icon limit value
+               MOV     R7,R2                   ;Start an icon counter
+               MOV     R6,#0                   ;Keep track of the bits
+               MOV     R5,R0                   ;And get the dialogue handle
+               MOV     R4,#-1                  ;No cancel as yet
+               BL      dbox_window             ;And turn it into a window
+               STR     R0,[R13,#-16]!          ;Save it on the stack
+               MOV     R14,#&00800000          ;Put deleted flag in BIC word
+               STR     R14,[R13,#12]           ;Store that away too
+
+05buttons_setup        LDR     R3,[R9],#4              ;Load the flags word
+               MOV     R0,#0                   ;No text for this icon
+
+               TST     R3,#bFlag_cancel        ;Is this a cancel button?
+               MOVNE   R4,R7                   ;Yes -- we have cancel
+               ADRNE   R0,but__cancelTag       ;Point to the message
+               BNE     %07buttons_setup        ;And skip onwards
+               TST     R3,#bFlag_ok            ;Is this an OK button?
+               ADRNE   R0,but__okTag           ;Point to the message
+               BNE     %10buttons_setup        ;And skip onwards
+               TST     R3,#bFlag_help          ;Is this a help button?
+               ADRNE   R0,but__helpTag         ;Point to the message
+               BNE     %07buttons_setup        ;And skip onwards
+
+07buttons_setup        TST     R3,#bFlag_text          ;Does this icon contain text?
+               BEQ     %10buttons_setup        ;Skip forwards to that bit
+               MOV     R0,R9                   ;Point to button message
+
+00             LDRB    R14,[R9],#1             ;Load a byte from the block
+               CMP     R14,#&20                ;Reached the end yet?
+               BCS     %b00                    ;No -- keep looping
+               ADD     R9,R9,#3                ;Word-align pointer
+               BIC     R9,R9,#3
+
+               ; --- Fill an icon with text ---
+
+10buttons_setup        CMP     R0,#0                   ;Is there text defined?
+               MOVEQ   R14,#&00800000          ;No -- delete the icon then
+               BEQ     %20buttons_setup        ;So go and do that
+               BL      msgs_lookup             ;Get the actual message
+               MOV     R2,R0                   ;Get the string in R2
+               MOV     R1,R7                   ;Get the icon handle
+               MOV     R0,R5                   ;And the dialogue handle
+               BL      dbox_setField           ;Write that in nicely
+               MOV     R14,#1                  ;Set this icon's bit
+               ORR     R6,R6,R14,LSL R7        ;Remember this icon exists
+
+               ; --- Delete or undelete an icon ---
+
+               MOV     R14,#0                  ;We want to undelete here
+20buttons_setup        STMIB   R13,{R7,R14}            ;Save icon and EOR mask
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetIconState       ;And make sure of that
+
+               ; --- See what to do next ---
+
+               ADD     R7,R7,#1                ;Move on to next icon
+               CMP     R7,R8                   ;Have we finished yet?
+               BCS     %30buttons_setup        ;Finished them all -- skip
+               TST     R3,#bFlag_last          ;Was that the last of them?
+               BEQ     %05buttons_setup        ;No -- go round again then
+
+               ; --- Delete the rest of the icons ---
+
+               MOV     R14,#&00800000          ;Get the deleted flag
+               STR     R14,[R13,#8]            ;Save it in the block
+               MOV     R1,R13                  ;Point at the block
+00             STR     R7,[R13,#4]             ;Save the icon number
+               SWI     Wimp_SetIconState       ;Delete the icon
+               ADD     R7,R7,#1                ;Move on to next icon
+               CMP     R7,R8                   ;Finished yet?
+               BCC     %b00                    ;More to go -- loop
+
+               ; --- That's it -- return ---
+
+30buttons_setup        MOV     R2,R6                   ;Get the button bits
+               MOV     R3,R4                   ;And get the cancel button
+               ADD     R13,R13,#16             ;Restore the stack pointer
+               LDMFD   R13!,{R0,R1,R4-R9,PC}^  ;And return to caller
+
+but__okTag     DCB     "ok",0
+but__cancelTag DCB     "can",0
+but__helpTag   DCB     "help",0
+
+               LTORG
+
+bFlag_cancel   EQU     (1<<0)                  ;This is the cancel button
+bFlag_ok       EQU     (1<<1)                  ;This is the OK button
+bFlag_help     EQU     (1<<2)                  ;This is the help button
+bFlag_text     EQU     (1<<3)                  ;This button contains text
+bFlag_last     EQU     (1<<31)                 ;This is the last item
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/chunk b/StraySrc/Libraries/Sapphire/s/chunk
new file mode 100644 (file)
index 0000000..713b922
--- /dev/null
@@ -0,0 +1,508 @@
+;
+; chunk.s
+;
+; Loading and management of options chunks (MDW)
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:fastMove
+               GET     sapphire:flex
+               GET     sapphire:string
+
+               GET     sapphire:xfer.xsave
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- chunk_create ---
+;
+; On entry:    --
+;
+; On exit:     R0 == chunk file handle
+;              May return an error
+;
+; Use:         Creates a new chunk file structure and returns a handle to
+;              it.
+
+               EXPORT  chunk_create
+chunk_create   ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               MOV     R0,#cBase__size         ;Get the size of the block
+               BL      alloc                   ;Try to allocate the block
+               BLCS    alloc_error             ;If it failed, get error
+               MOVCC   R14,#0                  ;Otherwise make list empty
+               STRCC   R14,[R0,#cBase__list]   ;By clearing the link
+               LDMFD   R13!,{R14}              ;Restore link register
+               BICCCS  PC,R14,#V_flag          ;If OK, return without error
+               ORRCSS  PC,R14,#V_flag          ;Else return the error
+
+               LTORG
+
+; --- chunk_destroy ---
+;
+; On entry:    R0 == chunk file handle
+;
+; On exit:     --
+;
+; Use:         Removes a chunk file structure from memory.  Chunk data in
+;              flex blocks is freed; chunk claimers who free flex blocks
+;              should clear the anchors to 0.
+
+               EXPORT  chunk_destroy
+chunk_destroy  ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R2,R0                   ;Look after the chunk base
+               LDR     R1,[R2,#0]              ;Load the first chunk block
+
+00chunk_destroy        MOVS    R0,R1                   ;Is this the end of the list?
+               BEQ     %f00chunk_destroy       ;Yes -- stop the loop
+               LDR     R14,[R0,#0]             ;Load the flex anchor
+               CMP     R14,#0                  ;Is there a block here?
+               BLNE    flex_free               ;Yes -- free it then
+               LDR     R1,[R0,#cLink__next]    ;Load the next block
+               BL      free                    ;Free this block
+               B       %b00chunk_destroy       ;And loop back
+
+00chunk_destroy        MOV     R0,R2                   ;Point to the chunk base
+               BL      free                    ;Don't need that any more
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- chunk_claim ---
+;
+; On entry:    R0 == chunk file handle
+;              R1 == pointer to chunk name
+;              R2 == pointer to saver routine, or 0 for none, or -1 for no
+;                      change
+;              R3 == R10 value to pass to saver
+;              R4 == R12 value to pass to saver
+;
+; On exit:     R1 == chunk handle/anchor
+;              CS if the chunk already existed
+;              May return an error
+;
+; Use:         Claims a chunk, installing a save handler for it.  The chunk
+;              handle returned is actually the address of a flex anchor for
+;              the chunk's data (use flex_size to find the block's size).
+;              If the save handle is 0, the data in the flex block (which
+;              may be modified) is saved directly from the block.  Otherwise
+;              the save routine is expected to save its data, using xsave.
+;
+;              The anchor is followed by 3 unused words -- you can use them
+;              for whatever you want.
+;
+;              Warning: this routine may move flex blocks.
+
+               EXPORT  chunk_claim
+chunk_claim    ROUT
+
+               BIC     R14,R14,#V_flag         ;Clear V and hope...
+               STMFD   R13!,{R0,R5,R6,R14}     ;Save some registers
+               SUB     R5,R0,#cLink__next      ;Look after the handle
+
+00chunk_claim  LDR     R6,[R5,#cLink__next]    ;Load the next pointer
+               CMP     R6,#0                   ;Is this the very end?
+               BEQ     %f00chunk_claim         ;Yes -- create a new chunk
+               ADD     R0,R6,#cLink__name      ;Point to the chunk's name
+               BL      str_icmp                ;Compare the names
+               MOVNE   R5,R6                   ;No match -- move on
+               BNE     %b00chunk_claim         ;Loop back to start
+
+               ; --- Found a matching chunk ---
+
+               CMP     R2,#-1                  ;Do we change the saver?
+               ADDNE   R14,R6,#cLink__saver    ;No -- point to saver info
+               STMNEIA R14,{R2-R4}             ;And stuff the values in
+               MOV     R1,R6                   ;Point to the anchor
+               LDMFD   R13!,{R0,R5,R6,R14}     ;Restore registers
+               ORRS    PC,R14,#C_flag          ;And return to caller
+
+               ; --- No match -- create a new chunk ---
+
+00chunk_claim  MOV     R0,#cLink__size         ;Get the block size I need
+               BL      alloc                   ;Try to allocate the memory
+               BLCS    alloc_error             ;If it failed, get error
+               BCS     %99chunk_claim          ;And return the failure
+               MOV     R6,R0                   ;Get the chunk handle
+               ADD     R0,R6,#cLink__name      ;Point to the name field
+               BL      str_cpy                 ;Fill in the new name
+
+               ; --- Allocate an empty flex block for it ---
+
+               MOV     R1,#0                   ;Allocate no memory
+               MOV     R0,R6                   ;Point to the anchor
+               BL      flex_alloc              ;Allocate the block
+               BLCS    alloc_error             ;If it failed, get error
+               BCS     %98chunk_claim          ;And tidy up on the way out
+
+               ; --- Fill in the rest of the chunk ---
+
+               MOV     R14,#0                  ;Fill in the next field
+               STR     R14,[R6,#cLink__next]   ;Clear the next pointer
+               STR     R6,[R5,#cLink__next]    ;And link in the new chunk
+               STR     R14,[R6,#cLink__flags]  ;Clear flags initially
+               CMP     R2,#-1                  ;Do we change the saver?
+               MOVEQ   R2,#0                   ;No -- then leave none there
+               ADD     R14,R6,#cLink__saver    ;Point to saver info
+               STMIA   R14,{R2-R4}             ;And stuff the values in
+
+               MOV     R1,R6                   ;Point to the anchor
+               LDMFD   R13!,{R0,R5,R6,R14}     ;Restore registers
+               BICS    PC,R14,#C_flag          ;And return to caller
+
+               ; --- Tidy up on the way out ---
+
+98chunk_claim  MOV     R5,R0                   ;Look after the error
+               MOV     R0,R6                   ;Point to new chunk block
+               BL      free                    ;Free the block
+               MOV     R0,R5                   ;Get the error pointer back
+
+99chunk_claim  ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R5,R6,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- chunk_makeBinary ---
+;
+; On entry:    R0 == chunk file handle
+;              R1 == chunk handle
+;
+; On exit:     --
+;
+; Use:         Marks a given chunk as containing binary data.
+
+               EXPORT  chunk_makeBinary
+chunk_makeBinary ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,[R1,#cLink__flags]  ;Load the flags word
+               ORR     R14,R14,#clFlag__binary ;Set the binary flag
+               STR     R14,[R1,#cLink__flags]  ;Save the flags back again
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- chunk_read ---
+;
+; On entry:    R0 == chunk file handle
+;              R1 == address of a flex anchor
+;
+; On exit:     May return an error
+;
+; Use:         Merges the data contained in the flex block with that already
+;              in the chunk file.  If the chunk file is empty, this is
+;              equivalent to a load.  Data from the flex block is appended
+;              to chunks already loaded where appropriate.
+;
+;              Warning: this routine may move flex blocks.
+
+               EXPORT  chunk_read
+chunk_read     ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Save some registers
+               LDR     R8,[R1,#0]              ;Load the block address
+               MOV     R7,R0                   ;Look after the chunk handle
+               MOV     R0,R1                   ;Point to the anchor
+               BL      flex_size               ;Read the block's size
+               ADD     R9,R8,R0                ;And find the limit pointer
+
+               ; --- Find the first chunk ---
+               ;
+               ; There'll probably be some comments at the top -- we don't
+               ; care about them.
+
+10chunk_read   MOV     R2,#&0A                 ;Say this is a new line
+00chunk_read   CMP     R8,R9                   ;Have we reached the end?
+               BCS     %90chunk_read           ;Yes -- nothing to read
+               LDRB    R1,[R8],#1              ;Load the next byte
+               CMP     R2,#&0A                 ;Is this a new line?
+               CMPEQ   R1,#'['                 ;And is this a chunk start?
+               MOVNE   R2,R1                   ;No -- stash previous char
+               BNE     %b00chunk_read          ;And skip back for more
+
+               ; --- Read the next chunk ---
+
+               MOV     R2,R11                  ;Copy name to scratchpad
+00chunk_read   CMP     R8,R9                   ;Reached the end yet?
+               BCS     %90chunk_read           ;Yes -- ignore bogus header
+               LDRB    R1,[R8],#1              ;Get a byte of name
+               CMP     R1,#']'                 ;Is it the end of it?
+               MOVEQ   R1,#0                   ;Yes -- terminate the name
+               STRB    R1,[R2],#1              ;Store this byte away
+               BNE     %b00chunk_read          ;Keep on going to the end
+               STRB    R1,[R11,#19]            ;Make sure name's <12 chars
+
+               ; --- Ignore the rest of this line ---
+
+               MOV     R3,#0                   ;Clear size just in case
+00chunk_read   CMP     R8,R9                   ;Reached the end yet?
+               BCS     %f05chunk_read          ;Yes -- stop here then
+               LDRB    R1,[R8],#1              ;Load the next byte out
+               CMP     R1,#&0A                 ;Is this the end of the line?
+               BNE     %b00chunk_read          ;No -- skip back then
+
+               ; --- Work out how big the chunk is ---
+
+               AND     R0,R8,#3                ;Get the non-word-alignedness
+               BIC     R1,R8,#3                ;And round down nicely
+               LDMIA   R1,{R2-R4}              ;Load next two fullwords
+               MOVS    R0,R0,LSL #3            ;Turn bytes into bits
+               RSB     R14,R0,#32              ;And work out other shift
+               MOVNE   R2,R2,LSR R0            ;Shift down lowest word
+               ORRNE   R2,R2,R3,LSL R14        ;Copy in bottom of next word
+               MOVNE   R3,R3,LSR R0            ;Shift rest of this one down
+               ORRNE   R3,R3,R4,LSL R14        ;Copy in bottom of top word
+
+               LDR     R14,=chunk__binMark     ;Is this the binary marker?
+               CMP     R2,R14                  ;Is this a binary chunk?
+               MOVNE   R5,#0                   ;No -- don't set any flags
+               MOVEQ   R5,#clFlag__binary      ;Yes -- set the binary flag
+               BNE     %f00chunk_read          ;No -- search for next chunk
+
+               ADD     R8,R8,#8                ;Skip past those two words
+               ADD     R8,R8,R3                ;And move on to end of chunk
+               B       %f05chunk_read          ;And skip on (size in R3)
+
+               ; --- Now search for a new chunk ---
+
+00chunk_read   MOV     R3,#0                   ;No bytes counted so far
+00chunk_read   CMP     R8,R9                   ;Reached the end yet?
+               BCS     %f05chunk_read          ;Yes -- stop here then
+               LDRB    R0,[R8],#1              ;Load the next byte
+               CMP     R1,#&0A                 ;Is this a new line?
+               CMPEQ   R0,#'['                 ;And is this a new chunk?
+               ADDNE   R3,R3,#1                ;No -- bump the counter
+               MOVNE   R1,R0                   ;Remember the last character
+               BNE     %b00chunk_read          ;And go back found
+
+               SUB     R8,R8,#1                ;Go back to the newline char
+
+               ; --- Now claim a chunk for us ---
+
+05chunk_read   MOV     R0,R7                   ;Get the chunk handle
+               MOV     R1,R11                  ;Point to the chunk's name
+               MOV     R2,#-1                  ;Don't care about savers
+               FSAVE   "R8,R9"                 ;Stash flex pointers
+               BL      chunk_claim             ;Claim this block please
+               BVS     %99chunk_read           ;It failed -- tidy up
+               MOV     R6,R1                   ;Look after the link block
+
+               LDR     R14,[R6,#cLink__flags]  ;Load the flags word
+               ORR     R14,R14,R5              ;Set any flags we need
+               STR     R14,[R6,#cLink__flags]  ;Save the flags back again
+
+               ; --- Grow the flex block and copy ---
+
+               MOV     R0,R6                   ;Point to the anchor
+               BL      flex_size               ;Read the block's size
+               MOV     R5,R0                   ;Look after this
+               ADD     R1,R0,R3                ;Add on a little size
+               MOV     R0,R6                   ;Point to the anchor again
+               BL      flex_extend             ;Make the block bigger
+               BLCS    alloc_error             ;If it failed, moan a lot
+               BCS     %99chunk_read           ;And go off in a huff
+
+               LDR     R0,[R6,#0]              ;Load the block base
+               ADD     R0,R0,R5                ;Find the destination addr
+               FLOAD   "R8,R9"                 ;Reload my saved pointers
+               SUB     R1,R8,R3                ;Reclaim my data
+               MOV     R2,R3                   ;Set the amount to copy
+               BL      fastMove                ;And copy it all across
+
+               ; --- That's done -- now do the rest ---
+
+               B       %10chunk_read           ;Go back to the top again
+
+               ; --- We made it -- huzzah! ---
+
+90chunk_read   LDMFD   R13!,{R0-R9,R14}        ;Restore registers
+               BICS    PC,R14,#V_flag          ;And return with no error
+
+               ; --- Something went awry ---
+
+99chunk_read
+               FLOAD   "R8,R9"                 ;Restore regs from flex stack
+               ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R9,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- chunk_enum ---
+;
+; On entry:    R0 == chunk file handle
+;              R1 == 0 for first call or continuation value
+;
+; On exit:     CC if this isn't over yet, and
+;                R1 == continuation value for next call
+;                R2 == pointer to chunk name
+;              else CS and
+;                R1 == 0
+;                R2 preserved
+;
+; Use:         Allows you to enumerate the chunks in a chunk file structure.
+
+               EXPORT  chunk_enum
+chunk_enum     ROUT
+
+               CMP     R1,#0                   ;Is this a new call?
+               SUBEQ   R1,R0,#cLink__next      ;Yes -- set up continuation
+               LDR     R1,[R1,#cLink__next]    ;Move onto the next block
+               CMP     R1,#0                   ;Is this at the end?
+               ADDNE   R2,R1,#cLink__name      ;No -- point to the name
+               BICNES  PC,R14,#C_flag          ;And return OK
+               ORREQS  PC,R14,#C_flag          ;Otherwise say it's over
+
+               LTORG
+
+; --- chunk_save ---
+;
+; On entry:    R0 == chunk file handle
+;
+; On exit:     May return an error
+;
+; Use:         Saves a chunk file to xsave's current output.
+
+               EXPORT  chunk_save
+chunk_save     ROUT
+
+               STMFD   R13!,{R0-R4,R10,R12,R14} ;Save a few registers
+               LDR     R4,[R0,#0]              ;Load the list base
+05chunk_save   CMP     R4,#0                   ;Is there nothing to do?
+               BEQ     %90chunk_save           ;That's OK -- do nothing then
+
+               ; --- Write out this chunk's name ---
+
+               MOV     R0,#'['                 ;Output a `[' character
+               BL      xsave_byte              ;Write that OK
+               BVS     %99chunk_save           ;Die if that went wrong
+
+               ADD     R1,R4,#cLink__name      ;Point to the name
+00chunk_save   LDRB    R0,[R1],#1              ;Load the next byte
+               CMP     R0,#0                   ;Is this the end yet?
+               MOVEQ   R0,#']'                 ;Yes -- write terminator
+               BL      xsave_byte              ;Write that out
+               BVS     %99chunk_save           ;Die if that went wrong
+               BNE     %b00chunk_save          ;And if there's more, do it
+
+               ; --- Write any necessary preamble ---
+
+               MOV     R0,#&0A                 ;Start a new line
+               BL      xsave_byte              ;Write the newline byte
+               BVS     %99chunk_save           ;Die if that went wrong
+
+               LDR     R14,[R4,#cLink__flags]  ;Load the flags word
+               TST     R14,#clFlag__binary     ;Is this block binary?
+               LDRNE   R0,=chunk__binMark      ;Yes -- write a bin marker
+               BLNE    xsave_word              ;Yes -- write a whole word
+               BVS     %99chunk_save           ;Die if that went wrong
+
+               ; --- Now work out how to write this block ---
+
+               ADD     R14,R4,#cLink__saver    ;Point to saver info
+               LDMIA   R14,{R2,R10,R12}        ;Load that lot out
+               CMP     R2,#0                   ;Is this a real saver?
+               BEQ     %10chunk_save           ;No -- skip on then
+               MOV     R0,R4                   ;Point to the anchor
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R2                   ;And call the saver
+               LDRVC   R4,[R4,#cLink__next]    ;Find the next block
+               BVC     %05chunk_save           ;And loop back to the start
+               BVS     %99chunk_save           ;Die if that went wrong
+
+               ; --- We must save the chunk ourselves ---
+
+10chunk_save   LDR     R14,[R4,#cLink__flags]  ;Load the flags word
+               TST     R14,#clFlag__binary     ;Is this block binary?
+
+               MOV     R0,R4                   ;If OK, get flex anchor
+               BL      flex_size               ;Find the block's size
+               BLNE    xsave_word              ;If binary, write that out
+               MOVVC   R1,R0                   ;Look after that
+               LDRVC   R0,[R4,#0]              ;Load the flex base address
+               BLVC    xsave_block             ;And write out the whole lot
+               BVS     %99chunk_save           ;Die if anything went wrong
+               MOVNE   R0,#&0A                 ;Write a final line end
+               BLNE    xsave_byte              ;Just to make sure
+               BLNE    xsave_byte              ;Leave blank line under bin
+               LDRVC   R4,[R4,#cLink__next]    ;Find the next block
+               BVC     %05chunk_save           ;And loop back to the start
+               BVS     %99chunk_save           ;Die if anything went wrong
+
+               ; --- Finished writing the file ---
+
+90chunk_save   LDMFD   R13!,{R0-R4,R10,R12,R14} ;Restore registers
+               BICS    PC,R14,#V_flag          ;Return error-free
+
+               ; --- Something got messed up ---
+
+99chunk_save   ADD     R13,R13,#4              ;Don't restore R0
+               LDMFD   R13!,{R1-R4,R10,R12,R14} ;Restore other registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+;----- Data structures ------------------------------------------------------
+
+; --- Chunk base ---
+
+               ^       0
+cBase__list    #       4                       ;List of chunks
+cBase__size    #       0
+
+; --- Chunk link blocks ---
+
+               ^       0
+cLink__anchor  #       4                       ;Anchor for flex block
+cLink__userData        #       12                      ;12 bytes of user data
+cLink__next    #       4                       ;Link to next block
+cLink__flags   #       4                       ;Interesting things
+cLink__name    #       20                      ;Name of this chunk
+cLink__saver   #       12                      ;Saver routine for chunk
+cLink__size    #       0
+
+; --- Flags ---
+
+clFlag__binary EQU     (1<<0)                  ;Chunk contains binary data
+
+; --- Other magic values ---
+
+chunk__binMark EQU     &6E694200               ;Magic word for binary data
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/cmdLine b/StraySrc/Libraries/Sapphire/s/cmdLine
new file mode 100644 (file)
index 0000000..e65dfd9
--- /dev/null
@@ -0,0 +1,196 @@
+;
+; cmdLine.s
+;
+; Command line parsing (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- cl_next ---
+;
+; On entry:    R0 == pointer to a command line string (ctrl terminated)
+;              R1 == pointer to a buffer (may be equal to R0)
+;
+; On exit:     CS if another word found, and
+;                R0 == updated past next word
+;                R1 preserved, buffer filled with null terminated string
+;                R2 == pointer to terminating null character
+;              else CC and
+;                R0 == pointer to terminating character
+;                R1 preserved, buffer preserved
+;                R2 corrupted
+;
+; Use:         Extracts the next word from a command line string.  If the
+;              string is in a writable buffer, you can set R1 == R0 to
+;              start with.  You can build up a C-like argv array like this:
+;
+;                      ; R0 == pointer to command line in writable buffer
+;
+;                              MOV     R1,R0
+;                              ADR     R3,argv
+;                              MOV     R4,#0
+;                      loop    BL      cl_next
+;                              MOVCC   R1,#0
+;                              STR     R1,[R3],#4
+;                              ADDCS   R4,#0
+;                              BCS     loop
+;
+;                      ; R0-R3 corrupted
+;                      ; R4 == argc
+;
+;              This routine will handle quoted strings, considering them
+;              to be single arguments.  Either type of quote will do,
+;              quote doubling is required to insert quotes in quoted
+;              strings.
+
+               EXPORT  cl_next
+cl_next                ROUT
+
+               STMFD   R13!,{R1,R3,R14}        ;Save some registers
+               MOV     R2,R1                   ;Set up buffer pointer
+               MOV     R1,#0                   ;No quotes found yet
+               MOV     R3,#0                   ;Various flags:
+                                               ;  b0 == written a character
+                                               ;  b1 == currently in quotes
+                                               ;  b2 == just closed quotes
+
+               ; --- Skip past leading spaces ---
+
+00cl_next      LDRB    R14,[R0],#1             ;Load a byte from the string
+               CMP     R14,#' '                ;Is it a space?
+               CMPNE   R14,#9                  ;Or a tab will do too
+               BEQ     %00cl_next              ;Yes -- get another character
+
+               ; --- Main character reading loop ---
+
+10cl_next      CMP     R14,#' '                ;Is it the string end?
+               SUBLO   R0,R0,#1                ;Keep ptr at ctrl char
+               TSTEQ   R3,#2                   ;Are we currently in quotes?
+               BLS     %90cl_next              ;No -- deal with it nicely
+
+               CMP     R14,R1                  ;Is it the last quote char?
+               BEQ     %30cl_next              ;Yes -- deal with this
+
+               BIC     R3,R3,#4                ;Last one wasn't a quote
+
+               CMP     R14,#'"'                ;Is it a double quote?
+               CMPNE   R14,#'''                ;Or a single one?
+               TSTEQ   R3,#2                   ;Make sure not in quoted
+               BEQ     %20cl_next              ;Yes -- deal with this then
+
+               STRB    R14,[R2],#1             ;Otherwise store the byte
+               ORR     R3,R3,#1                ;Remember we've done it
+               LDRB    R14,[R0],#1             ;Load a byte from the string
+               B       %10cl_next              ;And go round again
+
+               ; --- Handle a new quote character ---
+
+20cl_next      MOV     R1,R14                  ;Remember the quote character
+               ORR     R3,R3,#2                ;We're now in quotes
+               LDRB    R14,[R0],#1             ;Load a byte from the string
+               B       %10cl_next              ;And go round again
+
+               ; --- Handle a matched quote character ---
+               ;
+               ; Now this may be a close quote, or it may be a double quote
+               ; to indicate a literal.  We handle this by the following:
+               ;
+               ; if lastWasCloseQuotes
+               ;   write literal quote char
+               ;   set inQuotes
+               ;   clear lastWasCloseQuotes
+               ; else if inQuotes
+               ;   clear inQuotes
+               ;   set lastWasCloseQuotes
+               ; end
+
+30cl_next      TST     R3,#6                   ;Was last quote, or inQuotes?
+               BEQ     %20cl_next              ;No -- then it's an open
+               TST     R3,#4                   ;Was last one a quote?
+               STRNEB  R14,[R2],#1             ;Yes -- then store quote
+               ORRNE   R3,R3,#1                ;Remember we store something
+               EOR     R3,R3,#6                ;And toggle the bits nicely
+               LDRB    R14,[R0],#1             ;Load a byte from the string
+               B       %10cl_next              ;Return to the loop
+
+               ; --- We reached the end of the string ---
+
+90cl_next      TST     R3,#1                   ;Did we write any text?
+               MOVNE   R14,#0                  ;A terminating null
+               STRNEB  R14,[R2],#0             ;If so, terminate the text
+               LDMFD   R13!,{R1,R3,R14}        ;Unstack the registers
+               ORRNES  PC,R14,#C_flag          ;If so, set C on exit
+               BICEQS  PC,R14,#C_flag          ;Otherwise clear C
+
+               LTORG
+
+; --- cl_buildArgv ---
+;
+; On entry:    R0 == command line string (writable)
+;              R1 == address of argv buffer
+;
+; On exit:     R1 == next unused location in argv buffer
+;
+; Use:         Turns the given string into an argv array which will make
+;              argument scanning easier.  This is pretty much the code
+;              given in the description of cl_next.
+
+               EXPORT  cl_buildArgv
+cl_buildArgv   ROUT
+
+               STMFD   R13!,{R0,R2,R3,R14}     ;Save some registers
+               MOV     R3,R1                   ;Move the argv address away
+               MOV     R1,R0                   ;Point to output buffer
+
+               ; --- Copy the argument pointers over ---
+
+00             BL      cl_next                 ;Fetch the next argument
+               MOVCC   R1,#0                   ;If done, null terminate list
+               STR     R1,[R3],#4              ;Store the pointer away
+               MOVCS   R1,R0                   ;More to come -- reset buffer
+               BCS     %b00                    ;And loop around
+
+               ; --- Tidy up and leave ---
+
+               SUB     R1,R3,#4                ;Point at terminating zero
+               LDMFD   R13!,{R0,R2,R3,PC}^     ;And return to caller
+
+               LTORG
+
+; --- cl_getopt ---
+;
+; On entry:    R1 = pointer to
+;
+; On exit:
+
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/coRoutine b/StraySrc/Libraries/Sapphire/s/coRoutine
new file mode 100644 (file)
index 0000000..a1b3e77
--- /dev/null
@@ -0,0 +1,297 @@
+;
+; coRoutine.s
+;
+; Basic coroutine handling (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:sapphire
+               GET     sapphire:seh
+               GET     sapphire:suballoc
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+coRout__stkSize        EQU     1024
+
+; --- coRout_create ---
+;
+; On entry:    R0 == pointer to coroutine
+;              R1 == R10 value to pass to coroutine
+;              R2 == R12 value to pass to coroutine
+;              R3 == size of stack to pass (0 for default)
+;
+; On exit:     R0 == coroutine handle
+;              May return an error
+;
+; Use:         Creates a new coroutine.  It may be given control using
+;              coRout_switch.  Its registers are on entry:
+;
+;              R0 == its coroutine handle
+;              R10 == value passed to coRout_create in R1
+;              R12 == value passed to coRout_create in R2
+;              R13 == pointer to the stack created for it
+
+               EXPORT  coRout_create
+coRout_create  ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers away
+
+               ; --- Allocate a coroutine block ---
+
+               MOV     R0,#coRout__blkSize     ;Get the block size ready
+               BL      sub_alloc               ;Allocate the block
+               BVS     %99coRout_create        ;Quit if it failed
+               MOV     R4,R0                   ;Keep the block pointer
+
+               ; --- Allocate a stack ---
+
+               CMP     R3,#0                   ;Does he want default stack?
+               MOVEQ   R3,#coRout__stkSize     ;Yes -- give it to him
+               MOV     R0,R3                   ;Get the size in R0
+               BL      alloc                   ;Try to allocate the stack
+               BLCS    alloc_error             ;If it failed, get an error
+               BCS     %98coRout_create        ;And quit if it didn't work
+               STR     R0,[R4,#coRout__stack]  ;Save the stack pointer away
+
+               ; --- Set up the try list ---
+
+               MOV     R14,#0                  ;Must clear the list head
+               STR     R14,[R4,#coRout__tryList] ;Save that away for later
+
+               ; --- Fix everything up right ---
+
+               ADD     R0,R0,R3                ;Point to the stack top
+               ADR     R3,coRout__start        ;Point to the start routine
+               MOV     R14,PC                  ;Get the processor flags
+               AND     R14,R14,#&FC000003      ;Leave only the flags
+               ORR     R14,R3,R14              ;And add them on to it
+               MOV     R3,R2                   ;Get coroutine's R12 in R3
+               MOV     R2,R11                  ;Point to scratchpad in R2
+               STMFD   R0!,{R1-R3,R14}         ;And save all that lot away
+               SUB     R0,R0,#32               ;Don't care about other regs
+               LDR     R14,[R13,#0]            ;Load the coroutine address
+               STMFD   R0!,{R4,R14}            ;Save them in R0 and R1
+               STR     R0,[R4,#coRout__sp]     ;And save its stack pointer
+
+               ; --- Return to caller ---
+
+               MOV     R0,R4                   ;Point to the coroutine block
+               ADD     R13,R13,#4              ;Don't restore caller's R0
+               LDMFD   R13!,{R1-R4,R14}        ;And return to caller
+               BICS    PC,R14,#V_flag
+
+               ; --- Handle errors ---
+
+98coRout_create        MOV     R3,R0                   ;Save the error pointer
+               MOV     R0,R4                   ;Point to the coroutine block
+               MOV     R1,#coRout__blkSize     ;Get the block's size
+               BL      sub_free                ;Free the block nicely
+               MOV     R0,R3                   ;Restore the error pointer
+
+99coRout_create        ADD     R13,R13,#4              ;Don't restore caller's R0
+               LDMFD   R13!,{R1-R4,R14}        ;And return to caller
+               ORRS    PC,R14,#V_flag
+
+               LTORG
+
+; --- coRout_switch ---
+;
+; On entry:    R0 == coroutine to switch to, or 0 for main
+;
+; On exit:     --
+;
+; Use:         Switches context to another coroutine.
+
+               EXPORT  coRout_switch
+coRout_switch  ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  coRout__wSpace          ;Find my workspace address
+               LDR     R14,coRout__current     ;Get the current coroutine
+               CMP     R14,R0                  ;Switch to current one?
+               LDMEQFD R13!,{R12,PC}^          ;Silly sausage!
+
+               ; --- Perform a context switch ---
+
+               STMFD   R13!,{R0-R11}           ;Save all the other registers
+               MOV     R1,R14                  ;Move this to another reg
+               STR     R0,coRout__current      ;Save the new coroutine
+               BL      seh_setListBase         ;Use this try list now
+               CMP     R1,#0                   ;Are we running main routine?
+               ADREQ   R1,coRout__main         ;Yes -- point to dummy block
+               CMP     R0,#0                   ;Do we switch to main routine
+               ADREQ   R0,coRout__main         ;Yes -- point to dummy block
+               STR     R13,[R1,#coRout__sp]    ;Save the new stack pointer
+               LDR     R13,[R0,#coRout__sp]    ;Get a new stack pointer
+               LDMFD   R13!,{R0-R12,PC}^       ;And switch context to it
+
+               LTORG
+
+; --- coRout_destroy ---
+;
+; On entry:    R0 == coroutine handle to destroy
+;
+; On exit:     --
+;
+; Use:         Destroys a coroutine.
+
+               EXPORT  coRout_destroy
+coRout_destroy ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers away
+               WSPACE  coRout__wSpace          ;Find my workspace address
+               LDR     R14,coRout__current     ;Get the current coroutine
+               CMP     R14,R0                  ;Terminate the current one?
+               LDMEQFD R13!,{R12,R14}          ;Yes -- unstack registers
+               BEQ     coRout_end              ;And end it normally
+
+               ; --- Now just destroy a coroutine ---
+
+               STMFD   R13!,{R0,R1}            ;Save some registers
+               MOV     R1,R0                   ;Keep the coroutine handle
+               LDR     R0,[R1,#coRout__stack]  ;Find the stack's address
+               BL      free                    ;Free up the space it took
+               MOV     R0,R1                   ;Point at the coroutine blk
+               MOV     R1,#coRout__blkSize     ;Get the coroutine block size
+               BL      sub_free                ;And dispose of that too
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- coRout__start ---
+;
+; On entry:    R0 == coroutine handle
+;              R1 == pointer to coroutine code
+;
+; On exit:     R14 == pointer to coRout_end
+;
+; Use:         Sets up a coroutine so that when it returns, it calls
+;              coRout_end and dies properly.
+
+coRout__start  ROUT
+
+               ; --- Set up a handler to kill the coroutine ---
+
+               ADR     R0,coRout__catch        ;Point to our catch handler
+               BL      seh_try                 ;Register that nicely
+
+               ; --- Now start up the coroutine proper ---
+
+               MOV     R14,PC                  ;Set up the return address
+               MOV     PC,R1                   ;And call the main code
+
+               ; --- Fall through into coRout_end when done ---
+
+; --- coRout_end ---
+;
+; On entry:    --
+;
+; On exit:     Doesn't.
+;
+; Use:         Terminates the current coroutine.
+
+               EXPORT  coRout_end
+coRout_end     ROUT
+
+               ; --- Destroy the current coroutine ---
+
+               WSPACE  coRout__wSpace          ;Find my workspace
+               LDR     R13,coRout__main+coRout__sp ;Return to main stack
+               LDR     R1,coRout__current      ;Get the current coroutine
+               LDR     R0,[R1,#coRout__stack]  ;Find the stack's address
+               BL      free                    ;Free up the space it took
+               MOV     R0,R1                   ;Point at the coroutine blk
+               MOV     R1,#coRout__blkSize     ;Get the coroutine block size
+               BL      sub_free                ;And dispose of that too
+
+               ; --- Now rejoin the main routine ---
+
+               MOV     R0,#0                   ;Going back to main routine
+               STR     R0,coRout__current      ;So remember that
+               BL      seh_setListBase         ;Use main exception list
+               LDMFD   R13!,{R0-R12,PC}^       ;And rejoin everything nicely
+
+               LTORG
+
+; --- Exception handling ---
+
+coRout__catch  MOVS    PC,R14                  ;No need for tidy-up
+               DCD     -1                      ;Catch all exceptions
+               B       coRout__throw           ;And throw them on again
+               DCD     0
+
+coRout__throw  WSPACE  coRout__wSpace          ;Find my workspace
+               LDR     R13,coRout__main+coRout__sp ;Return to main stack
+               STMFD   R13!,{R0-R3}            ;Remember the exception
+               LDR     R1,coRout__current      ;Load the old coroutine hnd
+               LDR     R0,[R1,#coRout__stack]  ;Find the stack's address
+               BL      free                    ;Free up the space it took
+               MOV     R0,R1                   ;Point at the coroutine blk
+               MOV     R1,#coRout__blkSize     ;Get the coroutine block size
+               BL      sub_free                ;And dispose of that too
+
+               MOV     R0,#0                   ;Going back to main routine
+               STR     R0,coRout__current      ;So remember that
+               BL      seh_setListBase         ;Use main exception list
+               LDMFD   R13!,{R0-R3}            ;Restore exception
+               B       seh_throw               ;And raise it again
+
+coRout__wSpace DCD     0
+
+;----- Coroutine blocks -----------------------------------------------------
+
+               ^       0
+coRout__tryList        #       4                       ;SEH try list head for stack
+coRout__stack  #       4                       ;Pointer to the stack
+coRout__sp     #       4                       ;Coroutine's current R13
+coRout__blkSize        #       0                       ;Size of a coroutine block
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+coRout__wStart #       0
+
+coRout__current        #       4                       ;The current coroutine or 0
+coRout__main   #       coRout__blkSize         ;Dummy coroutine block
+
+coRout__wSize  EQU     {VAR}-coRout__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     coRout__wSize
+               DCD     coRout__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/colourBox b/StraySrc/Libraries/Sapphire/s/colourBox
new file mode 100644 (file)
index 0000000..a94b543
--- /dev/null
@@ -0,0 +1,451 @@
+;
+; colourBox.s
+;
+; Gives you a nice box from which the user may choose a WIMP colour
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+
+               GET     sapphire:keyMap
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- colourBox ---
+;
+; On entry:    R0 == pointer to a title string (message tag)
+;              R1 == the current colour in bottom byte, and flags:
+;                      bit 8 == allow transparent colour
+;              R2 == event handler to call
+;              R3 == R10 value to pass to handler
+;              R4 == R12 value to pass to handle
+;
+; On exit:     May return an error
+;
+; Use:         Opens a dialogue box which allows the user to choose
+;              one of the wimp colours.  A transparent colour is supported,
+;              and represented as colour 255.
+
+               EXPORT  colourBox
+colourBox      ROUT
+
+               STMFD   R13!,{R0-R5,R12,R14}
+               WSPACE  cb__wSpace
+
+               ; --- Set up some workspace ---
+
+               STMIB   R12,{R2-R4}             ;Save useful information
+               STRB    R1,cb__defColour        ;Store default colour
+
+               ; --- Create my dialogue box ---
+
+               ADR     R0,cb__name             ;Point to the dbox name
+               BL      dbox_create             ;Try to create it
+               BVS     %90colourBox            ;Return possible error
+               MOV     R4,R0                   ;Look after dialogue handle
+
+               ; --- Set up current and old colours ---
+
+               MOV     R2,#-1                  ;No old icon yet
+               BL      cb__borderIcon          ;Draw the border
+
+               STRB    R1,cb__currentCol       ;Currently selected colour
+               AND     R14,R1,#&FF             ;Get the actual colour
+               CMP     R14,#&FF                ;Is colour transparent?
+               MOVEQ   R14,#7                  ;Yes -- use black then
+               STRB    R14,cb__oldCol          ;Make this last colour
+
+               ; --- If necessary, delete the transparent icon ---
+
+               TST     R1,#256                 ;Is the transparent bit set?
+               BNE     %10colourBox            ;Yes -- leave it then
+               BL      dbox_window             ;Find dialogue's window
+               MOV     R1,#cbIcon__trans       ;Get transparent icon handle
+               MOV     R2,#1<<23               ;Set the deleted flag
+               MOV     R3,#1<<23
+               STMFD   R13!,{R0-R3}            ;Save that on the stack
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetIconState       ;And set the icons up
+               ADD     R13,R13,#16             ;Restore the stack
+
+               ; --- Set up the dialogue box now ---
+
+10colourBox    MOV     R0,R4                   ;Fetch dialogue handle
+               ADR     R1,cb__eventHandler     ;Point to the event handler
+               MOV     R2,#0                   ;No R10 required
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      dbox_eventHandler       ;Set up the event handler
+
+               ; --- Fill in the dialogue title ---
+
+               LDR     R0,[R13,#0]             ;Load title pointer
+               BL      msgs_lookup             ;Translate the tag
+               MOV     R2,R0                   ;Put this in R2
+               MOV     R0,R4                   ;Get handle back
+               MOV     R1,#-1                  ;Change the title
+               BL      dbox_setField           ;Set the title
+
+               ; --- Display the dialogue ---
+
+               MOV     R1,#dbOpen_pointer      ;Open over the pointer
+               BL      dbox_open               ;Open the dbox then
+
+               ; --- Move the caret out of the icon ---
+
+               BL      dbox_window             ;Get the window handle
+               MOV     R1,#-1                  ;Move out of any icons
+               MOV     R2,#&FFFFFF             ;Move well away from visible
+               MOV     R3,#&FFFFFF             ;area so no-one will see
+               MOV     R4,#16                  ;Make the caret fairly small
+               MOV     R5,#-1                  ;No sensible string index
+               SWI     Wimp_SetCaretPosition   ;Set the caret position
+
+               ; --- That's it, then ---
+
+               LDMFD   R13!,{R0-R5,R12,R14}    ;Load back registers
+               BICS    PC,R14,#V_flag          ;Return without error
+
+90colourBox    ADD     R13,R13,#4              ;Skip over R0
+               LDMFD   R13!,{R1-R5,R12,R14}    ;Load back registers
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+cb__name       DCB     "colourBox",0
+
+               LTORG
+
+; --- cb__borderIcon ---
+;
+; On entry:    R0 == dbox handle
+;              R1 == colour to `border'
+;              R2 == old colour (-1 for none)
+;
+; On exit:     --
+;
+; Use:         Removes the border from the old icon, and puts one on the
+;              new icon.
+
+cb__borderIcon ROUT
+
+               CMP     R1,R2                   ;Are colours the same?
+               MOVEQS  PC,R14                  ;Yes -- return then
+
+               ; --- Sort out what to do now ---
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               SUB     R13,R13,#80             ;Make a big block
+               AND     R5,R1,#&FF              ;Clear extraneous flag bits
+               MOV     R4,R0                   ;Look after dialogue handle
+               CMP     R2,#-1                  ;Old colour to clear?
+               BEQ     %10cb__borderIcon       ;No -- don't bother then
+
+               ; --- Clear border from old colour ---
+
+               CMP     R2,#255                 ;Is colour transparent?
+               BEQ     %05cb__borderIcon       ;Yes -- handle that then
+
+               BL      dbox_window             ;Get window handle of dbox
+               ADD     R1,R2,#cbIcon__colours  ;Find icon handle of colour
+               MOV     R2,#0                   ;Don't set any bits
+               MOV     R3,#5                   ;Clear border and text bits
+               STMIA   R13,{R0-R3}             ;Save them in my block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetIconState       ;And change the icon
+               B       %10cb__borderIcon       ;Now border the new colour
+
+               ; --- Turn off the `transparent' switch ---
+
+05             MOV     R1,#cbIcon__trans       ;Get the icon handle
+               MOV     R2,#0                   ;Turn the icon off
+               BL      dbox_select             ;And deselect the icon
+
+               ; --- Now turn on the new colour ---
+
+10             CMP     R5,#&FF                 ;Is new colour transparent?
+               BEQ     %15cb__borderIcon       ;Yes -- handle that then
+
+               ; --- Sort out a contrasting colour ---
+               ;
+               ; This is actually quite hard.  RISC_OSLib uses a hack
+               ; to do this job.  I use ColourTrans instead, because it's
+               ; easier.  The algorithm is simple: take the original
+               ; colour, and decide which, out of black and white, is
+               ; furthest away from it.  Then try and find the closest
+               ; match to that in the Wimp palette.
+
+               MOV     R1,R13                  ;Point to my big block
+               SWI     Wimp_ReadPalette        ;Read the Wimp's palette
+               LDR     R0,[R13,R5,LSL #2]      ;Load the palette entry
+               MOV     R1,#0                   ;Choose a two-colour mode
+               ADR     R2,cb__bwPal            ;Point to black'n'white pal
+               SWI     ColourTrans_ReturnOppColourNumberForMode ;!!!
+               LDR     R0,[R2,R0,LSL #2]       ;Load `black' or `white'
+               MOV     R1,#12                  ;Choose a 16 colour mode
+               MOV     R2,R13                  ;And point at Wimp palette
+               SWI     ColourTrans_ReturnColourNumberForMode ;!!
+
+               ; --- Now set the icon border ---
+
+               MOV     R2,R0,LSL #24           ;Set this as foreground col
+               MOV     R0,R4                   ;Get the dialogue handle
+               BL      dbox_window             ;Get a window handle from it
+               ADD     R1,R5,#cbIcon__colours  ;Find the icon handle
+               ORR     R2,R2,#5                ;Set the border and text bits
+               MOV     R3,#5                   ;Change border and text
+               ORR     R3,R3,#&0F000000        ;Also change foreground col
+               STMIA   R13,{R0-R3}             ;Save them in my block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetIconState       ;And change the icon
+               B       %50cb__borderIcon       ;Tidy up and go home
+
+cb__bwPal      DCD     &00000000
+               DCD     &FFFFFF00
+
+               ; --- Turn on the `transparent' switch ---
+               ;
+               ; `Hey, transparent switch, I really dig you.'
+
+15             MOV     R0,R4                   ;Get the dialogue handle
+               MOV     R1,#cbIcon__trans       ;Get transparent icon handle
+               MOV     R2,#1                   ;Turn the icon on
+               BL      dbox_select             ;Select this icon
+
+               ; --- Tidy up and return ---
+
+50             ADD     R13,R13,#80             ;Restore the stack
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               LTORG
+
+; --- cb__eventHandler ---
+;
+; On entry:    R0 == dbox event
+;              R1-R8 depend on event code
+;              R9 == dbox handle
+;
+; On exit:     --
+;
+; Use:         Handles events onthe colour box.
+
+cb__eventHandler ROUT
+
+               CMP     R0,#dbEvent_close       ;Has the dbox been closed?
+               BEQ     %10cb__eventHandler     ;Yes -- destroy it then
+               CMP     R0,#dbEvent_cancel      ;Was cancel pressed?
+               CMPNE   R0,#cbIcon__cancel
+               BEQ     %20cb__eventHandler     ;Yes -- do the right thing
+               CMP     R0,#dbEvent_OK          ;How about OK?
+               CMPNE   R0,#cbIcon__ok          ;Well -- it had to happen
+               BEQ     %30cb__eventHandler     ;Yes -- do the right thing
+               CMP     R0,#cbIcon__trans       ;Click on transparent switch?
+               BEQ     %40cb__eventHandler     ;Yes -- do the right thing
+               CMP     R0,#dbEvent_key         ;Was a key pressed?
+               BEQ     %50cb__eventHandler     ;Yes -- deal with it then
+
+               ; --- Must be a click on a colour ---
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack registers
+               SUB     R1,R0,#cbIcon__colours  ;Turn into a colour
+               CMP     R1,#16                  ;Is it in range?
+               LDMCSFD R13!,{R0-R2,PC}^        ;No -- then ignore it
+               LDRB    R2,cb__currentCol       ;Load the old colour
+               MOV     R0,R9                   ;Get the handle
+               BL      cb__borderIcon          ;Select it
+               STRB    R1,cb__currentCol       ;Store back the new colour
+               STRB    R1,cb__oldCol           ;Remember this
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               ; --- Dialogue box has been closed ---
+
+10             STMFD   R13!,{R0,R14}           ;Stack registers
+               MOV     R0,R9                   ;Put handle in R0
+               BL      dbox_destroy            ;Destroy the dbox
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               ; --- User clicked the cancel button ---
+
+20             STMFD   R13!,{R0-R3,R14}        ;Stack registers
+               MOV     R0,R9                   ;Get the dbox handle
+               MOV     R3,R1                   ;Remember the button status
+               MOV     R1,#cbIcon__cancel      ;The cancel button
+               BL      dbox_slab               ;Slab in the icon
+               TST     R3,#1                   ;Was Adjust clicked?
+               BEQ     %25cb__eventHandler     ;No -- jump ahead
+
+               LDRB    R2,cb__currentCol       ;Load the old colour
+               LDRB    R1,cb__defColour        ;And the default colour
+               BL      cb__borderIcon          ;Select it
+               STRB    R1,cb__currentCol       ;Store back the new colour
+               CMP     R1,#255                 ;Is the colour transparent?
+               MOVEQ   R1,#7                   ;Yes -- use black instead
+               STRB    R1,cb__oldCol           ;Save old colour
+
+25             TST     R3,#1                   ;Was Adjust clicked?
+               BLEQ    dbox_close              ;No -- close the dbox
+               BL      dbox_unslab             ;Unslab the icon
+               BLEQ    dbox_destroy            ;No -- destroy the dbox
+               LDMFD   R13!,{R0-R3,PC}         ;Return to caller
+
+               ; --- User clicked OK ---
+
+30             STMFD   R13!,{R0-R3,R14}        ;Stack registers
+               MOV     R0,R9                   ;Get the dbox handle
+               MOV     R3,R1                   ;Remember the button status
+               MOV     R1,#cbIcon__ok          ;The OK button
+               BL      dbox_slab               ;Slab in the icon
+
+               LDRB    R2,cb__currentCol       ;Load the current colour
+               STRB    R2,cb__defColour        ;Store this as default colour
+               MOV     R1,R2                   ;Put the colour in R1
+               MOV     R0,#cbEvent_select      ;The event type
+               BL      cb__dispatch            ;Dispatch the event
+
+               MOV     R0,R9                   ;Get the handle back again
+               TST     R3,#1                   ;Was `Adjust' clicked?
+               BLEQ    dbox_close              ;No -- close the dbox
+               BL      dbox_unslab             ;Unslab the icon
+               BLEQ    dbox_destroy            ;No -- destroy the dbox
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               ; --- User clicked on transparent ---
+
+40             STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R0,R9                   ;Fetch dialogue handle
+               MOV     R1,#cbIcon__trans       ;Get transparent icon handle
+               BL      dbox_isSelected         ;Is this icon selected?
+               MOVCC   R1,#255                 ;No -- turn it on
+               LDRCCB  R2,cb__currentCol       ;And get the old colour
+               LDRCSB  R1,cb__oldCol           ;Otherwise get previous col
+               MOVCS   R2,#255                 ;And say current is trans
+               BL      cb__borderIcon          ;Border the icon nicely
+               STRB    R1,cb__currentCol       ;And update current colour
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               ; --- User pressed a key ---
+
+50             CMP     R1,#&100                ;Is the code in top half?
+               MOVCCS  PC,R14                  ;No -- ignore the code
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               LDRB    R2,cb__currentCol       ;What's the current colour?
+               CMP     R2,#&FF                 ;Is it transparent?
+               LDMEQFD R13!,{R0-R2,PC}^        ;And return to caller
+
+               AND     R1,R1,#&FF              ;Keep only the bottom byte
+               MOV     R14,#0                  ;Clear the mask value
+
+               CMP     R1,#key_Left :AND: &FF  ;Is this a left cursor?
+               MOVEQ   R14,#2_1100             ;Yes -- check top bits
+               MOVEQ   R0,#-1                  ;And subtract one
+               CMP     R1,#key_Right :AND: &FF ;Is this a right cursor?
+               MOVEQ   R14,#2_1100             ;Yes -- check top bits
+               MOVEQ   R0,#1                   ;And add one
+               CMP     R1,#key_Up :AND: &FF    ;Is this an up cursor?
+               MVNEQ   R14,#2_1100             ;Yes -- check bottom bits
+               MOVEQ   R0,#-4                  ;And subtract four
+               CMP     R1,#key_Down :AND: &FF  ;Is this a down cursor?
+               MVNEQ   R14,#2_1100             ;Yes -- check bottom bits
+               MOVEQ   R0,#4                   ;And add four
+
+               CMP     R14,#0                  ;Is R14 now set?
+               LDMEQFD R13!,{R0-R2,PC}^        ;No -- then leave now
+
+               ADD     R1,R2,R0                ;Add the correct value
+               EOR     R0,R1,R2                ;Check which bits changed
+               TST     R0,R14                  ;Did something wrong happen?
+               MOVEQ   R0,R9                   ;Fetch dialogue handle
+               BLEQ    cb__borderIcon          ;Border the correct icon
+               STREQB  R1,cb__currentCol       ;And store the new colour
+               STREQB  R1,cb__oldCol           ;And as the last non-trans
+               LDMFD   R13!,{R0-R2,R14}        ;Restore registers
+               ORRS    PC,R14,#C_flag          ;Claim the keypress
+
+               LTORG
+
+; --- cb__dispatch ---
+;
+; On entry:    R0-R8 to be sent to event handler
+;
+; On exit:     --
+;
+; Use:         Sends an event the owner of the colour box.
+
+cb__dispatch   ROUT
+
+               STMFD   R13!,{R9,R10,R12,R14}   ;Stak registers
+               LDMIB   R12,{R9,R10,R12}        ;Load data things
+               CMP     R9,#0                   ;Sanity check
+               MOV     R14,PC                  ;Set up return address
+               MOVNE   PC,R9                   ;Call the handler
+               LDMFD   R13!,{R9,R10,R12,PC}^   ;Return to caller
+
+               LTORG
+
+cb__wSpace     DCD     0
+
+;----- Events ---------------------------------------------------------------
+
+               ^       0
+cbEvent_select #       1                       ;User selected a colour
+                                               ;R1 == colour selected
+
+;----- Icon numbers ---------------------------------------------------------
+
+cbIcon__ok     EQU     0                       ;The OK button
+cbIcon__cancel EQU     1                       ;The Cancel button
+cbIcon__trans  EQU     2                       ;The Transparent switch
+cbIcon__colours        EQU     4                       ;Base of colour patches
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+cb__wStart     #       0
+
+cb__defColour  #       1                       ;The default colour
+cb__currentCol #       1                       ;Currently selected colour
+cb__oldCol     #       1                       ;Last non-transparent colour
+cb__handler    #       12                      ;User handler information
+
+cb__wSize      EQU     {VAR}-cb__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     cb__wSize
+               DCD     cb__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/dBanner b/StraySrc/Libraries/Sapphire/s/dBanner
new file mode 100644 (file)
index 0000000..c9f9e86
--- /dev/null
@@ -0,0 +1,31 @@
+;
+; dBanner.s
+;
+; Startup banner for dynamically linked Sapphire
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               EXPORT  banner
+banner         EQU     0
+
+               GBLL    bnr__dynaLink
+               LNK     s.banner
diff --git a/StraySrc/Libraries/Sapphire/s/dKernel b/StraySrc/Libraries/Sapphire/s/dKernel
new file mode 100644 (file)
index 0000000..2a6ddc5
--- /dev/null
@@ -0,0 +1,37 @@
+;
+; dKernel.s
+;
+; Library kernel for dynamically linked Sapphire
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               EXPORT  sapphire_init
+sapphire_init  EQU     0
+
+               EXPORT  sapphire_libInit
+sapphire_libInit EQU   0
+
+               EXPORT  sapphire_disable
+sapphire_disable EQU   0
+
+               GBLL    sapphire__dynaLink
+               LNK     s.kernel
diff --git a/StraySrc/Libraries/Sapphire/s/dbox b/StraySrc/Libraries/Sapphire/s/dbox
new file mode 100644 (file)
index 0000000..c890f12
--- /dev/null
@@ -0,0 +1,2278 @@
+;
+; dbox.s
+;
+; Dialogue box handling (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:akbd
+               GET     sapphire:alloc
+               GET     sapphire:event
+               GET     sapphire:keyMap
+               GET     sapphire:help
+               GET     sapphire:hour
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:string
+               GET     sapphire:subAlloc
+               GET     sapphire:template
+               GET     sapphire:transWin
+               GET     sapphire:win
+               GET     sapphire:winUtils
+
+;----- Creating and deleting dialogue boxes ---------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- dbox_create ---
+;
+; On entry:    R0 == pointer to dialogue template name
+;
+; On exit:     R0 == dialogue box handle for the dialogue
+;              May return an error
+;
+; Use:         Creates a dialogue box from a template definition.
+
+               EXPORT  dbox_create
+dbox_create    ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Save some registers
+
+               ; --- Locate the template and copy it ---
+
+               MOV     R3,R0                   ;Keep name pointer safe
+               MOV     R1,#0                   ;No template created yet
+               BL      template_find           ;Find the actual definition
+               MOVVC   R2,R0                   ;Keep this pointer
+               MOVVS   R2,#1                   ;Otherwise assume shared rsc
+               MOV     R0,R3                   ;Point at the name again
+               BL      template_copy           ;And create the copy I use
+               MOVVC   R1,R0                   ;Look after the copy
+
+               ; --- Now create a dialogue box around it ---
+
+               BLVC    dbox_fromDefn           ;Create dbox from window def
+               STRVC   R2,[R0,#dbox__template] ;Store the template pointer
+               LDMVCFD R13!,{R1-R3,R14}        ;Unstack the registers
+               BICVCS  PC,R14,#V_flag          ;And return errorless
+
+               ; --- Tidy up aftet an error
+
+               MOV     R2,R0                   ;Look after this
+               MOVS    R0,R1                   ;Get the template pointer
+               BLNE    template_free           ;Maybe we free it
+               MOVNE   R0,R2                   ;If not, get error back
+               ADDEQ   R2,R2,#4                ;Otherwise find error text
+               ADREQ   R0,dbox__createErr      ;Point to my skeleton error
+               BLEQ    msgs_error              ;Translate and substitute
+               LDMFD   R13!,{R1-R3,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;Return the error
+
+               LTORG
+
+; --- dbox_fromEmbedded ---
+;
+; On entry:    R0 == pointer to an embedded template
+;
+; On exit:     R0 == dialogue box handle
+;              May return an error
+;
+; Use:         Creates a dialogue box from an embedded template definition.
+
+               EXPORT  dbox_fromEmbedded
+dbox_fromEmbedded ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               MOV     R1,#0                   ;Clear template pointer
+               BL      template_embedded       ;Copy the template
+               MOVVC   R1,R0                   ;Look after this
+               BLVC    dbox_fromDefn           ;Create the dialogue box
+               MOVVC   R14,#1                  ;Mark as a template
+               STRVC   R14,[R0,#dbox__template] ;So it gets freed properly
+               LDMVCFD R13!,{R1,R2,R14}        ;Restore registers
+               BICVCS  PC,R14,#V_flag          ;And return with no error
+
+               MOV     R2,R0                   ;Look after this
+               MOVS    R0,R1                   ;Get the template pointer
+               BLNE    template_free           ;Maybe we free it
+               MOVNE   R0,R2                   ;If not, get error back
+               ADDEQ   R2,R2,#4                ;Otherwise find error text
+               ADREQ   R0,dbox__createErr      ;Point to my skeleton error
+               BLEQ    msgs_error              ;Translate and substitute
+               LDMFD   R13!,{R1,R2,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;Return the error
+
+               LTORG
+
+; --- dbox_fromDefn ---
+;
+; On entry:    R0 == pointer to a window definition
+;
+; On exit:     R0 == dialogue box handle for the dialogue
+;              May return an error
+;
+; Use:         Creates a dialogue box from an immediate window definition,
+;              rather than a template.  There are several things you need
+;              to be aware of when you use this call to create a dialogue
+;              box:
+;
+;              * The window definition is not copied, but used directly
+;                for the duration the dialogue box exists.  It must
+;                not move for this duration.  When the dialogue is
+;                destroyed, you can release the memory for the definition,
+;                although this is your responsibility.
+;
+;              * The indirected data is not copied either, so you'll have
+;                to copy it yourself if you want multiple dialogues from
+;                the same window definition.
+;
+;              * The window definition and the indirected data must both
+;                be writable.
+
+               EXPORT  dbox_fromDefn
+dbox_fromDefn  ROUT
+
+               STMFD   R13!,{R1-R3,R10,R14}    ;Save some registers away
+
+               ; --- Obtain a dbox block from the heap ---
+
+               MOV     R3,R0                   ;Look after the definition
+               MOV     R0,#dbox__blockSize     ;Find out how much I need
+               BL      alloc                   ;Allocate the memory
+               BLCS    alloc_error             ;If it failed, find error msg
+               BCS     %99dbox_fromDefn        ;... and quit if no memory
+
+               ; --- Now start filling in the structure ---
+
+               STR     R3,[R0,#dbox__defn]     ;Store the copy pointer away
+               MOV     R2,#0                   ;Start zeroing things
+               STR     R2,[R0,#dbox__proc]     ;No event handler yet
+               STR     R2,[R0,#dbox__flags]    ;Dialogue box has no flags
+               STR     R2,[R0,#dbx__defn]      ;Dbox not nabbed by dbx yet
+               STR     R2,[R0,#dbox__template] ;No template definition
+               MOV     R2,#-1                  ;No embedded title icon
+               STR     R2,[R0,#dbox__title]    ;So store it away
+               MOV     R10,R0                  ;Keep this pointer safe
+
+               ; --- Now we need to create a window ---
+
+               MOV     R1,R3                   ;Point to the window defn
+               SWI     XWimp_CreateWindow      ;Create the window
+               BVS     %98dbox_fromDefn        ;If it failed, tidy up
+               STR     R0,[R10,#dbox__window]  ;Store the window handle
+
+               ; --- Now register our event handler for it ---
+
+               ADR     R1,dbox__events         ;Point to my event handler
+               MOV     R2,R10                  ;Pass the dialogue box handle
+               WSPACE  dbox__wSpace,R3         ;And my workspace pointer
+               BL      win_eventHandler        ;Register the event handler
+               BVS     %97dbox_fromDefn        ;If that failed, tidy up
+
+               ; --- Now return the dialogue box handle ---
+
+               MOV     R0,R10                  ;Return pointer to my block
+               LDMFD   R13!,{R1-R3,R10,R14}    ;Restore the registers
+               BICS    PC,R14,#V_flag          ;Return with no errors
+
+               ; --- Tidy up after unfortunate events ---
+
+97dbox_fromDefn        MOV     R3,R0                   ;Keep error pointer
+               ADD     R1,R10,#dbox__window    ;Point to the window handle
+               SWI     Wimp_DeleteWindow       ;Delete the duff window
+               MOV     R0,R3                   ;Restore error pointer
+
+98dbox_fromDefn        MOV     R2,R0                   ;Keep error pointer
+               MOV     R0,R10                  ;Point to the block
+               BL      free                    ;Free it up -- it's useless
+               MOV     R0,R2                   ;Restore error pointer
+
+99dbox_fromDefn        ADD     R2,R0,#4                ;Point to the error message
+               ADR     R0,dbox__createErr      ;Point to my skeleton error
+               BL      msgs_error              ;Translate and substitute
+               LDMFD   R13!,{R1-R3,R10,R14}    ;Restore registers
+               ORRS    PC,R14,#V_flag          ;Return the error
+
+dbox__createErr        DCD     1
+               DCB     "dboxCRTERR",0
+
+; --- dbox_destroy ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Destroys a dialogue box, freeing all the memory it took
+;              up etc.
+
+               EXPORT  dbox_destroy
+dbox_destroy   ROUT
+
+               STMFD   R13!,{R0,R1,R10,R14}    ;Save some registers
+               MOV     R10,R0                  ;Get the dialogue handle
+
+               ; --- Make sure the dialogue's been closed ---
+
+               BL      dbox_close              ;Close the dialogue box
+               MOV     R0,#dbEvent_lifeCycle   ;Send a lifecycle message
+               MOV     R1,#dblc_destroy        ;Dialogue will be destroyed
+               BL      dbox__dispatch          ;Send the message
+
+               ; --- Remove the event handler ---
+
+               LDR     R0,[R10,#dbox__window]  ;Find the window handle
+               BL      win_windowDeleted       ;Window doesn't need handling
+
+               ; --- Delete the window ---
+
+               ADD     R1,R10,#dbox__window    ;Point to the window handle
+               SWI     Wimp_DeleteWindow       ;Delete the window
+
+               ; --- Free the template copy ---
+
+               LDR     R14,[R10,#dbox__template] ;Load the template address
+               CMP     R14,#0                  ;Is there one defined?
+               LDRNE   R0,[R10,#dbox__defn]    ;Point to the template copy
+               BLNE    template_free           ;Free it up now
+
+               ; --- Free the dialogue block ---
+
+               MOV     R0,R10                  ;Point to the dbox block
+               BL      free                    ;Free its memory up
+
+               ; --- Return to caller ---
+
+               LDMFD   R13!,{R0,R1,R10,PC}^    ;Return to caller
+
+;----- The event handler ---------------------------------------------------
+
+; --- dbox__events ---
+;
+; On entry:    R0 == the event code that happened
+;              R1 == pointer to the event data
+;              R10 == dialogue box it happened to
+;
+; On exit:     CS if we handled the event, CC otherwise
+;
+; Use:         Handles various events for a dialogue box
+
+dbox__events   ROUT
+
+               ; --- Dispatch the event to the right place ---
+
+               STR     R10,dbox__eventDbox     ;Remember this handle
+               CMP     R0,#9                   ;Is it a sensible event?
+               BGE     %00dbox__events         ;No -- check for messages
+               ADD     PC,PC,R0,LSL #2         ;Yes -- dispatch to handler
+
+               ; --- Event dispatch table ---
+
+               B       dbox__hint              ;Hint for the hint bar
+               MOVS    PC,R14                  ;Null event
+               B       dbox__redraw            ;Redraw window request
+               B       dbox__open              ;Open window request
+               B       dbox__close             ;Close window request
+               B       dbox__enterLeave        ;Pointer leaving window
+               B       dbox__enterLeave        ;Pointer entering window
+               B       dbox__mouse             ;Mouse clicked
+               MOVS    PC,R14                  ;Drag event
+               B       dbox__keyPress          ;Key pressed
+
+               ; --- Handle a message ---
+
+00dbox__events CMP     R0,#17                  ;User message
+               CMPNE   R0,#18                  ;Rubber message (bouncy!)
+               MOVNES  PC,R14                  ;No -- return unhandled
+               B       dbox__message           ;Handle the message event
+
+; --- dbox__dispatch ---
+;
+; On entry:    R0 == the (dbox-style) event code to dispatch
+;              R1-R7 == any additional arguments that want passing along
+;              R10 == the dialogue box to send the event to
+;
+; On exit:     CS or CC from the event handler
+;
+; Use:         Dispatches an event to the event handler associated with the
+;              dialogue box, and returns its response.
+
+dbox__dispatch ROUT
+
+               STMFD   R13!,{R8-R10,R12,R14}   ;Save lots of registers
+               MOV     R9,R10                  ;Pass dialogue handle in R9
+               ADDS    R0,R0,#0                ;Clear the carry flag
+               LDMIB   R10,{R8,R10,R12}        ;Get the event handler stuff
+               TEQ     R8,#0                   ;Is there an event handler?
+               MOVNE   R14,PC                  ;Set up return address
+               MOVNE   PC,R8                   ;Call the event handler
+               LDMFD   R13!,{R8-R10,R12,R14}   ;Restore the registers
+               ORRCSS  PC,R14,#C_flag          ;Return CS if it returned CS
+               BICCCS  PC,R14,#C_flag          ;Return CC if it returned CC
+
+               LTORG
+
+; --- dbox__checkIcon ---
+;
+; On entry:    R1 == icon handle
+;              R10 == dialogue box handle
+;
+; On exit:     R1 == icon handle or -1 if it was shaded
+;
+; Use:         Translates an icon handle to the window background if it
+;              is shaded, for passing to event handlers.
+
+dbox__checkIcon        ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R1                   ;Move icon handle along
+               BL      dbox__icon              ;Find the icon definition
+               LDR     R14,[R0,#16]            ;Load the icon flags
+               TST     R14,#&00400000          ;Is the icon shaded?
+               MOVNE   R1,#-1                  ;Yes -- return background
+               STR     R1,dbox__eventIcon      ;Store in workspace
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+; --- dbox__hint ---
+;
+; On entry:    R0 == -1
+;              R1 == pointer to hint event block
+;
+; On exit:     C set if handled
+;
+; Use:         Sends a hint event to the dbox handler
+
+dbox__hint     ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R0,#dbEvent_hint        ;The event code
+               ADD     R2,R1,#4                ;Point to the string
+               BL      dbox__dispatch          ;Send it to the handler
+               LDMFD   R13!,{R0-R2,PC}         ;Return with its flags
+
+               LTORG
+
+; --- dbox__redraw ---
+;
+; On entry:    R0 == 1
+;              R1 == pointer to window handle
+;
+; On exit:     C set
+;
+; Use:         Redraws a window using Sculptrix
+
+dbox__redraw   ROUT
+
+               STMFD   R13!,{R0,R2,R3,R14}     ;Save some registers
+
+               ; --- Start the redraw operation ---
+
+               SWI     Wimp_RedrawWindow       ;Start the redraw
+               CMP     R0,#0                   ;Is it over already?
+               BEQ     %10dbox__redraw         ;Yes -- skip to the end
+
+               ; --- Set up Sculptrix's sprite area ---
+
+               LDR     R0,[R10,#dbox__defn]    ;Find the window definition
+               LDR     R0,[R0,#64]             ;Load the sprite area pointer
+               SWI     XSculptrix_SetSpriteArea ;Set up the sprite area
+
+               ; --- Do any bits that need doing ---
+
+00dbox__redraw LDR     R2,[R1,#4]              ;Get the window left position
+               ADD     R0,R1,#16               ;Point to the top position
+               LDMIA   R0,{R0,R3,R14}          ;Load top, and scroll posns
+               SUB     R2,R2,R3                ;Convert to find origin x
+               SUB     R3,R0,R14               ;Convert to find origin y
+               MOV     R0,#dbEvent_redraw      ;Give user a redraw event
+               BL      dbox__dispatch          ;Send it to the handler
+               BCS     %01dbox__redraw         ;If it claimed it, skip ahead
+
+               LDR     R0,[R10,#dbox__title]   ;Get the embedded title icon
+               CMP     R0,#-1                  ;Has it been defined?
+               MOVNE   R0,R10                  ;Give it the dialogue box
+               BLNE    dbox_renderTitle        ;Yes -- render it nicely
+
+               SWI     XSculptrix_RedrawWindow ;Get Sculptrix to do its bit
+
+01dbox__redraw SWI     Wimp_GetRectangle       ;Get the next rectangle
+               CMP     R0,#0                   ;Is this the end yet?
+               BNE     %00dbox__redraw         ;No -- do the rest
+
+               ; --- That's it, then ---
+
+10dbox__redraw LDMFD   R13!,{R0,R2,R3,R14}     ;Unstack all the registers
+               ORRS    PC,R14,#C_flag          ;Set carry and return
+
+               LTORG
+
+; --- dbox__open ---
+;
+; On entry:    R0 == 2
+;              R1 == pointer to window open block
+;
+; On exit:     C set
+;
+; Use:         This just opens the window.  Later, it may do clever things
+;              with panes.
+
+dbox__open     SWI     Wimp_OpenWindow         ;Open the window
+               ORRS    PC,R14,#C_flag          ;Set carry and return
+
+; --- dbox__close ---
+;
+; On entry:    R0 == 3
+;              R1 == pointer to the window handle
+;
+; On exit:     C set
+;
+; Use:         Passes a close event to the user dialogue box handler.
+
+dbox__close    STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,#dbEvent_close       ;The close event code
+               BL      dbox__dispatch          ;Pass it to the handler
+               LDMFD   R13!,{R0,R14}           ;Unstack all the registers
+               ORRS    PC,R14,#C_flag          ;Set carry and return
+
+; --- dbox__mouse ---
+;
+; On entry:    R0 == 6
+;              R1 == pointer to mouse status block
+;
+; On exit:     C set if we understood the event, C clear otherwise
+;
+; Use:         Passes a click event to the dbox event handler.
+
+dbox__mouse    ROUT
+
+               STMFD   R13!,{R0-R2,R9,R14}     ;Save some registers
+               MOV     R9,R1                   ;Keep the event pointer
+               LDR     R1,[R9,#8]              ;Get the button status
+               TST     R1,#&5                  ;Is it Select or Adjust?
+               BNE     %10dbox__mouse          ;Yes -- handle it nicely
+               TST     R1,#&50                 ;Is it a drag event?
+               BNE     %20dbox__mouse          ;Yes -- handle it nicely
+               TST     R1,#&2                  ;Is it a menu click?
+               LDMEQFD R13!,{R0-R2,R9,PC}^     ;No -- we're clueless then
+
+               ; --- The user clicked Menu ---
+
+               LDR     R1,[R9,#16]             ;Get the icon handle out
+               MOV     R0,#dbEvent_menu        ;Give it a menu click
+               BL      dbox__checkIcon         ;Handle icon shadedness
+               BL      dbox__dispatch          ;Give it to the user
+               B       %80dbox__mouse          ;And return C set
+
+               ; --- The user clicked Select or Adjust ---
+
+10dbox__mouse  LDR     R1,[R9,#16]             ;Get the icon handle out
+               BL      dbox__checkIcon         ;Handle icon shadedness
+               MOV     R0,R1                   ;Return icon number as event
+               LDR     R1,[R9,#8]              ;Load the button state again
+               BL      dbox__dispatch          ;Dispatch the event out
+               BCS     %80dbox__mouse          ;If handled, skip this bit
+
+               MOV     R1,R0                   ;Get the icon handle in R1
+               MOV     R0,R10                  ;And dialogue handle in R0
+               BL      dbox_radio              ;Handle magic radio buttons
+
+               LDR     R0,[R10,#dbox__flags]   ;Get this dialogue's flags
+               TST     R0,#dbFlag__drag        ;Is the move on drag bit on?
+               BEQ     %80dbox__mouse          ;No -- skip this bit out
+
+               SUB     R13,R13,#56             ;Make a drag info block
+               LDR     R0,[R10,#dbox__window]  ;Get the window handle
+               STR     R0,[R13,#0]             ;Store the window handle
+               MOV     R0,#1                   ;Move the window
+               STR     R0,[R13,#4]             ;Store the drag type
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_DragBox            ;Start the window moving
+               ADD     R13,R13,#56             ;Reclaim the stack space
+               B       %80dbox__mouse          ;Skip ahead to claim event
+
+               ; --- The user dragged an icon ---
+
+20dbox__mouse  LDR     R1,[R9,#16]             ;Get the icon handle out
+               BL      dbox__checkIcon         ;Handle shadiness nicely
+               MOV     R2,R1                   ;Move handle to right place
+               LDR     R1,[R9,#8]              ;Load button status again
+               MOV     R0,#dbEvent_drag        ;Give handler a drag event
+               BL      dbox__dispatch          ;And pass it to the handler
+               B       %80dbox__mouse          ;And claim the event
+
+               ; --- Finish everything off nicely ---
+
+80dbox__mouse  LDMFD   R13!,{R0-R2,R9,R14}     ;Restore the registers
+               ORRS    PC,R14,#C_flag          ;Claim the event nicely
+
+               LTORG
+
+; --- dbox__enterLeave ---
+;
+; On entry:    R0 == 4 for leaving, 5 for entering
+;
+; On exit:     --
+;
+; Use:         Informs dialogue handlers that pointer has entered or left
+;              a window.
+
+dbox__enterLeave ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               ADD     R0,R0,#dbEvent_leave-4  ;Convert to appropriate event
+               BL      dbox__dispatch          ;Send it to the handler
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               LTORG
+
+; --- dbox__keyPress ---
+;
+; On entry:    R0 == 8
+;              R1 == pointer to caret block
+;
+; On exit:     C clear
+;
+; Use:         Handles key events for a dialogue box
+
+dbox__keyPress ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Send the event to the user ---
+
+               LDR     R2,[R1,#4]              ;Get the icon handle
+               STR     R2,dbox__eventIcon      ;Store it in workspace
+               LDR     R0,[R1,#24]             ;Get the key code
+               BL      akbd_translate          ;Mangle for extended keyset
+               MOV     R1,R0                   ;Move into right register
+               MOV     R0,#dbEvent_key         ;Key event code
+               BL      dbox__dispatch          ;Send it to the user
+               BCS     %50dbox__keyPress       ;If processed, skip ahead
+
+               ; --- Now see if it's one of ours ---
+
+               CMP     R1,#&100                ;Is it an extended code?
+               BGE     %20dbox__keyPress       ;Yes -- skip forward
+
+               CMP     R1,#key_Return          ;Is it a return?
+               MOVEQ   R0,#dbEvent_OK          ;Yes -- give out an OK event
+               BEQ     %10dbox__keyPress       ;Send it on its way
+               CMP     R1,#key_Esc             ;Or maybe an escape
+               MOVEQ   R0,#dbEvent_cancel      ;Yes -- give a Cancel event
+               BEQ     %10dbox__keyPress       ;Send it on its way
+
+00             LDMFD   R13!,{R0-R3,PC}^        ;Forget it -- don't know
+
+               ; --- Send a key event on ---
+
+10             MOV     R1,#4                   ;Pretend Select was pressed
+               BL      dbox__dispatch          ;Send it to the client
+               B       %50dbox__keyPress       ;Now we've done the deed...
+
+11             MOV     R1,#1                   ;Pretend Adjust was pressed
+               BL      dbox__dispatch          ;Send it to the client
+               B       %50dbox__keyPress       ;Now we've done the deed...
+
+               ; --- Handle an extended key ---
+
+20             AND     R2,R1,#&FF              ;Leave the bottom byte
+
+               ; --- Straight cursor keys ---
+
+               MOV     R0,#0
+
+               CMP     R2,#key_kEnter-256
+               MOVEQ   R0,#dbEvent_OK
+               BEQ     %10dbox__keyPress
+
+               CMP     R2,#key_sReturn-256
+               CMPNE   R2,#key_skEnter-256
+               MOVEQ   R0,#dbEvent_OK
+               BEQ     %11dbox__keyPress
+
+               CMP     R2,#key_sEsc-256
+               MOVEQ   R0,#dbEvent_cancel
+               BEQ     %11dbox__keyPress
+
+               CMP     R2,#key_Up-256
+               CMPNE   R2,#key_sTab-256
+               MOVEQ   R1,#-1
+               BEQ     %40dbox__keyPress
+
+               CMP     R2,#key_Down-256
+               CMPNE   R2,#key_Tab-256
+               MOVEQ   R1,#+1
+               BEQ     %40dbox__keyPress
+
+               ; --- Control cursor keys ---
+
+               MOV     R0,#1
+
+               CMP     R2,#key_cUp-256
+               MOVEQ   R1,#+1
+               BEQ     %40dbox__keyPress
+
+               ; --- Cursor up ---
+
+               CMP     R2,#key_cDown-256
+               MOVEQ   R1,#-1
+               BEQ     %40dbox__keyPress
+
+               ; --- Nothing worth knowing about ---
+
+               B       %00dbox__keyPress
+
+               ; --- Actually do a cursor move ---
+
+40             BL      dbox__moveCaret         ;Do the cursor move
+
+               ; --- Return and claim the keypress ---
+
+50             LDMFD   R13!,{R0-R3,R14}
+               ORRS    PC,R14,#C_flag
+
+               LTORG
+
+; --- dbox__message ---
+;
+; On entry:    R0 == 17 or 18
+;              R1 == pointer to message data
+;
+; On exit:     C set if the event was handled, or clear otherwise
+;
+; Use:         Handles messages sent to dialogue boxes.
+
+dbox__message  ROUT
+
+               STMFD   R13!,{R0-R4,R9,R14}     ;Save some registers
+               MOV     R9,R1                   ;Point to the event block
+               LDR     R14,[R9,#16]            ;Get the message type number
+               CMP     R14,#1                  ;Is it a save message?
+               CMPNE   R14,#3                  ;Or a load message?
+               BEQ     %10dbox__message        ;Yes -- handle them the same
+               MOV     R0,#&500                ;&502 is a help request
+               ORR     R0,R0,#&002             ;Build the full number
+               CMP     R14,R0                  ;Is it a help request?
+               LDMNEFD R13!,{R0-R4,R9,PC}^     ;No -- we don't understand
+
+               ; --- Handle help requests for the dbox ---
+
+               LDR     R1,[R9,#36]             ;Obtain the icon handle
+               BL      dbox__checkIcon         ;Handle icon shadiness
+               MOV     R0,#dbEvent_help        ;Pass a help request on
+               BL      dbox__dispatch          ;Send it to the client
+               B       %80dbox__message        ;Skip on and claim the event
+
+               ; --- Handle save and load events ---
+
+10dbox__message        CMP     R14,#1                  ;Is it a save message?
+               MOVEQ   R0,#dbEvent_save        ;Yes -- give a save event
+               MOVNE   R0,#dbEvent_load        ;No -- give a load event
+               LDR     R1,[R9,#24]             ;Get the icon handle
+               BL      dbox__checkIcon         ;Handle icon shadiness
+               LDR     R2,[R9,#40]             ;Get filetype in R2
+               ADD     R3,R9,#44               ;Point to filename with R3
+               LDR     R4,[R9,#36]             ;Estimated size in R4
+               BL      dbox__dispatch          ;Send the message on
+               B       %80dbox__message        ;Skip on and claim the event
+
+               ; --- We did something, so claim event ---
+
+80dbox__message        LDMFD   R13!,{R0-R4,R9,R14}     ;Restore all the registers
+               ORRS    PC,R14,#C_flag          ;Return, claiming the event
+
+               LTORG
+
+;----- Locating icons -------------------------------------------------------
+
+; --- dbox__find ---
+;
+; On entry:    R0 == icon number to start from or -1
+;              R1 == AND mask for flags
+;              R2 == flags word to match
+;              R3 == direction to scan in (either +1 or -1 unless you're
+;                    very odd)
+;              R10 == dialogue box handle
+;
+; On exit:     R0 == icon number of found icon or -1
+;              Other registers preserved
+;
+; Use:         Locates an icon within a window with flags that match the
+;              ones given.  Note that icon definitions within the cached
+;              window definition are scanned, not icons in their actual
+;              current state.
+;
+;              Searching from icon `-1' means to start from one end and
+;              keep looking until you've gone through all of them.
+;              Otherwise, the scan starts from the icon *after* the one
+;              specified in R0 on entry.
+;
+;              The return value is the number of the first icon that
+;              matched the specification, or -1 if none of them matched.
+
+dbox__find     ROUT
+
+               STMFD   R13!,{R4-R6,R14}        ;Save some registers
+
+               ; --- Find the cached window defintion ---
+
+               LDR     R4,[R10,#dbox__defn]    ;Locate the definition
+
+               ; --- Work out a sensible scanning start position ---
+
+               CMP     R0,#-1                  ;Extremity requested?
+               ADDNE   R0,R0,R3                ;No -- skip over start icon
+               BNE     %00dbox__find           ;And skip past this bit
+               CMP     R3,#0                   ;Is the increment positive?
+               MOVGT   R0,#0                   ;Yes -- start from 0
+               LDRLT   R0,[R4,#84]             ;No -- load the icon count
+               SUBLT   R0,R0,#1                ;And bump down -- zero index
+
+               ; --- Now work out when to stop scanning ---
+
+00dbox__find   CMP     R3,#0                   ;What's the increment again?
+               BEQ     %02dbox__find           ;If it's silly, find nothing
+               LDRGT   R5,[R4,#84]             ;Positive -- stop at the
+               SUBGT   R5,R5,#1                ;...number of icons -1
+
+               ; --- A few other pre-scan bits ---
+
+               AND     R2,R2,R1                ;Make sure flags aren't silly
+               ADD     R6,R4,#88               ;Point to icon number 0
+               ADD     R6,R6,R0,LSL #5         ;Point to the right icon
+
+               ; --- The main scanning loop ---
+               ;
+               ; The comparison at the end is slightly tricky.  It works
+               ; on the basis that if R3>0, the condition is that R0>R5,
+               ; and if R3<0, the condition is that R0<0.  Each of these
+               ; double-barrelled conditions can be done in two ARM
+               ; instructions, and both together, complete with branches
+               ; can be done in 6.
+               ;
+               ; Rather oddly, we start with the termination condition.
+
+01dbox__find   CMP     R3,#0                   ;What's the increment like?
+               CMPLT   R0,#0                   ;Check not gone too low
+               BLT     %02dbox__find           ;Yes -- exit the loop
+               CMP     R3,#0                   ;Check increment again
+               CMPGT   R0,R5                   ;Check not gone too high
+               BGT     %02dbox__find           ;Yes -- exit the loop
+
+               ; --- Now see if we got a match ---
+
+               LDR     R14,[R6,#16]            ;Get icon flags for this one
+               AND     R14,R14,R1              ;Apply the AND mask to them
+               CMP     R14,R2                  ;Is this a match?
+               LDMEQFD R13!,{R4-R6,PC}^        ;Yes -- return to caller
+
+               ; --- Set up for the next one ---
+
+               ADD     R0,R0,R3                ;Move the icon number on
+               ADD     R6,R6,R3,LSL #5         ;And bump icon pointer too
+               B       %01dbox__find           ;Jump back to the loop start
+
+               ; --- We failed to find it -- return -1 ---
+
+02dbox__find   MOV     R0,#-1                  ;Return funny failure value
+               LDMFD   R13!,{R4-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- dbox__icon ---
+;
+; On entry:    R0 == icon number wanted
+;              R10 == dialogue box block pointer
+;
+; On exit:     R0 == pointer to numbered icon's definition
+;
+; Use:         Locates an icon definition given its number
+
+dbox__icon     STMFD   R13!,{R14}              ;Save link register a bit
+               LDR     R14,[R10,#dbox__defn]   ;Find window definition
+               ADD     R14,R14,#88             ;Point to the first icon
+               ADD     R0,R14,R0,LSL #5        ;Add R0*32 to point to icon
+               LDMFD   R13!,{PC}^              ;Return to caller nicely
+
+;----- Main initialisation --------------------------------------------------
+
+; --- dbox_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the dbox system.
+
+               EXPORT  dbox_init
+dbox_init      ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save a load of registers
+               WSPACE  dbox__wSpace            ;Find my workspace
+
+               ; --- Make sure I'm not running yet ---
+
+               LDR     R14,dbox__wFlags        ;Get hold of my flags word
+               TST     R14,#dbFlag__inited     ;Am I running yet?
+               LDMNEFD R13!,{R12,PC}^          ;Yes -- return immediately
+
+               ; --- Set up the flags nicely ---
+
+               MOV     R14,#dbFlag__inited     ;I am initialised now
+               STR     R14,dbox__wFlags        ;Save my flags back again
+               MOV     R14,#0                  ;Zero some workspace bits
+               STR     R14,dbox__clickList     ;Nothing on the click list
+               BL      win_init                ;Make sure win's awake
+               BL      transWin_init           ;And also for transWin
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+dbox__wSpace   DCD     0
+
+;----- Opening and closing dialogue boxes -----------------------------------
+
+; --- dbox_open ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == how to open the dialogue box
+;              Other registers depend on R1, and are described at the end
+;              of this header file
+;
+; On exit:     --
+;
+; Use:         Displays the dialogue box on the screen in the given manner.
+
+               EXPORT  dbox_open
+dbox_open      ROUT
+
+               STMFD   R13!,{R0-R6,R10,R12,R14}
+               WSPACE  dbox__wSpace            ;Locate my workspace
+               MOV     R10,R0                  ;Move the dbox handle away
+
+               ; --- Is this a submenu request? ---
+
+               ADDS    R0,R0,#0                ;Clear the C flag
+               TST     R1,#dbOpen_nonSub       ;Do we ignore this?
+               BLEQ    transWin_subWaiting     ;No -- waiting for a submenu?
+               BCS     %60dbox_open            ;Yes -- open as a submenu
+
+               ; --- Now work out how to open it ---
+
+               LDR     R6,[R10,#dbox__flags]   ;Get the dialogue's flags
+               TST     R1,#dbOpen_persist      ;Is this a persistent dbox?
+               BICEQ   R6,R6,#dbFlag__static   ;No -- clear static flag
+               ORRNE   R6,R6,#dbFlag__static   ;Yes -- set static flag
+               MOV     R4,R1                   ;Look after open style
+
+               ; --- Read the dialogue's position ---
+
+               SUB     R13,R13,#36             ;Enough for a window block
+               LDR     R0,[R10,#dbox__window]  ;Get the window handle
+               STR     R0,[R13,#0]             ;Store it in the block
+               MOV     R1,R13                  ;Point to the window handle
+               SWI     Wimp_GetWindowState     ;Read in the information
+
+               ; --- Move the dialogue box to the right position ---
+
+               BIC     R0,R4,#dbOpen_persist + dbOpen_nonSub
+               BL      winUtils_setPosition    ;Position the window nicely
+               TST     R6,#dbFlag__static      ;Is it static?
+               BEQ     %40dbox_open            ;No -- skip ahead a bit
+
+               ; --- Open a persistent dialogue box ---
+
+               SWI     Wimp_OpenWindow         ;Open the window
+               ADD     R13,R13,#36             ;Reclaim the stack space
+
+               ; --- If the window was already open, quit now ---
+
+               TST     R6,#dbFlag__open        ;Is the dialogue box open
+               BNE     %80dbox_open            ;Yes -- skip past this bit
+
+               ; --- Now find out if there's a caret to handle ---
+
+               MOV     R0,#-1                  ;Start searching from start
+               MOV     R1,#&0000E000           ;Find all Writable icons
+               MOV     R2,#&0000E000           ;Only check button type bits
+               MOV     R3,#+1                  ;Search forwards
+               BL      dbox__find              ;Find the icon
+               CMP     R0,#-1                  ;Is there a writable icon?
+               BICEQ   R6,R6,#dbFlag__rCaret   ;Don't have to restore caret
+               BEQ     %10dbox_open            ;No -- skip ahead
+
+               ; --- Read the old caret position ---
+
+               ADD     R1,R10,#dbox__oldCaret  ;Point to old caret block
+               SWI     Wimp_GetCaretPosition   ;Read the current position
+               LDR     R0,[R10,#dbox__window]  ;Get the dialogue window
+               MOV     R1,#-1                  ;In no particular icon
+               MOV     R2,#&ff000000           ;Quite a long way away
+               ORR     R2,R2,#&00ff0000
+               MOV     R3,#0                   ;Doesn't really matter
+               MOV     R4,#&02000000           ;Hide caret, make it small
+               MOV     R5,#-1                  ;No index into icon, please
+               SWI     Wimp_SetCaretPosition   ;Set the caret's position
+               ORR     R6,R6,#dbFlag__rCaret   ;Remember to restore caret
+
+               ; --- That's it, so finish things off ---
+
+10dbox_open    B       %80dbox_open            ;Perform wrapping-up actions
+
+               ; --- Open as a transient menu ---
+
+40dbox_open    LDR     R1,[R10,#dbox__window]  ;Get the window handle ready
+               SWI     Wimp_CreateMenu         ;Create it as a menu :-/
+               BIC     R6,R6,#dbFlag__rCaret   ;Don't restore the caret
+               ADD     R13,R13,#36             ;Reclaim the stack we used
+               MOV     R0,R1                   ;Get the window handle again
+               BL      transWin_register       ;This is transient window
+               B       %80dbox_open            ;Perform wrapping-up actions
+
+               ; --- Open in the correct submenu position ---
+
+60dbox_open    LDR     R0,[R10,#dbox__window]  ;Load the window handle
+               BL      transWin_openSub        ;And display as submenu
+               LDR     R6,[R10,#dbox__flags]   ;Read the dialogue box flags
+               BIC     R6,R6,#dbFlag__static :OR: dbFlag__rCaret
+
+               ; --- Wrap everything up now ---
+
+80dbox_open    ORR     R6,R6,#dbFlag__open     ;The window is at last open
+               STR     R6,[R10,#dbox__flags]   ;Store the flags away now
+               MOV     R0,#dbEvent_lifeCycle   ;A lifecycle event
+               MOV     R1,#dblc_open           ;Box has opened
+               BL      dbox__dispatch          ;Send a message
+               LDMFD   R13!,{R0-R6,R10,R12,PC}^
+
+               LTORG
+
+; --- dbox_close ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Closes a dialogue box, by clearing the current menu if
+;              necessary.
+
+               EXPORT  dbox_close
+dbox_close     ROUT
+
+               STMFD   R13!,{R0-R6,R10,R12,R14} ;Save some registers away
+               WSPACE  dbox__wSpace            ;Locate my workspace
+               MOV     R10,R0                  ;Move dbox handle away
+
+               ; --- First things first -- check it's open ---
+
+               LDR     R6,[R10,#dbox__flags]   ;Get the dialogue's flags
+               TST     R6,#dbFlag__open        ;Is the open flag on?
+               BEQ     %80dbox_close           ;No -- skip forward
+
+               ; --- Now restore the caret if needs be ---
+               ;
+               ; Try not to be overly upset if we can't put the caret back.
+               ; After all, the window may have closed by now.  An X SWI
+               ; is called for, and we ignore V on exit.
+
+               TST     R6,#dbFlag__rCaret      ;Does caret need restoring?
+               BEQ     %00dbox_close           ;No -- skip forwards
+               ADD     R0,R10,#dbox__oldCaret  ;Point to old caret block
+               LDMIA   R0,{R0-R5}              ;Load the old caret state
+               SWI     XWimp_SetCaretPosition  ;And try to put it back
+
+               ; --- Now handle transientness properly ---
+
+00dbox_close   TST     R6,#dbFlag__static      ;Is this a static dialogue?
+               LDREQ   R0,[R10,#dbox__window]  ;Yes -- find the window
+               BLEQ    transWin_close          ;And close it
+               ADDNE   R1,R10,#dbox__window    ;Point to the window handle
+               SWINE   Wimp_CloseWindow        ;Close the window now
+
+               BIC     R6,R6,#dbFlag__open :OR: dbFlag__rCaret
+               STR     R6,[R10,#dbox__flags]   ;Store flags away again
+
+               ; --- Send a lifecycle warning ---
+
+               MOV     R0,#dbEvent_lifeCycle   ;Get the event code
+               MOV     R1,#dblc_close          ;Box has closed
+               BL      dbox__dispatch          ;Send the event
+
+80dbox_close   LDMFD   R13!,{R0-R6,R10,R12,PC}^ ;Return to caller
+
+               LTORG
+
+; --- dbox_writePos ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Saves the dialogue's current position so that it will be
+;              opened here the next time it is created.  If the dialogue
+;              box was created from a template, the template is updated.
+;              Otherwise, the new state is written back to the definition
+;              supplied to dbox_fromDefn.
+
+               EXPORT  dbox_writePos
+dbox_writePos  ROUT
+
+               STMFD   R13!,{R0-R5,R10,R14}    ;Save a load of registers
+               MOV     R10,R0                  ;Keep the dialogue handle
+               SUB     R13,R13,#36             ;Make space on the stack
+               LDR     R14,[R10,#dbox__window] ;Get the dialogue's window
+               STR     R14,[R13,#0]            ;Save in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window's position
+               LDMIB   R13,{R0-R5}             ;Load pos and scroll settings
+               LDR     R14,[R10,#dbox__template] ;Find the template address
+               CMP     R14,#0                  ;Is it actually there?
+               CMPNE   R14,#1                  ;Check for embedded templates
+               LDREQ   R14,[R10,#dbox__defn]   ;No -- just use definition
+               STMIA   R14,{R0-R5}             ;Yes -- save them for later
+               ADD     R13,R13,#36             ;Reclaim the used stack space
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;Return to caller
+
+               LTORG
+
+;----- Caret handling functions ---------------------------------------------
+
+; --- dbox__viewIcon ---
+;
+; On entry:    R0 == an icon number
+;              R10 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Scrolls the given dialogue box so that the specified icon
+;              is visible.  The icon is assumed to be in the same position
+;              as it was when it was created.
+;
+;              This is translated fairly literally from the STEEL code
+;              in dbox__nextWritable.
+
+dbox__viewIcon ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Save a load of registers
+
+               ; --- Locate the icon definition ---
+
+               BL      dbox__icon              ;Find the icon position
+               MOV     R9,R0                   ;Keep a pointer to it
+
+               ; --- Find the window position ---
+
+               SUB     R13,R13,#36             ;Make space for a window def
+               LDR     R14,[R10,#dbox__window] ;Find the dbox's window hnd
+               STR     R14,[R13,#0]            ;Store it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Find the window information
+
+               ; --- Now read the window scroll positions ---
+
+               LDMIB   R13,{R0-R5}             ;Load window visible coords
+
+               SUB     R0,R2,R0                ;R0 == window width
+               SUB     R1,R3,R1                ;R1 == window height
+               ADD     R2,R4,R0                ;R2 == window right hand side
+               SUB     R3,R5,R1                ;R3 == window bottom edge
+                                               ;R4 == window left hand side
+                                               ;R5 == window top edge
+
+               LDMIA   R9,{R6-R8,R14}          ;Load icon coordinates nicely
+
+               SUB     R6,R6,#24               ;Add a bit of extra around
+               SUB     R7,R7,#24
+               ADD     R8,R8,#24
+               ADD     R14,R14,#24
+
+               ; --- Bodge the scroll positions until icon is visible ---
+               ;
+               ; This section is fairly self-explanatory, and the comments
+               ; are very dull.
+
+               CMP     R7,R3
+               ADDLT   R5,R7,R1
+               CMP     R14,R5
+               MOVGT   R5,R14
+               CMP     R6,R4
+               MOVLT   R4,R6
+               CMP     R8,R2
+               SUBGT   R4,R8,R0
+
+               ; --- Now store the scroll offsets back and reopen ---
+
+               ADD     R1,R13,#20              ;Point to scroll offsets
+               STMIA   R1,{R4,R5}              ;Store them back in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_OpenWindow         ;Now open the window nicely
+
+               ; --- Reclaim the stack and return ---
+
+               ADD     R13,R13,#36
+               LDMFD   R13!,{R0-R9,PC}^        ;Return to caller
+
+               LTORG
+
+; --- dbox__moveCaret ---
+;
+; On entry:    R0 == 0 to move relative to current input focus
+;                    1 to move absolute (for ctrl cursor keys)
+;              R1 == direction to move in (+1 or -1, if you've any sense)
+;              R10 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Moves the caret between writable icons, responding to cursor
+;              key presses.
+
+dbox__moveCaret        ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save a few registers
+
+               ; --- Find out where the cursor is ---
+
+               SUB     R13,R13,#24             ;Make way for a caret block
+               MOV     R1,R13                  ;Point to it
+               SWI     Wimp_GetCaretPosition   ;Find the caret nicely
+
+               ; --- Check this is the right window ---
+
+               LDMIA   R13,{R0,R5}             ;Get the input focus window
+               LDR     R14,[R10,#dbox__window] ;Get dialogue box window
+               ADD     R13,R13,#24             ;Reclaim that stack space
+               CMP     R0,R14                  ;Do they match nicely?
+               LDMNEFD R13!,{R0-R5,PC}^        ;No -- return to caller
+
+               ; --- Now set up a search for the icon ---
+
+               LDMIA   R13,{R0,R3}             ;Get the stacked start pos
+               CMP     R0,#0                   ;Is it a zero?
+               MOVNE   R0,#-1                  ;No -- start from one end
+               MOVEQ   R0,R5                   ;Yes -- start from current
+
+               ; --- Load the icon flags to search for ---
+
+               MOV     R2,#&0000E000           ;Find writable icons
+               ORR     R1,R2,#&00400000        ;Also check shaded bit
+               BL      dbox__find              ;Find the icon nicely
+               CMP     R0,#-1                  ;Did it find one?
+               BLEQ    dbox__find              ;No -- search from one end
+
+               ; --- Now it's come up with the goods ---
+
+               CMP     R0,#-1                  ;Did it fail this time?
+               CMPNE   R0,R5                   ;Or just come back again?
+               LDMEQFD R13!,{R0-R5,PC}^        ;Yes -- nothing doing then
+
+               ; --- Scroll to make icon visible ---
+
+               BL      dbox__viewIcon          ;Scroll the window nicely
+
+               ; --- Set the caret position nicely ---
+
+               MOV     R1,R0                   ;Icon number to R1
+               BL      dbox__fieldLen          ;Find the string length
+               MOV     R5,R0                   ;This is icon text index
+               MOV     R4,#-1                  ;Calculate things for me
+               LDR     R0,[R10,#dbox__window]  ;Get the window handle
+               SWI     Wimp_SetCaretPosition   ;Move the caret nicely now
+
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller at last
+
+               LTORG
+
+;----- Selecting and shading icons ------------------------------------------
+
+; --- dbox_select ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number
+;              R2 == 0 to deselect the icon, 1 to select it, 2 to toggle
+;                    its current selected state
+;
+; On exit:     --
+;
+; Use:         Selects or deselects the specified icon in the Acorn sense
+;              (i.e. by flipping its selected bit).  The state is only
+;              changed if required, to reduce flicker.
+
+               EXPORT  dbox_select
+dbox_select    ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers away
+
+               ; --- Find the old state ---
+
+               SUB     R13,R13,#40             ;Make space for an icon block
+               LDR     R0,[R0,#dbox__window]   ;Get the window handle
+               STMIA   R13,{R0,R1}             ;Save the handles away
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetIconState       ;Find out about the icon
+
+               ; --- Find out the current selection state ---
+
+               LDR     R14,[R13,#24]           ;Load the flags word
+               AND     R14,R14,#&00200000      ;Clear all but the select bit
+               CMP     R2,#1                   ;Are we to select the icon?
+               MOVEQ   R2,#&00200000           ;Yes -- set the select bit
+               CMP     R2,#2                   ;Are we to toggle it?
+               EOREQ   R2,R14,#&00200000       ;Yes -- toggle it then
+
+               ; --- Make sure we need to do something ---
+
+               CMP     R2,R14                  ;Are the states the same?
+               ADDEQ   R13,R13,#40             ;Yes -- restore the stack
+               LDMEQFD R13!,{R0-R2,PC}^        ;And return right now
+
+               ; --- Now change the icon state ---
+
+               ADD     R0,R13,#8               ;Point to the flags masks
+               MOV     R14,#&00200000          ;Clear only the selected bit
+               STMIA   R0,{R2,R14}             ;Save the masks in the block
+               SWI     Wimp_SetIconState       ;Set the state nicely
+
+               ADD     R13,R13,#40             ;Restore the stack nicely
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- dbox_shade ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number
+;              R2 == 0 to unshade the icon, 1 to shade it, 2 to toggle its
+;                    current shaded state
+;
+; On exit:     --
+;
+; Use:         Makes the icon look dimmer, to indicate that it is not
+;              available.  It uses its own shading algorithms, rather than
+;              the WindowManager's, so there are some things you must watch
+;              out for:
+;
+;              * Don't use any other method of shading icons
+;
+;              * Don't assume that a shaded icon isn't going to give you
+;                events.  At the user level, this should have been tidied
+;                up, but at the Sapphire level, it's still a problem.
+;                There is a routine in winUtils which will tell you if an
+;                icon is shaded.
+;
+;              This routine has been written so that it only flickers icons
+;              when they actually need it.
+
+               EXPORT  dbox_shade
+dbox_shade     ROUT
+
+               STMFD   R13!,{R0-R6,R10,R14}    ;Save a load of registers
+
+               ; --- Make sure we need to do something ---
+
+               MOV     R10,R0                  ;Look after the dbox handle
+               MOV     R0,R1                   ;Get the original icon handle
+               BL      dbox__icon              ;Find my cached icon defn
+               MOV     R4,R0                   ;Look after this pointer
+               LDR     R6,[R4,#16]             ;Load the icon's flags
+               AND     R5,R6,#&00400000        ;Leave only the selected bit
+
+               ; --- Work out what needs to be done ---
+
+               CMP     R2,#1                   ;Do we have to shade it?
+               MOVEQ   R2,#&00400000           ;Yes -- set the bit
+               CMP     R2,#2                   ;Do we have to toggle it?
+               EOREQ   R2,R5,#&00400000        ;Yes -- get the toggled state
+
+               ; --- Now quit if there's nothing to do ---
+
+               CMP     R2,R5                   ;Are they the same now?
+               LDMEQFD R13!,{R0-R6,R10,PC}^    ;Yes -- return right now
+
+               ; --- Find the old state from the icon ---
+
+               LDR     R0,[R10,#dbox__window]  ;Get the window handle
+               SUB     R13,R13,#40             ;Make way for an icon block
+               STMIA   R13,{R0,R1}             ;Save window and icon handles
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetIconState       ;Get the icon information
+               LDR     R5,[R13,#24]            ;Get the current icon flags
+
+               ; --- Now process the cached flags nicely ---
+               ;
+               ; We can just flip the bit now, because we know it must be
+               ; different to its old state.
+
+               EOR     R6,R6,#&00400000        ;Toggle the flag
+               STR     R6,[R4,#16]             ;Store it back in the block
+
+               ; --- Now work out exactly what we have to do ---
+
+               TST     R6,#&00400000           ;Are we meant to be shading?
+               BEQ     %50dbox_shade           ;No -- unshade nicely
+
+               ; --- Lots of messing about with bitmasks ---
+               ;
+               ; We need to change the icon colours, the button type and
+               ; the ESG number for text icons, and the shaded bit for
+               ; sprite icons.  If there's a sprite, or nothing at all, then
+               ; we set the shaded bit.  If there's text and a sprite, then
+               ; we /don't/ do the text hacking if anti-aliased fonts are
+               ; being used, since everything looks nasty.
+
+               MOV     R0,#8                   ;Read the font handle
+               SWI     XWimp_ReadSysInfo       ;Read the handle then
+               MOVVS   R0,#0                   ;Unknown -- not supported
+
+               AND     R14,R5,#3               ;Get the contents bits
+               TST     R14,#2                  ;Do we have a sprite?
+               CMPNE   R0,#0                   ;And is there a font?
+               TSTEQ   R5,#&40                 ;Or is the icon anti-aliased?
+               BICNE   R14,R14,#1              ;Yes -- clear text bit then
+
+               CMP     R14,#1                  ;Is it text only?
+               ORRNE   R5,R5,#&00400000        ;No -- set the shaded bit
+               TST     R14,#1                  ;Does it contain text?
+               BICNE   R5,R5,#&0f100000        ;Clear foreg colour and ESG 5
+               BICNE   R5,R5,#&000ff000        ;Clear ESG and button type
+               ORRNE   R5,R5,#&02100000        ;Set foreg and ESG bit 5
+               ORRNE   R5,R5,#&000f0000        ;Set ESG to 31, leave btype
+
+               MOV     R14,#-1                 ;Clear all the flags bits
+               ADD     R0,R13,#8               ;Point to flags masks
+               STMIA   R0,{R5,R14}             ;Store them in the block
+               MOV     R1,R13                  ;Point to the block again
+               SWI     Wimp_SetIconState       ;And `shade' the icon
+
+               ; --- Now make sure the caret's not in it ---
+
+               LDMIA   R1,{R2,R3}              ;Get the window and icon
+               SWI     Wimp_GetCaretPosition   ;Find where the caret is
+               LDMIA   R1,{R4,R5}              ;Get the focus window and icn
+               CMP     R2,R4                   ;Check the windows match
+               CMPEQ   R3,R5                   ;And check the icons match
+               BNE     %80dbox_shade           ;If not, skip ahead a bit
+
+               ; --- Now kick the caret into cyberspace ---
+
+               LDMIA   R1,{R0-R5}              ;Load the caret registers
+               MOV     R1,#-1                  ;Kick caret out of icon
+               MOV     R2,#&ff000000           ;Quite a long way away
+               ORR     R2,R2,#&00ff0000
+               SWI     Wimp_SetCaretPosition   ;Set the new caret position
+               B       %80dbox_shade           ;Tidy everything up
+
+               ; --- Now handle unshading -- this is easy :-/ ---
+
+50dbox_shade   BIC     R6,R6,#&f000000f        ;Clear some bits
+               BIC     R6,R6,#&00e00000        ;Clear some more bits
+               BIC     R6,R6,#&00000ff0        ;Clear yet more bits
+
+               BIC     R5,R5,#&0f500000        ;Clear another load of bits
+               BIC     R5,R5,#&000ff000        ;And the last load of bits
+
+               ORR     R5,R5,R6                ;Now merge them all together
+               MOV     R14,#-1                 ;Update all of the flags
+               ADD     R0,R13,#8               ;Point to the flags masks
+               STMIA   R0,{R5,R14}             ;Save the masks away
+               SWI     Wimp_SetIconState       ;Now flicker the icon
+
+               ; --- Tidy everything up finally ---
+
+80dbox_shade   ADD     R13,R13,#40             ;Restore the stack position
+               LDR     R0,[R10,#dbox__defn]    ;Find the window definition
+               LDR     R0,[R0,#64]             ;Load the sprite area pointer
+               SWI     XSculptrix_SetSpriteArea ;Set the sprite area up
+               LDR     R1,[R13,#4]             ;Get the icon handle back
+               LDR     R0,[R10,#dbox__window]  ;Get the window handle
+               SWI     XSculptrix_UpdateIcon   ;And redraw the 3D border
+               LDMFD   R13!,{R0-R6,R10,PC}^    ;Return to caller
+
+               LTORG
+
+; --- dbox_selectMany ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to icon handle list, -1 terminated
+;              R2 == select action (0 == unselect, 1 == select, 2 == toggle)
+;
+; On exit:     --
+;
+; Use:         Changes the select state of a group of icons.
+
+               EXPORT  dbox_selectMany
+dbox_selectMany        ROUT
+
+               STMFD   R13!,{R1,R3,R14}        ;Save some registers
+               MOV     R3,R1                   ;Remember this pointer
+00             LDR     R1,[R3],#4              ;Load next icon handle
+               CMP     R1,#-1                  ;Is it the end of the list?
+               BLNE    dbox_select             ;No -- then do the select
+               BNE     %b00                    ;And loop round again
+               LDMFD   R13!,{R1,R3,PC}^        ;And return to caller
+
+               LTORG
+
+; --- dbox_shadeMany ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to icon handle list, -1 terminated
+;              R2 == shade action (0 == unshade, 1 == shade, 2 == toggle)
+;
+; On exit:     --
+;
+; Use:         Changes the shade state of a group of icons.
+
+               EXPORT  dbox_shadeMany
+dbox_shadeMany ROUT
+
+               STMFD   R13!,{R1,R3,R14}        ;Save some registers
+               MOV     R3,R1                   ;Remember this pointer
+00             LDR     R1,[R3],#4              ;Load next icon handle
+               CMP     R1,#-1                  ;Is it the end of the list?
+               BLNE    dbox_shade              ;No -- then do the select
+               BNE     %b00                    ;And loop round again
+               LDMFD   R13!,{R1,R3,PC}^        ;And return to caller
+
+               LTORG
+
+; --- dbox_isSelected ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number
+;
+; On exit:     CS if the icon is selected, CC otherwise
+;
+; Use:         Returns whether an icon is currently selected.
+
+               EXPORT  dbox_isSelected
+dbox_isSelected        ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save the registers away
+               SUB     R13,R13,#40             ;Make space for an icon block
+               LDR     R0,[R0,#dbox__window]   ;Load the dialogue's window
+               STMIA   R13,{R0,R1}             ;Store them in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetIconState       ;Get the icon information
+               LDR     R14,[R13,#24]           ;Load the icon flags
+               ADD     R13,R13,#40             ;Recover the stack space
+               TST     R14,#&00200000          ;Check the selected bit
+               LDMFD   R13!,{R0,R1,R14}        ;Load the saved registers
+               ORRNES  PC,R14,#C_flag          ;If flag set, return with CS
+               BICEQS  PC,R14,#C_flag          ;Otherwise, clear carry
+
+               LTORG
+
+; --- dbox_radio ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon handle
+;
+; On exit:     --
+;
+; Use:         Checks to see if the icon is a radio button as defined by
+;              Sapphire, i.e. button type 3 (debounced) and non-zero ESG.
+;              If it is, it selects it, and deselects all other icons with
+;              this ESG.
+
+               EXPORT  dbox_radio
+dbox_radio     ROUT
+
+               STMFD   R13!,{R0-R4,R9,R10,R14} ;Save some registers
+               MOV     R10,R0                  ;Get the dialogue handle
+               MOV     R9,R1                   ;Look after the icon number
+
+               ; --- Locate the icon and check it's a radio button ---
+
+               MOV     R0,R1                   ;Icon in R0 for dbox__icon
+               BL      dbox__icon              ;Find the icon definition
+               LDR     R14,[R0,#16]            ;Load the icon flags
+               AND     R4,R14,#&0000f000       ;Leave only the button type
+               CMP     R4,#&00003000           ;Make sure it's Debounced
+               LDMNEFD R13!,{R0-R4,R9,R10,PC}^ ;No -- return right now
+               ANDS    R4,R14,#&001f0000       ;Leave only the ESG
+               CMPNE   R4,#&001f0000           ;Or 31 (i.e. it's shaded)
+               LDMEQFD R13!,{R0-R4,R9,R10,PC}^ ;Yes -- return right now
+
+               ; --- The ESG is now in R4 -- process it ---
+
+               MOV     R0,#-1                  ;Start from the beginning
+
+00dbox_radio   MOV     R1,#&001f0000           ;Mask out all but the ESG
+               MOV     R2,R4                   ;Move ESG in to test it
+               MOV     R3,#+1                  ;Search forwards nicely
+               BL      dbox__find              ;Get the next matching icon
+               CMP     R0,#-1                  ;None found?
+               LDMEQFD R13!,{R0-R4,R9,R10,PC}^ ;Return to caller then
+               MOV     R1,R0                   ;Icon number in R1 required
+               MOV     R0,R10                  ;Dialogue box handle in R0
+               CMP     R1,R9                   ;Is this the clicked icon?
+               MOVEQ   R2,#1                   ;Yes -- select it
+               MOVNE   R2,#0                   ;No -- deselect it
+               BL      dbox_select             ;Change its selection state
+               MOV     R0,R1                   ;Start search where we left
+               B       %00dbox_radio           ;And loop round again
+
+               LTORG
+
+;----- Clicking and unclicking icons ----------------------------------------
+
+; --- dbox_slab ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon handle
+;
+; On exit:     May return an error
+;
+; Use:         Slabs an icon in properly, to give visual feedback when you
+;              click it.
+
+               EXPORT  dbox_slab
+dbox_slab      ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers away
+               WSPACE  dbox__wSpace            ;Find my workspace pointer
+
+               ; --- Allocate a new block ---
+
+               MOV     R0,#20                  ;Make space for a new block
+               BL      sub_alloc               ;Try to allocate the block
+               BVS     %90dbox_slab            ;If it failed, skip forward
+
+               ; --- Link the block into the list ---
+
+               LDR     R14,dbox__clickList     ;Load the old list head
+               STR     R0,dbox__clickList      ;Store this block as new head
+               STR     R14,[R0,#0]             ;And store link to next one
+
+               ; --- Now actually slab the icon ---
+
+               ADD     R2,R0,#4                ;Point to slab descriptor
+               LDR     R0,[R13,#0]             ;Get the saved dbox handle
+               LDR     R0,[R0,#dbox__window]   ;Get the window handle
+               SWI     XSculptrix_SlabIcon     ;Slab the icon in nicely
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller
+
+               ; --- Tidy up after an error ---
+
+90dbox_slab    ADD     R13,R13,#4              ;Skip past stacked R0
+               LDMFD   R13!,{R1,R2,R12,R14}    ;Load the saved registers
+               ORRS    PC,R14,#V_flag          ;Set V flag on exit
+
+               LTORG
+
+; --- dbox_unslab ---
+;
+; On entry:    --
+;
+; On exit:     CS if there are no more slabbed icons after this one, CC
+;              if there are more left.
+;
+; Use:         Unslabs an icon slabbed with dbox_slab.  Icons are unslabbed
+;              in reverse order to that in which they were slabbed.  The
+;              carry flag is returned as an indication of whether there
+;              are any more icons left in the list -- you can unslab all
+;              icons in one go by doing:
+;
+;                              BL      dbox_unslab
+;                              SUBCC   PC,PC,#12       ;Avoids a label!
+;
+;              It is recommended that, if you are going to close a window,
+;              you unslab icons within it *after* you close, but before you
+;              actually destroy it, e.g.
+;
+;                              LDR     R0,my_dbox
+;                              BL      dbox_close
+;                              BL      dbox_unslab
+;                              BL      dbox_destroy
+
+               EXPORT  dbox_unslab
+dbox_unslab    ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers away
+               WSPACE  dbox__wSpace            ;Find my workspace pointer
+               LDR     R1,dbox__clickList      ;Find the last slabbed icon
+
+               ; --- Get the descriptor to free ---
+
+               CMP     R1,#0                   ;Is there one at all?
+               LDMEQFD R13!,{R0-R2,R12,R14}    ;No -- restore the registers
+               ORREQS  PC,R14,#C_flag          ;And return with C set
+
+               ; --- Unslab the icon and unlink the block ---
+               ;
+               ; Make sure the hourglass stays off all this time.
+
+               ADD     R2,R1,#4                ;Point to the slab descriptor
+               SUB     R13,R13,#8              ;Make an hourglass status blk
+               MOV     R0,R13                  ;Point to the block
+               BL      hour_suspend            ;Save the old state a while
+               SWI     XSculptrix_UnslabIcon   ;Unslab the icon nicely
+               BL      hour_resume             ;Resume the hourglass now
+               ADD     R13,R13,#8              ;And restore the stack
+               LDR     R2,[R1,#0]              ;Get the next field out
+               STR     R2,dbox__clickList      ;Store it as the new head
+
+               ; --- Free the block now ---
+
+               MOV     R0,R1                   ;Point to the slab block
+               MOV     R1,#20                  ;suballoc wants the size
+               BL      sub_free                ;Free the block again
+
+               ; --- Now return the status to the user ---
+
+               CMP     R2,#0                   ;Was the next block null?
+               LDMFD   R13!,{R0-R2,R12,R14}    ;Restore all the registers
+               ORREQS  PC,R14,#C_flag          ;Yes -- return and set C
+               BICNES  PC,R14,#C_flag          ;No -- return and clear C
+
+               LTORG
+
+;----- Messing with dialogue box fields -------------------------------------
+
+; --- dbox__fieldLen ---
+;
+; On entry:    R1 == icon number
+;              R10 == dialogue box handle
+;
+; On exit:     R0 == length of the text in the icon
+;
+; Use:         Returns the length of the field in the given icon
+
+dbox__fieldLen ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+
+               ; --- Find the icon definition ---
+
+               SUB     R13,R13,#40             ;Make space for icon block
+               LDR     R0,[R10,#dbox__window]  ;Get the window handle
+               STMIA   R13,{R0,R1}             ;Store handles in block
+               MOV     R1,R13                  ;Point at the block
+               SWI     Wimp_GetIconState       ;Find the *current* icon info
+
+               ; --- Get the icon flags and find the data ---
+
+               LDR     R0,[R13,#24]            ;Load the flags word
+               ANDS    R0,R0,#1<<8             ;Check indir flag (clever)
+               BEQ     %10dbox__fieldLen       ;Yes -- skip ahead a bit
+
+               ; --- Handle indirectedness ---
+
+               LDR     R0,[R13,#28]            ;Load the icon data pointer
+               ADD     R13,R13,#40             ;Reclaim the stack block
+               LDMFD   R13!,{R1,R14}           ;Unstack the registers
+               B       str_len                 ;Find the string length
+
+               ; --- Handle nonindirectedness ---
+               ;
+               ; We know at this point that R0 is 0, because we used ANDS
+               ; not TST above.  This is a pointless optimisation.
+
+10             ADD     R1,R13,#28              ;Point to the data string
+11             LDRB    R14,[R1],#1             ;Get a byte from the string
+               CMP     R14,#' '                ;Is it the end yet?
+               BLT     %12dbox__fieldLen       ;Yes -- skip forward
+               ADD     R0,R0,#1                ;Bump on the counter
+               CMP     R0,#12                  ;Is it maximum length yet?
+               BLT     %11dbox__fieldLen       ;No -- skip back again
+
+               ; --- Return the calculated length ---
+
+12             ADD     R13,R13,#40             ;Reclaim the stack again
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- dbox_setField ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number to write to (may be -1 for title)
+;                    flags in top byte if not -1:
+;                      dbFlag_dots (bit 31) == add `...' if text overflows
+;              R2 == pointer to string to use
+;
+; On exit:     --
+;
+; Use:         Writes the string specified into the indirection buffer
+;              for the given icon.  If the icon is not indirected, an
+;              error is generated.  If the indirected buffer is too small,
+;              the string is shortened by chopping off the beginning or
+;              the end, according to the setting of the icon's right
+;              justify flag.
+;
+;              The icon is only flickered if the text has actually changed.
+;              The caret is moved correctly if it is within the icon to
+;              prevent it `falling off' the end and deleting the validation
+;              string, or being positioned incorrectly in centred icons if
+;              the length changes.
+;
+;              Note that this routine requires a string to already be in
+;              the buffer, and doesn't perform any substitution or other
+;              transformations.  This helps to prevent buffer full errors
+;              and similar problems.
+
+               EXPORT  dbox_setField
+dbox_setField  ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Stash registers away
+
+               ; --- Handle the title bar nicely ---
+
+               CMP     R1,#-1                  ;Does he want the title?
+               BEQ     %30dbox_setField        ;Yes -- jump ahead to do it
+
+               ; --- Find out about the icon ---
+
+               AND     R4,R1,#&FF000000        ;Get the flag bits out
+               BIC     R1,R1,#&FF000000        ;Leave just the icon number
+               LDR     R0,[R0,#dbox__window]   ;Get the dbox's window handle
+               SUB     R13,R13,#40             ;Make space for icon block
+               STMIA   R13,{R0,R1}             ;Store the info in it
+               MOV     R1,R13                  ;Point to the icon block
+               SWI     Wimp_GetIconState       ;Get the icon's information
+
+               ; --- Make sure we can change the text ---
+
+               LDR     R1,[R13,#24]            ;Get the icon's flags
+               TST     R1,#&100                ;Check the indirected bit
+               BEQ     %80dbox_setField        ;It's an error if it's clear
+
+               ; --- Now find how much we actually have to copy ---
+
+               LDR     R5,[R13,#36]            ;Get the buffer length
+               SUB     R5,R5,#1                ;Take terminator into account
+               MOV     R0,R2                   ;Point to the string to copy
+               BL      str_len                 ;Find out how long it is
+               SUBS    R0,R0,R5                ;Find out the difference
+               BICLE   R4,R4,#(1<<31)          ;If it fits, don't add dots
+               BLE     %00dbox_setField        ;And skip ahead
+               TST     R1,#1<<9                ;Is it right aligned?
+               ADDNE   R2,R2,R0                ;Yes, chop off front
+               ORRNE   R4,R4,#1                ;And set a flag to remember
+
+               ; --- Copy the text into the buffer ---
+
+00dbox_setField        LDR     R0,[R13,#28]            ;Find the buffer address
+               MOV     R3,#0                   ;Count the length too
+
+10dbox_setField        CMP     R5,R3                   ;How much space left in buff?
+               MOVLE   R1,#0                   ;None -- pretend null char
+               LDRGTB  R1,[R2],#1              ;Get a byte from the string
+               CMP     R1,#' '                 ;Is it a control char?
+               MOVLO   R1,#0                   ;Yes -- say it's a zero
+               BLO     %15dbox_setField        ;And don't bother with dots
+
+               ; --- Handle ellipsis generation ---
+
+               TST     R4,#(1<<31)             ;Do we put the ellipsis in?
+               BEQ     %15dbox_setField        ;No -- skip ahead then
+               TST     R4,#1                   ;Are we right-justified?
+               ADDNE   R14,R3,#1               ;Yes -- just get the length
+               SUBEQ   R14,R5,R3               ;Otherwise find what's left
+               CMP     R14,#4                  ;Are we within three?
+               MOVLO   R1,#'.'                 ;Yes -- put in a dot then
+
+               ; --- Return to normality ---
+
+15dbox_setField        LDRB    R14,[R0],#1             ;Get one from the buffer
+               CMP     R14,#' '                ;Same for the buffer char
+               MOVLO   R14,#0
+
+               CMP     R1,R14                  ;Are they different
+               ORRNE   R4,R4,#2                ;Yes -- remember this
+               STRNEB  R1,[R0,#-1]             ;And store the different char
+
+               CMP     R1,#0                   ;Is that end of the string?
+               ADDNE   R3,R3,#1                ;No -- bump the length on
+               BNE     %10dbox_setField        ;And go round for another
+
+               ; --- We've copied the string -- now update the icon ---
+
+               TST     R4,#2                   ;Is the string different?
+               BEQ     %20dbox_setField        ;No -- skip ahead
+
+               MOV     R1,#0
+               STR     R1,[R13,#8]             ;The EOR mask for setstate
+               STR     R1,[R13,#12]            ;The BIC mask for setstate
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetIconState       ;Flicker the icon nastily
+
+               ; --- Now check for the caret ---
+
+               SWI     Wimp_GetCaretPosition   ;Find out where the caret is
+               LDMIA   R13,{R2,R4}             ;Get the window and icon
+               ADD     R0,R13,#40              ;Point past this block
+               LDMIA   R0,{R0,R1}              ;Get the old dbox and icon
+               LDR     R0,[R0,#dbox__window]   ;Get the window handle
+               CMP     R0,R2                   ;Do the window handles match?
+               CMPEQ   R1,R4                   ;And the icon handles?
+               BNE     %20dbox_setField        ;No -- skip ahead
+
+               ; --- Push the caret back a little ---
+
+               LDR     R5,[R13,#20]            ;Get the caret index
+               CMP     R5,R3                   ;Is this bigger than new len?
+               MOVGT   R5,R3                   ;Yes -- trim the index
+
+               ; --- Now put the caret in the right place ---
+
+               MOV     R2,#-1                  ;Don't set the x coord
+               MOV     R3,#-1                  ;Don't set the y coord
+               MOV     R4,#-1                  ;Don't set the height
+               SWI     Wimp_SetCaretPosition   ;Put the caret in its place
+
+               ; --- Return nicely ---
+
+20dbox_setField        ADD     R13,R13,#40             ;Reclaim that temporary space
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+               ; --- Caller wants to update the title bar ---
+
+30dbox_setField        LDR     R14,[R0,#dbox__defn]    ;Load the window definition
+               LDR     R5,[R14,#56]            ;Load the title bar's flags
+               TST     R5,#&00000100           ;Check the indirected bit
+               BEQ     %80dbox_setField        ;If clear, generate the error
+
+               LDR     R1,[R14,#72]            ;Load the buffer pointer
+               LDR     R2,[R0,#dbox__window]   ;Load the window handle
+               LDR     R0,[R13,#8]             ;Load the string pointer
+               BL      winUtils_setTitle       ;And set the title string
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+               ; --- Icon wasn't indirected ---
+
+80dbox_setField        ADR     R0,dbox__nind           ;Point to error
+               BL      msgs_error              ;Translate the message
+               SWI     OS_GenerateError
+
+dbox__nind     DCD     1
+               DCB     "dboxNIND",0
+
+               LTORG
+
+; --- dbox_getField ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number to interrogate
+;
+; On exit:     R0, R1 preserved
+;              R2 == pointer to the icon text
+;
+; Use:         Returns a pointer to the text associated with an icon.
+;              Note that if the icon is *not* indirected, the text will
+;              be copied into the scratchpad.  Otherwise you get a pointer
+;              to the actual indirected data.  You shouldn't write to the
+;              string returned at all -- dbox_setField is specially
+;              designed to do that sort of thing very well (i.e. not
+;              flickering the text unless it has to, truncating if it's too
+;              long, and handling the caret correctly).  You *are* allowed
+;              to zero terminate the string if you want to, though.
+;
+;              Despite all the PRM's assurances to the contrary, chances
+;              are the text will be terminated by some weird control char,
+;              so you'll have to handle this, and not just assume it's
+;              going to be null-terminated.
+;
+;              Note: The indirected case is immensely quick -- just load a
+;              pointer.  The non-indirected case has been optimised as much
+;              as possible.
+
+               EXPORT  dbox_getField
+dbox_getField  ROUT
+
+               STMFD   R13!,{R0,R1,R10,R14}    ;Save some registers
+
+               ; --- Find the icon defintion ---
+
+               MOV     R10,R0                  ;Keep dialogue box handle
+               MOV     R0,R1                   ;Put icon handle in R0
+               BL      dbox__icon              ;Find icon definition
+
+               ; --- Find out about indirectedness ---
+
+               LDR     R14,[R0,#16]            ;Load the icon flags word
+               TST     R14,#1<<8               ;Is the bit set?
+               LDRNE   R2,[R0,#20]             ;Yes -- load the pointer
+               LDMNEFD R13!,{R0,R1,R10,PC}^    ;And return
+
+               ; --- Copy the text to the scratchpad ---
+
+               ADD     R0,R0,#20               ;Point to the text string
+               LDMIA   R0,{R0,R1,R14}          ;Load the 12 bytes of text
+               STMIA   R11,{R0,R1,R14}         ;Store them in scratchpad
+               MOV     R0,#0                   ;Zero terminate nicely
+               STRB    R0,[R11,#12]            ;In case string is too long
+               MOV     R2,R11                  ;Point to string in scratch
+               LDMFD   R13!,{R0,R1,R10,PC}^    ;Return to caller
+
+               LTORG
+
+;---- Other utility functions -----------------------------------------------
+
+; --- dbox_eventHandler ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to handler routine
+;              R2 == value to pass to handler in R10
+;              R3 == value to pass to handler in R12
+;
+; On exit:     R0 preserved
+;              R1 == pointer to old handler
+;              R2 == old R10 value
+;              R3 == old R12 value
+;
+; Use:         Sets up an event handler for a dialogue box, and returns
+;              the previous one.  If the pointer to handler is 0, there is
+;              no dialogue box event handler.
+
+               EXPORT  dbox_eventHandler
+dbox_eventHandler
+               ROUT
+
+               STMFD   R13!,{R4-R6,R14}        ;Save some registers
+               LDR     R14,[R0,#dbx__defn]     ;Load the dbx pointer
+               CMP     R14,#0                  ;Is there a dbx definition?
+               ADDEQ   R14,R0,#dbox__proc      ;Point to the correct user...
+               ADDNE   R14,R0,#dbx__proc       ;... handler
+               LDMIA   R14,{R4-R6}             ;Load the old values out
+               STMIA   R14,{R1-R3}             ;Store the new ones in
+               MOV     R1,R4                   ;Move the old values to...
+               MOV     R2,R5                   ;... the correct registers...
+               MOV     R3,R6                   ;... for returning
+               LDMFD   R13!,{R4-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- dbox_renderTitle ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to redraw block
+;
+; On exit:     --
+;
+; Use:         Renders a dialogue box's embedded title if there is one.
+
+               EXPORT  dbox_renderTitle
+dbox_renderTitle
+               ROUT
+
+               STMFD   R13!,{R0-R3,R10,R14}    ;Save a load of registers
+
+               MOV     R10,R0                  ;Move the handle into R10
+               LDR     R0,[R10,#dbox__title]   ;Get the icon number out
+               CMP     R0,#-1                  ;Check there really is one
+               LDMEQFD R13!,{R0-R3,R10,PC}^    ;Return to caller if not
+
+               BL      dbox__icon              ;Find the icon pointer
+               MOV     R2,#0                   ;Group box type 0, please
+               LDR     R3,[R10,#dbox__defn]    ;Find the window definition
+               LDR     R3,[R3,#72]             ;Get the actual data pointer
+               SWI     XSculptrix_PlotGroupBox ;Draw the group box
+
+               LDMFD   R13!,{R0-R3,R10,PC}^    ;Return to caller now
+
+               LTORG
+
+; --- dbox_setEmbeddedTitle ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon which should contain the embedded title
+;
+; On exit:     --
+;
+; Use:         Declares a given dialogue box as requiring an embedded title
+;              (rather than the one the WindowManager put on).
+
+               EXPORT  dbox_setEmbeddedTitle
+dbox_setEmbeddedTitle
+               STR     R1,[R0,#dbox__title]    ;Store the icon number
+               MOVS    PC,R14
+
+; --- dbox_setClickDrag ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Sets a given dialogue box so that the user can move it by
+;              dragging from any part of the window, not just the title
+;              bar.
+
+               EXPORT  dbox_setClickDrag
+dbox_setClickDrag
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,[R0,#dbox__flags]   ;Load the flags word
+               ORR     R14,R14,#dbFlag__drag   ;Set the click-drag flag
+               STR     R14,[R0,#dbox__flags]   ;Save the flags back again
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+; --- dbox_hasTitle ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     CS if the dialogue box has a title bar, CC if not
+;
+; Use:         Informs the caller whether the dialogue box has a title bar.
+;              This is mainly useful for other library sections which
+;              conditionally add in embedded titles etc.
+
+               EXPORT  dbox_hasTitle
+dbox_hasTitle  ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,[R0,#dbox__defn]    ;Load the window definition
+               LDR     R14,[R14,#28]           ;Load the window flags
+               TST     R14,#1<<31              ;Using new gadget flags?
+               BEQ     %10dbox_hasTitle        ;No -- skip to handle this
+               TST     R14,#1<<26              ;Test the title bar flag
+               B       %20dbox_hasTitle        ;And skip the other test
+
+10dbox_hasTitle        TST     R14,#1<<0               ;Test the old-fashioned bit
+
+20dbox_hasTitle        LDMFD   R13!,{R14}              ;Restore the register I saved
+               ORRNES  PC,R14,#C_flag          ;If bit set, return carry
+               BICEQS  PC,R14,#C_flag          ;Otherwise clear carry
+
+               LTORG
+
+; --- dbox_window ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     R0 == the dialogue box's window handle
+;
+; Use:         Returns the Wimp window handle associated with a dialogue
+;              box.  This may be useful if you want to perform lowlevel
+;              Wimp operation on it, or to subclass it using win.
+
+               EXPORT  dbox_window
+dbox_window    LDR     R0,[R0,#dbox__window]   ;Load the window handle
+               MOVS    PC,R14                  ;Return to caller
+
+; --- dbox_help ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Adds a help line to the current help message, read by
+;              scanning the icon to which the help was sent for an `H'
+;              validation string.
+
+               EXPORT  dbox_help
+dbox_help      ROUT
+
+               STMFD   R13!,{R0-R4,R10,R12,R14} ;Save some registers
+               WSPACE  dbox__wSpace            ;Find my workspace quickly
+
+               LDR     R10,dbox__eventDbox     ;Find the helpful dbox
+               LDR     R0,dbox__eventIcon      ;Find the icon too
+               CMP     R0,#0                   ;Is it a sensible number?
+               BLT     %99dbox_help            ;No -- skip to the end
+
+               ; --- Locate the validation string ---
+
+               BL      dbox__icon              ;Find the icon definition
+               MOV     R1,#'H'                 ;Find `H' validation commands
+               MOV     R2,#0                   ;Start from the beginning
+               BL      winUtils_findValid      ;Find the validation string
+               BCC     %99dbox_help            ;If not there, skip to end
+
+               ; --- Copy the message tag to scratchpad ---
+
+               MOV     R0,R11                  ;Point to scratchpad
+               MOV     R1,#0                   ;We are not escaped yet
+               ADD     R2,R2,#1                ;Skip past `H' character
+
+10dbox_help    LDRB    R14,[R2],#1             ;Get the next byte
+
+               CMP     R14,#'\'                ;Is it a backslash?
+               CMPEQ   R1,#0                   ;Make sure it's not escaped
+               MOVEQ   R1,#1                   ;Yes -- escape next char
+               BEQ     %10dbox_help            ;And loop for next char
+
+               CMP     R14,#' '                ;Is it a control character
+               MOVLT   R14,#0                  ;Yes -- terminate string
+               CMP     R14,#';'                ;Is it validation string end?
+               CMPEQ   R1,#0                   ;Make sure it's not escaped
+               MOVEQ   R14,#0                  ;Yes -- terminate string
+               STRB    R14,[R0],#1             ;Store character in buffer
+               CMP     R14,#0                  ;Was that the end?
+               BNE     %10dbox_help            ;No -- try for another one
+
+               ; --- Send the message to !Help ---
+
+               MOV     R0,R11                  ;Point to buffer start again
+               BL      msgs_lookup             ;Lookup the message tag
+               BL      help_add                ;Add it to the help message
+
+99dbox_help    LDMFD   R13!,{R0-R4,R10,R12,PC}^ ;No -- return right now
+
+               LTORG
+
+;----- Useful constants -----------------------------------------------------
+
+; --- Ways of opening dialogue boxes ---
+
+               ^       0
+dbOpen_current #       1                       ;In its current position
+dbOpen_centre  #       1                       ;Centred on the screen
+dbOpen_pointer #       1                       ;Centred over the pointer
+dbOpen_givenY  #       1                       ;At a given height on screen
+                                               ;  R2 == y coordinate to open
+
+dbOpen_trans   EQU     &00                     ;Make the dbox transient
+dbOpen_persist EQU     &80                     ;Make the dbox persistent
+dbOpen_nonSub  EQU     &40                     ;Don't open as a submenu
+
+; --- Dialogue box event codes ---
+
+dbEvent_close  EQU     -2                      ;The user closed the dialogue
+                                               ;C flag ignored on exit
+
+dbEvent_help   EQU     -3                      ;The user wants some help
+                                               ;R1 == icon number
+                                               ;C flag ignored on exit
+
+dbEvent_OK     EQU     -4                      ;The user clicked OK
+                                               ;R1 == mouse button status
+                                               ;C flag ignored on exit
+
+dbEvent_cancel EQU     -5                      ;The user clicked Cancel
+                                               ;R1 == mouse button status
+                                               ;C flag ignored on exit
+
+dbEvent_redraw EQU     -6                      ;Redraw a single rectangle
+                                               ;R1 == pointer to redraw blk
+                                               ;R2,R3 == coords of origin
+                                               ;CS => don't do default draw
+
+dbEvent_menu   EQU     -7                      ;User clicked Menu button
+                                               ;R1 == icon handle clicked
+                                               ;C flag ignored on exit
+
+dbEvent_drag   EQU     -8                      ;User dragged an icon
+                                               ;R1 == mouse button status
+                                               ;R2 == icon handle dragged
+                                               ;C flag ignored on exit
+
+dbEvent_save   EQU     -9                      ;User wants to import data
+                                               ;R1 == icon handle dropped on
+                                               ;R2 == filetype of data
+                                               ;R3 == pointer to filename
+                                               ;R4 == estimated file size
+                                               ;C flag ignored on exit
+
+dbEvent_load   EQU     -10                     ;User wants to load data
+                                               ;R1 == icon handle dropped on
+                                               ;R2 == filetype of data
+                                               ;R3 == pointer to filename
+                                               ;R4 == estimated file size
+                                               ;C flag ignored on exit
+
+dbEvent_key    EQU     -11                     ;User pressed a key
+                                               ;R1 == key code received
+                                               ;R2 == icon handle with caret
+                                               ;CC => unknown keypress
+                                               ;Key code has been translated
+
+dbEvent_hint   EQU     -12                     ;Received a hint message
+                                               ;R2 == pointer to hint string
+
+dbEvent_enter  EQU     -13                     ;Pointer has entered window
+
+dbEvent_leave  EQU     -14                     ;Pointer has left window
+
+dbEvent_lifeCycle EQU  -15                     ;Interesting points in cycle
+                                               ;R1 == life cycle code
+
+; --- Life cycle codes ---
+
+               ^       0
+dblc_create    #       1                       ;Creation (used by dbx)
+dblc_open      #       1                       ;Opening
+dblc_close     #       1                       ;Closing
+dblc_destroy   #       1                       ;Destruction
+
+; --- Other values ---
+
+dbFlag_dots    EQU     (1<<31)                 ;Add dots if text overflows
+                                               ;  in dbox_setField
+
+;----- Dialogue box data structure ------------------------------------------
+
+               ^       0
+
+dbox__window   #       4                       ;The real window handle
+dbox__proc     #       4                       ;Pointer to event handler
+dbox__R10      #       4                       ;Magic handle for event proc
+dbox__R12      #       4                       ;Workspace for event proc
+dbox__oldCaret #       24                      ;Caret position to restore
+dbox__defn     #       4                       ;Pointer to window template
+dbox__template #       4                       ;Pointer to original template
+dbox__title    #       4                       ;Embedded title icon number
+dbox__flags    #       4                       ;Various interesting flags
+
+dbx__proc      #       4                       ;Pointer to user event proc
+dbx__R10       #       4                       ;Object pointer for user proc
+dbx__R12       #       4                       ;Workspace for user proc
+dbx__defn      #       4                       ;Pointer to control def block
+
+dbox__blockSize        #       0                       ;Size of the above block
+
+dbFlag__open   EQU     (1<<0)                  ;Dialogue box is on-screen
+dbFlag__static EQU     (1<<1)                  ;Dialogue box is static
+dbFlag__rCaret EQU     (1<<2)                  ;We have to restore the caret
+dbFlag__drag   EQU     (1<<3)                  ;Clicking window starts move
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+dbox__wStart   #       0
+
+dbox__wFlags   #       4                       ;Various magic flags for me
+dbox__clickList        #       4                       ;List of button slabbings
+dbox__eventDbox        #       4                       ;Dbox last event happened to
+dbox__eventIcon        #       4                       ;Icon number from last event
+
+dbFlag__inited EQU     (1<<0)                  ;The dbox system is running
+
+dbox__wSize    EQU     {VAR}-dbox__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     dbox__wSize
+               DCD     dbox__wSpace
+               DCD     16
+               DCD     dbox_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/defHandler b/StraySrc/Libraries/Sapphire/s/defHandler
new file mode 100644 (file)
index 0000000..7615b5e
--- /dev/null
@@ -0,0 +1,121 @@
+;
+; defHandler.s
+;
+; Default event handler (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:resspr
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- defHandler ---
+;
+; On entry:    R0 == Wimp_Poll reason code
+;              R1 == pointer to Wimp_Poll event block
+;
+; On exit:     CS if we handled the event, CC otherwise.
+;
+; Use:         Handles events no-one else is interested in.  It's basically
+;              a catch-all for things that probably should have been
+;              handled elsewhere, and does some useful tidying up
+;              operations (like calling Wimp_ProcessKey on key events).
+
+               EXPORT  defHandler
+defHandler     ROUT
+
+               ORR     R14,R14,#C_flag         ;Set carry flag on return
+               CMP     R0,#9                   ;Is it a low-numbered event?
+               ADDLO   PC,PC,R0,LSL #2         ;Yes -- dispatch
+               B       %10defHandler           ;No -- handle specially
+
+               ; --- The event dispatch table ---
+
+               BICS    PC,R14,#C_flag          ;Null events are ignored
+               B       def__redraw             ;Do a dummy redraw op
+               B       def__open               ;Open unopened windows
+               B       def__close              ;Close unclosed windows
+               BICS    PC,R14,#C_flag          ;So pointer's left a window
+               BICS    PC,R14,#C_flag          ;Gone back inside again
+               BICS    PC,R14,#C_flag          ;Mouse click -- yawn
+               B       def__drag               ;Turn off DragASprite
+               B       def__key                ;Pass keypresses onwards
+
+               ; --- Handle high-numbered events ---
+
+10defHandler   CMP     R0,#17                  ;Is it a message?
+               CMPNE   R0,#18                  ;Or another message?
+               BICNES  PC,R14,#C_flag          ;No -- nothing we can do
+
+               ; --- Handle Message_Quit properly ---
+
+               STMFD   R13!,{R14}              ;Save the link register
+               LDR     R14,[R1,#16]            ;Get the message action
+               CMP     R14,#0                  ;Is it a quit message?
+               LDMFD   R13!,{R14}              ;Restore link register
+               SWIEQ   OS_Exit                 ;Yes -- kill everything off
+               BICS    PC,R14,#C_flag          ;Couldn't understand message
+
+; --- def__<event> ---
+;
+; Entry/exit:  As for defHandler above
+;
+; Use:         Handles default behaviour for an individual event type
+
+def__redraw    ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               BL      resspr_area             ;Find the sprite area
+               SWI     XSculptrix_SetSpriteArea ;Register it with Sculptrix
+               SWI     Wimp_RedrawWindow       ;Start the redraw operation
+00def__redraw  CMP     R0,#0                   ;Is this the end of the line?
+               SWINE   XSculptrix_RedrawWindow ;Use Sculptrix if it's there
+               SWINE   Wimp_GetRectangle       ;No -- get another rectangle
+               BNE     %00def__redraw          ;And go back again
+               LDMFD   R13!,{R0,R1,PC}^        ;Yes -- return
+
+def__open      SWI     Wimp_OpenWindow         ;Open the window then
+               MOVS    PC,R14
+
+def__close     SWI     Wimp_CloseWindow        ;Close the window
+               MOVS    PC,R14
+
+def__drag      SWI     XDragASprite_Stop       ;Stop any spritely drags
+               MOVS    PC,R14
+
+def__key       STMFD   R13!,{R0,R14}           ;Save some registers
+               LDR     R0,[R1,#24]             ;Get the key number out
+               SWI     Wimp_ProcessKey         ;Pass it to other apps
+               LDMFD   R13!,{R0,PC}^           ;Return to the caller
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/divide b/StraySrc/Libraries/Sapphire/s/divide
new file mode 100644 (file)
index 0000000..a97661b
--- /dev/null
@@ -0,0 +1,313 @@
+;
+; divide.s
+;
+; Various routines of a division-related nature (MDW/TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Simple mathematics ---------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- divide ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         A standard divide routine.  Fairly speedy, hopefully.
+;              The results are always such that
+;
+;                      |quotient| <= |(divisor/dividend)|,
+;
+;                      |remainder| < |divisor|
+;
+;              and
+;
+;                      quotient * divisor + remainder == dividend
+
+               EXPORT  divide
+divide         ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+
+               ; --- First, mess about with the signs ---
+
+               ANDS    R2,R0,#&80000000        ;Get the dividend's sign bit
+               ORR     R2,R2,R2,LSR #1         ;Copy -- this is sign of mod
+               RSBNE   R0,R0,#0                ;Take absolute value of R0
+               ANDS    R14,R1,#&80000000       ;Get the divisor's sign too
+               RSBNE   R1,R1,#0                ;Take absolute value of R1
+               EOR     R2,R2,R14               ;Calculate sign of quotient
+
+               ; --- Now do the division ---
+
+               BL      div_unsigned            ;That's done for us elsewhere
+
+               ; --- Now tidy everything up ---
+
+               TST     R2,#&40000000           ;Is remainder to be negative?
+               RSBNE   R1,R1,#0                ;Yes -- negate it
+               TST     R2,#&80000000           ;Is quotient to be negative?
+               RSBNE   R0,R0,#0                ;Yes -- negate it
+
+               LDMFD   R13!,{R2,PC}^           ;Return to caller
+
+               LTORG
+
+; --- div_unsigned ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         As for divide, except that it considers its operands to be
+;              unsigned.
+
+               EXPORT  div_unsigned
+               EXPORT  div_byZero
+div_unsigned   ROUT
+
+               CMP     R1,#0                   ;Check for divide by zero
+               BEQ     div_byZero              ;Yes -- make the error
+               STMFD   R13!,{R2,R3,R14}        ;Save some registers
+
+               ; --- A note about the method ---
+               ;
+               ; We use traditional long division, but unroll the loop a
+               ; lot to keep the thing ticking over at a good rate.
+
+               MOV     R14,R1                  ;Look after the divisor
+               ANDS    R3,R0,#&80000000        ;Is the top dividend bit set?
+               MOVEQ   R3,R0                   ;No -- use the real thing
+
+               ; --- Shift divisor up for long division ---
+               ;
+               ; We keep shifting the divisor up until it's greater than
+               ; the dividend, and then we skip ahead to the divide section
+
+               MOV     R2,#0                   ;Quotient starts off at 0
+00div_unsigned CMP     R3,R14,LSL #0
+               BLS     %10div_unsigned
+               CMP     R3,R14,LSL #1
+               BLS     %11div_unsigned
+               CMP     R3,R14,LSL #2
+               BLS     %12div_unsigned
+               CMP     R3,R14,LSL #3
+               BLS     %13div_unsigned
+               CMP     R3,R14,LSL #4
+               BLS     %14div_unsigned
+               CMP     R3,R14,LSL #5
+               BLS     %15div_unsigned
+               CMP     R3,R14,LSL #6
+               BLS     %16div_unsigned
+               CMP     R3,R14,LSL #7
+               MOVHI   R14,R14,LSL #8
+               BHI     %00div_unsigned
+
+               ; --- Now we have the shift-down loop ---
+               ;
+               ; This is where the actual job of dividing is performed.
+               ; We shift the divisor back down until it's back where we
+               ; started again.
+
+17div_unsigned CMP     R0,R14,LSL #7
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R14,LSL #7
+16div_unsigned CMP     R0,R14,LSL #6
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R14,LSL #6
+15div_unsigned CMP     R0,R14,LSL #5
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R14,LSL #5
+14div_unsigned CMP     R0,R14,LSL #4
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R14,LSL #4
+13div_unsigned CMP     R0,R14,LSL #3
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R14,LSL #3
+12div_unsigned CMP     R0,R14,LSL #2
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R14,LSL #2
+11div_unsigned CMP     R0,R14,LSL #1
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R14,LSL #1
+10div_unsigned CMP     R0,R14,LSL #0
+               ADC     R2,R2,R2
+               SUBCS   R0,R0,R14,LSL #0
+
+               CMP     R14,R1                  ;Have we finished dividing?
+               MOVHI   R14,R14,LSR #8          ;No -- shift down a byte
+               BHI     %17div_unsigned         ;And loop round again
+
+               ; --- Now tidy everything up ---
+
+               MOV     R1,R0                   ;Copy results into registers
+               MOV     R0,R2
+
+               LDMFD   R13!,{R2,R3,PC}^        ;Return to caller
+
+div_byZero     ADR     R0,divByZero
+               SWI     OS_GenerateError
+
+divByZero      DCD     1
+               DCB     "Division by zero",0
+
+               LTORG
+
+; --- div10 ---
+;
+; On entry:    R0 == integer to divide
+;
+; On exit:     R0 == quotient after division by 10
+;              R1 == remainder after division by 10
+;
+; Use:         Divides an integer very quickly by 10.
+;
+; [Generated by Straylight divc]
+
+               EXPORT  div10
+div10          ROUT
+
+               STMFD   R13!,{R2,R14}
+               MOVS    R2,R0
+               RSBMI   R0,R0,#0
+               MOV     R1,R0
+
+               ADD     R0,R0,R0,LSR #1
+               ADD     R0,R0,R0,LSR #4
+               ADD     R0,R0,R0,LSR #8
+               ADD     R0,R0,R0,LSR #16
+
+               MOV     R0,R0,LSR #4
+
+               ADD     R14,R0,R0,LSL #2
+               SUB     R1,R1,R14,LSL #1
+               SUBS    R1,R1,#10
+               ADDGE   R0,R0,#1
+               ADDLT   R1,R1,#10
+
+               CMP     R2,#0
+               RSBMI   R0,R0,#0
+               RSBMI   R1,R1,#0
+               LDMFD   R13!,{R2,PC}^
+
+               LTORG
+
+; --- div_round ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient, rounded to nearest integer
+;              R1 == remainder
+;
+; Use:         Calculates a rounded-to-nearest quotient, rather than one
+;              rounded towards zero, which is what divide returns you.
+;
+;              The remainder is fiddled during this process, so that the
+;              properties
+;
+;                      quotient * divisor + remainder == dividend
+;
+;              and
+;
+;                      |remainder| < |divisor|
+;
+;              still hold (so the remainder's sign may well change).
+
+               EXPORT  div_round
+div_round      ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,R0                   ;Keep a copy of the dividend
+               CMP     R1,#0                   ;Is the divisor positive?
+               MOVGE   R14,R1                  ;Yes -- just copy it
+               RSBLT   R14,R1,#0               ;No -- negate it on the way
+               CMP     R0,#0                   ;Is the dividend positive?
+               ADDGE   R0,R0,R14,ASR #1        ;Yes -- add half the divisor
+               SUBLT   R0,R0,R14,ASR #1        ;No -- subtract it
+               SUB     R2,R2,R0                ;Remember this difference
+               BL      divide                  ;Do the division
+               ADD     R1,R1,R2                ;Modify remainder suitably
+               LDMFD   R13!,{R2,PC}^           ;Return to caller
+
+               LTORG
+
+; --- div_u64x32 ---
+;
+; On entry:    R0,R1 == dividend (high word in R1)
+;              R2 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         Divides a 64-bit unsigned value by a 32-bit unsigned value
+;              yielding 32-bit unsigned quotient and remainder.  If there
+;              are more than 32 bits of quotient, the return values are
+;              undefined.
+
+               EXPORT  div_u64x32
+div_u64x32     ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+
+               MOV     R14,#8                  ;Initialise the loop counter
+
+00div_u64x32
+
+               GBLA    count
+count          SETA    4
+
+               WHILE   count>0
+
+               CMP     R1,R2                   ;Can we subtract here?
+               SUBCS   R1,R1,R2                ;Yes -- do that then
+               ADCS    R0,R0,R0                ;Shift up quotient/dividend
+               ADC     R1,R1,R1                ;Put next dividend bit in R1
+
+count          SETA    count-1
+               WEND
+
+               SUBS    R14,R14,#1              ;Decrement loop counter
+               BGT     %00div_u64x32           ;If more to do, loop round
+
+               CMP     R1,R2                   ;Can we subtract here?
+               SUBCS   R1,R1,R2                ;Yes -- do that then
+               ADCS    R0,R0,R0                ;Shift up quotient
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/drag b/StraySrc/Libraries/Sapphire/s/drag
new file mode 100644 (file)
index 0000000..959f423
--- /dev/null
@@ -0,0 +1,728 @@
+;
+; drag.s
+;
+; Support code for dragging operations (MDW)
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:akbd
+               GET     sapphire:idle
+               GET     sapphire:intKeys
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+               GET     sapphire:win
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- drag_start ---
+;
+; On entry:    R0 == window containing the drag
+;              R1 == flags word (see flags below)
+;              R2 == pointer to drag routine
+;              R3 == magic number to pass in R9
+;              R4 == value to pass to routine in R10
+;              R5 == value to pass to routine in R12
+;
+; On exit:     --
+;
+; Use:         Starts a drag operation.  Any outstanding drag operation
+;              is cancelled on the assumption that someone stole our
+;              UserDragBox event.
+
+               EXPORT  drag_start
+drag_start     ROUT
+
+               STMFD   R13!,{R0-R7,R12,R14}    ;Save some registers
+               WSPACE  drag__wSpace            ;Find my workspace address
+
+               ; --- Cancel any current drag operation ---
+
+               LDR     R14,drag__window        ;Load current window
+               CMP     R14,#0                  ;Is there one defined?
+               BLNE    drag_cancel             ;Yes -- cancel it then
+
+               ; --- Ensure that this isn't a silly ---
+               ;
+               ; Rather irritatingly, the WIMP's drag-detection is a little
+               ; suspect; it thinks that moving the pointer outside of
+               ; a window while the button is held down is actually a drag.
+               ; We try to hack around this little problem.
+
+               SWI     OS_Mouse                ;Read the current mouse pos.
+               CMP     R2,#0                   ;Are any buttons pressed?
+               LDMEQFD R13!,{R0-R7,R12,PC}^    ;No -- do nothing then
+
+               ; --- Set up handlers for new drag op ---
+
+               MOV     R0,#0                   ;Call me very often please
+               ADR     R1,drag__idles          ;Point to the handler
+               MOV     R2,#0                   ;Nothing to pass in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      idle_handler            ;Install the handler
+               LDMVSFD R13!,{R0-R7,R12,PC}^    ;If it failed, return now
+
+               ; --- Set up all the new information ---
+
+               LDMIA   R13,{R0-R3}             ;Load information off stack
+               STMIA   R12,{R0-R5}             ;Save all that lot away
+
+               MOV     R0,#&3F                 ;Reset the dash pattern
+               STRB    R0,drag__dash           ;This is the current dash
+               STRB    R0,drag__oldDash        ;And the previous one
+               BL      drag_setDash            ;Make it the current pattern
+
+               SWI     OS_ReadMonotonicTime    ;Find the current time
+               STR     R0,drag__lastTime       ;And store that away too
+
+               ; --- Now read the current position of the drag ---
+
+               SUB     R13,R13,#44             ;Make space for window state
+               LDR     R14,drag__window        ;Load the window handle
+               STR     R14,[R13,#0]            ;Save it in the block
+               MOV     R1,R13                  ;Point to this block
+               SWI     Wimp_GetWindowState     ;Read the window's position
+
+               BL      drag__find              ;Find the current position
+               ADR     R14,drag__startPos      ;Point to the current posn
+               STMIA   R14!,{R4,R5}            ;Load the coordinates out
+               STMIA   R14!,{R4,R5}            ;Store them in start position
+
+               MOV     R0,#drEvent_draw        ;Do some drawing please
+               BL      drag__draw              ;And draw the dash box
+               ADD     R13,R13,#44             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R7,R12,PC}^    ;Return to caller finally
+
+               LTORG
+
+; --- drag_scroll ---
+;
+; On entry:    R1 == pointer to window state block
+;
+; On exit:     R2,R3 == new scroll positions to set
+;              R14 == R1+20 (pointer to scroll offsets)
+;
+; Use:         Works out the scroll positions which should be set to auto-
+;              scroll the window.  The algorithm is simple: the window is
+;              scrolled so that the point beneath the mouse pointer is
+;              within the window's visible work area.
+
+               EXPORT  drag_scroll
+drag_scroll    ROUT
+
+               STMFD   R13!,{R0,R1,R4-R7,R14}  ;Save some registers
+
+               ; --- Find the mouse pointer position ---
+
+               LDMIB   R1!,{R4-R7}             ;Load the bounding box out
+               LDMIB   R1!,{R2,R3}             ;And the current scroll pos
+               SUB     R13,R13,#20             ;Make a PointerInfo block
+               MOV     R1,R13                  ;Point at this
+               SWI     Wimp_GetPointerInfo     ;Read the information
+               LDMIA   R13,{R0,R1}             ;Load the current position
+
+               ; --- Now fiddle the scroll positions ---
+
+               SUBS    R14,R0,R4               ;Compare x to left side
+               ADDLT   R2,R2,R14               ;If too far left, then scroll
+               SUBS    R14,R1,R5               ;Compare y to bottom
+               ADDLT   R3,R3,R14               ;If too low, then scroll
+               SUBS    R14,R0,R6               ;Compare x to right side
+               ADDGT   R2,R2,R14               ;If too far right, scroll
+               SUBS    R14,R1,R7               ;Compare y to top
+               ADDGT   R3,R3,R14               ;If too high, then scroll
+
+               ; --- Return everything to caller ---
+
+               ADD     R13,R13,#20             ;Restore the stack pointer
+               LDR     R14,[R13,#4]            ;Load the pointer out
+               ADD     R14,R14,#20             ;Point to scroll offsets
+               LDMFD   R13!,{R0,R1,R4-R7,PC}^  ;And return to caller
+
+               LTORG
+
+; --- drag__dispatch ---
+;
+; On entry:    R0 == event code
+;              R1-R7 depend on event
+;
+; On exit:     --
+;
+; Use:         Dispatches a drag event to the current handler.
+
+drag__dispatch ROUT
+
+               STMFD   R13!,{R8-R10,R12,R14}   ;Save some registers
+               ADR     R14,drag__handler       ;Point to the handler
+               LDMIA   R14,{R8-R10,R12}        ;Load the registers out
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R8                   ;Call the routine nicely
+               LDMFD   R13!,{R8-R10,R12,PC}^   ;And return to caller
+
+               LTORG
+
+; --- drag__draw ---
+;
+; On entry:    R0 == event code to pass
+;              R1 == pointer to window state block (44 bytes required)
+;
+; On exit:     --
+;
+; Use:         Updates a window using the given event.
+
+drag__draw     ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Save some registers
+               MOV     R8,R0                   ;Look after the event code
+               LDR     R9,[R1,#28]             ;Load the `behind' pointer
+
+               ; --- Build the update block ---
+
+               LDMIB   R1,{R2-R5,R7,R14}       ;Load the values out of it
+
+               SUB     R6,R2,R7                ;Find the x origin position
+               SUB     R4,R4,R2                ;Find the window width
+               MOV     R2,R7                   ;Get left side of update box
+               ADD     R4,R2,R4                ;Get right side of update box
+
+               SUB     R7,R5,R14               ;Find the y origin position
+               SUB     R3,R5,R3                ;Find the window height
+               MOV     R5,R14                  ;Get top of update box
+               SUB     R3,R5,R3                ;Get bottom of update box
+
+               STMIB   R1,{R2-R5}              ;Save the box back
+
+               ; --- Set up other registers for the job ---
+
+               ADR     R14,drag__startPos      ;Find the start position
+               LDMIA   R14,{R2-R5}             ;Load the positions out
+
+               ; --- Finally do the actual update ---
+
+               SWI     Wimp_UpdateWindow       ;Start the update job
+               CMP     R0,#0                   ;Is there anything to do?
+               BEQ     %90drag__draw           ;No -- then skip ahead
+
+00             MOV     R0,R8                   ;Get caller's event code
+               BL      drag__dispatch          ;Call the event handler
+               SWI     Wimp_GetRectangle       ;Get the next rectangle
+               CMP     R0,#0                   ;Is there anything left?
+               BNE     %b00                    ;Yes -- loop back to do it
+
+               ; --- Tidy up and return to caller ---
+
+90drag__draw   STR     R9,[R1,#28]             ;Store `behind' pointer back
+               LDMFD   R13!,{R0-R9,PC}^        ;And return to caller
+
+               LTORG
+
+; --- drag__find ---
+;
+; On entry:    R1 == pointer to window state block
+;
+; On exit:     R4,R5 == coordinates, suitably transformed
+;              R6,R7 == window origin coordinates
+;              CS if mouse button still down, else CC
+;
+; Use:         Locates the mouse pointer within the window.
+
+drag__find     ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               MOV     R2,R1                   ;Remember initial pointer
+               SUB     R13,R13,#20             ;Make space for pointer info
+               MOV     R1,R13                  ;Point to this block
+               SWI     Wimp_GetPointerInfo     ;Find the pointer position
+               MOV     R1,R2                   ;Point to original block
+
+               ; --- Set up for calling event handler ---
+
+               LDR     R2,[R1,#4]              ;Load the left hand side
+               ADD     R14,R1,#16              ;Find top and scroll position
+               LDMIA   R14,{R5-R7}             ;Load them out nicely
+               SUB     R6,R2,R6                ;Find the x origin position
+               SUB     R7,R5,R7                ;And the y origin position
+
+               LDMIA   R13,{R4,R5}             ;Load the coordinates out
+               SUB     R4,R4,R6                ;Translate to window coords
+               SUB     R5,R5,R7                ;Do that to y coord too
+               MOV     R0,#drEvent_trans       ;Get handler to translate
+               BL      drag__dispatch          ;Go and do that then
+
+               ; --- Tidy up and return ---
+
+               LDR     R14,[R13,#8]            ;Load the mouse status
+               CMP     R14,#0                  ;Are all buttons released?
+               ADD     R13,R13,#20             ;Restore the stack block
+               LDMFD   R13!,{R0-R3,R14}        ;Restore registers
+               ORRNES  PC,R14,#C_flag          ;If button pressed, return CS
+               BICEQS  PC,R14,#C_flag          ;Else return CC
+
+               LTORG
+
+; --- drag__getPosition ---
+;
+; On entry:    R1 == pointer to window state block
+;              R4,R5 == new position
+;              R6,R7 == window origin position
+;
+; On exit:     R4,R5 == new position, translated further
+;
+; Use:         Reads the position of the current drag operation.  This
+;              allows the client to do clever things like gridlocking and
+;              autoscrolling.
+
+drag__getPosition ROUT
+
+               STMFD   R13!,{R0,R2,R3,R14}     ;Save some registers
+               ADR     R14,drag__startPos      ;Find the start position
+               LDMIA   R14,{R2,R3}             ;Load those coordinates out
+               MOV     R0,#drEvent_getPos      ;Tell client to translate
+               BL      drag__dispatch          ;Send the event off
+               LDMFD   R13!,{R0,R2,R3,PC}^     ;And return to caller
+
+               LTORG
+
+; --- drag_setDash ---
+;
+; On entry:    R0 == dash pattern byte
+;
+; On exit:     --
+;
+; Use:         Sets the dash pattern to be the given value.
+
+               EXPORT  drag_setDash
+drag_setDash   ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Build VDU block ---
+
+               AND     R0,R0,#&FF              ;Clear top bits of R0
+               ORR     R1,R0,R0,LSL #8         ;Duplicate the byte
+               ORR     R1,R1,R1,LSL #16        ;Fill a word with it
+               MOV     R0,#23                  ;Get the VDU command code
+               ORR     R0,R0,#6<<8             ;OR in the command type
+               ORR     R0,R0,R1,LSL #16        ;Put in first two patterns
+               MOV     R2,R1,LSR #16           ;Put in last two patterns
+               STMIA   R11,{R0-R2}             ;Save that on the stack
+
+               ; --- Set the dash pattern length ---
+
+               MOV     R0,#163                 ;Write general graphics info
+               MOV     R1,#242                 ;Set dash pattern length
+               MOV     R2,#8                   ;Set the repeat length
+               SWI     OS_Byte                 ;Set the length then
+
+               ; --- Now set the dash pattern itself ---
+
+               MOV     R0,R11                  ;Point to my VDU block
+               MOV     R1,#10                  ;Size of block in bytes
+               SWI     OS_WriteN               ;Write that to the VDU things
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+; --- drag__idles ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Handles idle events during a drag operation.
+
+drag__idles    ROUT
+
+               STMFD   R13!,{R0-R7,R14}        ;Save some registers
+
+               ; --- Check for a cancelled drag ---
+
+               MOV     R0,#intk_Esc            ;Get the Escape kep code
+               BL      akbd_test               ;Test the key
+               BCS     %70drag__idles          ;Cancelled -- abort it then
+
+               ; --- Update the dash pattern ---
+
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               LDR     R14,drag__lastTime      ;Load the old time nicely
+               SUB     R0,R0,R14               ;Find the difference
+               MOV     R0,R0,LSR #2            ;Divide by 4
+               ADD     R14,R14,R0,LSL #2       ;Add on rounded value
+               STR     R14,drag__lastTime      ;Save that back
+
+               LDRB    R14,drag__dash          ;Load the dash position
+               STRB    R14,drag__oldDash       ;This is now the old one
+               MOV     R0,R0,LSL #1            ;Multiply difference by 2
+               MOV     R0,R14,ROR R0           ;Rotate the dash pattern
+               ORR     R0,R0,R0,ROR #24        ;Fake an 8-bit rotate
+               ORR     R0,R0,R0,ROR #16        ;Make sure it's done properly
+               STRB    R0,drag__dash           ;This is the new pattern
+
+               ; --- Read the new position ---
+
+               SUB     R13,R13,#44             ;Make a window state block
+               LDR     R14,drag__window        ;Load the window handle out
+               STR     R14,[R13,#0]            ;Store handle in there
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Read the window information
+
+               BL      drag__find              ;Find the new position
+               BL      drag__getPosition       ;Do any exra processing reqd
+               BCC     %50drag__idles          ;If done, skip onwards
+
+               ; --- Work out what needs to be done ---
+
+               ADR     R14,drag__currPos       ;Find the current position
+               LDMIA   R14,{R2,R3}             ;Load that out
+               CMP     R2,R4                   ;Has the drag box moved?
+               CMPEQ   R3,R5                   ;Check both coordinates
+               BEQ     %30drag__idles          ;No -- handle speciallt
+
+               ; --- Force the update of the drag box ---
+
+               LDRB    R0,drag__oldDash        ;Get the old dash pattern
+               BL      drag_setDash            ;Set this as the pattern
+               MOV     R0,#drEvent_undraw      ;Tell client to undraw
+               BL      drag__draw              ;Go and do that then
+
+               ; --- Now draw the new one ---
+
+               ADR     R14,drag__currPos       ;Find the current position
+               STMIA   R14,{R4,R5}             ;Save new position in there
+               LDRB    R0,drag__dash           ;Load the new dash pattern
+               BL      drag_setDash            ;Set this as the pattern
+               MOV     R0,#drEvent_draw        ;Tell client to draw
+               BL      drag__draw              ;Go and do that then
+               B       %90drag__idles          ;Now go and tidy up
+
+               ; --- Update the drag box in place ---
+
+30drag__idles  LDR     R14,drag__flags         ;Load any interesting flags
+               TST     R14,#drFlag_noUpdate    ;Do we send update events?
+               BNE     %90drag__idles          ;No -- then do nothing
+
+               LDR     R0,drag__oldDash        ;Load the two dash patterns
+               EOR     R0,R0,R0,LSR #8         ;Exclusive OR them together
+               BL      drag_setDash            ;Set this as the pattern
+               MOV     R0,#drEvent_update      ;Tell client to update drag
+               BL      drag__draw              ;Go and do that then
+               B       %90drag__idles          ;Now go and tidy up
+
+               ; --- Tidy up at the end of the drag ---
+
+50drag__idles  LDRB    R0,drag__oldDash        ;Get the old dash pattern
+               BL      drag_setDash            ;Set this as the pattern
+               MOV     R0,#drEvent_undraw      ;Now remove the drag box
+               BL      drag__draw              ;Go and do that then
+
+               ADR     R14,drag__startPos      ;Point to start position
+               LDMIA   R14,{R2-R5}             ;Load all that lot
+               MOV     R0,#drEvent_done        ;Say it's all over
+               BL      drag__dispatch          ;Send that to the user
+
+               ; --- Remove this idle handler ---
+
+               MOV     R0,#0                   ;We're called very often
+               ADR     R1,drag__idles          ;Point to the handler
+               MOV     R2,#0                   ;Passed nothing in R10
+               MOV     R3,R12                  ;Passed workspace in R12
+               BL      idle_removeHandler      ;Remove the handler
+
+               MOV     R14,#0                  ;A convenient zero
+               STR     R14,drag__window        ;Clear the window handle
+
+               B       %90drag__idles          ;Now go and tidy up
+
+               ; --- Cancel the drag ---
+
+70drag__idles  BL      drag_cancel             ;Cancel the drag
+               B       %95drag__idles          ;Now go and tidy up
+
+               ; --- Now tidy up and go home ---
+
+90drag__idles  ADD     R13,R13,#44             ;Recover any lost stack space
+95drag__idles  LDMFD   R13!,{R0-R7,PC}^        ;And return to caller
+
+               LTORG
+
+; --- drag_cancel ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Cancels the current drag operation.
+
+               EXPORT  drag_cancel
+drag_cancel    ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Save some registers
+               WSPACE  drag__wSpace            ;Find my workspace
+
+               ; --- Make sure this is worth it ---
+
+               LDR     R14,drag__window        ;Load current drag window
+               CMP     R14,#0                  ;Is it defined?
+               LDMEQFD R13!,{R0-R3,R12,PC}^    ;No -- then do nothing
+
+               ; --- Undraw the drag box ---
+
+               SUB     R13,R13,#44             ;Drop the stack by a bit
+               LDR     R14,drag__window        ;Load the window handle out
+               STR     R14,[R13,#0]            ;Store handle in there
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Read the window information
+               LDR     R0,drag__dash           ;Load the current dash pos
+               BL      drag_setDash            ;Set the dash pattern
+               MOV     R0,#drEvent_undraw      ;Undraw the drag box
+               BL      drag__draw              ;Go and do that then
+               MOV     R0,#drEvent_cancel      ;Say the drag was cancelled
+               BL      drag__dispatch          ;Inform the client of this
+
+               ; --- Now tidy up and return ---
+
+               MOV     R0,#0                   ;We're called very often
+               ADR     R1,drag__idles          ;Point to the handler
+               MOV     R2,#0                   ;Passed nothing in R10
+               MOV     R3,R12                  ;Passed workspace in R12
+               BL      idle_removeHandler      ;Remove the handler
+
+               MOV     R14,#0                  ;A convenient zero
+               STR     R14,drag__window        ;Clear the window handle
+
+               ADD     R13,R13,#44             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- drag_redraw ---
+;
+; On entry:    R1 == pointer to redraw block
+;
+; On exit:     --
+;
+; Use:         Redraws the drag box, if the redraw takes place in the
+;              currently dragging window.
+
+               EXPORT  drag_redraw
+drag_redraw    ROUT
+
+               STMFD   R13!,{R0-R7,R12,R14}    ;Save some registers
+               WSPACE  drag__wSpace            ;Find the workspace address
+
+               ; --- Make sure there's something to do ---
+
+               LDR     R0,[R1,#0]              ;Load the window handle
+               LDR     R14,drag__window        ;Load current drag window
+               CMP     R0,R14                  ;Do these match up?
+               LDMNEFD R13!,{R0-R7,R12,PC}^    ;No -- do nothing then
+
+               ; --- Set up registers ---
+
+               LDR     R2,[R1,#4]              ;Load left hand side
+               ADD     R14,R1,#16              ;Find top and scroll
+               LDMIA   R14,{R5-R7}             ;Load that lot out
+               SUB     R6,R2,R6                ;Find the x origin pos
+               SUB     R7,R5,R7                ;And the y origin pos
+               ADR     R14,drag__startPos      ;Find the start position
+               LDMIA   R14,{R2-R5}             ;Load position out nicely
+
+               ; --- Now do the drawing ---
+
+               LDRB    R0,drag__dash           ;Load current dash pattern
+               BL      drag_setDash            ;Set the dash pattern
+               MOV     R0,#drEvent_draw        ;Now do some drawing
+               BL      drag__dispatch          ;Send to event handler
+               LDMFD   R13!,{R0-R7,R12,PC}^    ;Now return to caller
+
+               LTORG
+
+; --- drag_eorColour ---
+;
+; On entry:    R0 == colour A
+;              R1 == colour B
+;
+; On exit:     --
+;
+; Use:         Sets the foreground colour to be an EOR colour such that
+;              when painted over Wimp colour A, it appears as Wimp colour B.
+
+               EXPORT  drag_eorColour
+drag_eorColour ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               MOV     R2,R0,LSL #2            ;Keep the background colour
+               MOV     R3,R1,LSL #2            ;And the foreground colour
+               MOV     R1,R11                  ;Point to the block
+               SWI     Wimp_ReadPalette        ;Read the current palette
+               LDR     R0,[R11,R2]             ;Load the fore palette entry
+               SWI     ColourTrans_ReturnColourNumber
+               MOV     R2,R0                   ;Save the colour number
+               LDR     R0,[R11,R3]             ;Load the back palette entry
+               SWI     ColourTrans_ReturnColourNumber
+               EOR     R1,R0,R2                ;Get the EOR colour number
+               MOV     R0,#3                   ;Set EOR colour please
+               SWI     XOS_SetColour           ;Set the colour, please
+               BVC     %90drag_eorColour       ;If it worked, return
+
+               ; --- We must be running RISC OS 2 ---
+               ;
+               ; This is very tedious -- we have to set the colour by hand.
+
+               BL      screen_getInfo          ;Read the screen cache
+               LDR     R0,[R0,#screen_bpp]     ;Load the current BPP
+               CMP     R0,#8                   ;Are we in a 256 colour mode?
+               BEQ     %50drag_eorColour       ;Yes -- handle it specially
+
+               ; --- Just set the GCOL from R1 ---
+
+               SWI     OS_WriteI+18            ;Set graphics colour
+               SWI     OS_WriteI+3             ;Use XOR colour
+               MOV     R0,R1                   ;Get the colour to set
+               SWI     OS_WriteC               ;Set the colour
+               B       %90drag_eorColour       ;Return -- we did it
+
+               ; --- Set the colour in a 256 colour mode ---
+
+50             MOV     R0,R1                   ;Get colour in R0
+               SWI     ColourTrans_ColourNumberToGCOL
+               MOV     R1,R0                   ;Keep the GCOL safe
+               SWI     OS_WriteI+18            ;Set graphics colour
+               SWI     OS_WriteI+3             ;Use XOR colour
+               MOV     R0,R1,LSR #2            ;Get the GCOL part of it
+               SWI     OS_WriteC               ;Set the colour
+
+               ; --- Now set the tint ---
+
+               MOV     R0,#23                  ;VDU code for tint setting
+               ORR     R0,R0,#17<<8            ;Subreason code for tint
+               ORR     R0,R0,#2<<16            ;Set the graphics foreground
+               ORR     R0,R0,R1,LSL #30        ;Get the tint bits in too
+               MOV     R1,#0                   ;Other bytes are all 0
+               MOV     R2,#0                   ;Two words of them
+               STMIA   R11,{R0-R2}             ;Save them in scratchpad
+               MOV     R0,R11                  ;Point at them
+               MOV     R1,#10                  ;VDU 23 is 10 bytes long
+               SWI     OS_WriteN               ;Write the whole lot out
+
+90             LDMFD   R13!,{R0-R3,PC}^
+
+               LTORG
+
+drag__wSpace   DCD     0
+
+;----- Flags ----------------------------------------------------------------
+
+drFlag_noUpdate        EQU     (1<<0)                  ;Don't generate update events
+
+;----- Drag handler events --------------------------------------------------
+
+; --- Note ---
+;
+; The events which request that you draw something are called for each
+; rectangle of the draw operation -- i.e. do not call Wimp_GetRectangle
+; because this is done for you.
+
+               ^       0
+drEvent_draw   #       1                       ;Draw dragged object
+                                               ;R1 == pointer to redraw blk
+                                               ;R2,R3 == drag start posn
+                                               ;R4,R5 == drag current posn
+                                               ;R6,R7 == window origin
+                                               ;Dash pattern set up
+
+drEvent_undraw #       1                       ;Undraw dragged object
+                                               ;Regs as for drEvent_draw
+                                               ;Normally use the same code
+
+drEvent_update #       1                       ;Redraw dragged object in
+                                               ;place
+                                               ;Regs as for drEvent_draw
+                                               ;Dash pattern set up so that
+                                               ;single plot will rotate box,
+                                               ;so may share code with
+                                               ;drEvent_draw
+
+drEvent_trans  #       1                       ;Translate coordinates
+                                               ;R1 == ptr to window state
+                                               ;R4,R5 == pointer position
+                                               ;R6,R7 == window origin
+                                               ;Translate pointer position
+                                               ;to internal coordinates if
+                                               ;this is useful to you.
+                                               ;Return new coords in R4,R5
+
+drEvent_getPos #       1                       ;Read pointer position
+                                               ;R1 == ptr to window state
+                                               ;R2,R3 == start position
+                                               ;R4,R5 == pointer position
+                                               ;R6,R7 == window origin
+                                               ;Used to read pointer posn.
+                                               ;Do any grid snapping here
+                                               ;and return with R4,R5 as
+                                               ;coords to use.
+
+drEvent_done   #       1                       ;Drag operation completed
+                                               ;R1 == ptr to window state
+                                               ;R2,R3 == drag start posn
+                                               ;R4,R5 == drag current posn
+
+drEvent_cancel #       1                       ;Drag operation aborted
+                                               ;No other registers set up
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+drag__wStart   #       0
+
+drag__window   #       4                       ;Window handle of drag
+drag__flags    #       4                       ;Various interesting flags
+drag__handler  #       16                      ;All the handler information
+drag__oldDash  #       1                       ;The old dash pattern
+drag__dash     #       1                       ;The current dash pattern
+               #       2                       ;Align to word boundary
+drag__lastTime #       4                       ;Last time we changed pattern
+drag__startPos #       8                       ;Find the start position
+drag__currPos  #       8                       ;Find the end position
+
+drag__wSize    EQU     {VAR}-drag__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     drag__wSize
+               DCD     drag__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/draw b/StraySrc/Libraries/Sapphire/s/draw
new file mode 100644 (file)
index 0000000..05cf507
--- /dev/null
@@ -0,0 +1,924 @@
+;
+; draw.s
+;
+; Renders DrawFiles (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:divide
+               GET     sapphire:mem
+               GET     sapphire:msgs
+               GET     sapphire:roVersion
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+               GET     sapphire:sprite
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- Register allocation ---
+;
+; R12 == pointer to font array
+; R10 == pointer to transform matrix
+;  R9 == pointer to clipping block (in Draw units)
+;  R8 == pointer to end of objects to render
+;  R7 == pointer to start of current object
+
+; --- draw_render ---
+;
+; On entry:    R0 == scale to plot drawfile (16.16 form)
+;              R1 == pointer to a redraw block
+;              R2 == pointer to drawfile in memory
+;              R3 == size of drawfile block
+;
+; On exit:     --
+;
+; Use:         Renders a DrawFile in a window.  Objects which aren't
+;              recognised are not rendered.  The objects which are handled
+;              are as follows:
+;
+;              * Font table objects
+;              * Text objects (in fonts, or in system font)
+;              * Draw path objects, filled and unfilled, including
+;                dotted outlines
+;              * Group objects
+;              * Tagged objects
+;              * Sprite objects, rendered as well as we can make it
+;              * Transformed text, only on RISC OS 3
+;              * Transformed sprite, only on RISC OS 3
+
+               EXPORT  draw_render
+draw_render    ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save a load of registers
+
+               ; --- Set up the transformation matrix ---
+
+               LDR     R4,[R1,#4]              ;Load minimum x coord
+               ADD     R14,R1,#16              ;Point to maximum y coord
+               LDMIA   R14,{R5-R7}             ;Load y coord and scroll pos
+               SUB     R4,R4,R6                ;Work out x origin position
+               SUB     R5,R5,R7                ;And the y origin position
+
+               SUB     R13,R13,#24             ;Make way for the transform
+               MOV     R10,R13                 ;Point to it nicely
+               MOV     R14,R13                 ;Point to it for filling
+               MOV     R6,R0                   ;Set up x scale from user
+               MOV     R7,#0                   ;Don't do fancy x transforms
+               MOV     R8,#0                   ;Don't do fancy y transforms
+               MOV     R9,R0                   ;And scale y from user
+               STMIA   R14!,{R6-R9}            ;Save this in the block
+               MOV     R6,R4,LSL #8            ;Convert offset to draw units
+               MOV     R7,R5,LSL #8            ;And convert y offset too
+               STMIA   R14,{R6,R7}             ;Save these in the matrix too
+
+               ; --- Set up the adjusted clipping block too ---
+
+               SUB     R13,R13,#16             ;Make way for a clipping blk
+               ADD     R14,R1,#28              ;Point to original block
+               LDMIA   R14,{R6-R9}             ;Load the clipping coords
+               SUB     R6,R6,R4                ;Convert these to window...
+               SUB     R7,R7,R5                ;... coordinates for easy...
+               SUB     R8,R8,R4                ;... clipping
+               SUB     R9,R9,R5
+               MOV     R4,R0                   ;Get the scale factor safe
+
+               ; --- Now we have to divide by the scale factor ---
+
+               MOV     R12,#&18000             ;A useful constant (1 1/2)
+               RSB     R0,R12,R6,LSL #16       ;Take minimum x position
+               MOV     R1,R4,LSR #8            ;And the scale factor
+               BL      divide                  ;Do the division
+               MOV     R6,R0                   ;Take the result away nicely
+
+               RSB     R0,R12,R7,LSL #16       ;Take minimum y position
+               MOV     R1,R4,LSR #8            ;And the scale factor
+               BL      divide                  ;Do the division
+               MOV     R7,R0                   ;Take the result away nicely
+
+               ADD     R0,R12,R8,LSL #16       ;Take maximum x position
+               MOV     R1,R4,LSR #8            ;And the scale factor
+               ADD     R0,R0,R1                ;Make it round upwards
+               BL      divide                  ;Do the division
+               MOV     R8,R0                   ;Take the result away nicely
+
+               ADD     R0,R12,R9,LSL #16       ;Take maximum y position
+               MOV     R1,R4,LSR #8            ;And the scale factor
+               ADD     R0,R0,R1                ;Make it round upwards
+               BL      divide                  ;Do the division
+               MOV     R9,R0                   ;Take the result away nicely
+
+               STMIA   R13,{R6-R9}             ;Save the modified values
+               MOV     R9,R13                  ;Point to the coords block
+
+               ; --- Set up start and end values ---
+
+               MOV     R7,R2                   ;Get start address to render
+               ADD     R8,R7,R3                ;And calculate end address
+               MOV     R0,R7                   ;Point to the drawfile
+               BL      draw_checkValid ;Make sure the drawfile's OK
+               BVS     %10draw_render          ;If not don't draw it
+               ADD     R7,R7,#40               ;Point to renderable part
+
+               ; --- And finally initialise the font array ---
+
+               SUB     R13,R13,#1024           ;The font array is *big*
+               MOV     R12,R13                 ;Point to it
+               MOV     R0,R12                  ;Point to font array
+               MOV     R1,#1024                ;Get its size
+               MOV     R2,#0                   ;We're going to fill it
+               BL      mem_set                 ;So make it all zeroes
+
+               ; --- Do the main rendering and tidy up ---
+
+               BL      draw__doRender          ;And do the main job
+10draw_render  ADD     R13,R10,#24             ;Reclaim all the stack
+               BL      draw__resetTextSize     ;Make the text size sensible
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller now
+
+; --- draw_checkValid ---
+;
+; On entry:    R0 == pointer to start of drawfile
+;
+; On exit:     May return an error
+;
+; Use:         Checks whether a drawfile is basically sound.  This checking
+;              isn't compulsory, and just checks the initial word and the
+;              format version number -- nothing very exciting.
+
+               EXPORT  draw_checkValid
+draw_checkValid        ROUT
+
+               BIC     R14,R14,#V_flag         ;Assume everything's OK
+               STMFD   R13!,{R1,R14}           ;Save a register away
+               LDR     R14,draw__drawMagic     ;Load the magic word out
+               LDR     R1,[R0,#0]              ;Load the first word out
+               CMP     R14,R1                  ;Do they match perfectly?
+               BNE     %90draw_checkValid      ;No -- then return error
+               LDR     R14,[R0,#4]             ;Load major format version
+               CMP     R14,#201                ;Is it old enough for me?
+               LDMLEFD R13!,{R1,PC}^           ;Return to caller if OK
+
+               ; --- Version number is wrong ---
+
+               ADR     R0,draw__tooNew         ;Point to the error message
+               B       %95draw_checkValid      ;And handle the error
+
+draw__drawMagic        DCB     "Draw"
+
+draw__tooNew   DCD     1
+               DCB     "drawTOONEW",0
+
+               ; --- It isn't a drawfile ---
+
+90             ADR     R0,draw__badFile        ;Point to the error message
+95             BL      msgs_error              ;Translate the error
+               LDMFD   R13!,{R1,R14}           ;Unstack some registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+draw__badFile  DCD     1
+               DCB     "drawBADFILE",0
+
+               LTORG
+
+; --- draw__doRender ---
+;
+; On entry:    R7 == pointer to object to start rendering
+;              R8 == pointer to first object not to render
+;              R9 == pointer to coordinate clipping block
+;              R10 == pointer to transformation matrix
+;              R12 == pointer to font array
+;
+; On exit:     R7 points past last object rendered
+;              R0-R6 may be corrupted
+;
+; Use:         Renders a group of objects.
+
+draw__doRender ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+00             CMP     R7,R8                   ;Is there anything to do?
+               BLLT    draw__renderObject      ;Yes -- render an object
+               BLT     %00draw__doRender       ;And go round again
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- draw__renderObject ---
+;
+; On entry:    R7 == pointer to object to render
+;              R8 == pointer to first object not to render
+;              R9 == pointer to coordinate clipping block
+;              R10 == pointer to transformation matrix
+;              R12 == pointer to font array
+;
+; On exit:     R7 == pointer to next object to render
+;              R0-R6 may be corrupted
+;
+; Use:         The main object rendering dispatch routine.
+
+draw__renderObject ROUT
+
+               LDR     R0,[R7,#0]              ;Get the object's type
+               CMP     R0,#(%10-%00)/4         ;Is it in range of my table?
+               ADDLO   PC,PC,R0,LSL #2         ;Yes -- dispatch it then
+               B       %10draw__renderObject   ;Out of range -- ignore it
+
+00             B       draw__readFontTable     ;Font table object
+               B       draw__renderText        ;Render a text string
+               B       draw__renderPath        ;Render a standard draw path
+               B       %10draw__renderObject   ;Type 3 is not defined
+               B       %10draw__renderObject   ;Type 4 is not defined
+               B       draw__renderSprite      ;Render a sprite
+               B       draw__renderGroup       ;Handle a group of objects
+               B       draw__renderTagged      ;Render a tagged object
+               B       %10draw__renderObject   ;Type 8 is not defined
+               B       %10draw__renderObject   ;Text area is too difficult
+               B       %10draw__renderObject   ;Text column is too difficult
+               B       %10draw__renderObject   ;Options are not renderable
+               B       draw__renderTransformedText ;Render rotated text
+               B       draw__renderTransformedSprite ;Render rotated sprite
+
+10             B       draw__next              ;Ignore unknown objects
+
+               LTORG
+
+; --- draw__next ---
+;
+; On entry:    R7 == pointer to a draw object
+;
+; On exit:     R7 == pointer to next draw object
+;              R0 corrupted
+;
+; Use:         Moves the current pointer on to the next object
+
+draw__next     ROUT
+
+               LDR     R0,[R7,#4]              ;Load the object size
+               ADD     R7,R7,R0                ;Advance the object pointer
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- draw__clip ---
+;
+; On entry:    R7 == pointer to a draw object
+;              R9 == pointer to current clipping rectangle
+;
+; On exit:     R0-R6 corrupted
+;              CS if the object appears within the clipping rectangle,
+;              CC if it doesn't
+;
+; Use:         Determines if a draw object needs rendering in the current
+;              redraw job.
+
+draw__clip     STMFD   R13!,{R7}               ;Save a register
+               ADD     R7,R7,#8                ;Point to the bounding box
+               LDMIA   R7,{R4-R7}              ;Load the box from it
+               LDMIA   R9,{R0-R3}              ;And load the clipping box
+               CMP     R0,R6                   ;Make sure the rectangles...
+               CMPLE   R1,R7                   ;... overlap
+               CMPLE   R4,R2
+               CMPLE   R5,R3
+               LDMFD   R13!,{R7}               ;Restore the R7 I saved
+               ORRLES  PC,R14,#C_flag          ;If it is within, set C
+               BICGTS  PC,R14,#C_flag          ;Otherwise clear C on exit
+
+               LTORG
+
+; --- draw__setTextSize ---
+;
+; On entry:    R0 == x size in pixels
+;              R1 == y size in pixels
+;
+; On exit:     --
+;
+; Use:         Sets the VDU 5 text size.
+
+draw__setTextSize ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save a load of registers
+               MOV     R1,R1,LSL #16           ;Shift up the y sizes
+               ORR     R1,R1,R0                ;Add in the x sizes
+               MOV     R0,#23                  ;Build initial VDU sequence
+               ORR     R0,R0,#17<<8            ;Add in more chars
+               ORR     R0,R0,#7<<16
+               ORR     R0,R0,#2<<24
+               MOV     R2,#0                   ;Wrap up the sequence nicely
+               STMFD   R13!,{R0-R2}            ;Save it on the stack
+               MOV     R0,R13                  ;Point to the sequence
+               MOV     R1,#10                  ;Get the sequence size in R1
+               SWI     OS_WriteN               ;Write it to the VDU stream
+               MOV     R14,#4                  ;Now set the spacing up
+               STRB    R14,[R13,#3]            ;Save it in the stream
+               MOV     R0,R13                  ;Point to the sequence
+               MOV     R1,#10                  ;Get the sequence size in R1
+               SWI     OS_WriteN               ;Write it to the VDU stream
+               ADD     R13,R13,#12             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- draw__resetTextSize ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Makes the text size nice again after doing all sorts of
+;              horrid things to it for the sake of plotting text in the
+;              system font.
+
+draw__resetTextSize ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               BL      screen_getInfo          ;Read the screen information
+               LDMIA   R0,{R0,R1}              ;Load the eigen factors
+               MOV     R14,#16                 ;Normal width 16 OS units
+               MOV     R0,R14,LSR R0           ;Scale it into pixels
+               MOV     R14,#32                 ;Normal height 32 OS units
+               MOV     R1,R14,LSR R1           ;Scale it into pixels
+               BL      draw__setTextSize       ;Set the pixel size nicely
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Object handlers ------------------------------------------------------
+;
+; All of these have the same entry and exit conditions as draw__renderObject.
+
+; --- draw__readFontTable ---
+
+draw__readFontTable ROUT
+
+               LDR     R1,[R7,#4]              ;Find the object size
+               ADD     R1,R7,R1                ;Convert to object end
+               ADD     R0,R7,#8                ;Find start of font data
+
+               ; --- Read an entry from the table ---
+
+00             CMP     R0,R1                   ;Have we finished yet?
+               BGE     draw__next              ;Yes -- return to caller
+               LDRB    R2,[R0],#1              ;Get the internal font handle
+               CMP     R2,#0                   ;Is this a null one?
+               BEQ     draw__next              ;Yes -- that's it then
+
+               STR     R0,[R12,R2,LSL #2]      ;Save the name pointer away
+10             LDRB    R2,[R0],#1              ;Get a font name character
+               CMP     R2,#0                   ;Is this the end of the name?
+               BNE     %10draw__readFontTable  ;No -- go round again then
+
+               B       %00draw__readFontTable  ;Read the next font name
+
+               LTORG
+
+; --- draw__renderText ---
+
+draw__renderText ROUT
+
+               STMFD   R13!,{R14}              ;Save the link temporarily
+               BL      draw__clip              ;Do we have to render it?
+               LDMFD   R13!,{R14}              ;Restore the link again
+               BCC     draw__next              ;No -- then return
+
+               ; --- Make sure the text isn't invisible ---
+
+               ADD     R6,R7,#24               ;Point to the object data
+               LDR     R0,[R6,#0]              ;Load the foreground colour
+               CMP     R0,#-1                  ;Is it transparent?
+               MOVEQS  PC,R14                  ;Yes -- do nothing then
+
+               ; --- Find the font name ---
+
+               LDR     R5,[R6,#8]              ;Load internal font handle
+               CMP     R5,#0                   ;Is the handle 0?
+               BEQ     draw__renderSystemText  ;Yes -- use the system font
+               LDR     R5,[R12,R5,LSL #2]      ;Load the font name pointer
+               CMP     R5,#0                   ;Is it defined?
+               BEQ     draw__renderSystemText  ;No -- use the system font
+
+               ; --- Work out the text size I need ---
+
+               STMFD   R13!,{R14}              ;Save the link again
+               ADD     R2,R6,#12               ;Point to the text sizes
+               LDMIA   R2,{R2,R3}              ;Load x and y sizes
+               LDR     R4,[R10,#0]             ;Load the scale factor
+               MOV     R4,R4,LSR #8            ;Scale it down a little
+               MUL     R2,R4,R2                ;Scale up the x size
+               MUL     R3,R4,R3                ;And scale up the y size
+               MOV     R4,#5                   ;So div10 rounds to nearest
+               ADD     R2,R4,R2,LSR #10        ;Scale values down further
+               ADD     R3,R4,R3,LSR #10        ;Both the x and the y
+               MOV     R0,R2                   ;Get the x size
+               BL      div10                   ;Convert to points
+               MOV     R2,R0                   ;Move back into position
+               MOV     R0,R3                   ;Get the y size
+               BL      div10                   ;Convert to points
+               MOV     R3,R0                   ;Move back into position
+               LDMFD   R13!,{R14}              ;Restore the link again
+
+               ; --- Get a font handle ---
+
+               MOV     R1,R5                   ;Get the font name pointer
+               MOV     R4,#0                   ;Default scaling, please
+               MOV     R5,#0                   ;On x and y axes
+               SWI     XFont_FindFont          ;Try to get a font handle
+               BVS     draw__renderSystemText  ;Couldn't -- use system font
+
+               ; --- Set the right colours ---
+
+               LDR     R1,[R6,#4]              ;Load the background colour
+               LDR     R2,[R6,#0]              ;Load the foreground colour
+               MOV     R3,#14                  ;Antialias lots and lots
+               SWI     ColourTrans_SetFontColours
+
+               ; --- Work out where to paint the text ---
+
+               ADD     R3,R6,#20               ;Point to the coordinates
+               LDMIA   R3,{R3,R4}              ;Load the coordinates out
+               LDR     R5,[R10,#0]             ;Load the scale factor out
+               MOV     R5,R5,LSR #8            ;Scale it down a little
+               MUL     R3,R5,R3                ;Multiply up the x position
+               MUL     R4,R5,R4                ;Multiply up the y position
+               MOV     R3,R3,ASR #16           ;Scale down the x position
+               MOV     R4,R4,ASR #16           ;Scale down the y position
+               ADD     R1,R10,#16              ;Point to the plot offset
+               LDMIA   R1,{R1,R2}              ;Load the offsets out
+               ADD     R3,R3,R1,ASR #8         ;Add it on (convert to OS)
+               ADD     R4,R4,R2,ASR #8         ;Convert the y coordinate too
+
+               ; --- Paint the actual text then ---
+
+               ADD     R1,R6,#28               ;Point to the text string
+               MOV     R2,#&10                 ;Coordinates are in OS units
+               SWI     Font_Paint              ;Paint the text on the screen
+
+               ; --- Tidy everything up then ---
+
+               SWI     Font_LoseFont           ;Lose the font handle now
+               B       draw__next              ;Find next draw object
+
+               LTORG
+
+; --- draw__renderSystemText ---
+;
+; Notes:       This routine is entered with R6 set up as pointer to the
+;              specific object data, and havng made sure that the text
+;              actually does have to be rendered.
+
+draw__renderSystemText ROUT
+
+               ; --- Set up the plotting colour ---
+
+               STMFD   R13!,{R14}              ;Save the link register
+               LDR     R0,[R6,#0]              ;Load the foreground colour
+               MOV     R3,#0                   ;Don't bother dithering it
+               MOV     R4,#0                   ;And set normal GCOL action
+               SWI     ColourTrans_SetGCOL     ;Set up the colour
+
+               ; --- Set up the text size ---
+
+               BL      screen_getInfo          ;Get things about the screen
+               LDMIA   R0,{R2,R3}              ;Load the eigen factors
+               ADD     R14,R6,#12              ;Point to the size arguments
+               LDMIA   R14,{R0,R1}             ;Load the text sizes out
+               LDR     R4,[R10,#0]             ;Load the scale factor
+               MOV     R4,R4,LSR #8            ;Shift it down a little
+               MUL     R0,R4,R0                ;Multiply x size up
+               MUL     R1,R4,R1                ;Multiply y size up too
+               MOV     R0,R0,LSR #16           ;Scale x size down more
+               MOV     R0,R0,LSR R2            ;And divide by pixel size
+               MOV     R1,R1,LSR #16           ;Scale y size down more
+               MOV     R1,R1,LSR R3            ;And divide by pixel size
+               BL      draw__setTextSize       ;Set the VDU 5 text size
+               MOV     R3,R1,LSL R3            ;Multply y size up a bit
+
+               ; --- Move to the right place ---
+
+               ADD     R14,R6,#20              ;Point to the position data
+               LDMIA   R14,{R1,R2}             ;Load the text positions
+               MUL     R1,R4,R1                ;Scale up the x position
+               MUL     R2,R4,R2                ;Scale up the y position
+               MOV     R1,R1,ASR #16           ;Scale down the x pos
+               MOV     R2,R2,ASR #16           ;Scale down the y pos
+               SUB     R3,R3,R3,LSR #3         ;Find 7/8 of character height
+               ADD     R2,R2,R3                ;Find top of text line
+               ADD     R14,R10,#16             ;Find render offsets nicely
+               LDMIA   R14,{R3,R4}             ;Load the offsets out
+               ADD     R1,R1,R3,ASR #8         ;Add them and convert to OS
+               ADD     R2,R2,R4,ASR #8         ;Both the x and the y please
+               MOV     R0,#4                   ;Move cursor absolute
+               SWI     OS_Plot                 ;Move graphics cursor nicely
+
+               ; --- Plot the text and go home ---
+
+               ADD     R0,R6,#28               ;Point to the text string
+               SWI     OS_Write0               ;Plot it on the screen
+               LDMFD   R13!,{R14}              ;Unstack the link register
+               B       draw__next              ;And move to the next object
+
+               LTORG
+
+; --- draw__renderPath ---
+
+draw__renderPath ROUT
+
+               STMFD   R13!,{R14}              ;Save the link temporarily
+               BL      draw__clip              ;Do we have to render it?
+               LDMCCFD R13!,{R14}              ;Restore the link again
+               BCC     draw__next              ;No -- then return
+
+               LDR     R6,[R7,#36]             ;Load the path style word
+               TST     R6,#&80                 ;Is there a dot-dash pattern?
+               ADDEQ   R5,R7,#40               ;No -- find path data then
+               LDRNE   R5,[R7,#44]             ;Yes -- load dot-dash length
+               ADDNE   R5,R7,R5,LSL #2         ;Add this to object start
+               ADDNE   R5,R5,#48               ;And add fixed part of dash
+
+               ; --- Handle the filled in bit ---
+
+               LDR     R0,[R7,#24]             ;Load the fill colour
+               CMP     R0,#-1                  ;Is it transparent?
+               BEQ     %50draw__renderPath     ;Yes -- just draw outline
+
+               ; --- Render a filled path ---
+
+               MOV     R3,#&100                ;Try and dither the fill
+               MOV     R4,#0                   ;Set normal GCOL action
+               SWI     ColourTrans_SetGCOL     ;Set the colour up
+
+               MOV     R0,#&c80000             ;The basic flatness is 200
+               LDR     R1,[R10,#0]             ;Load the scale factor
+               BL      div_round               ;Divide to get the flatness
+               MOV     R3,R0                   ;Get flatness in R3 nicely
+
+               AND     R1,R6,#&40              ;Get the path winding rule
+               MOV     R1,R1,LSR #5            ;Shift it down into place
+               ORR     R1,R1,#&30              ;And add in other fill bits
+               MOV     R0,R5                   ;Point to path specification
+               MOV     R2,R10                  ;Point to transform matrix
+               SWI     Draw_Fill               ;And render the filled path
+
+               ; --- Now handle an outline ---
+
+50             LDR     R0,[R7,#28]             ;Load the outline colour
+               CMP     R0,#-1                  ;Is it transparent?
+               BEQ     %90draw__renderPath     ;Yes -- wrap everything up
+
+               ; --- Render a path outline ---
+
+               MOV     R3,#&100                ;Try and dither the outline
+               MOV     R4,#0                   ;Set normal GCOL action
+               SWI     ColourTrans_SetGCOL     ;Set the colour up
+
+               ; --- Build the cap and join block ---
+               ;
+               ; Note that in fact the end cap and start cap specs are
+               ; reversed.  This is a result of Acorn stupidity, bad
+               ; documentation, or both.  We sit back and laugh as
+               ; WimpExtension gets it wrong.
+
+               AND     R0,R6,#&03              ;Get the join style style
+               AND     R4,R6,#&30              ;Get the start cap style
+               ORR     R0,R0,R4,LSL #12        ;Move that into byte 2
+               AND     R4,R6,#&0C              ;Get the end cap style
+               ORR     R0,R0,R4,LSL #6         ;Move that into byte 1
+
+               MOV     R1,#&A0000              ;Mitre limit is 10.0
+
+               AND     R2,R6,#&00FF0000        ;Get triangle cap width
+               MOV     R2,R2,LSR #12           ;Move it into position
+               AND     R4,R6,#&FF000000        ;Get triangle cap height
+               ORR     R2,R2,R4,LSR #4         ;Move that into position
+
+               MOV     R3,R2                   ;End triangle == start one
+
+               STMFD   R13!,{R0-R3}            ;Save cap and join spec
+
+               ; --- Finally, plot the path ---
+
+               MOV     R0,#&c80000             ;The basic flatness is 200
+               LDR     R1,[R10,#0]             ;Load the scale factor
+               BL      div_round               ;Divide to get the flatness
+               MOV     R3,R0                   ;Get flatness in R3 nicely
+               MOV     R0,R5                   ;Point to the path spec
+               MOV     R1,#&38                 ;A set fill style, please
+               MOV     R2,R10                  ;Point to transform matrix
+               LDR     R4,[R7,#32]             ;Load the line width
+               MOV     R5,R13                  ;Point to join and cap block
+               TST     R6,#&80                 ;Is there a dash pattern?
+               MOVEQ   R6,#0                   ;No -- don't plot one then
+               ADDNE   R6,R7,#40               ;Yes -- find the data
+               SWI     Draw_Stroke             ;Plot the path outline
+               ADD     R13,R13,#16             ;Recover used stack space
+
+               ; --- Wrap it all up nicely ---
+
+90             LDMFD   R13!,{R14}              ;Restore the link again
+               B       draw__next              ;Find the next draw object
+
+               LTORG
+
+; --- draw__renderSprite ---
+
+draw__renderSprite ROUT
+
+               ; --- Make sure I have to render it ---
+
+               STMFD   R13!,{R14}              ;Save the link temporarily
+               BL      draw__clip              ;Do we have to render it?
+               LDMCCFD R13!,{R14}              ;Restore the link again
+               BCC     draw__next              ;No -- then return
+
+               ; --- Get a colour translation table for it ---
+
+               ADD     R0,R7,#24               ;Point to the sprite def
+               MOV     R1,R11                  ;Put table in scratchpad
+               BL      sprite_getTable         ;Find a translation table
+
+               ; --- Work out the correct scaling ---
+
+               MOV     R0,#40                  ;Read sprite info
+               ADD     R0,R0,#512              ;Sprite is pointed at
+               MOV     R1,#&1000               ;Don't care about sprite area
+               ADD     R2,R7,#24               ;Point to sprite block
+               SWI     OS_SpriteOp             ;Read the sprite info
+               BL      screen_getInfo          ;Read some screen info
+               LDMIA   R0,{R0,R1}              ;Load the eigen factors
+               MOV     R5,R4,LSL R1            ;Scale the y value into R5
+               MOV     R4,R3,LSL R0            ;Scale the x value into R4
+
+               ADD     R0,R7,#8                ;Point to sprite bounding box
+               LDMIA   R0,{R0-R3}              ;Load the values out
+               SUB     R2,R2,R0                ;Get sprite width in R2
+               SUB     R3,R3,R1                ;Get sprite height in R3
+               MOV     R2,R2,LSR #8            ;Scale the dimensions down
+               MOV     R3,R3,LSR #8            ;In both directions
+               LDR     R14,[R10,#0]            ;Load the scale factor
+               MUL     R2,R14,R2               ;Scale the x size
+               MUL     R3,R14,R3               ;And the y size
+               MOV     R2,R2,LSR #16           ;And scale the value down
+               MOV     R3,R3,LSR #16           ;Both directions again
+               STMFD   R13!,{R2-R5}            ;Save the resulting zoom blk
+
+               MOV     R14,R14,LSR #8          ;Shift scale factor down
+               MUL     R3,R14,R0               ;Scale the x position
+               MUL     R4,R14,R1               ;And the y position
+               MOV     R3,R3,ASR #16           ;Scale down the resulting pos
+               MOV     R4,R4,ASR #16           ;In both directions
+               ADD     R0,R10,#16              ;Find the transform offsets
+               LDMIA   R0,{R0,R1}              ;Load them from the block
+               ADD     R3,R3,R0,ASR #8         ;Add the x offset on
+               ADD     R4,R4,R1,ASR #8         ;Add the y offset on too
+
+               ; --- Now plot the sprite in the right place ---
+
+               STMFD   R13!,{R7}               ;Save R7 -- we need to use it
+               MOV     R0,#52                  ;Plot sprite scaled, please
+               ADD     R0,R0,#512              ;Tell it I have a sprite ptr
+               MOV     R1,#&1000               ;A dummy sprite area
+               ADD     R2,R7,#24               ;Point to the sprite def
+               MOV     R5,#8                   ;Plot with mask, please
+               ADD     R6,R13,#4               ;Point to my zoom block
+               MOV     R7,R11                  ;Point to my translate table
+               SWI     OS_SpriteOp             ;Plot the sprite
+               LDMFD   R13!,{R7}               ;Unstack R7 again
+               ADD     R13,R13,#16             ;Recover the zoom block
+               LDMFD   R13!,{R14}              ;Unstack the link register
+               B       draw__next              ;And render the next object
+
+               LTORG
+
+; --- draw__renderGroup ---
+
+draw__renderGroup ROUT
+
+               STMFD   R13!,{R14}              ;Save the link temporarily
+               BL      draw__clip              ;Do we have to render it?
+               LDMFD   R13!,{R14}              ;Restore the link again
+               BCC     draw__next              ;No -- then return
+
+               ADD     R7,R7,#36               ;Render the objects in there
+               MOVS    PC,R14                  ;I've mangled the object ptr
+
+               LTORG
+
+; --- draw__renderTagged ---
+
+draw__renderTagged ROUT
+
+               STMFD   R13!,{R14}              ;Save the link temporarily
+               BL      draw__clip              ;Do we have to render it?
+               LDMCCFD R13!,{R14}              ;Restore the link again
+               BCC     draw__next              ;No -- then return
+
+               STMFD   R13!,{R7,R8}            ;Save the object pointer
+               ADD     R7,R7,#28               ;Point to the enclosed object
+               LDR     R8,[R7,#4]              ;Get the object size
+               ADD     R8,R7,R8                ;Point past the object
+               BL      draw__doRender          ;Render the object
+               LDMFD   R13!,{R7,R8,R14}        ;Restore registers
+               B       draw__next              ;And move to the next object
+
+               LTORG
+
+; --- draw__renderTransformedText ---
+
+draw__renderTransformedText ROUT
+
+               STMFD   R13!,{R14}              ;Save the link temporarily
+               BL      draw__clip              ;Do we have to render it?
+               BLCS    rov_version             ;Get the current OS version
+               CMPCS   R0,#300                 ;Is it RISC OS 3 yet?
+               LDMFD   R13!,{R14}              ;Restore the link again
+               BCC     draw__next              ;No -- then return
+
+               ; --- Make sure the text isn't invisible ---
+
+               ADD     R6,R7,#24               ;Point to the object data
+               LDR     R0,[R6,#0]              ;Load the foreground colour
+               CMP     R0,#-1                  ;Is it transparent?
+               MOVEQS  PC,R14                  ;Yes -- do nothing then
+
+               ; --- Find the font name ---
+
+               LDR     R5,[R6,#36]             ;Load internal font handle
+               CMP     R5,#0                   ;Is the handle 0?
+               BEQ     %90draw__renderTransformedText
+               LDR     R5,[R12,R5,LSL #2]      ;Load the font name pointer
+               CMP     R5,#0                   ;Is it defined?
+               BEQ     %90draw__renderTransformedText
+
+               ; --- Work out the text size I need ---
+
+               STMFD   R13!,{R14}              ;Save the link again
+               ADD     R2,R6,#40               ;Point to the text sizes
+               LDMIA   R2,{R2,R3}              ;Load x and y sizes
+               LDR     R4,[R10,#0]             ;Load the scale factor
+               MOV     R4,R4,LSR #8            ;Scale it down a little
+               MUL     R2,R4,R2                ;Scale up the x size
+               MUL     R3,R4,R3                ;And scale up the y size
+               MOV     R4,#5                   ;So div10 rounds to nearest
+               ADD     R2,R4,R2,LSR #10        ;Scale values down further
+               ADD     R3,R4,R3,LSR #10        ;Both the x and the y
+               MOV     R0,R2                   ;Get the x size
+               BL      div10                   ;Convert to points
+               MOV     R2,R0                   ;Move back into position
+               MOV     R0,R3                   ;Get the y size
+               BL      div10                   ;Convert to points
+               MOV     R3,R0                   ;Move back into position
+               LDMFD   R13!,{R14}              ;Restore the link again
+
+               ; --- Get a font handle ---
+
+               MOV     R1,R5                   ;Get the font name pointer
+               MOV     R4,#0                   ;Default scaling, please
+               MOV     R5,#0                   ;On x and y axes
+               SWI     XFont_FindFont          ;Try to get a font handle
+               BVS     %90draw__renderTransformedText
+
+               ; --- Set the right colours ---
+
+               LDR     R1,[R6,#32]             ;Load the background colour
+               LDR     R2,[R6,#28]             ;Load the foreground colour
+               MOV     R3,#14                  ;Antialias lots and lots
+               SWI     ColourTrans_SetFontColours
+
+               ; --- Work out where to paint the text ---
+
+               ADD     R3,R6,#48               ;Point to the coordinates
+               LDMIA   R3,{R3,R4}              ;Load the coordinates out
+               LDR     R5,[R10,#0]             ;Load the scale factor out
+               MOV     R5,R5,LSR #8            ;Scale it down a little
+               MUL     R3,R5,R3                ;Multiply up the x position
+               MUL     R4,R5,R4                ;Multiply up the y position
+               MOV     R3,R3,ASR #16           ;Scale down the x position
+               MOV     R4,R4,ASR #16           ;Scale down the y position
+               ADD     R1,R10,#16              ;Point to the plot offset
+               LDMIA   R1,{R1,R2}              ;Load the offsets out
+               ADD     R3,R3,R1,ASR #8         ;Add it on (convert to OS)
+               ADD     R4,R4,R2,ASR #8         ;Convert the y coordinate too
+
+               ; --- Scale position to millipoints ---
+               ;
+               ; Multiply by 500 (very quickly)
+
+               ADD     R3,R3,R3,LSL #2         ;Multiply R3 by 5 (*5)
+               ADD     R3,R3,R3,LSL #2         ;Multiply R3 by 5 (*25)
+               MOV     R3,R3,LSL #4            ;Multiply R3 by 16 (*400)
+
+               ADD     R4,R4,R4,LSL #2         ;Multiply R3 by 5 (*5)
+               ADD     R4,R4,R4,LSL #2         ;Multiply R3 by 5 (*25)
+               MOV     R4,R4,LSL #4            ;Multiply R3 by 16 (*400)
+
+               ; --- Paint the actual text then ---
+
+               ADD     R1,R6,#56               ;Point to the text string
+               LDR     R2,[R6,#24]             ;Load the special magic flags
+               MOV     R2,R2,LSL #9            ;Shift flags into position
+               ORR     R2,R2,#&40              ;Specify transform matrix
+               STMFD   R13!,{R0}               ;Save the font handle
+               SWI     XFont_Paint             ;Paint the text on the screen
+               LDMFD   R13!,{R0}               ;Restore the font handle
+
+               ; --- Tidy everything up then ---
+
+               SWI     Font_LoseFont           ;Lose the font handle now
+90             B       draw__next              ;Find next draw object
+
+               LTORG
+
+; --- draw__renderTransformedSprite ----
+
+draw__renderTransformedSprite ROUT
+
+               ; --- Make sure I have to render it ---
+
+               STMFD   R13!,{R14}              ;Save the link temporarily
+               BL      draw__clip              ;Do we have to render it?
+               BLCS    rov_version             ;Get the current OS version
+               CMPCS   R0,#300                 ;Is it RISC OS 3 yet?
+               LDMCCFD R13!,{R14}              ;Restore the link again
+               BCC     draw__next              ;No -- then return
+
+               ; --- Get a colour translation table for it ---
+
+               ADD     R0,R7,#48               ;Point to the sprite def
+               MOV     R1,R11                  ;Put table in scratchpad
+               BL      sprite_getTable         ;Find a translation table
+
+               ; --- Build the transformation matrix ---
+
+               ADD     R14,R7,#24              ;Find the transform matrix
+               LDMIA   R14,{R0-R5}             ;Load all the bits I need
+               LDR     R6,[R10,#0]             ;Load the scale factor
+               MOV     R6,R6,LSR #8            ;Shift scale factor down
+               MOV     R0,R0,ASR #8            ;Also shift down sprite scale
+               MOV     R1,R1,ASR #8            ;Also shift down sprite scale
+               MOV     R2,R2,ASR #8            ;Also shift down sprite scale
+               MOV     R3,R3,ASR #8            ;Also shift down sprite scale
+               MUL     R0,R6,R0                ;Apply scale to sprite matrix
+               MUL     R1,R6,R1                ;Apply scale to sprite matrix
+               MUL     R2,R6,R2                ;Apply scale to sprite matrix
+               MUL     R3,R6,R3                ;Apply scale to sprite matrix
+               SUB     R13,R13,#24             ;Make space for matrix
+               STMIA   R13,{R0-R3}             ;Save transform on stack
+               ADD     R14,R10,#16             ;Point to my offsets
+               LDMIA   R14,{R0,R1}             ;Load the offsets out
+               MUL     R4,R6,R4                ;Scale the sprite x offset
+               MUL     R5,R6,R5                ;Scale the sprite y offset
+               ADD     R4,R0,R4,ASR #8         ;Add on to original offset
+               ADD     R5,R1,R5,ASR #8         ;Add on to original offset
+               ADD     R14,R13,#16             ;Point to bit of matrix
+               STMIA   R14,{R4,R5}             ;Save these in the matrix
+
+               ; --- Now plot the sprite in the right place ---
+
+               STMFD   R13!,{R7}               ;Save R7 -- we need to use it
+               MOV     R0,#56                  ;Plot sprite scaled, please
+               ADD     R0,R0,#512              ;Tell it I have a sprite ptr
+               MOV     R1,#&1000               ;A dummy sprite area
+               ADD     R2,R7,#48               ;Point to the sprite def
+               MOV     R3,#0                   ;R6 points to a matrix
+               MOV     R4,#0                   ;No source rectangle thing
+               MOV     R5,#8                   ;Plot with mask, please
+               ADD     R6,R13,#4               ;Point to my matrix
+               MOV     R7,R11                  ;Point to my translate table
+               SWI     OS_SpriteOp             ;Plot the sprite
+               LDMFD   R13!,{R7}               ;Unstack R7 again
+               ADD     R13,R13,#24             ;Recover the matrix block
+               LDMFD   R13!,{R14}              ;Unstack the link register
+               B       draw__next              ;And render the next object
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/dynPtr b/StraySrc/Libraries/Sapphire/s/dynPtr
new file mode 100644 (file)
index 0000000..28ce78f
--- /dev/null
@@ -0,0 +1,198 @@
+;
+; dynPtr.s
+;
+; Dynamic pointer changing (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:ptr
+               GET     sapphire:resspr
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- dynPtr_change ---
+;
+; On entry:    R0 == pointer to string to use
+;              R1 == pointer to pointer name
+;              R2 == x hot spot
+;              R3 == y hot spot
+;
+; On exit:     --
+;
+; Use:         Attaches a string to the default pointer shape.
+
+               EXPORT  dynPtr_change
+dynPtr_change  ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Stack some registers
+
+               MOV     R9,R0                   ;Remember this pointer
+
+               ; --- Output VDU operations to our sprite ---
+
+               BL      resspr_area             ;Get the address
+               MOV     R8,R0                   ;Remember this
+               MOV     R1,R0                   ;Put that in R1
+               MOV     R0,#60+256              ;Output to a sprite
+               ADR     R2,dynPtr__blank        ;To this sprite please
+               MOV     R3,#0                   ;No save area
+               SWI     OS_SpriteOp             ;Okay dokay
+               STMFD   R13!,{R0-R3}            ;For the reversal operation
+
+               ; --- Clear the background ---
+
+               SWI     OS_WriteI+16            ;CLG (Me... cheat?)
+
+               ; --- Copy the default pointer into our sprite ---
+
+               BL      resspr_area             ;Get callers sprite area
+               MOV     R1,R0                   ;Put it in R1
+               MOV     R0,#256                 ;Use area pointer
+               ADD     R0,R0,#40               ;Get info
+               LDR     R2,[R13,#20]            ;Load the name ptr
+               SWI     XOS_SpriteOp            ;Try it then
+               MOVVS   R0,#40                  ;If no go -- try WIMP area
+               SWIVS   Wimp_SpriteOp           ;Get the info
+
+               MOV     R0,R6                   ;The screen mode
+               MOV     R1,#4                   ;XEig factor
+               SWI     OS_ReadModeVariable     ;Read it now
+               MOV     R5,R2                   ;Remember this
+               MOV     R1,#5                   ;YEig factor
+               SWI     OS_ReadModeVariable     ;Read it now
+
+               MOV     R14,#1                  ;Get a nice unit value
+               MOV     R0,R14,LSL R5           ;Turn it into a useful value
+               MOV     R1,R14,LSL R2           ;This one too
+               SUB     R13,R13,#16             ;Get a block
+               MOV     R14,R13                 ;Remember this value
+               STMIA   R14!,{R0,R1}            ;Put this in the block
+               MOV     R0,#2                   ;XEig of our sprite
+               MOV     R1,#2                   ;YEig of our sprite
+               STMIA   R14!,{R0,R1}            ;Put this in the block too
+
+               MOV     R4,R4,LSL R2            ;Height in OS pixels
+               RSB     R4,R4,#64               ;Plot it here please
+               MOV     R3,#0                   ;And here too
+               MOV     R5,#&08                 ;Plot action
+               MOV     R6,R13                  ;Point to the block
+               MOV     R7,#0                   ;No translation table
+               LDR     R2,[R13,#36]            ;Load the name ptr
+               BL      resspr_area             ;Get callers sprite area
+               MOV     R1,R0                   ;Put it in R1
+               MOV     R0,#256                 ;Use area pointer
+               ADD     R0,R0,#52               ;Plot scaled
+               SWI     XOS_SpriteOp            ;Try it then
+               MOVVS   R0,#52                  ;If no go -- try WIMP area
+               SWIVS   Wimp_SpriteOp           ;Plot it
+               ADD     R13,R13,#12             ;Mark remembered it!!!
+
+               ; --- Now work out the width of the text ---
+
+               MOV     R7,#2                   ;Width so far
+               MOV     R14,#0                  ;A NULL word
+               STRB    R14,[R13,#1]            ;A NULL terminated string!
+               MOV     R14,R9                  ;Point to the string
+               MOV     R1,R8                   ;The sprite area
+               MOV     R0,#40+256              ;Sprite info
+               MOV     R2,R13                  ;Point to our name buffer
+10dynPtr_change        LDRB    R3,[R14],#1             ;Load out a character
+               CMP     R3,#32                  ;Is it a control character
+               BLT     %20dynPtr_change        ;Yes -- skip out of loop
+               STRB    R3,[R2]                 ;Store in my block
+               SWI     OS_SpriteOp             ;Get the width
+               ADD     R7,R7,R3,LSL #1         ;Add on the width
+               ADD     R7,R7,#2                ;Don't forget the gap
+               B       %10dynPtr_change        ;Keep on looping
+
+               ; --- Do a background rectangle ---
+
+20dynPtr_change        SWI     OS_WriteI+18            ;Change colour
+               SWI     OS_WriteI+0             ;Still doing it
+               SWI     OS_WriteI+1             ;Ahhh... this is the colour
+               MOV     R0,#4                   ;Do a move absolute
+               MOV     R1,#0                   ;Start at the left
+               MOV     R2,#0                   ;Bottom left
+               SWI     OS_Plot                 ;Move to the point
+               MOV     R0,#101                 ;Rectangle fill
+               MOV     R1,R7                   ;The width
+               MOV     R2,#26                  ;Draw it this high
+               SWI     OS_Plot                 ;Fill in the rectangle
+
+               ; --- Now plot the string ---
+
+               MOV     R0,#1                   ;Don't scale horizontally
+               MOV     R1,#2                   ;Double height
+               MOV     R2,#1                   ;Don't divide
+               MOV     R3,#1                   ;No, not at all
+               STMFD   R13!,{R0-R3}            ;Save the scale factors
+               MOV     R1,R8                   ;Point to the sprite area
+               ADD     R2,R13,#16              ;Point to sprite names
+               MOV     R10,#2                  ;Current x position
+
+30dynPtr_change        LDRB    R14,[R9],#1             ;Get byte from string
+               CMP     R14,#32                 ;Is it the end?
+               BLO     %40dynPtr_change        ;Yes -- skip to the end then
+
+               STRB    R14,[R2]                ;Save the sprite name
+               MOV     R0,#52+256              ;Plot sprite scaled, please
+               MOV     R3,R10                  ;Get x position
+               MOV     R4,#4                   ;And a little bit up
+               MOV     R5,#0                   ;No GCOL action
+               MOV     R6,R13                  ;Point to scale factors
+               MOV     R7,#0                   ;No translate table please
+               SWI     OS_SpriteOp             ;Plot the sprite nicely
+
+               MOV     R0,#40+256              ;Get sprite information
+               SWI     OS_SpriteOp             ;Read the sprite information
+               ADD     R10,R10,R3,LSL #1       ;Add on the sprite's width
+               ADD     R10,R10,#2              ;And a little bit of space
+               B       %30dynPtr_change        ;And go round for more
+
+               ; --- Reset screen context, set shape and return ---
+
+40dynPtr_change        ADD     R13,R13,#20             ;Reset the stack pointer
+               LDMFD   R13!,{R0-R3}            ;Load back the context
+               SWI     OS_SpriteOp             ;Back to the screen please
+
+               ADR     R0,dynPtr__blank        ;Point to the sprite name
+               ADD     R14,R13,#8              ;Point to the hot spot values
+               LDMIA   R14,{R1,R2}             ;Lad them out
+               BL      ptr_setShape            ;And set the pointer
+               LDMFD   R13!,{R0-R10,PC}^       ;Ta-da!  Return to caller
+
+dynPtr__blank  DCB     "ptr_blank",0,0,0
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/errorBox b/StraySrc/Libraries/Sapphire/s/errorBox
new file mode 100644 (file)
index 0000000..b1e9939
--- /dev/null
@@ -0,0 +1,303 @@
+;
+; errorBox.s
+;
+; Reports errors in an error box (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:buttons
+               GET     sapphire:dbox
+               GET     sapphire:msgs
+               GET     sapphire:nopoll
+               GET     sapphire:sapphire
+               GET     sapphire:string
+               GET     sapphire:template
+               GET     sapphire:wimp
+
+;----- Icon numbers ---------------------------------------------------------
+
+ebIcon__title  EQU     3
+ebIcon__error  EQU     4
+ebIcon__buttons        EQU     5
+
+eb__buts       EQU     4
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- errorBox_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Initialises the errorBox system nicely.  It creates the
+;              dialogue box now, and just uses it for the rest of the
+;              time.
+
+               EXPORT  errorBox_init
+errorBox_init  ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Save some registers
+               WSPACE  eb__wSpace              ;Load my workspace pointer
+
+               ; --- Am I running yet? ---
+
+               LDR     R14,eb__dbox            ;Load the dialogue box handle
+               CMP     R14,#0                  ;Has it been defined yet?
+               LDMNEFD R13!,{R0-R3,R12,PC}^    ;Yes -- return right now
+
+               ; --- Initialise other useful things ---
+
+               BL      wimp_init               ;Initialise the WindowMangler
+               BL      template_init           ;Load lots of templates
+               BL      dbox_init               ;Allow me to make dboxes
+               BL      nopoll_init             ;I'll want to use nopoll too
+
+               ; --- Create my dialogue box ---
+
+               ADR     R0,eb__dbName           ;Point to the dialogue name
+               BL      dbox_create             ;Create the dialogue box
+               SWIVS   OS_GenerateError        ;If it failed, abort nastily
+               STR     R0,eb__dbox             ;Store the handle away
+
+               ; --- Fill in the dialogue box title ---
+
+               ADR     R0,eb__errorFrom        ;Point to the skeleton
+               BL      msgs_lookup             ;Translate the string
+               MOV     R1,R11                  ;Fill it in the scratchpad
+               LDR     R2,[R13,#0]             ;Find the application name
+               BL      str_subst               ;Substitute the string then
+               MOV     R2,R0                   ;Point to the string
+               LDR     R0,eb__dbox             ;Get the dialogue handle
+               MOV     R1,#-1                  ;Fill in the title bar
+               BL      dbox_setField           ;Actually write the string
+
+               ; --- Set up the rest of the dialogue box ---
+
+               MOV     R1,#ebIcon__title       ;Icon for the embedded title
+               BL      dbox_setEmbeddedTitle   ;Set up the embedded title
+               ADR     R1,eb__dbHandler        ;Point to my event handler
+               MOV     R2,R0                   ;Pass dbox handle in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      dbox_eventHandler       ;Set up the event handler
+
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;Return to the caller
+
+eb__dbName     DCB     "error",0
+eb__errorFrom  DCB     "ebERRFRM",0
+
+               LTORG
+
+eb__wSpace     DCD     0
+
+; --- eb__dbHandler ---
+;
+; On entry:    R0 == reason code
+;              R1-... dependant on reason code
+;              R10 == dialogue box handle
+;              R12 == pointer to workspace
+;
+; On exit:     Registers preserved
+;
+; Use:         Handles events for the error box
+
+eb__dbHandler  ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               CMP     R0,#dbEvent_OK          ;Is it a return press?
+               MOVEQ   R0,#ebIcon__buttons     ;Yes -- use the default
+               CMP     R0,#dbEvent_cancel      ;Is it a cancel?
+               LDREQ   R0,eb__cancel           ;Yes -- load the button
+               CMPEQ   R0,#-1                  ;Was that defined?
+               MOVEQ   R0,#ebIcon__buttons     ;No -- use default here too
+
+               SUB     R14,R0,#ebIcon__buttons ;Get the button index
+               CMP     R14,#eb__buts           ;Is it in range?
+               LDMCSFD R13!,{PC}^              ;No -- return
+
+               STMFD   R13!,{R0,R1}            ;Save some more registers
+               LDR     R1,eb__butFlags         ;Which buttons are there?
+               MOV     R14,#1                  ;Use a bit to test
+               TST     R1,R14,LSL R0           ;Test the correct bit
+               LDMEQFD R13!,{R0,R1,PC}^        ;Not created -- return
+
+               MOV     R1,R0                   ;Put icon into R1
+               LDR     R0,eb__dbox             ;Find the dialogue handle
+               BL      dbox_slab               ;Slab the icon in
+               BL      dbox_close              ;Close the window
+               BL      dbox_unslab             ;Unslab the icon cunningly
+               MOV     R0,R1                   ;Return the icon number
+               BL      nopoll_close            ;Return that to errorBox
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+; --- errorBox_beep ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sounds the bell (VDU 7) if the CMOS settings dictate that
+;              error boxes should cause a beep.
+
+               EXPORT  errorBox_beep
+errorBox_beep  ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R0,#161                 ;Read CMOS locations nicely
+               MOV     R1,#197                 ;Read WimpFlags location
+               SWI     OS_Byte                 ;Do the read operation
+               TST     R2,#1<<4                ;Do we make noises then?
+               SWIEQ   OS_WriteI+7             ;Yes -- bleep
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- errorBox ---
+;
+; On entry:    R0 == pointer to error block
+;              R1 == button style code, or pointer to buttons block
+;
+; On exit:     R0 == icon number clicked (ordered from the right)
+;              CS if R0 == 0, else CC
+;
+; Use:         Displays an error box on the screen.  The error block
+;              doesn't have to have a sensible error number, and doesn't
+;              have to be word aligned, either.
+;
+;              Since errorBox claims a dialogue box handle on
+;              initialisation, it isn't possible for this call to fail.
+;              Hence it is ideal for reporting problems like `Out of
+;              memory' or `Too many windows'.
+;
+;              The buttons in the error box may be given either by a code
+;              or by a pointer to a buttons block (these may easily be
+;              distinguished, since the codes are lower than &8000).
+;
+;              Standard button arrangements are given by codes, as follows:
+;
+;              0 == Cancel
+;              1 == OK
+;              2 == OK, Cancel
+;              4 == OK, Help
+;              5 == OK, Cancel, Help
+
+               EXPORT  errorBox
+errorBox       ROUT
+
+               STMFD   R13!,{R1-R4,R12,R14}    ;Save some registers away
+               WSPACE  eb__wSpace              ;Find my workspace address
+               MOV     R4,R0                   ;Look after error pointer
+               LDR     R0,eb__dbox             ;Load the dbox handle
+
+               ; --- Deal with button codes ---
+
+               CMP     R1,#eb__endButs-eb__stdButs
+               ADRCC   R14,eb__stdButs         ;If it's a code, find the tbl
+               LDRCCB  R1,[R14,R1]             ;Load the offset of the block
+               ADDCC   R1,R14,R1               ;And find the button block
+
+               ; --- Set up the buttons ---
+
+               MOV     R2,#ebIcon__buttons     ;Find icon base
+               MOV     R3,#eb__buts            ;Get the number allowed
+               BL      buttons_setup           ;Set up the dialogue box
+               STR     R2,eb__butFlags         ;Save the button flags
+               STR     R3,eb__cancel           ;Save the cancel button
+
+               ; --- Set the string in the dbox ---
+
+               MOV     R1,#ebIcon__error       ;The right icon for the job
+               ADD     R2,R4,#4                ;Find the error string
+               BL      dbox_setField           ;Write the string in nicely
+
+               ; --- Display the dialogue ---
+
+               BL      errorBox_beep           ;Sound the bell if we need to
+               MOV     R1,#dbOpen_centre+dbOpen_persist+dbOpen_nonSub
+               BL      dbox_open               ;Open centred on the screen
+
+               ; --- Handle the dialogue properly ---
+
+               BL      dbox_window             ;Find the window handle again
+               BL      nopoll_open             ;Stop polling for a while
+               BL      nopoll_process          ;Let nopoll take over
+               LDMFD   R13!,{R1-R4,R12,R14}    ;Return to caller
+               SUBS    R0,R0,#ebIcon__buttons  ;Was it the default?
+               ORREQS  PC,R14,#C_flag          ;Yes -- set C on exit
+               BICNES  PC,R14,#C_flag          ;No -- clear C then
+
+eb__stdButs    DCB     eb__type0-eb__stdButs
+               DCB     eb__type1-eb__stdButs
+               DCB     eb__type2-eb__stdButs
+               DCB     eb__type3-eb__stdButs
+               DCB     eb__type4-eb__stdButs
+eb__endButs
+
+eb__type1      BOK
+               BUTEND
+eb__type2      BOK
+eb__type0      BCANCEL
+               BUTEND
+eb__type3      BOK
+               BHELP
+               BUTEND
+eb__type4      BOK
+               BCANCEL
+               BHELP
+               BUTEND
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+eb__wStart     #       0
+
+eb__dbox       #       4                       ;The dialogue box handle
+eb__cancel     #       4                       ;The cancel button, or none
+eb__butFlags   #       4                       ;Which buttons are available
+
+eb__wSize      EQU     {VAR}-eb__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     eb__wSize
+               DCD     eb__wSpace
+               DCD     0
+               DCD     errorBox_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/event b/StraySrc/Libraries/Sapphire/s/event
new file mode 100644 (file)
index 0000000..2399bb7
--- /dev/null
@@ -0,0 +1,401 @@
+;
+; event.s
+;
+; Event handling routines (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:sapphire
+               GET     sapphire:suballoc
+               GET     sapphire:hour
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+               BUFCOPY
+
+               LCLA    counter
+counter                SETA    0
+
+               STMFD   R13!,{R0-R6}
+
+       WHILE counter<8
+
+               LDMIA   R9!,{R0-R6,R14}
+               STMIA   R8!,{R0-R6,R14}
+counter                SETA    counter+1
+
+       WEND
+
+               LDMFD   R13!,{R0-R6}
+
+               MEND
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+
+; --- event__addToList ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R12 value to call routine
+;              R2 == pointer to list head to use
+;
+; On exit:     R0-R1 preserved, unless V set (when R0 points to error)
+;
+; Use:         Adds a rountine to the given list. Later added
+;              routines are called first
+
+event__addToList
+               ROUT
+
+               STMFD   R13!,{R0-R1,R14}        ;Stack some registers
+
+               ; --- Allocate a block ---
+
+               MOV     R0,#list__size          ;Size to allocate
+               BL      sub_alloc               ;Allocate the block
+               BVS     %01                     ;Branch ahead if error
+
+               ; --- Fill the block in ---
+
+               LDR     R1,[R2]                 ;Get the list head
+               STR     R1,[R0,#list__next]     ;Store in next field
+               STR     R0,[R2]                 ;Store new block at head
+
+               LDMFD   R13,{R1,R2}             ;Get parameters
+               STMIB   R0,{R1,R2}              ;Store them in the block
+
+               ; --- And return to user ---
+
+               LDMFD   R13!,{R0-R1,R14}        ;Load back link
+               BICS    PC,R14,#V_flag          ;Return without error
+
+               ; --- Barf if an error occured ---
+
+01             ADD     R13,R13,#4              ;Skip over R0
+               LDMFD   R13!,{R1,R14}           ;Branch if error
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- event_preFilter ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R12 value to call routine
+;
+; On exit:     May return an error
+;
+; Use:         Adds a routine to the pre-filter list. Later added
+;              routines are called first.
+
+               EXPORT  event_preFilter
+event_preFilter        ROUT
+
+               STMFD   R13!,{R2,R10,R14}       ;Save some registers
+
+               ; --- Be careful not to alter flags ---
+
+               WSPACE  event__wSpace,R10       ;Get my workspace pointer
+               ADR     R2,event__preList       ;Get the pre-list pointer
+               BL      event__addToList        ;Add the routine to the list
+               LDMFD   R13!,{R2,R10,PC}        ;Return cunningly
+
+               LTORG
+
+; --- event_fakeHandler ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R12 value to call routine
+;
+; On exit:     May return an error
+;
+; Use:         Adds a routine to the fake handler list. Later added
+;              routines are called first.
+
+               EXPORT  event_fakeHandler
+event_fakeHandler
+               ROUT
+
+               STMFD   R13!,{R2,R10,R14}       ;Save some registers
+
+               ; --- Be careful not to alter flags ---
+
+               WSPACE  event__wSpace,R10       ;Get my workspace pointer
+               ADR     R2,event__fakeList      ;Get the fake-list pointer
+               BL      event__addToList        ;Add the routine to the list
+               LDMFD   R13!,{R2,R10,PC}        ;Return cunningly
+
+               LTORG
+
+; --- event_postFilter ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R12 value to call routine
+;
+; On exit:     May return an error
+;
+; Use:         Adds a routine to the post-poll list. Later added
+;              routines are called first.
+
+               EXPORT  event_postFilter
+event_postFilter
+               ROUT
+
+               STMFD   R13!,{R2,R10,R14}       ;Save some registers
+
+               ; --- Be careful not to alter flags ---
+
+               WSPACE  event__wSpace,R10       ;Get my workspace pointer
+               ADR     R2,event__postList      ;Get the post-list pointer
+               BL      event__addToList        ;Add the routine to the list
+               LDMFD   R13!,{R2,R10,PC}        ;Return cunningly
+
+               LTORG
+
+; --- event_poll ---
+;
+; On entry:    R0 == event mask and flags
+;              R1 == pointer to block to use
+;              R2 == earliest time to return with NULL event
+;              R3 == optional pointer to poll word
+;
+; On exit:     R0 == reason code
+;              CS if the event was claimed, CC otherwise
+;
+; Use:         This call perform a Wimp_Poll, and dispatches events to
+;              interested parties.
+
+               EXPORT  event_poll
+event_poll     ROUT
+
+               STMFD   R13!,{R8-R10,R12,R14}
+               WSPACE  event__wSpace,R10       ;Find my workspace
+
+               ; --- Run through the pre poll list here ---
+
+               ADDS    R0,R0,#0                ;Clear the carry flag
+               LDR     R8,event__preList       ;Get pre-list pointer
+00event_poll   TEQ     R8,#0                   ;Are we at the end
+               BEQ     %05event_poll           ;Yes -- branch ahead
+               LDMIA   R8,{R8,R9,R12}          ;Get list fields
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R9                   ;Branch to client routine
+               BCC     %00event_poll           ;Keep going through list
+
+               ; -- If carry is set, jump the Wimp_Poll & fake list ---
+
+               BCS     %19event_poll           ;Jump ahead
+
+               ; --- If we are faking, do fake like things ---
+
+05event_poll   LDR     R8,event__fakePos       ;Get the current fake pos
+               CMP     R8,#-1                  ;Are there any waiting?
+               BEQ     %10event_poll           ;No -- do the Wimp_Poll
+               MOV     R8,R1                   ;Point to users buffer
+               ADR     R9,event__buffer        ;Point to my buffer
+               BUFCOPY                         ;Copy the event
+               LDR     R0,event__prevR0        ;Get the event type
+               B       %11event_poll           ;Continue with fakes
+
+               ; --- Do the Wimp_Poll ---
+               ;
+               ; Make sure the hourglass goes off during the poll, though
+
+10event_poll   SUB     R13,R13,#8              ;Make space for hourglass blk
+               STMFD   R13!,{R0}               ;Save the event mask
+               ADD     R0,R13,#4               ;Point to the block
+               BL      hour_suspend            ;Turn the hourglass off a bit
+               LDR     R0,[R13,#0]             ;Load the event mask again
+
+               CMP     R2,#0                   ;Are we getting NULLs ASAP
+               SWIEQ   Wimp_Poll               ;Yes -- Normal Poll
+               SWINE   Wimp_PollIdle           ;No -- PollIdle
+
+               STR     R0,[R13,#0]             ;Save the Wimp_Poll reason
+               ADD     R0,R13,#4               ;Point to the block
+               BL      hour_resume             ;Restore the hourglass state
+               LDMFD   R13!,{R0}               ;Restore the reason code
+               ADD     R13,R13,#8              ;And reclaim the stack space
+
+               ; --- Copy over the event ---
+
+               ADR     R8,event__buffer        ;Point to my buffer
+               MOV     R9,R1                   ;Point to users buffer
+               BUFCOPY                         ;Copy the event
+               STR     R0,event__prevR0        ;Remember event type
+
+               ; --- Deal with fake events ---
+
+11event_poll   LDR     R8,event__fakePos       ;Get the fake list
+               CMP     R8,#-1                  ;Is there one?
+               LDREQ   R8,event__fakeList      ;Get fake list if !resuming
+               ADDS    R0,R0,#0                ;Clear the carry flag
+12event_poll   TEQ     R8,#0                   ;Is there a fake handler?
+               MOVEQ   R8,#-1                  ;No more to do
+               BEQ     %13event_poll           ;No -- Scan filters
+               LDMIA   R8,{R8-R9,R12}          ;Get arguments
+               MOV     R14,PC                  ;Set return point
+               MOV     PC,R9                   ;Branch to handler
+               BCC     %12event_poll           ;Keep trying
+
+13event_poll   STR     R8,event__fakePos       ;Store the fake position
+
+               ; --- Store the last event away ---
+
+19event_poll   ADR     R14,event__lastCode     ;Point to last event cache
+               STMIA   R14,{R0,R1}             ;Save the information away
+
+               ; --- Scan the post-filters ---
+
+               LDR     R8,event__postList      ;Get post-list pointer
+               ADDS    R0,R0,#0                ;Clear carry
+20event_poll   TEQ     R8,#0                   ;Are we at the end
+               BEQ     %30event_poll           ;Yes -- branch ahead
+               LDMIA   R8,{R8-R9,R12}          ;Get list fields
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R9                   ;Branch to client routine
+               BCC     %20event_poll           ;Keep going through list
+
+30event_poll   LDMFD   R13!,{R8-R10,R12,R14}
+               BICCCS  PC,R14,#C_flag          ;Clear C if C clear :-)
+               ORRCSS  PC,R14,#C_flag          ;Set C if C set
+
+               LTORG
+
+; --- event_last ---
+;
+; On entry:    --
+;
+; On exit:     R0 == last event code received from Wimp_Poll
+;              R1 == pointer to accompanying event data
+;
+; Use:         Allows you to read the full event information.  The event
+;              is the same one currently being or most recently dispatched
+;              to the postfilter list, i.e. fake events are also returned
+;              by this call.  If no event has yet been received, the return
+;              values are undefined.
+
+               EXPORT  event_last
+event_last     ROUT
+
+               LDR     R0,event__wSpace        ;Load my workspace offset
+               LDR     R1,sapph_workspace      ;Load workspace base
+               ADD     R0,R1,R0                ;Find actual workspace addr
+               ADD     R0,R0,#:INDEX: event__lastCode
+               LDMIA   R0,{R0,R1}              ;Load the information
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- event_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the event system.
+
+               EXPORT  event_init
+event_init     ROUT
+
+               STMFD   R13!,{R0-R3,R10,R14}    ;Stack some registers
+               WSPACE  event__wSpace,R10       ;Get my workspace
+
+               ; --- Are we already initialised? ---
+
+               LDR     R0,event__flags         ;Get my flags
+               TST     R0,#event__INITED       ;Are we initialised?
+               LDMNEFD R13!,{R0-R3,R10,PC}^    ;Yes -- return
+
+               ORR     R0,R0,#event__INITED    ;Set initialised flag
+               STR     R0,event__flags         ;And store them back
+
+               ; --- Clear rest of workspace ---
+
+               MOV     R0,#0                   ;Zero some registers
+               MOV     R1,#0
+               MOV     R2,#0
+               MOV     R3,#-1
+               STMIB   R10,{R0-R3}             ;Clear pre/post list
+
+               ; --- Initialise suballoc ---
+
+               BL      sub_init                ;Sub, short for SUBmarine
+
+               ; --- That's it now ---
+
+               LDMFD   R13!,{R0-R3,R10,PC}^    ;Return
+
+               LTORG
+
+event__wSpace  DCD     0                       ;My workspace pointer
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R10
+event__wStart  #       0
+
+event__flags   #       4                       ;Flags
+
+event__INITED  EQU     (1<<0)                  ;I've been initialised
+
+event__preList #       4                       ;Pre-Poll list
+event__fakeList        #       4                       ;Event-faking list
+event__postList        #       4                       ;Post-Poll list
+event__fakePos #       4                       ;The current fake position
+
+event__lastCode        #       4                       ;The last event reason code
+event__lastData        #       4                       ;The last event data pointer
+
+event__prevR0  #       4                       ;R0 for real event
+event__buffer  #       256                     ;The event received
+
+event__wSize   EQU     {VAR}-event__wStart
+
+; --- Pre/Post list structure ---
+
+               ^       0
+list__next     #       4
+list__proc     #       4
+list__r12      #       4
+
+list__size     #       0
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     event__wSize            ;Workspace size
+               DCD     event__wSpace           ;Workspace pointer
+               DCD     0                       ;Scratchpad size
+               DCD     event_init              ;Initialisation code
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/except b/StraySrc/Libraries/Sapphire/s/except
new file mode 100644 (file)
index 0000000..6a7a80d
--- /dev/null
@@ -0,0 +1,458 @@
+;
+; except.s
+;
+; Sapphire exception handling (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:sapphire
+               GET     sapphire:suballoc
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- except_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the exception handler.
+
+               EXPORT  except_init
+except_init    ROUT
+
+               STMFD   R13!,{R0,R12,R14}       ;Stash registers away
+               WSPACE  exc__wSpace             ;Point to my workspace
+
+               ; --- Make sure I'm not already going ---
+
+               LDR     R0,exc__flags           ;Find the flags word
+               TST     R0,#eFlag__inited       ;Am I going yet?
+               LDMNEFD R13!,{R0,R12,PC}^       ;Yes -- return right now
+
+               ; --- Start up suballocation for exit list ---
+
+               BL      sub_init                ;Make sure suballoc's going
+
+               ; --- Fill in the flags and exit list ---
+
+               MOV     R0,#eFlag__inited       ;Set the initialised flag
+               STR     R0,exc__flags           ;Store it away nicely
+
+               MOV     R0,#0
+               STR     R0,exc__exitList        ;No atexit routines yet
+               STR     R0,exc__query           ;No error handler either
+               STR     R11,exc__R11            ;Save R11 pointer
+
+               LDMFD   R13!,{R0,R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- exc__setHnd ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets up the OS handlers so we get called when strange things
+;              happen.
+
+exc__setHnd    ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save registers
+
+               ; --- Make sure we need to do this ---
+
+               LDR     R0,exc__flags           ;Get my current flags
+               TST     R0,#eFlag__handling     ;Are we now handling errors?
+               LDMNEFD R13!,{R0-R4,PC}^        ;Yes -- return right now
+
+               ADR     R4,exc__handlers        ;Point to old handlers block
+
+               ; --- Set up the error handler ---
+
+               MOV     R0,#6                   ;Error handler number
+               ADR     R1,exc__err             ;Point to my handler routine
+               MOV     R2,R12                  ;I want my workspace pointer
+               MOV     R3,R11                  ;Use scratchpad for error
+               SWI     XOS_ChangeEnvironment   ;Set the handler up
+               STMIA   R4!,{R1-R3}             ;Save the old handler away
+
+               ; --- Set up the exit handler ---
+
+               MOV     R0,#11                  ;Exit handler number
+               ADR     R1,exc__exit            ;Point to my handler
+               MOV     R2,R12                  ;Give me my workspace
+               SWI     XOS_ChangeEnvironment   ;Set the handler up
+               STMIA   R4!,{R1-R3}             ;Save the old handler away
+
+               ; --- Set up the UpCall handler ---
+
+               MOV     R0,#16                  ;UpCall handler number
+               ADR     R1,exc__upc             ;Point to my handler
+               MOV     R2,R12                  ;Give me my workspace
+               SWI     XOS_ChangeEnvironment   ;Set the handler up
+               STMIA   R4!,{R1-R3}             ;Save the old handler away
+
+               ; --- Done ---
+
+               LDR     R0,exc__flags           ;Get my current flags
+               ORR     R0,R0,#eFlag__handling  ;We are now handling errors
+               STR     R0,exc__flags           ;Store them away again
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- exc__killHnd ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Releases any handlers we set up.
+
+exc__killHnd   ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save registers
+
+               ; --- Make sure we need to do this ---
+
+               LDR     R0,exc__flags           ;Get my current flags
+               TST     R0,#eFlag__handling     ;Are we now handling errors?
+               LDMEQFD R13!,{R0-R4,PC}^        ;No -- return right now
+
+               ADR     R4,exc__handlers        ;Point to old handlers block
+
+               ; --- Reset the error handler ---
+
+               MOV     R0,#6                   ;Error handler number
+               LDMIA   R4!,{R1-R3}             ;Get the old handler
+               SWI     XOS_ChangeEnvironment   ;Set the handler up
+
+               ; --- Reset the exit handler ---
+
+               MOV     R0,#11                  ;Exit handler number
+               LDMIA   R4!,{R1-R3}             ;Get the old handler
+               SWI     XOS_ChangeEnvironment   ;Set the handler up
+
+               ; --- Reset the UpCall handler ---
+
+               MOV     R0,#16                  ;UpCall handler number
+               LDMIA   R4!,{R1-R3}             ;Get the old handler
+               SWI     XOS_ChangeEnvironment   ;Set the handler up
+
+               ; --- Done ---
+
+               LDR     R0,exc__flags           ;Get my current flags
+               BIC     R0,R0,#eFlag__handling  ;We are not handling errors
+               STR     R0,exc__flags           ;Store them away again
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- exc__error ---
+;
+; On entry:    R0 == pointer to workspace
+;
+; On exit:     Doesn't, really
+;
+; Use:         Handles an error, and dispatches it to the right place,
+;              properly handling multiple exceptions (i.e. it falls over
+;              and dies).
+
+exc__err       ROUT
+
+               MOV     R12,R0                  ;Because RISC OS is weird
+               LDR     R11,exc__R11            ;Find the scratchpad pointer
+
+               ; --- Am I already handling an error? ---
+
+               LDR     R0,exc__flags           ;Find the flags word
+               TST     R0,#eFlag__inError      ;Check the flag bit
+               BNE     %50exc__err             ;Yes -- skip ahead
+
+               ; --- Remember that I'm handling an error ---
+
+               ORR     R0,R0,#eFlag__inError   ;Set the bit
+               STR     R0,exc__flags           ;And put my flags word away
+
+               ; --- Do I have an error handler? ---
+
+               LDR     R2,exc__query           ;Find the handler function
+               CMP     R2,#0                   ;Is it defined?
+               BEQ     %20exc__err             ;No -- skip ahead
+
+               ; --- Locate the error buffer and dispatch the error ---
+
+               ADD     R0,R11,#4               ;Point to the error block
+               STMFD   R13!,{R12}              ;Save my workspace on stack
+               LDR     R12,exc__qR12           ;Get the workspace they want
+               MOV     R14,PC                  ;Get a return address
+               MOV     PC,R2                   ;Call the handler
+
+               ; --- We now have a resume routine to call ---
+
+               LDMFD   R13!,{R12}              ;Restore my workspace pointer
+               LDR     R2,exc__flags           ;Find the flags word
+               BIC     R2,R2,#eFlag__inError   ;We're leaving the handler
+               STR     R2,exc__flags           ;And put my flags word away
+               LDR     R13,exc__stackPtr       ;Get the stack pointer
+               MOV     R12,R1                  ;Get the resumer's wSpace
+               MOV     PC,R0                   ;And call the resumer.
+
+               ; --- No error handler registered ---
+
+20exc__err     LDR     R13,sapph_stackBase     ;We won't be coming back
+               BL      exc__killHnd            ;Reset all the handlers
+               BL      exc__atexits            ;Perform tidy-up operations
+               ADD     R0,R11,#4               ;Point to the error block
+               SWI     OS_GenerateError        ;And report error to caller
+
+               ; --- Something went catastrophically wrong ---
+
+50exc__err     ADD     R0,R11,#4               ;Point to the error block
+               B       except_fatal            ;And report the error
+
+               LTORG
+
+exc__wSpace    DCD     0                       ;Pointer to my workspace
+
+; --- except_fatal ---
+;
+; On entry:    R0 == pointer to an error block
+;
+; On exit:     Doesn't
+;
+; Use:         Reports an error to our /caller's/ error handler.  We quit
+;              and die at this point.  Don't use unless you have absolutely
+;              no choice in the matter.
+
+               EXPORT  except_fatal
+except_fatal   ROUT
+
+               WSPACE  exc__wSpace             ;Find my workspace address
+               LDR     R13,sapph_stackBase     ;Find a good piece of stack
+               BL      exc__killHnd            ;Get rid of our handlers
+               SWI     OS_GenerateError        ;And report the error
+
+               LTORG
+
+; --- exc__atexits ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Calls all the registered atexit functions
+
+exc__atexits   ROUT
+
+               STMFD   R13!,{R1,R10-R12,R14}   ;Save the registers I want
+               LDR     R10,exc__exitList       ;Get the list of handlers
+
+01exc__atexits CMP     R10,#0                  ;Is the list empty
+               LDMEQFD R13!,{R1,R10-R12,PC}^   ;Return to call if so
+               LDR     R12,[R10,#eExit__R12]   ;Get the required R12
+               LDR     R1,[R10,#eExit__handler] ;Get pointer to handler
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R1                   ;Call atexit routine
+               LDR     R10,[R10,#eExit__next]  ;Get next handler
+               B       %01exc__atexits
+
+               LTORG
+
+; --- exc__exit ---
+;
+; On entry:    R12 == pointer to my workspace
+;
+; On exit:     Doesn't
+;
+; Use:         Gets called by OS_Exit
+
+exc__exit      ROUT
+
+               ; --- Find a stack somewhere ---
+
+               LDR     R11,exc__R11            ;Load scratchpad pointer
+               BL      sapphire_resetStack     ;Use initial stack
+               BL      exc__killHnd            ;Kill existing handlers
+               BL      exc__atexits            ;Call things on the exit list
+               SWI     XOS_Exit                ;Quit the application
+
+               LTORG
+
+; --- exc__upc ---
+;
+; On entry:    R12 == pointer to my workspace
+;
+; On exit:     Handlers are restored
+;
+; Use:         Upcall handler
+
+exc__upc       ROUT
+
+               ; --- Are we interested in this UpCall? ---
+
+               CMP     R0,#256                 ;Is a new app starting?
+               MOVNES  PC,R14                  ;No -- return to caller
+
+               ; --- Stick everything on the SVC stack ---
+
+               STMFD   R13!,{R14}              ;Save the return address
+               TEQP    PC,#0                   ;Enter USR mode to keep the
+                                               ;atexit routines happy
+               MOV     R0,R0                   ;Keep ARM happy too
+               LDR     R11,exc__R11            ;Load scratchpad pointer
+               BL      sapphire_resetStack     ;Use initial stack
+               BL      exc__killHnd            ;Restore the handlers
+               BL      exc__atexits            ;Close everything down now
+               SWI     OS_EnterOS              ;Go back to SVC mode
+               LDMFD   R13!,{PC}^              ;Return and be killed :-)
+
+               LTORG
+
+; --- except_atExit ---
+;
+; On entry:    R0 == pointer to routine to call on exit
+;              R1 == R12 value to call with
+;
+; On exit:     --
+;
+; Use:         Registers a routine to get called when the application quits.
+;              Later-registered routines are called earlier than earlier-
+;              registered routines, so everything closes down in a nice
+;              manner.
+
+               EXPORT  except_atExit
+except_atExit  ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Save everything on stack
+               WSPACE  exc__wSpace             ;Find my workspace
+               BL      exc__setHnd             ;Set up my handlers
+
+               ; --- Create the list item ---
+
+               MOV     R0,#eExit__size         ;Size of the block to get
+               BL      sub_alloc               ;Allocate the memory
+               SWIVS   OS_GenerateError        ;Barf if it failed
+               MOV     R2,R0                   ;Move to a nicer register
+
+               ; --- Fill it in and link it to the list ---
+
+               LDR     R0,exc__exitList        ;Get the current list head
+               STR     R0,[R2,#eExit__next]    ;Store this in the link
+               LDMIA   R13!,{R0,R1}            ;Get the stuff from the stack
+               STMIB   R2,{R0,R1}              ;Store them in the block
+               STR     R2,exc__exitList        ;This is the new list head
+
+               ; --- Done ---
+
+               LDMFD   R13!,{R2,R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- except_returnPt ---
+;
+; On entry:    R0 == pointer to exception handler routine
+;              R1 == R12 value to enter routine with
+;              R2 == R13 value to enter routine with
+;
+; On exit:     --
+;
+; Use:         Sets up a routine to be called whenever there's an error.
+;              The idea is that it should ask the user whether to quit,
+;              and if not, resume to some known (safe?) state.
+;
+;              The routine is called with R0 == pointer to error block, and
+;              R12 and R13 being the values set up here(*).  It should
+;              return with R0 == pointer to a routine to resume at, and R1
+;              being the value to pass to the resume routine in R12.  If
+;              you decide to quit, just call OS_Exit -- this should tidy
+;              everything up.
+;
+;              Note that the error is held in the scratchpad buffer, so
+;              you can't use the first 256 bytes of that until you've
+;              finished with the error message.
+;
+;              (*) Actually, R13 is 4 bytes lower because it's assumed that
+;              it points to a full descending stack that we can use.  This
+;              shouldn't make any difference as long as you're using R13
+;              as a full descending stack pointer.
+
+               EXPORT  except_returnPt
+except_returnPt        ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  exc__wSpace             ;Get my workspace pointer
+               BL      exc__setHnd             ;Set up all the handlers
+               ADR     R14,exc__query          ;Point to my stack variable
+               STMIA   R14,{R0-R2}             ;Store the handler away
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+exc__wStart    #       0
+
+exc__flags     #       4                       ;Error handling flags
+exc__handlers  #       36                      ;Old handlers information
+exc__query     #       4                       ;Pointer to query routine
+exc__qR12      #       4                       ;R12 for query routine
+exc__stackPtr  #       4                       ;Stack pointer for handling
+exc__exitList  #       4                       ;The list of exit routines
+exc__R11       #       4                       ;Sapphire's R11 magic pointer
+
+exc__wSize     EQU     {VAR}-exc__wStart       ;My workspace size
+
+eFlag__inited  EQU     (1<<0)                  ;Are we initialised?
+eFlag__inError EQU     (1<<1)                  ;Currently in error handler
+eFlag__handling        EQU     (1<<2)                  ;We have handlers set up
+
+; --- Exit routine block format ---
+
+               ^       0
+eExit__next    #       4                       ;Address of next block
+eExit__handler #       4                       ;Address of routine to call
+eExit__R12     #       4                       ;R12 to call handler with
+eExit__size    #       0                       ;Size of the block
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     exc__wSize
+               DCD     exc__wSpace
+               DCD     256
+               DCD     except_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/fastMove b/StraySrc/Libraries/Sapphire/s/fastMove
new file mode 100644 (file)
index 0000000..6e9b1f0
--- /dev/null
@@ -0,0 +1 @@
+               LNK     libs:s.fastMove
diff --git a/StraySrc/Libraries/Sapphire/s/flex b/StraySrc/Libraries/Sapphire/s/flex
new file mode 100644 (file)
index 0000000..984a7c2
--- /dev/null
@@ -0,0 +1,4 @@
+               GBLL    OPT_SAPPHIRE
+               GBLL    OPT_DYNAREA
+               GBLL    OPT_STACK
+               LNK     libs:s.flex
diff --git a/StraySrc/Libraries/Sapphire/s/fontMenu b/StraySrc/Libraries/Sapphire/s/fontMenu
new file mode 100644 (file)
index 0000000..022c300
--- /dev/null
@@ -0,0 +1,940 @@
+;
+; fontMenu.s
+;
+; Fontmenu creation
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:event
+               GET     sapphire:flex
+               GET     sapphire:menu
+               GET     sapphire:menuDefs
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:string
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- fm_create ---
+;
+; On entry:    R0 == current font name
+;              R1 == handler to call when selection made
+;              R2 == R10 value to call with
+;              R3 == R12 value to call with
+;              R4 == pointer to routine to call to create submenu
+;                    (ie. menu_create or tms_create)
+;
+; On exit:     CS if any fonts exist and
+;                 R0 == pointer to a menu definition
+;                R1 == event handler to call
+;                R2 == R10 value for event handler
+;                R3 == R12 value for event handler
+;              else CC and
+;                R0-R3 corrupted
+;              May return an error
+;
+; Use:         Creates a user menu definition suitable for passing directly
+;              to (menu|tms)_create. Note however, that the menu defintion
+;              does *not* include any title; this must be created first.
+;              If you require items such as the system font, then
+;              add these to the menu before creating the menu returned
+;              from this call.
+
+               EXPORT  fm_create
+fm_create      ROUT
+
+               STMFD   R13!,{R0,R4-R10,R12,R14} ;Save some registers
+               WSPACE  fm__wSpace
+
+               ; --- Save the caller's handler ---
+
+               ADR     R14,fm__userHandler     ;Point to the handler
+               STMIA   R14,{R1-R4}             ;Store it away
+
+               ; --- Ensure that we need to create it ---
+
+               MOV     R0,R11                  ;Build path in scratchpad
+               BL      fm__fontPath            ;Get the current fontpath
+               BCC     %70fm_create            ;None found -- no fonts then
+
+               LDR     R14,fm__flags           ;Load the flags word
+               TST     R14,#fmFlag__changed    ;Have the fonts changed?
+               BICNE   R14,R14,#fmFlag__changed ;Yes -- clear the flag
+               STRNE   R14,fm__flags           ;...store the flags
+               BNE     %00fm_create            ;...and recreate the menu
+
+               LDR     R1,fm__block            ;Load our block address
+               MOVS    R2,R1                   ;Is it defined yet?
+               ADRNE   R1,fm__path             ;Point to saved font path
+               BLNE    str_cmp                 ;Compare with current path
+               MOVNE   R2,#0                   ;If not equal, clear pointer
+               CMP     R2,#0                   ;So, do we recreate?
+               BNE     %40fm_create            ;No -- return current menu
+
+               MOV     R1,R11                  ;Point to font path string
+               ADR     R0,fm__path             ;Point to font path buffer
+               BL      str_cpy                 ;Take a copy of the path
+
+00fm_create    LDR     R0,fm__block            ;Load address of menu block
+               CMP     R0,#0                   ;Is it created currently?
+               BLNE    free                    ;Yes -- free it then
+
+               ; --- Set up a flex block ---
+               ;
+               ; We will read the font names into this block, to make it
+               ; easier to actually build our menu, and reduce heap
+               ; fragmentation.
+               ;
+               ; The format of the data in the block is as follows:
+               ;
+               ;        Size   Use
+               ;     /   4     Number of variants (0 for regular only)
+               ;     |   ?     Name of this family
+               ;     \ [ ?     Name of this variant
+
+               SUB     R13,R13,#12             ;Make a small anchor block
+               MOV     R0,R13                  ;Point to the block
+               MOV     R1,#1024                ;Start it off at 256 bytes
+               BL      flex_alloc              ;Allocate the block
+               BLCS    alloc_error             ;If it failed, get error
+               BCS     %80fm_create            ;And return to caller
+
+               MOV     R0,#0                   ;Start at the beginning
+               STMIB   R13,{R0,R1}             ;Save them in the block
+
+               MOV     R9,#4                   ;No length for main menu
+               MOV     R10,#0                  ;Or for the submenus
+
+               ; --- Start building font names now ---
+
+               MOV     R2,#0                   ;Start from the beginning
+               MOV     R1,R11                  ;Build string in ScratchPad
+               MOV     R3,#256                 ;Size of scratchpad buffer
+               SWI     Font_ListFonts          ;Read a font name
+               CMP     R2,#-1                  ;Is that the very end?
+               BEQ     %65fm_create            ;Yes -- abort now then
+               MOV     R4,#0                   ;Found one family so far
+
+               MOV     R6,#0                   ;Clear a flags word
+               MOV     R1,R11                  ;Point to the font name
+               BL      fm__parse               ;Break the name up
+               ORRCC   R6,R6,#1                ;If `Regular', set a flag
+               MOV     R3,R1                   ;Look after variant name
+               MOV     R8,R0                   ;Look after the family name
+
+               ; --- Set this family name up ---
+
+10fm_create    MOV     R5,#0                   ;This is the first variant
+
+               MOV     R0,R13                  ;Point to the anchor block
+               MOV     R1,#4                   ;Make space for count word
+               BL      fm__ensure              ;Allocate space for it
+               BVS     %79fm_create            ;If we couldn't, abort
+               ADD     R7,R0,#4                ;Point just past this word
+
+               FSAVE   R7                      ;Save R7 on relocation stack
+               MOV     R1,R8                   ;Get family name in R1
+               MOV     R0,R13                  ;Point to the anchor block
+               BL      fm__string              ;Write the family name out
+               BVS     %79fm_create            ;If it failed, abort now
+               ADD     R0,R0,#3+8              ;Word align returned length
+               BIC     R0,R0,#3                ;Tumtetiddlytumtetum
+               ADD     R9,R9,R0                ;Add on to main menu length
+               ADD     R9,R9,#4                ;Remember space for radio
+               ADD     R10,R10,R0              ;And add on submenu length
+
+               ; --- Write this variant out ---
+
+15fm_create    MOV     R0,R13                  ;Point to anchor block
+               MOV     R1,R3                   ;Point to variant name
+               BL      fm__string              ;Add this on the end
+               BVS     %79fm_create            ;If it failed, abort now
+               ADD     R0,R0,#3+12             ;Word align returned length
+               BIC     R0,R0,#3                ;Omtiddlyompepom
+               ADD     R10,R10,R0              ;Add this to submenu length
+               ADD     R5,R5,#1                ;Increment variant counter
+
+               ; --- Get the next font name ready ---
+
+               MOV     R8,R6                   ;Remember current flags
+               MOV     R1,R11                  ;Build string in ScratchPad
+               MOV     R3,#256                 ;Size of scratchpad buffer
+               SWI     Font_ListFonts          ;Read a font name
+               CMP     R2,#-1                  ;Is that the very end?
+               BEQ     %20fm_create            ;Yes -- we've finished then
+
+               BL      fm__parse               ;Break up the font name
+               ORRCC   R6,R6,#1                ;If `Regular', set a flag
+               BICCS   R6,R6,#1                ;Otherwise clear it
+
+               MOV     R3,R1                   ;Look after the variant name
+               FLOAD   R1                      ;Restore family name address
+               BL      str_cmp                 ;Do the strings match?
+               FSAVE   R1                      ;Save the address back
+               BEQ     %15fm_create            ;And loop round for more
+
+               ; --- Finished a family ---
+
+20fm_create
+               FLOAD   R7                      ;Reload family name address
+               CMP     R5,R8                   ;Is there only `Regular'?
+               MOVEQ   R5,#0                   ;Yes -- claim no variants
+               STR     R5,[R7,#-4]             ;Save it in the block
+               MOV     R8,R0                   ;Look after the family name
+               MOV     R0,R13                  ;Point to anchor block
+               BL      fm__align               ;Word align output pointer
+               ADD     R4,R4,#1                ;Increment family counter
+               CMP     R2,#-1                  ;Are there more font names?
+               BNE     %10fm_create            ;Yes -- put them in the block
+
+               ; --- Allocate a big heap block ---
+
+               ADD     R0,R9,R10               ;Add the menu sizes up
+               ADD     R0,R0,R4,LSL #2         ;And an indexing block
+               BL      alloc                   ;Allocate this block
+               BLCS    alloc_error             ;If it failed, get error
+               BCS     %79fm_create            ;And return to caller
+
+               STR     R0,fm__block            ;Store this block address
+
+               ; --- A note about register allocation ---
+               ;
+               ; Dear reader,
+               ;   I have decided, it being Saturday and all, to allocate
+               ; registers thusly:
+               ;
+               ;  R7 == pointer into submenu indexing table
+               ;  R8 == pointer into the main menu structure
+               ;  R9 == pointer into the submenu area
+               ; R10 == pointer into our juicy big flex table
+               ;
+               ;               Yours sincerely
+               ;
+               ;                       Mark Wooding (Straylight Dev Lab)
+
+               MOV     R7,R0                   ;Point to indexing table
+               ADD     R8,R7,R4,LSL #2         ;Find the main menu area
+               ADD     R9,R8,R9                ;And find the submenu area
+               LDR     R10,[R13,#0]            ;Load base of flex block
+               STR     R8,fm__menu             ;Store the menu address
+
+               ; --- Now the fun begins ---
+
+22fm_create    MOV     R0,#mFlag_radio         ;Get the flag ready
+               ORR     R0,R0,#mFlag_R12        ;And make data R12-relative
+               LDR     R6,[R10],#4             ;Load the number of variants
+               CMP     R6,#0                   ;Do we want a submenu?
+               ORRNE   R0,R0,#mFlag_subWarn    ;Yes -- set the flag then
+               STR     R0,[R8],#4              ;Save it in the menu block
+
+               MOVEQ   R14,#0                  ;No submenu -- get null ptr
+               STREQ   R14,[R7],#4             ;And clear submenu address
+               STRNE   R9,[R7],#4              ;Save this submenu address
+
+               MOV     R0,R10                  ;Look after this address
+23fm_create    LDRB    R14,[R10],#1            ;Load a family name byte
+               CMP     R14,#0                  ;Is this the end yet?
+               STRB    R14,[R8],#1             ;Save it in the menu block
+               BNE     %23fm_create            ;And go round for the rest
+
+               ADD     R8,R8,#3                ;Word align the output addr
+               BIC     R8,R8,#3                ;Yingtongiddleipo
+
+               MOV     R1,#4                   ;Offset 0 in radio block
+               MOV     R2,R8                   ;Magic radio group tag
+               STMIA   R8!,{R1,R2}             ;Save these in the block
+
+               ; --- Now build the variants submenu ---
+
+               CMP     R6,#0                   ;Do we want a submenu
+               BEQ     %28fm_create            ;No -- *still skip past name*
+
+               MOV     R14,#0                  ;Title flags
+               STR     R14,[R9],#4             ;Save in submenu block
+24fm_create    LDRB    R14,[R0],#1             ;Load a family name byte
+               STRB    R14,[R9],#1             ;Save it in the menu block
+               CMP     R14,#0                  ;Is this the end yet?
+               BNE     %24fm_create            ;And go round for the rest
+
+               ADD     R9,R9,#3                ;Word align the output addr
+               BIC     R9,R9,#3                ;Obblyjobblywibbledidee
+
+               ; --- Create an item for each variant ---
+
+25fm_create    MOV     R0,#mFlag_radio         ;Get the flag ready
+               ORR     R0,R0,#mFlag_R12        ;And make data R12-relative
+               STR     R0,[R9],#4              ;Save in submenu block
+
+26fm_create    LDRB    R14,[R10],#1            ;Load a variant name byte
+               CMP     R14,#0                  ;Is this the end yet?
+               STRB    R14,[R9],#1             ;Save it in the menu block
+               BNE     %26fm_create            ;And go round for the rest
+
+               ADD     R9,R9,#3                ;Word align the output addr
+               BIC     R9,R9,#3                ;Obblyjobblywibbledidee
+
+               MOV     R1,#8                   ;Offset 8 in radio block
+               MOV     R2,R9                   ;Magic radio group tag
+               STMIA   R9!,{R1,R2}             ;Save these in the block
+
+               SUBS    R6,R6,#1                ;Decrement the counter
+               BGT     %25fm_create            ;And do the rest of them
+
+               MOV     R14,#mFlag_end          ;Terminate the menu
+               STR     R14,[R9],#4             ;Save that at the end
+
+               B       %30fm_create            ;Skip to end of family stuff
+
+               ; --- No variants -- omit the submenu ---
+               ;
+               ; For odd reasons, we actually leave a `(Regular)' item
+               ; in the flex block.  We need to skip over this here.
+
+28fm_create    LDRB    R14,[R10],#1            ;Load a variant name byte
+               CMP     R14,#0                  ;Is this the end yet?
+               BNE     %28fm_create            ;And go round for the rest
+
+30fm_create    ADD     R10,R10,#3              ;Word align flex block ptr
+               BIC     R10,R10,#3              ;[Silly comment omitted]
+
+               SUBS    R4,R4,#1                ;Done another family
+               BGT     %22fm_create            ;And go round for the rest
+
+               MOV     R14,#mFlag_end          ;Terminate the menu
+               STR     R14,[R8],#4             ;Save that at the end
+
+               ; --- Destroy the flex block ---
+
+               MOV     R0,R13                  ;Point to the flex anchor
+               BL      flex_free               ;Free the block
+               ADD     R13,R13,#12             ;Restore stack pointer
+
+               ; --- Now return the menu and things ---
+
+40fm_create    LDR     R0,[R13],#4             ;Load the name to tick
+               BL      fm_tickFont             ;Tick that font
+               LDR     R0,fm__menu             ;Find the menu address
+               ADR     R1,fm__handler1         ;I don't have a handler :-(
+               MOV     R2,#0                   ;No R10 value either :~-(
+               MOV     R3,R12                  ;And pass workspace in R12
+               LDMFD   R13!,{R4-R10,R12,R14}   ;Restore registers
+               ORR     R14,R14,#C_flag         ;Set C to say we did it
+               BICS    PC,R14,#V_flag          ;And return errorless
+
+               ; --- Couldn't find any fonts (oops) ---
+
+65fm_create    ADD     R13,R13,#12             ;Restore stack pointer
+70fm_create    LDMFD   R13!,{R0,R4-R10,R12,R14} ;Restore registers
+               BICS    PC,R14,#V_flag+C_flag   ;And return CC
+
+               ; --- Tidy up after catastrophes ---
+
+79fm_create    MOV     R10,R0                  ;Look after the error
+               MOV     R0,R13                  ;Point to the flex anchor
+               BL      flex_free               ;Free the flex block
+               MOV     R0,R10                  ;Restore the error pointer
+
+80fm_create    ADD     R13,R13,#12+4           ;Restore the stack nicely
+               LDMFD   R13!,{R4-R10,R12,R14}   ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- fm__handler1 ---
+;
+; On entry:    R0 == menu event
+;              R1 == menu item
+;              R12 == pointer to private workspace
+;
+; On exit:     --
+;
+; Use:         Handles events on the first level menu.
+
+fm__handler1   ROUT
+
+               CMP     R0,#mEvent_select       ;Is it a menu selection
+               CMPNE   R0,#mEvent_subMenu      ;Or a submenu event?
+               MOVNES  PC,R14                  ;Nope -- return
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack registers
+               CMP     R0,#mEvent_select       ;A selection?
+               BEQ     %50fm__handler1         ;Yes -- jump ahead
+
+               ; --- Handle submenu events ---
+
+               LDR     R0,fm__block            ;Point to useful table
+               LDR     R0,[R0,R1,LSL #2]       ;Load submenu address
+               MOV     R2,R1                   ;Pass item number in R10
+               ADR     R1,fm__handler2         ;And point to second handler
+               MOV     R3,R12                  ;And workspace in R12
+               LDR     R4,fm__creator          ;Load address of creator
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R4                   ;Call the creator
+               B       %90fm__handler1         ;Return to caller
+
+               ; --- User selected an item ---
+
+50fm__handler1 MOV     R3,R1                   ;Remember index value
+               BL      fm__familyName          ;Get family name pointer
+               MOV     R1,R0                   ;Put it in R1
+               ADR     R0,fm__name             ;Write the name here
+               BL      str_cpy                 ;Copy over family name
+               MOV     R2,R0                   ;Put terminator ptr in R2
+               LDR     R0,fm__block            ;Load table pointer
+               LDR     R0,[R0,R3,LSL #2]       ;Load submenu pointer
+               CMP     R0,#0                   ;Is there a submenu?
+               BEQ     %60fm__handler1         ;No -- jump ahead
+               MOV     R1,#0                   ;Just choose first index
+               BL      fm__variantName         ;Find the first variant name
+               CMP     R0,#0                   ;Is there one?
+               BEQ     %60fm__handler1         ;No -- return now then
+               MOV     R1,R0                   ;Put it in R1
+               MOV     R0,R2                   ;Copy it to here
+               MOV     R14,#'.'                ;We want a '.' first
+               STRB    R14,[R0],#1             ;Store in the string
+               BL      str_cpy                 ;Copy over the string
+
+60fm__handler1 MOV     R0,#fmEvent_select      ;The event type
+               ADR     R1,fm__name             ;Point to the name
+               BL      fm__dispatch            ;Dispatch the event
+
+90fm__handler1 LDMFD   R13!,{R1-R4,PC}^        ;Load back registers
+
+               LTORG
+
+; --- fm__handler2 ---
+;
+; On entry:    R0 == menu event
+;              R1 == menu item
+;              R10 == menu item submenu came from
+;              R12 == pointer to workspace
+;
+; On exit:     --
+;
+; Use:         Handles events for a second level submenu
+
+fm__handler2   ROUT
+
+               CMP     R0,#mEvent_select       ;Is it a menu selection
+               MOVNES  PC,R14                  ;Nope -- return
+
+               STMFD   R13!,{R1-R3,R14}        ;Stack registers
+
+               MOV     R3,R1                   ;Remember index value
+               MOV     R1,R10                  ;Get previous index
+               BL      fm__familyName          ;Get family name pointer
+               MOV     R1,R0                   ;Put it in R1
+               ADR     R0,fm__name             ;Write the name here
+               BL      str_cpy                 ;Copy over family name
+               MOV     R2,R0                   ;Put terminator ptr in R2
+               LDR     R0,fm__block            ;Load table pointer
+               LDR     R0,[R0,R10,LSL #2]      ;Load submenu pointer
+               MOV     R1,R3                   ;Put index in R1
+               BL      fm__variantName         ;Find the variant name
+               CMP     R0,#0                   ;Is there a name?
+               BEQ     %10fm__handler2         ;No -- retur now then
+               MOV     R1,R0                   ;Put it in R1
+               MOV     R0,R2                   ;Copy it to here
+               MOV     R14,#'.'                ;We want a '.' first
+               STRB    R14,[R0],#1             ;Store in the string
+               BL      str_cpy                 ;Copy over the string
+
+10fm__handler2 MOV     R0,#fmEvent_select      ;The event type
+               ADR     R1,fm__name             ;Point to the name
+               BL      fm__dispatch            ;Dispatch the event
+
+               LDMFD   R13!,{R1-R3,PC}^        ;Load back registers
+
+               LTORG
+
+; --- fm__dispatch ---
+;
+; On entry:    R0-R9 == event data
+;              R12 == workspace pointer
+;
+; On exit:     --
+;
+; Use:         Sends an event to the users font menu handler.
+
+fm__dispatch   ROUT
+
+               STMFD   R13!,{R9,R10,R12,R14}   ;Stack registers
+               ADR     R14,fm__userHandler     ;Point to the handler
+               LDMIA   R14,{R9,R10,R12}        ;Load registers
+               CMP     R9,#0                   ;Sanity check
+               MOV     R14,PC                  ;Sey up return address
+               MOVNE   PC,R9                   ;Call the handler
+               LDMFD   R13!,{R9,R10,R12,PC}^   ;Return to caller
+
+               LTORG
+
+; --- fm_tickFont ---
+;
+; On entry:    R0 == name to tick
+;
+; On exit:     --
+;
+; Use:         Ticks the font with tht given name in the fontmenu. If
+;              no font exists then the existing ticks are removed
+
+               EXPORT  fm_tickFont
+fm_tickFont    ROUT
+
+               CMP     R0,#0                   ;Is R0 NULL?
+               MOVEQS  PC,R14                  ;Yes -- return now
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+               WSPACE  fm__wSpace              ;Locate my workspace
+               MOV     R1,R0                   ;Put the name in R1
+               MOV     R0,R11                  ;Point to the scratchpad
+               BL      str_cpy                 ;Copy the string over
+               MOV     R1,R11                  ;Put the pointer in R1
+               BL      fm__parse               ;Parse up the string
+               MOVCS   R4,#1                   ;Not regular
+               MOVCC   R4,#0                   ;Yes it is sir
+               MOV     R3,R1                   ;Put variant name in R3
+
+               ; --- Clear the existing ticks ---
+
+               MOV     R14,#0                  ;Get a NULL word
+               STR     R14,fm__ticks           ;Clear first tick
+               STR     R14,fm__ticks+4         ;And second tick
+
+               ; --- Search for the font name ---
+
+               LDR     R1,fm__menu             ;Point to the menu definition
+               MOV     R2,#0                   ;Index so far
+00fm_tickFont  LDR     R14,[R1],#4             ;Load the flags word
+               TST     R14,#mFlag_end          ;Have we reached the end?
+               BNE     %90fm_tickFont          ;Yes -- return
+               BL      str_icmp                ;Does this name match
+               BEQ     %50fm_tickFont          ;Yes -- jump ahead
+10fm_tickFont  LDRB    R14,[R1],#1             ;Load a character
+               CMP     R14,#0                  ;Is it a terminator?
+               BNE     %10fm_tickFont          ;No -- keep on looking
+               ADD     R1,R1,#3+8              ;Word align, skip over data
+               BIC     R1,R1,#3
+               ADD     R2,R2,#1                ;Increment the index
+               B       %00fm_tickFont          ;Keep on looking
+
+               ; --- We have found a match ---
+               ;
+               ; First we must get the tick word thing
+
+50fm_tickFont  LDRB    R14,[R1],#1             ;Load a character
+               CMP     R14,#0                  ;Is it a terminator?
+               BNE     %50fm_tickFont          ;No -- keep on looking
+               ADD     R1,R1,#3+4              ;Word align, pount to thing
+               BIC     R1,R1,#3
+               LDR     R14,[R1]                ;Load the data word thing
+               STR     R14,fm__ticks           ;Store as first level tick
+
+               ; --- Now search the submenu ---
+
+               LDR     R1,fm__block            ;Point to table
+               LDR     R1,[R1,R2,LSL #2]       ;Load submenu pointer
+               CMP     R1,#0                   ;Is there one?
+               BEQ     %90fm_tickFont          ;Nope -- return
+
+               MOV     R0,R3                   ;Put variant name in R0
+
+               ; --- Skip over title data ---
+
+               ADD     R1,R1,#4                ;Skip over flags word
+52fm_tickFont  LDRB    R14,[R1],#1             ;Load a byte
+               CMP     R14,#0                  ;Have we reach the end?
+               BNE     %52fm_tickFont          ;No -- keep looking
+               ADD     R1,R1,#3                ;Word align
+               BIC     R1,R1,#3
+
+                ; --- Select 'Regular' if appropriate ---
+
+                CMP    R4,#0                   ;Did user select 'Regular'?
+                ADDEQ  R1,R1,#4                ;Yes -- skip over glags
+                BEQ    %58fm_tickFont          ;...and tick this one then
+
+               ; --- Now search for the family name ---
+
+54fm_tickFont  LDR     R14,[R1],#4             ;Load the flags word
+               TST     R14,#mFlag_end          ;Have we reached the end?
+               BNE     %90fm_tickFont          ;Yes -- return
+               BL      str_icmp                ;Does this name match
+               BEQ     %58fm_tickFont          ;Yes -- jump ahead
+56fm_tickFont  LDRB    R14,[R1],#1             ;Load a character
+               CMP     R14,#0                  ;Is it a terminator?
+               BNE     %56fm_tickFont          ;No -- keep on looking
+               ADD     R1,R1,#3+8              ;Word align, skip over data
+               BIC     R1,R1,#3
+               B       %54fm_tickFont          ;Keep on looking
+
+               ; --- We have found a match ---
+
+58fm_tickFont  LDRB    R14,[R1],#1             ;Load a character
+               CMP     R14,#0                  ;Is it a terminator?
+               BNE     %58fm_tickFont          ;No -- keep on looking
+               ADD     R1,R1,#3+4              ;Word align, pount to thing
+               BIC     R1,R1,#3
+               LDR     R14,[R1]                ;Load the data word thing
+               STR     R14,fm__ticks+4         ;Store as first level tick
+
+               ; --- Return to caller ---
+
+90fm_tickFont  LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- fm__familyName ---
+;
+; On entry:    R1 == index of name
+;              R12 == workspace pointer
+;
+; On exit:     R0 == poiner to family name
+;
+; Use:         Points to the family name for the given menu index
+
+fm__familyName ROUT
+
+               STMFD   R13!,{R1,R14}           ;Stack registers
+               LDR     R0,fm__menu             ;Point to the menu block
+
+               ADD     R0,R0,#4                ;Skip over flags word
+               CMP     R1,#0                   ;Is this index 0?
+               BEQ     %90fm__familyName       ;Yes -- return happy then
+00             LDRB    R14,[R0],#1             ;Load a byte
+               CMP     R14,#0                  ;Is it the end?
+               BNE     %00fm__familyName       ;No -- keep looking
+               ADD     R0,R0,#3+8+4            ;Word align and point to next
+               BIC     R0,R0,#3
+               SUBS    R1,R1,#1                ;Decrement the count
+               BNE     %00fm__familyName       ;And keep on looking
+
+90             LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- fm__variantName ---
+;
+; On entry:    R0 == pointer to submenu
+;              R1 == index of name
+;              R12 == workspace pointer
+;
+; On exit:     R0 == poiner to family name, or 0 for regular
+;
+; Use:         Points to the family name for the given menu index
+
+fm__variantName        ROUT
+
+               STMFD   R13!,{R1,R14}           ;Stack registers
+
+               ADD     R0,R0,#4                ;Skip over flags word
+
+00             LDRB    R14,[R0],#1             ;Load a byte
+               CMP     R14,#0                  ;Is it the end?
+               BNE     %00fm__variantName      ;No -- keep looking
+               ADD     R0,R0,#3+4              ;Word align and point to fst
+               BIC     R0,R0,#3
+
+               CMP     R1,#0                   ;Is this index 0?
+               BEQ     %90fm__variantName      ;Yes -- return happy then
+10             LDRB    R14,[R0],#1             ;Load a byte
+               CMP     R14,#0                  ;Is it the end?
+               BNE     %10fm__variantName      ;No -- keep looking
+               ADD     R0,R0,#3+8+4            ;Word align and point to next
+               BIC     R0,R0,#3
+               SUBS    R1,R1,#1                ;Decrement the count
+               BNE     %10fm__variantName      ;And keep on looking
+
+90             MOV     R1,R0                   ;Put string in R1
+               ADR     R0,fm__regular          ;Point to regular name
+               BL      msgs_lookup             ;Translate it
+               BL      str_cmp                 ;Is this a match?
+               MOVNE   R0,R1                   ;No -- return name then
+               MOVEQ   R0,#0                   ;Yes -- return 0 then
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- fm__parse ---
+;
+; On entry:    R1 == pointer to font name
+;
+; On exit:     R0 == pointer to font family name (R1 on entry)
+;              R1 == pointer to font variant name
+;              CS if variant spcified explicitly, CC if `Regular'
+;
+; Use:         Parses a font name into a family and variant.
+
+fm__parse      ROUT
+
+               STMFD   R13!,{R2,R3,R14}        ;Save some registers
+               MOV     R2,R1                   ;Look after start pointer
+
+00fm__parse    LDRB    R14,[R1],#1             ;Load next byte from name
+               CMP     R14,#'.'                ;Is this a dot?
+               BEQ     %10fm__parse            ;Yes -- found the variant
+               CMP     R14,#32                 ;Is this the end?
+               BCS     %00fm__parse            ;No -- keep looking then
+
+               ; --- Reached end of name -- must be (Regular) ---
+
+               MOV     R14,#0                  ;Zero terminate for luck
+               STRB    R14,[R1,#-1]            ;Save it over the terminator
+               ADR     R0,fm__regular          ;Find the regular message
+               BL      msgs_lookup             ;Translate it nicely
+               MOV     R3,R1                   ;Point to variant buffer
+05fm__parse    LDRB    R14,[R0],#1             ;Load a byte from `Regular'
+               CMP     R14,#32                 ;Is this a control char?
+               MOVCC   R14,#0                  ;Yes -- zero terminate then
+               STRB    R14,[R3],#1             ;Store in destination
+               BCS     %05fm__parse            ;And loop round for the rest
+
+               MOV     R0,R2                   ;Point to family name again
+               LDMFD   R13!,{R2,R3,R14}        ;Unstack registers
+               BICS    PC,R14,#C_flag          ;And return to caller
+
+               ; --- Found a variant ---
+
+10fm__parse    MOV     R14,#0                  ;Zero terminate for luck
+               STRB    R14,[R1,#-1]            ;Save it over the terminator
+               MOV     R0,R2                   ;Point to family name again
+               LDMFD   R13!,{R2,R3,R14}        ;Unstack registers
+               ORRS    PC,R14,#C_flag          ;And return to caller
+
+fm__regular    DCB     "fmREG:(Regular)",0
+
+               LTORG
+
+; --- fm__ensure ---
+;
+; On entry:    R0 == address of anchor and size info
+;              R1 == free space required
+;
+; On exit:     R0 == address of first free byte in area
+;              May return an error
+;
+; Use:         Ensures that there is the requested quantity of memory free
+;              in the given block.
+
+fm__ensure     ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               LDMIB   R0,{R2,R14}             ;Load used and size words
+               ADD     R1,R1,R2                ;Find new total size
+               STR     R1,[R0,#4]              ;Save this back
+               ADD     R1,R1,#255              ;Align up to next 256
+               BIC     R1,R1,#255              ;For niceness's sake
+               CMP     R1,R14                  ;Do we already have enough?
+               BHI     %50fm__ensure           ;No -- allocate some more
+10fm__ensure   STR     R1,[R0,#8]              ;Save new total size
+               LDR     R0,[R0,#0]              ;Load address of block
+               ADD     R0,R0,R2                ;Point to first free byte
+               LDMFD   R13!,{R1,R2,R14}        ;And return to caller
+               BICS    PC,R14,#V_flag
+
+50fm__ensure   BL      flex_extend             ;No -- then extend the block
+               BCC     %10fm__ensure           ;If OK, rejoin the main thing
+               BL      alloc_error             ;Find an error message
+               LDMFD   R13!,{R1,R2,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- fm__string ---
+;
+; On entry:    R0 == pointer to anchor and size info
+;              R1 == pointer to null terminated string
+;
+; On exit:     R0 == length of the string+1
+;              May return an error
+;
+; Use:         Writes a string on the end of the given block.
+
+fm__string     ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               MOV     R2,R0                   ;Look after the anchor ptr
+               MOV     R3,R1                   ;Keep the string address
+               MOV     R0,R1                   ;Point to the string
+               BL      str_len                 ;Find the length of it
+               ADD     R1,R0,#1                ;Allow space for terminator
+               STR     R1,[R13,#0]             ;Save this as return value
+               MOV     R0,R2                   ;Point to the anchor
+               BL      fm__ensure              ;Make sure there's enough
+               MOVVC   R1,R3                   ;Point to string to write
+               BLVC    str_cpy                 ;Copy the string over
+               STRVS   R0,[R13,#0]             ;If it failed, return error
+               LDMFD   R13!,{R0-R3,PC}         ;And return to caller
+
+               LTORG
+
+; --- fm__align ---
+;
+; On entry:    R0 == pointer to anchor and size info
+;
+; On exit:     --
+;
+; Use:         Word aligns the block output address.
+
+fm__align      ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,[R0,#4]             ;Load the current used offset
+               ADD     R14,R14,#3              ;Round up to word boundary
+               BIC     R14,R14,#3              ;And do the round op
+               STR     R14,[R0,#4]             ;Save the offset back again
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- fm__fontPath ---
+;
+; On entry:    R0 == pointer to buffer
+;
+; On exit:     CS if there is a font path
+;              CC otherwise
+;
+; Use:         Reads the environmental variable font$path and copies
+;              it into the buffer given. The buffer must be at least 256
+;              bytes long.
+
+fm__fontPath   ROUT
+
+               STMFD   R13!,{R0-R4,R14}
+               MOV     R1,R0                   ;But buffer ptr in R1
+               ADR     R0,fm__varName          ;Point to the name
+               MOV     R2,#256                 ;Length of buffer
+               MOV     R3,#0                   ;First (and last) call
+               MOV     R4,#0                   ;Don't expand the string
+               SWI     XOS_ReadVarVal          ;Read the variable
+               MOV     R14,#0                  ;We need a NULL byte
+               STRVCB  R14,[R1,R2]             ;Store the terminator
+               LDMFD   R13!,{R0-R4,R14}        ;Load registers
+               ORRVCS  PC,R14,#C_flag          ;Return C set if exists
+               BICVSS  PC,R14,#C_flag          ;Or clear otherwise
+
+fm__varName    DCB     "Font$Path",0
+
+               LTORG
+
+fm__wSpace     DCD     0
+
+; --- fm__postFilter ---
+;
+; On entry:    R0 == wimp event
+;              R1 == wimp poll block pointer
+;
+; On exit:     --
+;
+; Use:         Looks out for font changed events.
+
+fm__postFilter ROUT
+
+               CMP     R0,#17                  ;Is it a message?
+               CMPNE   R0,#18
+               MOVNES  PC,R14                  ;Nope -- return
+               STMFD   R13!,{R0,R14}           ;Stack registers
+               LDR     R0,[R1,#16]             ;Load the message type
+               LDR     R14,=&4A2C0             ;Fonts changed message number
+               CMP     R14,R0                  ;Is that the message?
+               LDMNEFD R13!,{R0,PC}^           ;No -- return now
+               LDR     R14,fm__flags           ;Load flags word
+               ORR     R14,R14,#fmFlag__changed
+               STR     R14,fm__flags           ;Store back flags
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+; --- fm_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the font menu system.
+
+               EXPORT  fm_init
+fm_init                ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Stack some registers
+               WSPACE  fm__wSpace
+               MOV     R14,#0
+               STR     R14,fm__flags           ;No flags set yet
+
+               ; --- Set up the post filter ---
+
+               BL      event_init              ;Ensure event is ready
+               ADR     R0,fm__postFilter       ;Point to the handler
+               MOV     R1,R12                  ;R12 value to pass
+               BL      event_postFilter        ;Add in the post filter
+               SWIVS   OS_GenerateError        ;Generate the error
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to caller
+
+               LTORG
+
+;----- Events ---------------------------------------------------------------
+
+               ^       0
+fmEvent_select #       1                       ;User selected a font
+                                               ;R1 == pointer to name
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+
+fm__wStart     #       0
+
+fm__block      #       4                       ;Address of our heap block
+fm__ticks      #       8                       ;Tick blocks
+fm__menu       #       4                       ;Pointer to existing menu
+fm__name       #       40                      ;Static buffer to return name
+fm__userHandler        #       4                       ;User handler function
+fm__R10                #       4                       ;R10 value to call with
+fm__R12                #       4                       ;R12 value to call with
+fm__creator    #       4                       ;Menu creation routine
+fm__flags      #       4                       ;Useful flags word
+fm__path       #       256                     ;Current font path
+
+fm__wSize      EQU     {VAR}-fm__wStart
+
+fmFlag__changed        EQU     (1<<0)                  ;The fonts have changed
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     fm__wSize
+               DCD     fm__wSpace
+               DCD     256
+               DCD     fm_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/gallery b/StraySrc/Libraries/Sapphire/s/gallery
new file mode 100644 (file)
index 0000000..9ec489c
--- /dev/null
@@ -0,0 +1,399 @@
+;
+; gallery.s
+;
+; Background-drawing viewers
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:idle
+               GET     sapphire:screen
+               GET     sapphire:viewer
+
+               IMPORT  vw__intSimple
+               IMPORT  vw__enum
+               IMPORT  vw__doUpdate
+               IMPORT  vw__callShape
+
+;----- Main code ------------------------------------------------------------
+;
+; Some of this makes deep assumptions about the way viewer works and which
+; registers we /can/ corrupt even though the docs say otherwise.  That's OK
+; though.  We don't care.
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- gallery_eventHandler ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == pointer to handler routine
+;              R2 == R10 value to pass to handler
+;              R3 == R12 value to pass to handler
+;
+; On exit:     --
+;
+; Use:         Sets up an event handler for the viewer, and adds in
+;              gallery's own special processing for background drawing.
+
+               EXPORT  gallery_eventHandler
+gallery_eventHandler ROUT
+
+               STMFD   R13!,{R4,R14}           ;Save some registers
+               ADD     R14,R0,#vw__handler+4   ;Find some spare space
+               MOV     R4,R1                   ;And get R10 value in R4
+               STMIA   R14,{R2-R4}             ;Store the new handler
+               ADR     R4,gl__events           ;Point to our handler
+               STR     R4,[R0,#vw__handler]    ;And store that away
+               LDMFD   R13!,{R4,PC}^           ;And return to caller
+
+               LTORG
+
+; --- gallery_drawBox ---
+;
+; On entry:    R0-R3 == window relative coords of box to plot
+;
+; On exit:     --
+;
+; Use:         Draws a box to indicate tht this item hasn't been
+;              displayed yet.  Use this routine to give a consistant
+;              look to applications which use the gallery.
+
+               EXPORT  gallery_drawBox
+gallery_drawBox        ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Stack some registers
+               SUB     R13,R13,#32             ;Get room for an icon block
+               STMIA   R13,{R0-R3}             ;Store away the coordinates
+               MOV     R0,#&00000024           ;The icon flags
+               ORR     R0,R0,#&27000000        ;Compete them
+               STR     R0,[R13,#16]            ;Store the icon flags
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+               ADD     R13,R13,#32             ;Increment the stack again
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- gallery_removeBox ---
+;
+; On entry:    R0-R3 == window relative coords of box to remove
+;
+; On exit:     --
+;
+; Use:         Removes a previously draw temporary box.  It is assumed that
+;              the background colour of the viewere is 1.
+
+               EXPORT  gallery_removeBox
+gallery_removeBox ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Stack some registers
+               SUB     R13,R13,#32             ;Get room for an icon block
+               STMIA   R13,{R0-R3}             ;Store away the coordinates
+               MOV     R0,#&00000024           ;The icon flags
+               ORR     R0,R0,#&11000000        ;Compete them
+               STR     R0,[R13,#16]            ;Store the icon flags
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+               ADD     R13,R13,#32             ;Increment the stack again
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- gl__events ---
+;
+; On entry:    R0 == event code
+;              R1-R7 == information from viewer
+;
+; On exit:     exits via user handler
+;
+; Use:         Intercepts viewer events to do background redraw.
+
+gl__events     ROUT
+
+               CMP     R0,#vwEvent_redraw      ;Is this a redraw request?
+               LDRNE   PC,[R9,#gl__handler]    ;No -- pass it on then
+
+               STMFD   R13!,{R0-R3,R10,R14}    ;Save some registers
+               MOV     R10,R9                  ;Point to viewer block
+               MOV     R0,#vwShape_slowBit     ;Is this intersecting?
+               BL      vw__callShape           ;Call the shape function
+               BCC     %10gl__events           ;No -- then skip round
+
+               MOV     R0,#0                   ;This icon is not drawn yet
+               BL      gl__drawn               ;So set the flag up nicely
+
+               LDR     R14,[R10,#vw__flags]    ;Load the flags word
+               TST     R14,#glFlag__drawing    ;Do we have the idle going?
+               BNE     %10gl__events           ;Yes -- then skip on
+
+               ORR     R14,R14,#glFlag__drawing;No -- set the flag then
+               STR     R14,[R10,#vw__flags]    ;And store them back again
+               MOV     R0,#0                   ;Call me all the time
+               ADR     R1,gl__idles            ;No -- point to the handler
+               MOV     R2,R10                  ;Point to the viewer block
+               MOV     R3,R12                  ;Point to someone else's wsp
+               BL      idle_handler            ;Register the handler
+
+10gl__events   LDMFD   R13!,{R0-R3,R10,R14}    ;And return to caller
+               LDR     PC,[R9,#gl__handler]    ;Continue processing event
+
+               LTORG
+
+; --- gallery_reset ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Resets all the icons in the gallery to their `undrawn' state.
+;              Use this before opening the window etc.
+
+               EXPORT  gallery_reset
+gallery_reset  ROUT
+
+               STMFD   R13!,{R0-R4,R10,R14}    ;Save some registers
+               MOV     R10,R0                  ;Get the viewer handle
+               MOV     R1,#0                   ;Start at the beginning
+               LDR     R4,[R10,#vw__listDef]   ;Find the list definition
+00             LDR     R0,[R10,#vw__list]      ;Find the list base address
+               MOV     R2,#2                   ;Match drawn icons
+               MOV     R3,#2                   ;And only the drawn ones
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R4,#vw__enumerate    ;Find the next item
+               BCC     %f00                    ;When finished, skip out
+               MOV     R3,#0                   ;Clear the bit now
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R4,#vw__setFlags     ;Set up the flags nicely
+               B       %b00                    ;And loop back round again
+00             LDMFD   R13!,{R0-R4,R10,PC}^    ;And return to caller
+
+               LTORG
+
+; --- gl__idles ---
+;
+; On entry:    R10 == pointer to viewer block
+;
+; On exit:     --
+;
+; Use:         Redraws the first unredrawn item in the viewer.
+
+gl__idles      ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               SUB     R13,R13,#36             ;Make space for a window blk
+               LDR     R14,[R10,#vw__window]   ;Load the window handle
+               STR     R14,[R13,#0]            ;Store it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window information
+               MOV     R3,R13                  ;And again please
+               BL      gl__clipBlock           ;Build the clipping info
+
+               MOV     R1,#0                   ;Start at the beginning
+00             ADD     R2,R13,#16              ;Point to a spare bit of blk
+               BL      vw__enum                ;Get another icon to do
+               BCC     %50gl__idles            ;No icons -- remove handler
+               BL      vw__intSimple           ;Do the boxes intersect?
+               BLCS    gl__isDrawn             ;Is the thing drawn yet?
+               BCC     %b00                    ;No -- then skip back
+
+               ; --- Draw this item ---
+
+               MOV     R0,#1                   ;It's now drawn (well, soon)
+               BL      gl__drawn               ;So remember this
+               MOV     R0,R10                  ;Point to the viewer block
+               MOV     R2,#vwEvent_unDraw      ;Undraw the temporary bit
+               BL      vw__doUpdate            ;Go and do the update
+               MOV     R2,#vwEvent_draw        ;Now draw it properly
+               BL      vw__doUpdate            ;And then draw it properly
+               ADD     R13,R13,#36             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               ; --- Remove this handler ---
+
+50gl__idles    MOV     R0,#0                   ;Call me all the time
+               ADR     R1,gl__idles            ;No -- point to the handler
+               MOV     R2,R10                  ;Point to the viewer block
+               MOV     R3,R12                  ;Point to someone else's wsp
+               BL      idle_removeHandler      ;Remove the handler thing
+               LDR     R14,[R10,#vw__flags]    ;Load the flags word
+               BIC     R14,R14,#glFlag__drawing;Not drawing any more
+               STR     R14,[R10,#vw__flags]    ;Store the flags away
+               ADD     R13,R13,#36             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+; --- gl__clipBlock ---
+;
+; On entry:    R1 == pointer to window-state block
+;              R3 == pointer to output block
+;
+; On exit:     --
+;
+; Use:         Replaces the window-state block with a block containing the
+;              window-relative coordinates of the visible part of the
+;              window.
+
+gl__clipBlock  ROUT
+
+               STMFD   R13!,{R0-R2,R4,R5,R14}  ;Save some registers
+               LDMIB   R1,{R0-R2,R4,R5,R14}    ;Load window position/scroll
+               SUB     R2,R2,R0                ;Find the window width
+               SUB     R1,R4,R1                ;And the window height
+               MOV     R0,R5                   ;This is the x0 position
+               ADD     R5,R5,R2                ;And this is the x1 position
+               SUB     R1,R14,R1               ;This is y0
+               STMIA   R3,{R0,R1,R5,R14}       ;Save that lot away now
+               LDMFD   R13!,{R0-R2,R4,R5,PC}^  ;And return to caller
+
+               LTORG
+
+; --- gl__drawn ---
+;
+; On entry:    R0 == 0 to say `undrawn', 1 to say `drawn'
+;              R1 == item handle
+;
+; On exit:     --
+;
+; Use:         Sets or resets an icon's drawn flag.
+
+gl__drawn      ROUT
+
+               STMFD   R13!,{R0,R2-R4,R14}     ;Save some registers
+               MOV     R2,#2                   ;Set the drawn flag
+               MOV     R3,R0,LSL #1            ;Do with it what he said
+               LDR     R0,[R10,#vw__list]      ;Load the list pointer
+               LDR     R4,[R10,#vw__listDef]   ;And the list defintion
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R4,#vw__setFlags     ;Read the item's flags
+               LDMFD   R13!,{R0,R2-R4,PC}^     ;Restore registers
+
+               LTORG
+
+; --- gl__isDrawn ---
+;
+; On entry:    R1 == item handle
+;
+; On exit:     CC if item has been drawn, else CS
+;
+; Use:         Tells you quickly whether an item has been drawn.
+
+gl__isDrawn    ROUT
+
+               STMFD   R13!,{R0,R2-R4,R14}     ;Save some registers
+               LDR     R0,[R10,#vw__list]      ;Load the list pointer
+               LDR     R4,[R10,#vw__listDef]   ;And the list defintion
+               MOV     R2,#0                   ;Read the flags please
+               MOV     R3,#0                   ;Don't change them, no missus
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R4,#vw__setFlags     ;Read the item's flags
+               TST     R2,#2                   ;Is the flag set?
+               LDMFD   R13!,{R0,R2-R4,R14}     ;Restore registers
+               ORREQS  PC,R14,#C_flag          ;If not set, return CS
+               BICNES  PC,R14,#C_flag          ;Else return CC
+
+               LTORG
+
+;----- List definition format -----------------------------------------------
+
+               ^       0
+vw__itemToIndex        #       4                       ;Item to index routine
+                                               ;Entry: R0 == pointer to list
+                                               ;       R1 == pointer to item
+                                               ;Exit:  R1 == index, or -1
+
+vw__indexToItem        #       4                       ;Index to item routine
+                                               ;Entry: R0 == pointer to list
+                                               ;       R1 == index of item
+                                               ;Exit:  R1 == item ptr, or 0
+
+vw__enumerate  #       4                       ;Enumeration function
+                                               ;Entry: R0 == list pointer
+                                               ;       R1 == item, or 0
+                                               ;       R2 == BIC mask
+                                               ;       R3 == test mask
+                                               ;Exit:  CS if match, and
+                                               ;       R1 == item ptr
+
+vw__items      #       4                       ;Function to return items
+                                               ;Entry: R0 == list pointer
+                                               ;Exit:  R1 == number of items
+
+vw__setFlags   #       4                       ;Function to set/read flags
+                                               ;Entry: R1 == pointer to item
+                                               ;       R2 == BIC mask
+                                               ;       R3 == EOR mask
+                                               ;Exit:  R2 == new flags
+
+;----- Viewer's icky bits which we poke around in ---------------------------
+
+               ^       0
+
+               ; --- Information about the window ---
+
+vw__window     #       4                       ;Window handle
+vw__extent     #       16                      ;Current window extent
+vw__flags      #       4                       ;Any flags of interest
+vw__list       #       4                       ;Pointer to list head
+vw__listDef    #       4                       ;Pointer to list handler
+vw__handler    #       12                      ;Viewer's event handler
+gl__handler    #       8                       ;Gallery's event handler(YUK)
+vw__shape      #       4                       ;Shape handler function
+vw__banner     #       4                       ;Pointer to banner string
+vw__fixedWidth #       4                       ;Width of banner/title
+
+               ; --- Icon sizing information ---
+
+vw__icons      #       4                       ;Cache number of icons
+vw__stdDimens  #       8                       ;`Standard' width and height
+vw__iconWidth  #       4                       ;Width of icons currently
+vw__iconHeight #       4                       ;Height of icons currently
+vw__across     #       4                       ;Number of icons across
+vw__down       #       4                       ;Number of icons down
+
+               ; --- Data for default selection model ---
+
+vw__tempSel    #       4                       ;Temporary selected icon
+
+               ; --- Big buffers at the end ---
+
+vw__title      #       256                     ;Title bar buffer
+
+vw__size       #       0                       ;Size of a viewer block
+
+               ; --- Flags bits ---
+               ;
+               ; We only have the top-end bits.
+
+glFlag__drawing        EQU     (1<<31)                 ;We have idle handler running
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/heap b/StraySrc/Libraries/Sapphire/s/heap
new file mode 100644 (file)
index 0000000..589c9d7
--- /dev/null
@@ -0,0 +1,2 @@
+               GBLL    OPT_SAPPHIRE
+               LNK     libs:s.heap
diff --git a/StraySrc/Libraries/Sapphire/s/help b/StraySrc/Libraries/Sapphire/s/help
new file mode 100644 (file)
index 0000000..84974c0
--- /dev/null
@@ -0,0 +1,432 @@
+;
+; help.s
+;
+; Sending and handling help messages (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:event
+               GET     sapphire:idle
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:string
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- help_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the help system for use.
+
+               EXPORT  help_init
+help_init      ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers
+
+               ; --- Make sure we're not going already ---
+
+               WSPACE  help__wSpace            ;Locate my workspace pointer
+               LDR     R14,help__flags         ;Get my flags word
+               TST     R14,#hFlag__inited      ;Am I initialised already?
+               LDMNEFD R13!,{R0,R1,R12,PC}^    ;Yes - return to caller
+               ORR     R14,R14,#hFlag__inited  ;I will be initialised soon
+               STR     R14,help__flags         ;Store the flags word back
+
+               ; --- Set up the workspace ---
+
+               MOV     R14,#20                 ;Start message size as 20
+               STR     R14,help__message+0     ;Store this in the block
+               MOV     R14,#0                  ;No message to reply to
+               STR     R14,help__msgTask       ;Store in the your_ref field
+
+               ; --- Set up my prefilter ---
+
+               BL      event_init              ;Make sure event is awake
+               ADR     R0,help__preFilter      ;Point to the prefilter
+               MOV     R1,R12                  ;Pass along my workspace
+               BL      event_preFilter         ;Register it with event
+               ADR     R0,help__postFilter     ;Point to the postfilter
+               BL      event_postFilter        ;Register that with event too
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to caller
+
+               LTORG
+
+help__wSpace   DCD     0
+
+; --- help__preFilter ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Dispatches the currently waiting help reply, if there is
+;              one.  Also fakes hint requests and dispatches finished hints
+;              to windows.
+
+help__preFilter        ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+
+               ; --- Check for hints first ---
+
+               LDR     R14,help__flags         ;Get my flags word
+               TST     R14,#hFlag__hinted      ;Do we have a waiting hint?
+               BNE     %50help__preFilter      ;Yes -- dispatch it to window
+               TST     R14,#hFlag__hinting     ;Do we need to make a hint?
+               BNE     %60help__preFilter      ;Yes -- build the block then
+
+               ; --- Otherwise, check for finished help messages ---
+
+               LDR     R14,help__msgTask       ;Get the your_ref for this
+               CMP     R14,#0                  ;Is this sensible?
+               LDMEQFD R13!,{PC}^              ;No -- return
+
+               STMFD   R13!,{R0-R3}            ;Save some more registers
+               LDR     R14,help__message+0     ;Load the message length
+               ADD     R14,R14,#4              ;Word align the size as reqd.
+               BIC     R14,R14,#3              ;Yep, indeedy
+               STR     R14,help__message+0     ;Store length back again
+
+               ADR     R1,help__message        ;Point to the message block
+               LDR     R2,help__msgTask        ;Load the task handle out
+               MOV     R0,#0                   ;No more messages waiting
+               STR     R0,help__msgTask        ;So zero the task handle
+               MOV     R0,#17                  ;Don't care if it bounces
+               SWI     Wimp_SendMessage        ;Send the message out
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               ; --- Send a finished hint to the hint window ---
+
+50             STMFD   R13!,{R1}               ;Save some registers away
+               BIC     R14,R14,#hFlag__hinted :OR: hFlag__hinting
+               STR     R14,help__flags         ;Clear all the hint flags
+               LDR     R14,help__window        ;Get the hint destination
+               STR     R14,[R1,#0]             ;Store in the poll block
+               ADD     R0,R1,#4                ;Point to next spare field
+               ADR     R1,help__message+20     ;Point to hint string
+               BL      str_cpy                 ;Copy it over
+               MOV     R0,#-1                  ;The magic hint reason code
+               LDMFD   R13!,{R1,R14}           ;Restore registers
+               ORRS    PC,R14,#C_flag          ;Return to caller
+
+               ; --- Try to get a new hint from the window ---
+
+60             STMFD   R13!,{R1-R5}            ;Save a load of registers
+               ORR     R14,R14,#hFlag__hinted  ;Dispatch hint next time
+               STR     R14,help__flags         ;Save new flags word
+
+               ; --- Build a skeleton hint in case of no reply ---
+
+               MOV     R0,#0                   ;A null string
+               STR     R0,help__message+20     ;Store over the string start
+
+               ; --- Build a help request in the poll block ---
+
+               MOV     R0,#44                  ;Size of help request message
+               MOV     R2,#-1                  ;A very bogus task handle
+               MOV     R3,#-1                  ;A similarly bogus my_ref
+               MOV     R4,#0                   ;This is not a reply
+               MOV     R5,#&500                ;Help request message code
+               ORR     R5,R5,#&002             ;Finish off message code
+               STMIA   R1!,{R0,R2-R5}          ;Build message header
+               STR     R4,help__msgTask        ;Zero destination task handle
+               SWI     Wimp_GetPointerInfo     ;Get the current pointer pos
+               MOV     R0,#18                  ;Make it look real!
+               LDMFD   R13!,{R1-R5,R14}        ;Restore registers
+               ORRS    PC,R14,#C_flag          ;Return to caller
+
+               LTORG
+
+; --- help__postFilter ---
+;
+; On entry:    R0 == event reason code
+;              R1 == pointer to event block
+;
+; On exit:     --
+;
+; Use:         Catches pointer-entering and pointer-leaving events and
+;              sets up the idle claimer appropriately.
+
+help__postFilter ROUT
+
+               ; --- Ensure that we want this event ---
+
+               CMP     R0,#4                   ;Pointer leaving?
+               MOVNES  PC,R14                  ;No -- return now
+
+               ; --- Pointer is leaving one of tasks windows ---
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+               LDR     R14,help__flags         ;Get my flags word
+               TST     R14,#hFlag__hintable    ;Is window hintable?
+               LDMEQFD R13!,{R0-R3,PC}^        ;No -- ignore this then
+               MOV     R0,#5                   ;Call it this frequently
+               ADR     R1,help__idles          ;Call this on idle events
+               MOV     R2,#0                   ;Our user handle
+               MOV     R3,R12                  ;Put our workspace in R12
+               BL      idle_removeHandler      ;Remove handler
+
+               ; --- Pointer has just left the window ---
+               ;
+               ; It looks really silly if the window we left still has a
+               ; hint in it, so we send it a dummy hint with a null string.
+
+               MOV     R0,#0                   ;A zero byte for the string
+               STR     R0,help__message+20     ;Store over the string start
+               LDR     R14,help__flags         ;Get my flags word
+               ORR     R14,R14,#hFlag__hinted  ;There's a hint waiting
+               BIC     R14,R14,#hFlag__hintable;Disable the hints system
+               STR     R14,help__flags         ;Store flags back again
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- help_sendHints ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Should be called on a pointer-entering-window event.  It
+;              enables hint requests for the window beneath the pointer.
+
+               EXPORT  help_sendHints
+help_sendHints ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Save some registers
+               WSPACE  help__wSpace            ;Load my workspace address
+               LDR     R14,help__flags         ;Load my flags word
+               TST     R14,#hFlag__hintable    ;Are hints enabled?
+               LDMNEFD R13!,{R0-R3,R12,PC}^    ;Yes -- then return now
+               ORR     R14,R14,#hFlag__hintable;Set the hints enabled flag
+               STR     R14,help__flags         ;And save the flags back
+
+               MOV     R0,#5                   ;Call it this frequently
+               ADR     R1,help__idles          ;Call this on idle events
+               MOV     R2,#0                   ;Our user handle
+               MOV     R3,R12                  ;Put our workspace in R12
+               BL      idle_handler            ;Add idle handler
+               MOV     R0,#-3                  ;Set up previous icon hnd
+               STR     R0,help__icon           ;...to a really weird value
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- help__idles ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Catches pointer movement between icons, and sets the hint
+;              flags accordingly.
+
+help__idles    ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers away
+               SUB     R13,R13,#24             ;Make space for a pointer blk
+               MOV     R1,R13                  ;Point to it
+               SWI     Wimp_GetPointerInfo     ;Get the current ptr posn
+               ADD     R14,R13,#12             ;Point to window/icon hnds
+               LDMIA   R14,{R0,R2}             ;Load them out of the block
+               ADD     R13,R13,#24             ;Reclaim the stack I used
+
+               ; --- Find out if we need to get a new hint ---
+
+               LDR     R1,help__icon           ;Get the old icon I was on
+               CMP     R1,R2                   ;Do they match?
+               BEQ     %90help__idles          ;Yes -- nothing more to do
+
+               CMP     R2,#0                   ;Is ptr over the background?
+               MOVLT   R2,#-3                  ;Yes -- give it a silly value
+               STR     R2,help__icon           ;No -- store as new old icon
+               STR     R0,help__window         ;Save the hint window handle
+               LDR     R14,help__flags         ;Get my flags word
+               ORR     R14,R14,#hFlag__hinting ;Get ready to send a hint rq
+               STR     R14,help__flags         ;Store the flags away again
+
+90help__idles  LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- help_add ---
+;
+; On entry:    R0 == pointer to message string to add
+;
+; On exit:     --
+;
+; Use:         Adds a line to the help message being built currently.  Note
+;              that overflows are trapped, and errors are generated if one
+;              would occur.
+
+               EXPORT  help_add
+help_add       ROUT
+
+               STMFD   R13!,{R0-R4,R12,R14}    ;Save some registers
+               WSPACE  help__wSpace            ;Find my workspace area
+               LDR     R14,help__msgTask       ;Get the destination task
+               CMP     R14,#0                  ;Is there one set up?
+               BNE     %10help_add             ;Yes -- add a subsequent line
+
+               ; --- We're starting a new help reply ---
+
+               BL      event_last              ;Get the last event out
+               MOV     R2,#&500                ;The message code to match
+               ORR     R2,R2,#&002             ;Can't load in one op
+               CMP     R0,#17                  ;Make sure it's a message
+               CMPNE   R0,#18                  ;Either one will do
+               LDREQ   R14,[R1,#16]            ;Get the message code
+               CMPEQ   R14,R2                  ;Does this match up?
+               LDMNEFD R13!,{R0-R4,R12,PC}^    ;If not, return right now
+
+               ; --- Set up the message block ---
+
+               ADD     R4,R2,#1                ;The reply code is one larger
+               MOV     R0,#20                  ;Size of the message block
+               LDR     R3,[R1,#8]              ;Load his my_ref value
+               MOV     R14,#0                  ;Null terminate the string
+               STMIB   R12,{R0-R4,R14}         ;Build the message block
+               LDR     R14,[R1,#4]             ;Get the task handle out
+               STR     R14,help__msgTask       ;Store the handle away
+
+               ; --- Set up for main copy loop ---
+
+               LDR     R0,[R13,#0]             ;Get the string pointer back
+               MOV     R1,R11                  ;Find a spare buffer
+               BL      msgs_build              ;Build the message nicely
+               ADR     R1,help__message+20     ;Current pointer for string
+               MOV     R2,#20                  ;Current length
+               B       %20help_add             ;Now skip to main code
+
+               ; --- Add in a line separator ---
+
+10help_add     MOV     R1,R11                  ;Find a spare buffer
+               BL      msgs_build              ;Build the message nicely
+
+               LDR     R2,help__message+0      ;Get the current message size
+               ADR     R1,help__message        ;Point to the message start
+               ADD     R1,R1,R2                ;Get current pointer
+               CMP     R2,#253                 ;Make sure it will fit
+               BGT     %90                     ;If it doesn't, make error
+
+               LDR     R14,help__flags         ;Load my flags word
+               TST     R14,#hFlag__hinted      ;Am I building a hint?
+               MOVEQ   R14,#'|'                ;No -- strings get GSTransed
+               MOVNE   R14,#' '                ;Yes -- spaces not newlines
+               STRB    R14,[R1],#1             ;Store the character
+               MOVEQ   R14,#'M'                ;`|M' is a return character
+               STRB    R14,[R1],#1             ;Store the character
+               ADD     R2,R2,#2                ;We've added two characters
+
+               ; --- Now copy the string over, trapping overflows ---
+
+20help_add     CMP     R2,#256                 ;Do we have room for another?
+               BGE     %90                     ;No -- moan bitterly
+               LDRB    R14,[R0],#1             ;Get an input character
+               CMP     R14,#' '                ;Is this a control character?
+               MOVLT   R14,#0                  ;Yes -- store a zero nicely
+               STRB    R14,[R1],#1             ;Store it in my message
+               ADD     R2,R2,#1                ;Bump the character count
+               BGE     %20help_add             ;Loop round for more
+
+               ; --- Set things up for next time ---
+
+               SUB     R2,R2,#1                ;Overwrite the last null byte
+               STR     R2,help__message+0      ;Store the message length
+               LDMFD   R13!,{R0-R4,R12,PC}^    ;Return to caller
+
+               ; --- We overflowed -- complain ---
+
+90help_add     MOV     R0,#0                   ;Zero the task handle...
+               STR     R0,help__msgTask        ;...to stop it being sent
+               ADR     R0,help__overflow       ;Point to the message
+               BL      msgs_error              ;Translate it as normal
+               SWI     OS_GenerateError        ;And generate the error
+
+help__overflow DCD     1
+               DCB     "helpOFLOW",0
+
+               LTORG
+
+; --- help_reset ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Resets the help system so that a hint request is sent to an
+;              icon that the pointer is already over. The proposed use
+;              is that the caller can change a help message for a given
+;              icon as soon as it is clicked on.
+
+               EXPORT  help_reset
+help_reset     ROUT
+
+               STMFD   R13!,{R12,R14}          ;Stack some registers
+               WSPACE  help__wSpace            ;Load my workspace address
+               MOV     R14,#-3                 ;Set up previous icon hnd
+               STR     R14,help__icon          ;...to a really weird value
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+help__wStart   #       0
+
+help__flags    #       4                       ;Various flags
+help__message  #       256                     ;The actual message to send
+help__msgTask  #       4                       ;Task to send message to
+help__msgNext  #       4                       ;Pointer to message tail
+help__window   #       4                       ;The window the ptr is over
+help__icon     #       4                       ;The icon the ptr is over
+
+help__wSize    EQU     {VAR}-help__wStart
+
+hFlag__inited  EQU     (1<<0)                  ;Am I initialised?
+hFlag__hintable        EQU     (1<<1)                  ;Current window wants hints
+hFlag__hinting EQU     (1<<2)                  ;We're gathering up a hint
+hFlag__hinted  EQU     (1<<3)                  ;Is a hint waiting?
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     help__wSize
+               DCD     help__wSpace
+               DCD     0
+               DCD     help_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/hour b/StraySrc/Libraries/Sapphire/s/hour
new file mode 100644 (file)
index 0000000..195c622
--- /dev/null
@@ -0,0 +1,335 @@
+;
+; hour.s
+;
+; Handling of the hourglass (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Here is Wisdom -------------------------------------------------------;
+; The standard Hourglass system is OK but for one small problem: you can't
+; stop the thing and restart where you left off.  So, we put a wrapper round
+; it so that we can do this.  This involves keeping our own record of
+; exactly what's going on.
+;
+; This module is designed to be very small and unobtrusive, so you can have
+; dependencies on it all over without much hassle.  The only external
+; dependency is on except, and wimp includes that anyway, so it's not really
+; a great problem.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:except
+               GET     sapphire:sapphire
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- hour_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the hour system, so it will display an hourglass
+;              when necessary.
+;
+;              Since this gets called at a random point during the Sapphire
+;              initialisation, and we can rely on Hourglass keeping its
+;              own count, the suggested way of handling everything properly
+;              is as follows:
+;
+;                              SWI     Hourglass_On
+;                              BL      sapphire_init
+;                              SWI     Hourglass_Off
+
+               EXPORT  hour_init
+hour_init      ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  hour__wSpace            ;Locate my workspace address
+
+               ; --- Make sure I haven't already done this ---
+
+               LDR     R14,hour__flags         ;Find my flags word nicely
+               TST     R14,#hFlag__inited      ;Am I initialised yet?
+               LDMNEFD R13!,{R12,PC}^          ;Yes -- return right now
+
+               ; --- Set up my workspace properly ---
+
+               STMFD   R13!,{R0-R2}            ;Save some more registers
+               MOV     R0,#hFlag__inited       ;Say I'm initialised
+               MOV     R1,#0                   ;No Hourglass count yet
+               MOV     R2,#255                 ;No other status stuff either
+               STMIA   R12,{R0-R2}             ;Save the stuff in workspace
+
+               ; --- Register my atexit handler ---
+
+               BL      except_init             ;Make sure except is awake
+               ADR     R0,hour__exit           ;Point to the handler
+               MOV     R1,R12                  ;Pass my workspace along
+               BL      except_atExit           ;Make sure I can tidy up
+
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller
+
+               LTORG
+
+hour__wSpace   DCD     0
+
+; --- hour__exit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Kills off the Hourglass if it's displaying when the program
+;              finally quits.
+
+hour__exit     ROUT
+
+               STMFD   R13!,{R14}              ;Store the return address
+               LDR     R14,hour__count         ;Find my Hourglass counter
+               CMP     R14,#0                  ;Is it not displaying?
+               SWIGT   Hourglass_Off           ;No -- turn it off then
+               LDMFD   R13!,{PC}^              ;Return to caller finally
+
+               LTORG
+
+; --- hour_on ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Turns the Hourglass on only if it isn't on already.
+;              Otherwise its status is left as it was.
+
+               EXPORT  hour_on
+hour_on                ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save a couple of registers
+               WSPACE  hour__wSpace            ;Load my workspace pointer
+               LDR     R14,hour__count         ;Find my Hourglass counter
+               ADD     R14,R14,#1              ;Bump the counter on one
+               STR     R14,hour__count         ;Store it back again
+               CMP     R14,#1                  ;Has it just been turned on?
+               SWIEQ   Hourglass_On            ;Yes -- turn it on then
+               LDMFD   R13!,{R12,PC}^          ;Return to caller finally
+
+               LTORG
+
+; --- hour_off ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Turns the Hourglass off if it's only been turned on once.
+;              If the Hourglass gets turned off, all the information about
+;              it (percentage and LEDs) get forgotten.
+
+               EXPORT  hour_off
+hour_off       ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  hour__wSpace            ;Load my workspace pointer
+               LDR     R14,hour__count         ;Find my Hourglass counter
+               SUBS    R14,R14,#1              ;Decrement it nicely
+               MOVLT   R14,#0                  ;If negative, keep at zero
+               STR     R14,hour__count         ;Store counter back anyway
+               STRLE   R14,hour__percent       ;If turning off, zero percent
+               SWILE   Hourglass_Off           ;and turn Hourglass off too
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+; --- hour_percent ---
+;
+; On entry:    R0 == percentage value to display, or -1 to remove
+;
+; On exit:     --
+;
+; Use:         Attaches a percentage display to the Hourglass.
+
+               EXPORT  hour_percent
+hour_percent   ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers away
+               WSPACE  hour__wSpace            ;Find my workspace address
+               LDR     R14,hour__count         ;Get the counter out
+               CMP     R14,#0                  ;Has it been turned on yet?
+               STRGTB  R0,hour__percent        ;Yes -- store the percentage
+               SWIGT   Hourglass_Percentage    ;And display it properly
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+; --- hour_leds ---
+;
+; On entry:    R0 == LED mask EOR value
+;              R1 == LED mask AND value
+;
+; On exit:     --
+;
+; Use:         Changes the Hourglass LED status.
+
+               EXPORT  hour_leds
+hour_leds      STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers away
+               WSPACE  hour__wSpace            ;Find my workspace address
+               LDR     R14,hour__count         ;Get the counter out
+               CMP     R14,#0                  ;Has it been turned on yet?
+               LDMLEFD R13!,{R0,R1,R12,PC}^    ;No -- just return then
+               LDR     R14,hour__leds          ;Get the current LED state
+               AND     R14,R14,R1              ;Apply the AND mask to it
+               EOR     R0,R14,R0               ;Apply the EOR mask to it
+               LDR     R0,hour__leds           ;Store the status back again
+               MOV     R1,#0                   ;Clear all LED bits
+               SWI     Hourglass_LEDs          ;Now set the actual LEDs
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- hour_suspend ---
+;
+; On entry:    R0 == pointer to 2 word block to save status in
+;
+; On exit:     --
+;
+; Use:         Saves the Hourglass state in a block you've pointed at,
+;              and disables the Hourglass.  Useful if you want to do some
+;              user interaction without polling (e.g. an error box).
+
+               EXPORT  hour_suspend
+hour_suspend   ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save a bunch of registers
+               WSPACE  hour__wSpace            ;Load my workspace address
+               LDMIB   R12,{R1,R2}             ;Load the Hourglass state
+               STMIA   R0,{R1,R2}              ;Save it in caller's block
+               CMP     R1,#0                   ;Is the Hourglass on ATM?
+               SWIGT   Hourglass_Off           ;Yes -- turn it off then
+               MOV     R1,#0                   ;Zero the counter
+               MOV     R2,#255                 ;And the other status bits
+               STMIB   R12,{R1,R2}             ;Save over my old state
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller nicely
+
+               LTORG
+
+; --- hour_save ---
+;
+; On entry:    R0 == pointer to 2 word block to save status in
+;
+; On exit:     --
+;
+; Use:         Saves the current Hourglass status without altering it.
+
+               EXPORT  hour_save
+hour_save      ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save a bunch of registers
+               WSPACE  hour__wSpace            ;Load my workspace address
+               LDMIB   R12,{R1,R2}             ;Load the Hourglass state
+               STMIA   R0,{R1,R2}              ;Save it in caller's block
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller finally
+
+               LTORG
+
+; --- hour_resume, hour_restore ---
+;
+; On entry:    R0 == pointer to 2 words filled by hour_suspend or hour_save
+;
+; On exit:     --
+;
+; Use:         Restores the Hourglass state to that saved away by one
+;              of the previous two calls.  This routine has two names.
+
+               EXPORT  hour_resume
+               EXPORT  hour_restore
+hour_resume
+hour_restore   ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers away
+               WSPACE  hour__wSpace            ;Load my workspace address
+               LDR     R14,hour__count         ;Load the current counter
+
+               ; --- Restore the workspace contents ---
+
+               LDMIA   R0,{R0,R1}              ;Load the saved status
+               CMP     R0,#0                   ;Is the Hourglass on?
+               MOVLT   R0,#0                   ;If negative, restore to 0
+               MOVLE   R1,#255                 ;If off, force percent off
+               STMIB   R12,{R0,R1}             ;Save in my workspace
+
+               ; --- Now restore the Hourglass onness ---
+
+               MOVGT   R0,#1                   ;If now on, store as 1
+               CMP     R14,#0                  ;Is the old state on?
+               MOVLT   R14,#0                  ;Force result nonnegative
+               MOVGT   R14,#1                  ;If was on, store as 1
+               CMP     R0,R14                  ;Are the states the same?
+               SWIGT   Hourglass_On            ;If now on, was off, enable
+               SWILT   Hourglass_Off           ;If now off, was on, disable
+               CMP     R0,#0                   ;Is it now off?
+               LDMEQFD R13!,{R0,R1,R12,PC}^    ;Yes -- return to caller
+
+               ; --- Now restore other Hourglass bits ---
+
+               AND     R0,R1,#&FF              ;Get the percentage state
+               SWI     Hourglass_Percentage    ;Send that to the Hourglass
+               AND     R0,R1,#&FF00            ;Get the LED state too
+               MOV     R0,R0,LSR #8            ;Shift down to bottom of R0
+               MOV     R1,#0                   ;Don't leave old state there
+               SWI     Hourglass_LEDs          ;And restore LED state
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return, we did everything
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+hour__wStart   #       0
+
+hour__flags    #       4                       ;A flags word (see later)
+hour__count    #       4                       ;no(hour_on) - no(hour_off)
+hour__percent  #       1                       ;Current percentage displayed
+hour__leds     #       1                       ;Current LED status
+hour__padding  #       2                       ;Pad size to word boundary
+
+hour__wSize    EQU     {VAR}-hour__wStart
+
+hFlag__inited  EQU     (1<<0)                  ;Am I initialised yet?
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     hour__wSize
+               DCD     hour__wSpace
+               DCD     0
+               DCD     hour_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/ibicon b/StraySrc/Libraries/Sapphire/s/ibicon
new file mode 100644 (file)
index 0000000..815c11b
--- /dev/null
@@ -0,0 +1,610 @@
+;
+; ibicon.s
+;
+; Icon bar icon handling (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:msgs
+               GET     sapphire:suballoc
+               GET     sapphire:sapphire
+               GET     sapphire:string
+               GET     sapphire:resspr
+               GET     sapphire:wimp
+               GET     sapphire:win
+
+;----- Event types ----------------------------------------------------------
+
+               ^       0
+ibEvent_select #       1
+ibEvent_menu   #       1
+ibEvent_adjust #       1
+ibEvent_save   #       1
+ibEvent_load   #       1
+ibEvent_help   #       1
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- ibicon__addToList ---
+;
+; On entry:    R0 == icon handle
+;              R1 == pointer to routine to call
+;              R2 == pointer to icon data
+;              R3 == pointer to validation string
+;              R4 == R10 value to call routine
+;              R5 == R12 value to call routine with
+;              R6 == pointer to list head to use
+;
+; On exit:     R0-R6 preserved
+;
+; Use:         Adds a rountine to the given list. Later added
+;              routines are called first
+
+ibicon__addToList
+               ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Stack some registers
+
+               ; --- Allocate a block ---
+
+               MOV     R0,#list__size          ;Size to allocate
+               BL      sub_alloc               ;Allocate the block
+               BVS     %01                     ;Branch ahead if error
+
+               ; --- Fill the block in ---
+
+               LDR     R1,[R6]                 ;Get the list head
+               STR     R1,[R0,#list__next]     ;Store in next field
+               STR     R0,[R6]                 ;Store new block at head
+
+               LDMIA   R13,{R1-R6}             ;Get parameters
+               STMIB   R0,{R1-R6}              ;Store them in the block
+
+               ; --- And return to user ---
+
+               LDMFD   R13!,{R0-R6,R14}        ;Load back link
+               BICS    PC,R14,#V_flag          ;Return without error
+
+               ; --- Barf if an error occured ---
+
+01             ADD     R13,R13,#4              ;Skip over R0
+               LDMFD   R13!,{R1-R6,R14}        ;Branch if error
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- ibicon__removeFromList ---
+;
+; On entry:    R0 == ibicon pointer
+;              R1 == pointer to list head to use
+;
+; On exit:     All registers/flags preserved
+;
+; Use:         Removes a routine from the given list. All values are
+;              compared.
+
+ibicon__removeFromList
+               ROUT
+
+               STMFD   R13!,{R0-R4,R14}
+
+               ; --- Find the block ---
+
+               MOV     R2,R1                   ;The previous pointer
+               LDR     R1,[R1]                 ;Get the head of the list
+01             TEQ     R1,#0                   ;Are we at the end?
+               LDMEQFD R13!,{R0-R4,PC}^        ;Yes -- return
+               LDR     R4,[R1]                 ;Get the next pointer
+               CMP     R1,R0                   ;Are pointers the same?
+               MOVNE   R2,R1                   ;If no, remember previous
+               MOVNE   R1,R4                   ;...get list pointer
+               BNE     %01                     ;...and keep looking
+
+               ; --- So now the block has been found ---
+
+               MOV     R0,R1                   ;Put the block in R0
+               MOV     R1,#list__size          ;Get the size
+               BL      sub_free                ;Free the block
+               STR     R4,[R2,#0]              ;Store in prev next ^
+
+               ; --- And return to the user ---
+
+               LDMFD   R13!,{R0-R4,PC}^
+
+               LTORG
+
+; --- ibicon__size ---
+;
+; On entry:    R0 == pointer to block to use
+;              R1 == sprite area to use
+;              R2 == pointer to sprite name
+;
+; On exit:     --
+;
+; Use:         Determines the size of the given icon, and fills in the
+;              block appropriatly (x0,y0,x1,y1)
+
+ibicon__size   ROUT
+
+               STMFD   R13!,{R0-R6}            ;Stack some registers
+
+               MOV     R0,#40                  ;Get sprite info
+               CMP     R1,#1                   ;Is it WIMP area?
+               ORRNE   R0,R0,#&100             ;No -- use user area
+               SWINE   XOS_SpriteOp            ;...do the SpriteOp
+               SWIEQ   Wimp_SpriteOp           ;Yes, SpriteOp on WIMP area
+               LDMVSFD R13!,{R0-R6}            ;Recover registers on error
+               ORRVSS  PC,R14,#V_flag          ;...and return with an error
+
+               MOV     R0,R6                   ;Get info on sprite's mode
+               MOV     R1,#4                   ;Read XEigFactor
+               SWI     OS_ReadModeVariable     ;Get the Eig Factor
+               MOV     R3,R3,LSL R2            ;Get the width in OS units
+               MOV     R1,#5                   ;Read yEigFactor
+               SWI     OS_ReadModeVariable     ;Get the Eig Factor
+               MOV     R4,R4,LSL R2            ;Get the height in OS units
+               MOV     R0,#0                   ;x0 coordinate
+               MOV     R1,#0                   ;y0 coordinate
+               LDR     R2,[R13,#0]             ;Get the block to use
+               STMIA   R2,{R0,R1,R3,R4}        ;Store the size info
+
+               LDMFD   R13!,{R0-R6}            ;Recover registers
+               MOVS    PC,R14                  ;And return
+
+; --- ibicon_create ---
+;
+; On entry:    R0 == pointer to sprite name
+;              R1 == pointer to text buffer (must be writable if you
+;                    intend to change the text)
+;              R2 == icon bar position indicator (`window handle')
+;              R3 == icon bar priority/icon handle
+;              R4 == pointer to event handler
+;              R5 == value to pass in R10
+;              R6 == value to pass in R12
+;
+; On exit:     R0 == ibicon icon handle
+;              May return an error
+;
+; Use:                 Places an icon on the icon bar. Your handler is called when
+;              an event occurs on the icon. On entry to the handler, R10
+;              and R12 are set up as for above, R0 is the event type, and
+;              R1 is the ibicon pointer.
+
+               EXPORT  ibicon_create
+ibicon_create  ROUT
+
+               ; --- Stack registers, locate workspace etc. ---
+
+               STMFD   R13!,{R1-R7,R9,R10,R12,R14} ;Stack loads of registers
+               WSPACE  ibicon__wSpace,R9       ;Find a bit of workspace
+
+               ; --- Stuff useful values into high registers ---
+
+               MOV     R12,R0                  ;Keep the sprite name safe
+               MOV     R10,R1                  ;Keep the text pointer safe
+               MOV     R7,R2                   ;Keep position thingy
+
+               ; --- Now create buffers for the sprite name ---
+
+               MOV     R0,#16                  ;Size for sprite buffer
+               BL      sub_alloc               ;Get a block (PDQ)
+               BVS     %99ibicon_create        ;And zip ahead if it failed
+
+               ; --- Build the sprite name in the buffer ---
+
+               MOV     R2,R0                   ;Keep the pointer for a while
+               CMP     R10,#0                  ;Is there any text?
+               MOVNE   R1,#'S'                 ;Yes -- stick an `S' on
+               STRNEB  R1,[R0],#1              ;And insert it at the front
+               MOV     R1,R12                  ;Point to sprite name
+               BL      str_cpy                 ;And build the name string
+               MOV     R12,R2                  ;Keep this buffer pointer now
+
+               ; --- Build the icon definition ---
+
+               SUB     R13,R13,#36             ;Make space for the icon blk
+               BEQ     %00ibicon_create        ;If sprite only, deal with it
+
+               ; --- Deal with text+sprite icons ---
+
+               MOV     R2,R1                   ;Point to original sname
+               MOV     R1,#1                   ;Wimp sprite area
+               ADD     R0,R13,#4               ;Fill in this block
+               BL      ibicon__size            ;Get the sprite size
+
+               LDR     R1,[R0,#4]              ;Get y0
+               SUB     R1,R1,#16               ;y0=y0-16
+               STR     R1,[R0,#4]              ;Store adjusted y0
+               LDR     R1,[R0,#12]             ;Get y1
+               ADD     R1,R1,#20               ;y1=y1+20
+               STR     R1,[R0,#12]             ;Store adjusted y1
+
+               STR     R10,[R13,#24]           ;Store text buffer ^ if text
+               STR     R12,[R13,#28]           ;And the validation string ^
+               MOV     R0,R10                  ;The text string
+               BL      str_len                 ;How long is it?
+               STR     R0,[R13,#32]            ;Store the value
+               LDR     R1,[R13,#12]            ;Get the x1 icon size
+               CMP     R1,R0,LSL#4             ;Is it less than length*16
+               MOVLT   R1,R0,LSL#4             ;Yes, make it equal
+               STRLT   R1,[R13,#12]            ;...and store it back
+               LDR     R0,=&1700312B           ;The icon flags
+               STR     R0,[R13,#20]            ;Store them
+               B       %01ibicon_create        ;Jump ahead
+
+               ; --- Deal with sprite only icons ---
+
+00ibicon_create        BL      resspr_area             ;Get the sprite area to use
+               STR     R0,[R13,#28]            ;Store that in the block
+
+               MOV     R10,R12                 ;R10 is icon data
+               MOV     R12,#0                  ;No validation needed
+
+               MOV     R1,R0                   ;Put sprite area in R1
+               MOV     R2,R10                  ;Point to sprite name
+               ADD     R0,R13,#4               ;Fill in this block
+               BL      ibicon__size            ;Get the sprite size
+               MOVVS   R1,#1                   ;If error -- try WIMP area
+               BLVS    ibicon__size            ;...try again
+               STR     R10,[R13,#24]           ;Store sprite name pointer
+               MOV     R0,R10                  ;Point to sprite name
+               BL      str_len                 ;Get its length
+               STR     R0,[R13,#32]            ;And store that too
+               LDR     R0,=&1700311A           ;The icon flags
+               STR     R0,[R13,#20]            ;Store them
+
+               ; --- Create the icon ---
+
+01ibicon_create        BL      wimp_version            ;Get the wimp version number
+               LDR     R1,=310                 ;Wimp version
+               MOV     R2,R7                   ;Get back position thingy
+               CMP     R0,R1                   ;Is it less than RISC OS 3.1
+               BGE     %02ibicon_create        ;No -- go ahead
+
+               ; --- Ensure position word works on RISCOS 2/3.0 ---
+
+               CMP     R2,#-5                  ;Left, scanning from left?
+               CMPNE   R2,#-6                  ;Left, scanning from right?
+               MOVEQ   R2,#-2                  ;Yes -- put it on left
+               BEQ     %02ibicon_create        ;Now go ahead
+
+               CMP     R2,#-7                  ;Right, scanning from left?
+               CMPNE   R2,#-8                  ;Right, scanning from right?
+               MOVEQ   R2,#-1                  ;Yes -- put it on right
+
+               ; --- Actually create it ---
+
+02ibicon_create        STR     R2,[R13,#0]             ;The position to put icon in
+               MOV     R0,R3                   ;Icon handle/priority
+               MOV     R1,R13                  ;Point to the block
+               SWI     XWimp_CreateIcon        ;Create the icon
+               ADD     R13,R13,#36             ;Reclaim stack
+               BVS     %99ibicon_create        ;Barf if error
+
+               ; --- Add the icon into the list ---
+
+               MOV     R2,R10                  ;Icon data
+               MOV     R3,R12                  ;Validation string
+               ADR     R6,ibicon__icons        ;The head of the list
+               ADD     R1,R13,#12              ;Point to relevent parameters
+               LDMIA   R1,{R1,R4,R5}           ;Routine to call, R10, R12
+               BL      ibicon__addToList       ;Add to the list
+               BVS     %99ibicon_create        ;Stop if error occurred
+
+               ; --- Return to the user ---
+
+               LDR     R0,ibicon__icons        ;Return the ibicon pointer
+               LDMFD   R13!,{R1-R7,R9,R10,R12,R14} ;Load my registers
+               BICS    PC,R14,#V_flag          ;Return without error
+
+               ; --- An error occurred ---
+
+99ibicon_create        LDMFD   R13!,{R1-R7,R9,R10,R12,R14} ;Load my registers
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- ibicon_changeSprite ---
+;
+; On entry:    R0 == ibicon pointer
+;              R1 == pointer to sprite name
+;
+; On exit:     --
+;
+; Use:         Changes the sprite of the ibicon passed to it.
+
+               EXPORT  ibicon_changeSprite
+ibicon_changeSprite
+               ROUT
+
+               STMFD   R13!,{R0-R3,R9,R14}     ;Stack some registers
+               WSPACE  ibicon__wSpace,R9       ;Get my workspace
+
+               LDR     R3,[R0,#list__iHandle]  ;Get the icon handle
+               LDR     R2,[R0,#list__valid]    ;Get the validation
+               CMP     R2,#0                   ;Is there any?
+               LDREQ   R0,[R0,#list__iData]    ;No -- point to data
+               ADDNE   R0,R2,#1                ;Yes -- point passed the 'S'
+               BL      str_cpy                 ;And copy the name across
+               SUB     R13,R13,#16             ;Get a block
+               MOV     R0,#-2                  ;The icon bar
+               MOV     R1,R3                   ;The icon handle
+               MOV     R2,#0                   ;EOR Word
+               MOV     R3,#0                   ;The clear word
+               STMIA   R13,{R0-R3}             ;Store in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetIconState       ;Update the icon
+               ADD     R13,R13,#16             ;Reclaim my stack
+               LDMFD   R13!,{R0-R3,R9,PC}^     ;Return to the user
+
+               LTORG
+
+; --- ibicon_changeText ---
+;
+; On entry:    R0 == ibicon pointer
+;              R1 == pointer to new text
+;
+; On exit:     --
+;
+; Use:         Changes the sprite of the ibicon passed to it.
+
+               EXPORT  ibicon_changeText
+ibicon_changeText
+               ROUT
+
+               STMFD   R13!,{R0-R3,R9,R14}     ;Stack some registers
+               WSPACE  ibicon__wSpace,R9       ;Get my workspace
+
+               LDR     R3,[R0,#list__iHandle]  ;Get the icon handle
+               LDR     R2,[R0,#list__valid]    ;Get the validation
+               CMP     R2,#0                   ;Is there any?
+               BEQ     %00                     ;No -- big time error
+               LDR     R0,[R0,#list__iData]    ;Point to the text buffer
+               BL      str_cpy                 ;Copy the text across
+               SUB     R13,R13,#16             ;Get a block
+               MOV     R0,#-2                  ;The icon bar
+               MOV     R1,R3                   ;The icon handle
+               MOV     R2,#0                   ;EOR Word
+               MOV     R3,#0                   ;The clear word
+               STMIA   R13,{R0-R3}             ;Store in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetIconState       ;Update the icon
+               ADD     R13,R13,#16             ;Reclaim my stack
+               LDMFD   R13!,{R0-R3,R9,PC}^     ;Return to the user
+
+               ; --- We can't change the text of a sprite only icon ---
+
+00             ADR     R0,ibicon__cantDo       ;Point to the error message
+               BL      msgs_error              ;Translate the message
+               SWI     OS_GenerateError        ;Cause an error
+
+ibicon__cantDo DCD     0
+               DCB     "ibCCT",0
+
+               LTORG
+
+; --- ibicon_remove ---
+;
+; On entry:    R0 == ibicon icon handle
+;
+; On exit:     --
+;
+; Use:         Removes the given icon from the icon bar.
+
+               EXPORT  ibicon_remove
+ibicon_remove  ROUT
+
+               STMFD   R13!,{R0-R3,R9,R14}     ;Stack some registers
+               WSPACE  ibicon__wSpace,R9       ;Locate my workspace
+
+               ; --- Delete the icon ---
+
+               MOV     R2,R0                   ;Remember ibicon pointer
+               SUB     R13,R13,#8              ;Get a block
+               LDR     R1,[R0,#list__iHandle]  ;Get the icon handle
+               MOV     R0,#-2                  ;The icon bar
+               STMIA   R13,{R0,R1}             ;Store handles in block
+               MOV     R1,R13                  ;Point to block
+               SWI     XWimp_DeleteIcon        ;Delete the icon
+               ADD     R13,R13,#8              ;Reclaim the block from stack
+
+               ; --- Delete the ibicon data ---
+
+               MOV     R0,R3                   ;Point to the ibicon
+               LDR     R1,ibicon__icons        ;Remove from this list
+               BL      ibicon__removeFromList  ;Remove the icon
+
+               ; --- And return from whence thy came ---
+
+               LDMFD   R13!,{R0-R3,R9,PC}^     ;Return to caller
+
+               LTORG
+
+; --- ibicon__handler ---
+;
+; On entry:    R0 == event returned from Wimp_Poll
+;              R1 == poll block
+;              R12 == workspace
+;
+; On exit:     C set if call is claimed
+;
+; Use:         Called as an event handler when the wimp reports iconbar
+;              activity
+
+ibicon__handler        ROUT
+
+               STMFD   R13!,{R0-R7,R9,R10,R14} ;Stack some registers
+               MOV     R9,R12                  ;R9 is workspace pointer
+
+               CMP     R0,#6                   ;Was it a button click
+               BNE     %50                     ;No try messages
+               LDR     R2,[R1,#8]              ;Get buttons
+               TST     R2,#1                   ;Was it Adjust
+               MOVNE   R0,#ibEvent_adjust      ;Yes -- set the type
+               TST     R2,#4                   ;Was it select
+               MOVNE   R0,#ibEvent_select      ;Yes -- set the type
+               TST     R2,#2                   ;Was it menu
+               MOVNE   R0,#ibEvent_menu                ;Yes -- set the type
+               LDR     R1,[R1,#16]             ;Get the icon handle
+
+10             ADDS    R0,R0,#0                ;Clear carry flag
+               LDR     R2,ibicon__icons        ;Get my icons list
+20             TEQ     R2,#0                   ;Are we at the end
+               BEQ     %30                     ;Yes -- jump ahead
+               MOV     R7,R2                   ;Remember this pointer
+               LDMIA   R2,{R2-R6,R10,R12}      ;Load parameters to pass
+               TEQ     R1,R3                   ;Are icon handles the same
+               BNE     %20                     ;No -- try another handler
+               TEQ     R4,#0                   ;Is there a handler?
+               BEQ     %20                     ;No -- keep trying
+               MOV     R1,R7                   ;Pass the pointer
+               MOV     R14,PC                  ;Set return address
+               MOV     PC,R4                   ;Branch to handler
+               BCC     %20                     ;Try next handler
+30             LDMFD   R13!,{R0-R7,R9,R10,R14} ;Load the registers
+               BICCCS  PC,R14,#C_flag          ;Return with carry clear
+               ORRCSS  PC,R14,#C_flag          ;... or with carry set
+
+               ; --- Was the event a suitable message ---
+
+50             CMP     R0,#17                  ;User_Message
+               CMPNE   R0,#18                  ;User_Message_Recorded
+               LDMNEFD R13!,{R0-R7,R9,R10,R14} ;No -- load the registers
+               BICNES  PC,R14,#C_flag          ;...and return with C clear
+
+               MOV     R3,R1                   ;We need R1
+               MOV     R0,#-1                  ;No type yet
+               LDR     R2,[R3,#16]             ;Get the message type
+               CMP     R2,#1                   ;Data Save
+               MOVEQ   R0,#ibEvent_save        ;Yes -- set the type
+               LDREQ   R1,[R3,#24]             ;...and get the icon handle
+               CMP     R2,#3                   ;Data Load
+               MOVEQ   R0,#ibEvent_load        ;Yes -- set the type
+               LDREQ   R1,[R3,#24]             ;...and get the icon handle
+               LDR     R4,=&502                ;Help request
+               CMP     R2,R4                   ;Is it?
+               MOVEQ   R0,#ibEvent_help        ;Yes -- set the type
+               LDREQ   R1,[R3,#36]             ;...and get the icon handle
+
+               CMP     R0,#-1                  ;Was the message valid
+               BNE     %10                     ;Yes -- dispatch the event
+               LDMEQFD R13!,{R0-R7,R9,R10,R14} ;No -- load the registers
+               BICEQS  PC,R14,#C_flag          ;...and return with C clear
+
+               LTORG
+
+; --- ibicon_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the ibicon unit.
+
+               EXPORT  ibicon_init
+ibicon_init    ROUT
+
+               STMFD   R13!,{R0-R3,R9,R14}     ;Stack some registers
+               WSPACE  ibicon__wSpace,R9       ;Locate my workspace
+
+               ; --- Are we already initialised? ---
+
+               LDR     R0,ibicon__flags        ;Get my flags
+               TST     R0,#ibicon__INITED      ;Are we initialised?
+               LDMNEFD R13!,{R0,R9,PC}^        ;Yes -- return
+
+               ORR     R0,R0,#ibicon__INITED   ;Set initialised flag
+               STR     R0,ibicon__flags        ;And store them back
+
+               ; --- Ensure win is initialised ---
+
+               BL      win_init                ;Initialise win
+
+               ; --- Initialise the workspace ---
+
+               MOV     R0,#0                   ;No handlers yet
+               STR     R0,ibicon__icons        ;No siree
+
+               ; --- Set up the event handler ---
+
+               MOV     R0,#-2                  ;Window is icon bar
+               ADR     R1,ibicon__handler      ;Routine to call
+               MOV     R2,#0                   ;My handle
+               MOV     R3,R9                   ;Pass workspace ^ to R12
+               BL      win_eventHandler        ;Add the handler
+               MOV     R0,R1                   ;Point to the handler again
+               BL      win_unknownHandler      ;Ooo.. An unknown one too
+
+               ; --- Return to caller ---
+
+               LDMFD   R13!,{R0-R3,R9,PC}^     ;Return
+
+               LTORG
+
+ibicon__wSpace DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R9
+ibicon__wStart #       0
+
+ibicon__flags  #       4                       ;Flags
+
+ibicon__INITED EQU     (1<<0)                  ;I've been initialised
+
+ibicon__icons  #       4                       ;Event handler list
+
+ibicon__wSize  EQU     {VAR}-ibicon__wStart
+
+; --- list structure ---
+
+               ^       0
+list__next     #       4                       ;The next block
+list__iHandle  #       4                       ;The window handle
+list__proc     #       4                       ;Handler code
+list__iData    #       4                       ;Pointer to icon data
+list__valid    #       4                       ;Pointer to validation
+list__r10      #       4                       ;R10 to call with
+list__r12      #       4                       ;R12 to call with
+
+list__size     #       0
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     ibicon__wSize           ;Workspace size
+               DCD     ibicon__wSpace          ;Workspace pointer
+               DCD     0                       ;Scratchpad size
+               DCD     ibicon_init             ;Initialisation code
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
+
diff --git a/StraySrc/Libraries/Sapphire/s/idle b/StraySrc/Libraries/Sapphire/s/idle
new file mode 100644 (file)
index 0000000..21950d1
--- /dev/null
@@ -0,0 +1,598 @@
+;
+; idle.s
+;
+; Idle event and alarm handling (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:sapphire
+               GET     sapphire:suballoc
+               GET     sapphire:event
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- idle__addToList ---
+;
+; On entry:    R0 == Time word
+;              R1 == pointer to routine to call
+;              R2 == R10 value to call routine
+;              R3 == R12 value to call routine with
+;              R4 == pointer to list head to use
+;
+; On exit:     R0-R4 preserved
+;
+; Use:         Adds a rountine to the given list. Later added
+;              routines are called first
+
+idle__addToList        ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+
+               ; --- Allocate a block ---
+
+               MOV     R0,#list__size          ;Size to allocate
+               BL      sub_alloc               ;Allocate the block
+               BVS     %01                     ;Branch ahead if error
+
+               ; --- Fill the block in ---
+
+               LDR     R1,[R4]                 ;Get the list head
+               STR     R1,[R0,#list__next]     ;Store in next field
+               STR     R0,[R4]                 ;Store new block at head
+
+               LDMIA   R13,{R1-R4}             ;Get parameters
+               STMIB   R0,{R1-R4}              ;Store them in the block
+
+               ; --- And return to user ---
+
+               LDMFD   R13!,{R0-R4,R14}        ;Load back link
+               BICS    PC,R14,#V_flag          ;Return without error
+
+               ; --- Barf if an error occured ---
+
+01             ADD     R13,R13,#4              ;Skip over R0,R1,R2
+               LDMFD   R13!,{R1-R4,R14}        ;Branch if error
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- idle__removeFromList ---
+;
+; On entry:    R0 == Time word
+;              R1 == pointer to routine to be called
+;              R2 == R10 value routine is called with
+;              R3 == R12 value routine is called with
+;              R4 == pointer to list head to use
+;
+; On exit:     All registers/flags preserved
+;
+; Use:         Removes a routine from the given list. All values are
+;              compared.
+
+idle__removeFromList
+               ROUT
+
+               STMFD   R13!,{R0-R10,R12,R14}
+
+               ; --- Find the block ---
+
+               MOV     R5,#0                   ;The previous pointer
+               MOV     R12,R4                  ;Remember where the head is
+               LDR     R4,[R4]                 ;Get the head of the list
+01             TEQ     R4,#0                   ;Are we at the end?
+               LDMEQFD R13!,{R0-R10,R12,PC}^   ;Yes -- return
+               LDR     R10,[R4],#4             ;Get the next pointer
+               LDMIA   R4,{R6-R9}              ;Load data from the block
+               CMP     R6,R0                   ;Are routines the same?
+               CMPEQ   R7,R1                   ;Yes -- and window/R4 handle?
+               CMPEQ   R8,R2                   ;Yes -- R10 value?
+               CMPEQ   R9,R3                   ;Yes -- R12 value?
+               SUBNE   R5,R4,#4                ;If no, remember previous
+               MOVNE   R4,R10                  ;...get list pointer
+               BNE     %01                     ;...and keep looking
+
+               ; --- So now the block has been found ---
+
+               SUB     R0,R4,#4                ;Put the block in R0
+               MOV     R1,#list__size          ;Get the size
+               BL      sub_free                ;Free the block
+               CMP     R5,#0                   ;Was there a previous block
+               STREQ   R10,[R12,#0]            ;No -- store next blk in head
+               STRNE   R10,[R5,#0]             ;Yes -- store in prev next ^
+
+               ; --- And return to the user ---
+
+               LDMFD   R13!,{R0-R10,R12,PC}^
+
+               LTORG
+
+; --- idle_handler ---
+;
+; On entry:    R0 == how frequently to call
+;              R1 == pointer to routine to call
+;              R2 == R10 value to call routine with
+;              R3 == R12 value to call routine with
+;
+; On exit:     May return an error
+;
+; Use:         Adds a routine to the idle handler list. Later added
+;              routines are called first. The idle handing routine
+;              may corrupt R10 and R12.
+;              A handler is only addeded if an identical one does not
+;              already exist.
+
+               EXPORT  idle_handler
+idle_handler   ROUT
+
+               BIC     R14,R14,#V_flag         ;Assume it's all OK
+               STMFD   R13!,{R4-R9,R14}        ;Save some registers
+               WSPACE  idle__wSpace,R9         ;Get my workspace pointer
+
+               ; --- Check through the list ---
+
+               LDR     R4,idle__iHandlers      ;Get my idle handlers list
+10idle_handler TEQ     R4,#0                   ;Are we at the end
+               BEQ     %20idle_handler         ;Yes -- jump ahead
+               LDMIA   R4,{R4-R8}              ;Load parameters to pass
+               CMP     R5,R0                   ;Is this identical?
+               CMPEQ   R6,R1
+               CMPEQ   R7,R2
+               CMPEQ   R8,R3
+               BEQ     %90idle_handler         ;Yes -- return now then
+               B       %10idle_handler         ;Try next handler
+
+               ; --- Be careful not to alter flags ---
+
+20idle_handler ADR     R4,idle__iHandlers      ;Get the idle handlers
+               BL      idle__addToList         ;Add the routine to the list
+               LDMVSFD R13!,{R4-R9,PC}         ;Return if it failed
+
+               ; --- Cache the minimum return time ---
+
+               LDR     R4,idle__minTime        ;Get the current minimum time
+               CMP     R4,#-1                  ;Is there one?
+               STREQ   R0,idle__minTime        ;No -- store the new one
+               LDMEQFD R13!,{R4-R9,PC}^        ;...and return
+               CMP     R0,R4                   ;Is the new time lower
+               STRLE   R0,idle__minTime        ;Yes -- Store the new one
+
+               ; --- Return to client ---
+
+90idle_handler LDMFD   R13!,{R4-R9,PC}^        ;Return cunningly
+
+; --- idle_removeHandler ---
+;
+; On entry:    R0 == How frequently it was called
+;              R1 == pointer to routine called
+;              R2 == R10 value routine is called with
+;              R3 == R12 value routine is called with
+;
+; On exit:     --
+;
+; Use:         Removes a routine from the idle handler list.
+
+               EXPORT  idle_removeHandler
+idle_removeHandler
+               ROUT
+
+               STMFD   R13!,{R4-R6,R9,R14}     ;Stack some registers
+
+               ; --- Free the handler ---
+
+               WSPACE  idle__wSpace,R9         ;Get my workspace pointer
+               ADR     R4,idle__iHandlers      ;Get the idle handlers
+               BL      idle__removeFromList    ;Remove routine from the list
+
+               ; --- Find the new minimum frequency ---
+
+               MOV     R5,#-1                  ;Lowest time found
+               LDR     R4,[R4]                 ;Get the first handler
+00             TEQ     R4,#0                   ;Is it the end?
+               BEQ     %01                     ;Yes -- finish
+               LDR     R6,[R4,#list__time]     ;Load the frequency
+               CMP     R6,R5                   ;Is it lower than lowest
+               MOVLO   R5,R6                   ;Yes -- remember it
+               LDR     R4,[R4]                 ;Get next in list
+               B       %00                     ;Try the rest
+
+01             STR     R5,idle__minTime        ;Store it found value
+               LDMFD   R13!,{R4-R6,R9,R14}     ;Load registers
+               BICS    PC,R14,#V_flag          ;Return without error
+
+; --- idle_setAlarm ---
+;
+; On entry:    R3 == Time to call
+;              R1 == pointer to routine to call
+;              R2 == R10 value to call routine with
+;              R3 == R12 value to call routine with
+;
+; On exit:     May return an error
+;
+; Use:         Adds a alarm to be called. The idle handing routine
+;              may corrupt R10 and R12.
+
+               EXPORT  idle_setAlarm
+idle_setAlarm  ROUT
+
+               STMFD   R13!,{R0-R4,R9,R14}     ;Stack some registers
+               WSPACE  idle__wSpace,R9         ;Get my workspace
+               MOV     R1,R0                   ;Put requested time in R1
+
+               ; --- Allocate a block ---
+
+               MOV     R0,#list__size          ;Size to allocate
+               BL      sub_alloc               ;Allocate the block
+               BVS     %02idle_setAlarm        ;Branch ahead if error
+
+               ; --- Work out where to put it ---
+
+               MOV     R2,#0                   ;Previous alarm
+               LDR     R4,idle__aHandlers      ;Get the list head
+00idle_setAlarm        CMP     R4,#0                   ;Are we at the end
+               BEQ     %01idle_setAlarm        ;Put it in here
+               LDR     R3,[R4,#4]              ;Get the time due
+               CMP     R3,R1                   ;Compare with new alarm
+               BGT     %01idle_setAlarm        ;If bigger, put it here
+               MOV     R2,R4                   ;Remember this alarm
+               LDR     R4,[R4,#0]              ;Get next alarm in list
+               B       %00idle_setAlarm
+
+               ; --- Put the alarm in between R2 and R4 ---
+
+01idle_setAlarm        STR     R4,[R0,#list__next]     ;Store in next field
+               CMP     R2,#0                   ;Was there a previous alarm
+               STREQ   R0,idle__aHandlers      ;No, store new block at head
+               STRNE   R0,[R2,#0]              ;Yes, store in its next field
+
+               ; --- Fill the block in ---
+
+               LDMIA   R13,{R1-R4}             ;Get parameters
+               STMIB   R0,{R1-R4}              ;Store them in the block
+
+               ; --- And return to user ---
+
+               LDMFD   R13!,{R0-R4,R9,R14}     ;Load back link
+               BICS    PC,R14,#V_flag          ;Return without error
+
+               ; --- Barf if an error occured ---
+
+02idle_setAlarm        ADD     R13,R13,#4              ;Skip over R0
+               LDMFD   R13!,{R1-R4,R9,R14}     ;Branch if error
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+
+; --- idle_removeAlarm ---
+;
+; On entry:    R0 == When it was to be called
+;              R1 == pointer to routine called
+;              R2 == R10 value routine is called with
+;              R3 == R12 value routine is called with
+;
+; On exit:     --
+;
+; Use:         Removes a routine from the idle handler list. It has
+;              no effect if it doesn't exist.
+
+               EXPORT  idle_removeAlarm
+idle_removeAlarm
+               ROUT
+
+               STMFD   R13!,{R4-R6,R9,R14}     ;Stack some registers
+
+               ; --- Free the handler ---
+
+               WSPACE  idle__wSpace,R9         ;Get my workspace pointer
+               ADR     R4,idle__aHandlers      ;Get the idle handlers
+               BL      idle__removeFromList    ;Remove routine from the list
+
+                ; --- And return ---
+
+               LDMFD   R13!,{R4-R6,R9,R14}     ;Load registers
+               BICS    PC,R14,#V_flag          ;Return without error
+
+; --- idle_removeAllAlarms ---
+;
+; On entry:    R0 == R10 value to look for
+;
+; On exit:     --
+;
+; Use:         Removes all alarms with the handle that was passed to them
+;              to be put into R10.  You should not remove an alarm within
+;              an alarm handler.
+
+
+               EXPORT  idle_removeAllAlarms
+idle_removeAllAlarms
+               ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Stack some registers
+               WSPACE  idle__wSpace,R9         ;Get the alarm handler list
+               MOV     R10,R0                  ;Remember handle
+
+               ; --- Find the first block with the handle block ---
+
+               MOV     R2,#0                   ;The previous pointer
+               LDR     R3,idle__aHandlers      ;Get the head of the list
+00             TEQ     R3,#0                   ;Are we at the end?
+               LDMEQFD R13!,{R0-R10,PC}^       ;Yes -- return
+               LDR     R4,[R3],#4              ;Get the next pointer
+               LDMIA   R3,{R5-R8}              ;Load data from the block
+               CMP     R7,R10                  ;Are handles the same?
+               SUBNE   R2,R3,#4                ;If no, remember previous
+               MOVNE   R3,R4                   ;...point to the next block
+               BNE     %00                     ;...and keep looking
+
+               ; --- So now the block has been found ---
+
+               SUB     R0,R3,#4                ;Put the block in R0
+               MOV     R1,#list__size          ;Get the size
+               BL      sub_free                ;Free the block
+               CMP     R2,#0                   ;Was there a previous block
+               STREQ   R4,idle__aHandlers      ;No -- store next blk in head
+               STRNE   R4,[R2,#0]              ;Yes -- store in prev next ^
+               MOV     R3,R4                   ;Point at the next block
+               B       %00                     ;Find more alarms
+
+               LTORG
+
+; --- idle__preFilter ---
+;
+; On entry:    R0 == reason code return from Wimp_Poll
+;              R1 == pointer to block
+;              R2 == earliest time to return with NULL
+;
+; On exit:     R2 altered as appropriate
+
+idle__preFilter        ROUT
+
+               STMFD   R13!,{R0,R5-R7,R9,R14}
+               MOV     R9,R12
+
+               ; --- Is the user requesting idles? ---
+
+               TST     R0,#1                   ;Is it masked off
+               CMPEQ   R2,#0                   ;If no, just Wimp_Poll?
+               LDMEQFD R13!,{R0,R5-R7,R9,PC}^  ;Return PDQ
+
+               ; --- Get the minimum time to return with ---
+
+               LDR     R5,idle__iHandlers      ;Get the idle handlers list
+               LDR     R6,idle__aHandlers      ;Get the alarm handlers list
+               CMP     R5,#0                   ;Do we have idle handlers?
+               CMPEQ   R6,#0                   ;If not, any alarm handlers?
+               LDMEQFD R13!,{R0,R5-R7,R9,PC}^  ;No idles/alarms -- return
+
+               ; --- Get the next time the quickest idle will call ---
+
+               LDR     R7,idle__minTime        ;Get the minimum frequency
+               CMP     R7,#-1                  ;Is there one?
+               SWINE   OS_ReadMonotonicTime    ;Yes -- get the current time
+               ADDNE   R5,R7,R0                ;...and time to return with
+
+               ; --- And the time of the next alarm ---
+
+               CMP     R6,#0                   ;Are there any alarms?
+               BEQ     %00                     ;No -- R5 contains quickest
+               LDR     R6,[R6,#list__time]     ;Get time of the next alarm
+               CMP     R7,#-1                  ;Was there an idle handler?
+               MOVEQ   R5,R6                   ;No, R6 is lowest
+               BEQ     %00                     ;...branch ahead
+               CMP     R6,R5                   ;Is it before next idle
+               MOVLT   R5,R6                   ;Yes, use this time
+
+               ; --- Now set up the mask word and return time ---
+
+00             LDR     R0,[R13],#4             ;Get event mask back
+               TST     R0,#1                   ;Is the user expecting idles
+               BEQ     %01                     ;Yes -- Do a comparison
+               BIC     R0,R0,#1                ;Clear the mask bit
+               MOV     R2,R5                   ;Put the minimum time in R2
+               LDMFD   R13!,{R5-R7,R9,PC}^     ;...and return
+
+               ; --- The user is expecting idles, so please him ---
+
+01             CMP     R5,R2                   ;Which is bigger?
+               MOVLT   R2,R5                   ;Swap if needed
+               LDMFD   R13!,{R5-R7,R9,PC}^     ;...and return
+
+; --- idle__dispatch ---
+;
+; On entry:    R0  == reason code returned from Wimp_Poll
+;              R1  == pointer to block
+;              R12 == pointer to workspace
+;
+; On exit:     --
+
+idle__dispatch  ROUT
+
+               CMP     R0,#0                   ;Is it a NULL event
+               MOVNES  PC,R14                  ;No - return
+               STMFD   R13!,{R2-R5,R9,R10,R14} ;Stack some registers
+               MOV     R9,R12                  ;Get my workspace
+
+               ; --- Go through the handlers list ---
+
+               LDR     R2,idle__iHandlers      ;Get my idle handlers list
+10             TEQ     R2,#0                   ;Are we at the end
+               BEQ     %20idle__dispatch       ;Yes -- jump ahead
+               LDMIA   R2,{R2,R3,R4,R10,R12}   ;Load parameters to pass
+               MOV     R14,PC                  ;Set return address
+               MOV     PC,R4                   ;Branch to handler
+               B       %10idle__dispatch       ;Try next handler
+20             LDMFD   R13!,{R2-R5,R9,R10,PC}^ ;Load registers if claimed
+
+               LTORG
+
+; --- idle__dispatchAlarm ---
+;
+; On entry:    R0  == reason code returned from Wimp_Poll
+;              R1  == pointer to block
+;              R12 == pointer to workspace
+;
+; On exit:     R0-R1 preserved
+
+idle__dispatchAlarm ROUT
+
+               CMP     R0,#0                   ;Is it a NULL event
+               MOVNES  PC,R14                  ;No - return
+               STMFD   R13!,{R0-R5,R9,R10,R14} ;Stack some registers
+               MOV     R9,R12                  ;Get my workspace
+
+               ; --- Go through the handlers list ---
+
+               LDR     R2,idle__aHandlers      ;Get my alarm handlers list
+10             SWI     OS_ReadMonotonicTime    ;Get the current time
+               TEQ     R2,#0                   ;Are we at the end
+               BEQ     %20idle__dispatchAlarm  ;Yes -- jump ahead
+               LDMIB   R2,{R3,R4,R10,R12}      ;Load parameters to pass
+               SUBS    R3,R0,R3                ;Call this handler?
+               BMI     %20idle__dispatchAlarm  ;No -- return
+               MOV     R14,PC                  ;Set return address
+               MOV     PC,R4                   ;Branch to handler
+
+               ; --- Remove the handler just called ---
+
+               LDMIA   R2,{R4}                 ;Get next (changed?) alarm
+               MOV     R0,R2                   ;Get the block
+               MOV     R1,#list__size          ;The size of the block
+               BL      sub_free                ;Free the block
+               STR     R4,idle__aHandlers      ;Store next in list head
+
+               ; --- And keep going ---
+
+               MOV     R2,R4                   ;Get next in list
+               B       %10idle__dispatchAlarm  ;Try next handler
+
+               ; --- Return to user ---
+
+20             LDMFD   R13!,{R0-R5,R9,R10,PC}^ ;Load registers if claimed
+
+               LTORG
+
+; --- idle_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the idle system.
+
+               EXPORT  idle_init
+idle_init      ROUT
+
+               STMFD   R13!,{R0,R1,R9,R14}     ;Stack some registers
+               WSPACE  idle__wSpace,R9         ;Get my workspace
+
+               ; --- Are we already initialised? ---
+
+               LDR     R0,idle__flags          ;Get my flags
+               TST     R0,#idle__INITED        ;Are we initialised?
+               LDMNEFD R13!,{R0,R1,R9,PC}^     ;Yes -- return
+
+               ORR     R0,R0,#idle__INITED     ;Set initialised flag
+               STR     R0,idle__flags          ;And store them back
+
+               ; --- Clear rest of workspace ---
+
+               MOV     R0,#0                   ;Zero some registers
+               STR     R0,idle__iHandlers      ;Clear idle handler list
+               STR     R0,idle__aHandlers      ;Clear alarm handler list
+               MOV     R0,#-1                  ;So minimum time yet
+               STR     R0,idle__minTime        ;Set the word
+
+               ; --- Initialise event system ---
+
+               BL      event_init              ;Initialise event system
+
+               ; --- Set up a post filter for the idle system ---
+
+               ADR     R0,idle__dispatch       ;Call this routine
+               MOV     R1,R9                   ;Put my workspace in R12
+               BL      event_postFilter        ;Add it to post-filter list
+
+               ; --- Set up a post filter for the alarm system ---
+
+               ADR     R0,idle__dispatchAlarm  ;Call this routine
+               MOV     R1,R9                   ;Put my workspace in R12
+               BL      event_postFilter        ;Add it to post-filter list
+
+               ; --- Set up the pre filter ---
+
+               ADR     R0,idle__preFilter      ;Call this routine
+               MOV     R1,R9                   ;Put my workspace in R12
+               BL      event_preFilter ;Add it to pre-filter list
+
+               ; --- That's it now ---
+
+               LDMFD   R13!,{R0,R1,R9,PC}^     ;Return
+
+               LTORG
+
+idle__wSpace   DCD     0                       ;My workspace pointer
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R9
+idle__wStart   #       0
+
+idle__flags    #       4                       ;Flags
+
+idle__INITED   EQU     (1<<0)                  ;I've been initialised
+
+idle__iHandlers        #       4                       ;Idle handler list
+idle__aHandlers        #       4                       ;Alarm handler list
+idle__minTime  #       4                       ;Minimum time to return with
+
+idle__wSize    EQU     {VAR}-idle__wStart
+
+; --- list structure ---
+
+               ^       0
+list__next     #       4                       ;The next block
+list__time     #       4                       ;Handler code
+list__proc     #       4                       ;The time word
+list__r10      #       4                       ;R10 to call with
+list__r12      #       4                       ;R12 to call with
+
+list__size     #       0
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     idle__wSize
+               DCD     idle__wSpace
+               DCD     0
+               DCD     idle_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/kernel b/StraySrc/Libraries/Sapphire/s/kernel
new file mode 100644 (file)
index 0000000..cc21cb7
--- /dev/null
@@ -0,0 +1,644 @@
+;
+; kernel.s
+;
+; Sapphire library kernel
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               [       :LNOT::DEF: sapphire__dynaLink
+
+               IMPORT  |Image$$RW$$Base|,WEAK
+               IMPORT  |Image$$RW$$Limit|,WEAK
+               IMPORT  |Sapphire$$ClientData$$Base|,WEAK
+               IMPORT  |Sapphire$$ClientData$$Limit|,WEAK
+               IMPORT  |Sapphire$$ExtTable$$Base|,WEAK
+               IMPORT  |Sapphire$$ExtTable$$Limit|,WEAK
+
+               ]
+
+               IMPORT  |Sapphire$$LibData$$Base|,WEAK
+               IMPORT  |Sapphire$$LibData$$Limit|,WEAK
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+               [       :LNOT::DEF: sapphire__dynaLink
+
+; --- sapphire_init ---
+;
+; On entry:    R0 == pointer to application name
+;              R1 == application's workspace size
+;              R2 == size of stack required
+;
+; On exit:     R10 == pointer to heap base
+;              R11 == pointer to ScratchPad
+;              R12 == pointer to application workspace
+;              R13 == pointer to full descending stack
+;              Other registers are corrupted
+;
+; Use:         Initialises the Sapphire kernel, sets up the memory map,
+;              and allocates workspace for library and client units.  The
+;              initialisation performed is fairly minimal; in particular,
+;              the library units are not initialised -- you must call
+;              sapphire_libInit for this to take place.  This allows you
+;              to check command line arguments etc. before initialising
+;              the Wimp.
+
+               EXPORT  sapphire_init
+sapphire_init  ROUT
+
+               ADR     R3,sapph__initTable     ;Point to initialisation tbl
+               B       sapphire_doInit         ;Do main initialisation
+
+               LTORG
+
+; --- sapphire_libInit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the Sapphire library and client units.
+
+               EXPORT  sapphire_libInit
+sapphire_libInit ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               ADR     R0,sapph__initTable     ;Point to initialisation tbl
+               BL      sapphire_doLibInit      ;Do library initialisation
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+; --- sapphire_disable ---
+;
+; On entry:    R0 == pointer to 0-terminated list of initialise routines
+;
+; On exit:     --
+;
+; Use:         Prevents the given initialisation routines from being called.
+;              This is mainly useful in the dynamic-linking environment,
+;              where all Sapphire units are normally active.  This routine
+;              allows you to inactivate units which for example do not
+;              have the resources they require, or use up unnecesary
+;              memory.
+
+               EXPORT  sapphire_disable
+sapphire_disable ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               ADR     R1,sapph__initTable     ;Point to initialisation tbl
+               BL      sapphire_doDisable      ;Do the disabling bits
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+sapph__initTable
+
+               DCD     |Image$$RW$$Limit|
+               DCD     |Sapphire$$ClientData$$Base|
+               DCD     |Sapphire$$ClientData$$Limit|
+               DCD     -1
+               DCD     |Sapphire$$ExtTable$$Base|
+               DCD     |Sapphire$$ExtTable$$Limit|
+
+               ]
+
+; --- sapphire_doInit ---
+;
+; On entry:    R0 == pointer to application name
+;              R1 == client workspace size
+;              R2 == requested stack size
+;              R3 == pointer to initialisation table
+;
+; On exit:     R10 == base address of Sapphire heap
+;              R11 == pointer to scratchpad and global data
+;              R12 == pointer to client global workspace
+;              R13 == pointer to a full descendion stack
+;
+; Use:         Performs initialisation of the Sapphire library and the
+;              client's sections.  This is intended for use by the Sapphire
+;              stub, while initialising the dynamically linked version of
+;              Sapphire.
+
+               EXPORT  sapphire_doInit
+sapphire_doInit ROUT
+
+               ; --- Stash arguments in high registers ---
+
+               MOV     R6,R0                   ;Pointer to application name
+               MOV     R5,R1                   ;Client's workspace size
+               MOV     R7,R2                   ;Client's stack size
+               MOV     R8,R3                   ;Pointer to intialise table
+
+               ; --- Find the top of our memory area ---
+
+               SWI     OS_GetEnv               ;Find the memory limit
+               MOV     R13,R1                  ;This will do as a stack
+               LDR     R12,[R8],#4             ;Load the application end
+
+               ; --- Set up workspace allocation registers ---
+
+               ADD     R9,R12,#sapph__wSize    ;Allocate my workspace
+               ADD     R7,R7,#3                ;Make sure stack size...
+               BIC     R7,R7,#3                ;... is word aligned
+               CMP     R7,#sapph__minStack     ;Is his stack big enough?
+               SUBCC   R10,R13,#sapph__minStack ;No -- allocate it big
+               SUBCS   R10,R13,R7              ;Yes -- allocate his amount
+
+               CMP     R9,R10                  ;Do we have enough memory?
+               BCS     %90sapphire_doInit      ;No -- complain then
+
+               ; --- Now find out how much we need ---
+
+               STMFD   R13!,{R5,R6,R14}        ;Save some registers
+               ADD     R5,R5,#3                ;Amount of workspace required
+               BIC     R5,R5,#3                ;Make sure it's aligned
+               MOV     R6,#20                  ;Space below R11 used so far
+               MOV     R7,#256                 ;Force scratchpad to 256
+
+               ADR     R4,sapph__ownTable      ;Point to the internal table
+               LDMIA   R4,{R0,R1}              ;Load the base and limit
+               BL      sapph__readSize         ;Work out sizes here
+
+               MOV     R4,R8                   ;Point to init table
+00             LDMIA   R4!,{R0,R1}             ;Load the base and limit
+               CMP     R0,#-1                  ;Is it the end of the table?
+               BLNE    sapph__readSize         ;No -- work out the sizes
+               BNE     %00sapphire_doInit      ;And go back for more
+
+               SUB     R4,R4,#4                ;We went a little too far
+               LDMIA   R4,{R3,R4}              ;Load these values out
+05             CMP     R3,R4                   ;Reached the end yet?
+               BCS     %09sapphire_doInit      ;Yes -- skip onwards
+               MOV     R14,PC                  ;Set up return address
+               LDR     PC,[R3],#4              ;Get next return address
+               CMP     R2,R6                   ;Need more space below R11?
+               MOVHI   R6,R2                   ;Yes -- then increase size
+               BL      sapph__readSize         ;Work out the sizes here
+               B       %05sapphire_doInit      ;And go back for more
+
+               ; --- Make initial allocations ---
+
+09             SUB     R11,R10,R7              ;Allocate the scratchpad
+               SUB     R10,R11,R6              ;And allocate workspace ptrs
+
+               ADD     R1,R9,R5                ;Add on workspace reqments
+               SUBS    R3,R10,R1               ;Do we have enough memory?
+               BCC     %90sapphire_doInit      ;No -- make an error then
+
+               ; --- Set up initial contents of magic area ---
+
+               LDR     R0,[R13,#4]             ;Load application name ptr
+               ADD     R7,R13,#12              ;Find stack base address
+               STMDB   R11,{R0,R1,R7,R9}       ;Save values in the area
+
+               ; --- Initialise the heap ---
+
+               MOV     R0,#0                   ;Initialise a heap area
+               SWI     OS_Heap                 ;Set it up then
+
+               ; --- Set up kernel workspace ---
+
+               MOV     R0,#0                   ;No global areas allocated
+               STR     R0,sapph__globCnt       ;So clear the counter value
+
+               ; --- Now start setting up workspace ---
+
+               MOV     R7,#0                   ;Current workspace offset
+               MOV     R2,#4                   ;Current R11 negative offset
+
+               ADR     R6,sapph__ownTable      ;Point to internal table
+               LDMIA   R6,{R0,R1}              ;Load the base and limit
+               BL      sapph__setWSpace        ;Set up the workspace for it
+
+10             LDMIA   R8!,{R0,R1}             ;Load the base and limit
+               CMP     R0,#-1                  ;Is this the end yet?
+               BLNE    sapph__setWSpace        ;No -- set up workspace
+               BNE     %10sapphire_doInit      ;And go back round again
+
+               ; --- Allocate the client's workspace ---
+
+               ADD     R9,R9,R7                ;Find current workspace pos
+               LDMIA   R13!,{R5,R6}            ;Load workspace size back
+               STR     R9,sapph_clientWS       ;Save client workspace ptr
+               ADD     R9,R9,R5                ;Move past client work size
+               MOV     R7,#0                   ;Clear offset now
+
+               ; --- Now allocate workspace for extensions ---
+
+               SUB     R8,R8,#4                ;We overshot at the end
+               LDMIA   R8,{R5,R6}              ;Load the values out
+15             CMP     R5,R6                   ;Have we finished yet?
+               BCS     %19sapphire_doInit      ;Yes -- skip out then
+               MOV     R14,PC                  ;Set up return address
+               LDR     PC,[R5],#4              ;Call the routine
+               ADD     R9,R9,R7                ;Get updated workspace offset
+               STR     R9,[R11,-R2]            ;Save in magic place
+               MOV     R7,#0                   ;No offset set up yet
+               BL      sapph__setWSpace        ;Set up its workspace
+               B       %15sapphire_doInit      ;And go back round again
+
+               ; --- That's it -- we're done ---
+
+19             LDR     R12,sapph_clientWS      ;Load client's workspace
+               LDR     R10,sapph_heapBase      ;Load the heap base too
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               ; --- Not enough memory to start up ---
+
+90             ADR     R0,sapph__noMem         ;Point to the error message
+               SWI     OS_GenerateError        ;Generate the error
+
+sapph__ownTable DCD    |Sapphire$$LibData$$Base|
+               DCD     |Sapphire$$LibData$$Limit|
+
+sapph__noMem   DCD     0
+               DCB     "Not enough memory to initialise",0
+
+               LTORG
+
+; --- sapph__readSize ---
+;
+; On entry:    R0 == base of initialisation block
+;              R1 == limit of initialisation block
+;              R5 == amount of workspace required so far
+;              R7 == required size of scratchpad
+;
+; On exit:     R5, R7 updated as necessary
+;
+; Use:         Adjusts workspace parameters given an initialisation block.
+
+sapph__readSize ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+00             CMP     R0,R1                   ;Have we finished yet?
+               LDMCSFD R13!,{R0-R4,PC}^        ;Yes -- then return
+               LDMIA   R0!,{R2-R4,R14}         ;Load values from block
+               ADD     R2,R2,#3                ;Make sure workspace is...
+               BIC     R2,R2,#3                ;... word aligned
+               ADD     R5,R5,R2                ;Incrment offset nicely
+               CMP     R4,R7                   ;Is scratchpad big enough?
+               MOVHI   R7,R4                   ;No -- make it bigger then
+               B       %00sapph__readSize      ;And go back for the rest
+
+               LTORG
+
+; --- sapph__setWSpace ---
+;
+; On entry:    R0 == base of initialisation block
+;              R1 == limit of initialisation block
+;              R7 == current workspace offset
+;              R9 == workspace chunk base address
+;
+; On exit:     R7 updated
+;
+; Use:         Lays out workspace and sets up workspace offsets.
+
+sapph__setWSpace ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+00             CMP     R0,R1                   ;Have we finished yet?
+               LDMCSFD R13!,{R0-R4,PC}^        ;Yes -- then return
+               LDMIA   R0!,{R2-R4,R14}         ;Load values from block
+               ADD     R2,R2,#3                ;Make sure workspace is...
+               BICS    R2,R2,#3                ;... word aligned
+               STRNE   R7,[R3,#0]              ;If any wanted, save offset
+               MOVNE   R14,#0                  ;Zero the first word
+               STRNE   R14,[R7,R9]             ;Save that in there
+               ADD     R7,R7,R2                ;And move pointer on
+               B       %00sapph__setWSpace     ;And keep on going round
+
+               LTORG
+
+; --- sapphire_doLibInit ---
+;
+; On entry:    R0 == address of library initialisation table
+;
+; On exit:     --
+;
+; Use:         Initialises all currently uninitialised library units.
+
+               EXPORT  sapphire_doLibInit
+sapphire_doLibInit ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               ADD     R4,R0,#4                ;Look after this pointer
+
+               ADR     R0,sapph__ownTable      ;Point to our own init table
+               LDMIA   R0,{R0,R1}              ;Load base and limit
+               LDR     R2,sapph_workspace      ;Load workspace base address
+               BL      sapph__init             ;Initialise from block
+
+00             LDMIA   R4!,{R0,R1}             ;Load values from the block
+               CMP     R0,#-1                  ;Have we reached the end yet?
+               BLNE    sapph__init             ;No -- do more initialising
+               BNE     %00sapphire_doLibInit   ;And go round again
+
+               SUB     R4,R4,#4                ;We overshot a bit
+               LDMIA   R4,{R3,R4}              ;Load extension table values
+05             CMP     R3,R4                   ;Have we finished yet?
+               BCS     %09sapphire_doLibInit   ;Yes -- skip out then
+               MOV     R14,PC                  ;Set up return address
+               LDR     PC,[R3],#4              ;Call finding routine
+               LDR     R2,[R11,-R2]            ;Load workspace base address
+               BL      sapph__init             ;Do more initialising
+               B       %05sapphire_doLibInit   ;And go back round for more
+
+09             LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+; --- sapph__init ---
+;
+; On entry:    R0 == pointer to base of initialise table
+;              R1 == pointer to limit of initialise table
+;              R2 == base of workspace chunk
+;
+; On exit:     --
+;
+; Use:         Initialises currently uninitialised library units.
+
+sapph__init    ROUT
+
+               STMFD   R13!,{R0-R7,R14}        ;Save some registers
+               MOV     R3,R0                   ;Look after this pointer
+               LDR     R0,sapph_appName        ;Find application's name
+00             CMP     R3,R1                   ;Have we finished yet?
+               LDMCSFD R13!,{R0-R7,PC}^        ;Yes -- then return
+               LDMIA   R3!,{R4-R7}             ;Load values from block
+               CMP     R7,#0                   ;Is there a init routine?
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               MOVNE   PC,R7                   ;And call the routine
+               B       %00sapph__init          ;And go round again
+
+               LTORG
+
+; --- sapphire_doDisable ---
+;
+; On entry:    R0 == pointer to list of initialise routines to disable
+;              R1 == pointer to initialisation table
+;
+; On exit:     --
+;
+; Use:         Prevents the given initialisation routines from being
+;              called.  This is mainly useful in a dynamically linked
+;              environment.
+
+               EXPORT  sapphire_doDisable
+sapphire_doDisable ROUT
+
+               STMFD   R13!,{R0-R7,R14}        ;Save some registers
+               MOV     R7,R0                   ;Keep pointer safe
+               ADD     R6,R1,#4                ;Point to initialise table
+
+00             LDR     R5,[R7],#4              ;Load next entry to remove
+               TEQ     R5,#0                   ;Is this the end yet?
+               BEQ     %90sapphire_doDisable   ;Yes -- then return
+
+               LDR     R14,[R5,#0]             ;Load the first instruction
+               AND     R0,R14,#&FF000000       ;Get the opcode bits out
+               CMP     R0,#&EA000000           ;Is this a branch instruction
+               BICEQ   R14,R14,#&FF000000      ;Yes -- zap instruction bits
+               ADDEQ   R14,R14,#2              ;Compensate for pipeline
+               ADDEQ   R5,R5,R14,LSL #2        ;And work out destination
+
+               ; --- Now find this routine somewhere ---
+
+               ADR     R0,sapph__ownTable      ;Point to our own table
+               LDMIA   R0,{R0,R1}              ;Load base and limit pointers
+               LDR     R2,sapph_workspace      ;Load workspace base address
+               BL      sapph__disable          ;See if it's in there
+               BCS     %00sapphire_doDisable   ;If so, move to next routine
+
+               ; --- Try the client table then ---
+
+               MOV     R4,R6                   ;Point to init table
+05             LDMIA   R4!,{R0,R1}             ;Load the values out
+               CMP     R0,#0                   ;Have I finished here yet?
+               BEQ     %09sapphire_doDisable   ;Yes -- skip out then
+               BL      sapph__disable          ;See if it's in there
+               BCS     %00sapphire_doDisable   ;If so, move to next routine
+               B       %05sapphire_doDisable   ;Else try the next lot
+
+               ; --- Now try the external table ---
+
+09             SUB     R4,R4,#4                ;We overshot as usual
+               LDMIA   R4,{R3,R4}              ;Load base and limit out
+10             CMP     R3,R4                   ;Reached the end yet?
+               BEQ     %00sapphire_doDisable   ;If so, move to next routine
+               MOV     R14,PC                  ;Set up return address
+               LDR     PC,[R3],#4              ;Find next init table
+               LDR     R2,[R11,-R2]            ;Load the workspace base
+               BL      sapph__disable          ;See if it's in there
+               BCS     %00sapphire_doDisable   ;If so, move to next routine
+               B       %10sapphire_doDisable   ;Else try the next lot
+
+               ; --- Finished all of them ---
+
+90             LDMFD   R13!,{R0-R7,PC}^        ;Return to caller
+
+               LTORG
+
+; --- sapph__disable ---
+;
+; On entry:    R0 == base of initialise table
+;              R1 == limit of initialise table
+;              R2 == base of workspace for table
+;              R5 == address of init routine to match
+;
+; On exit:     CS if routine found, else CC
+;              R0 corrupted
+;
+; Use:         Finds and disables a given initialise routine.
+
+sapph__disable ROUT
+
+               BIC     R14,R14,#C_flag         ;Clear carry flag initially
+               STMFD   R13!,{R3,R4,R6,R14}     ;Save some registers
+00             CMP     R0,R1                   ;Reached the end yet?
+               LDMCSFD R13!,{R3,R4,R6,PC}^     ;Yes -- return sadly then
+               LDMIA   R0!,{R3,R4,R6,R14}      ;Load values from table
+               CMP     R3,#0                   ;Is there any workspace?
+               BEQ     %00sapph__disable       ;No -- ignore this entry
+               CMP     R14,R5                  ;Is this the routine?
+               BNE     %00sapph__disable       ;No -- ignore this entry
+               LDR     R4,[R4,#0]              ;Load workspace offset
+               MOV     R14,#-1                 ;Set all of the bits
+               STR     R14,[R2,R4]             ;Save it in workspace
+               LDMFD   R13!,{R3,R4,R6,R14}     ;Unstack the registers
+               ORRS    PC,R14,#C_flag          ;And return with C set
+
+               LTORG
+
+; --- sapphire_heapAddr ---
+;
+; On entry:    --
+;
+; On exit:     R1 == pointer to the heap base (for passing to OS_Heap)
+;
+; Use:         Returns the address of the Sapphire heap.
+
+               EXPORT  sapphire_heapAddr
+sapphire_heapAddr ROUT
+
+               LDR     R1,sapph_heapBase
+               MOVS    PC,R14
+
+               LTORG
+
+; --- sapphire_appName ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to application name (NULL terminated)
+;
+; Use:         Returns a pointer to the application's name.
+
+               EXPORT  sapphire_appName
+sapphire_appName ROUT
+
+               LDR     R0,sapph_appName
+               MOVS    PC,R14
+
+               LTORG
+
+; --- sapphire_resetStack ---
+;
+; On entry:    --
+;
+; On exit:     R13 == stack pointer
+;
+; Use:         Resets R13 to point to the top of the stack.
+
+               EXPORT  sapphire_resetStack
+sapphire_resetStack
+               ROUT
+
+               LDR     R13,sapph_stackBase
+               MOVS    PC,R14
+
+               LTORG
+
+; --- sapphire_global ---
+;
+; On entry:    R0 == magic identifier for global variable
+;              R1 == size of area required
+;
+; On exit:     R0 == pointer to area
+;              CS if the area already exists, CC otherwise
+;
+; Use:         Locates (and creates if necessary) a `named' global area
+;              which can be used for inter-section communication without
+;              the necessity for dependencies.
+;
+;              There is a limit on the number of global areas allowed, but
+;              this can be raised fairly easily if necessary.
+;
+;              If an area can't be created, an error is generated.
+
+               EXPORT  sapphire_global
+sapphire_global ROUT
+
+               ORR     R14,R14,#C_flag         ;Clear C flag normally
+               STMFD   R13!,{R1-R4,R12,R14}    ;Save some registers
+               LDR     R12,sapph_workspace     ;Find workspace base address
+               SUB     R12,R12,#sapph__wSize   ;Subtract to get kernel space
+
+               ; --- Try and find a matching global name ---
+
+               ADR     R4,sapph__globals       ;Point to the globals block
+               LDR     R2,sapph__globCnt       ;Load my current pointer
+               MOVS    R3,R2                   ;Is it zero?
+               BEQ     %10sapphire_global      ;If not present, skip ahead
+
+00             LDR     R14,[R4],#8             ;Load the name of this one
+               CMP     R0,R14                  ;Is this a match then?
+               LDREQ   R0,[R4,#-4]             ;Yes -- point to the block
+               LDMEQFD R13!,{R1-R4,R12,PC}^    ;Yes -- return the pointer
+               SUBS    R3,R3,#1                ;Decrement the counter
+               BGT     %00sapphire_global      ;If more left, check 'em
+
+               ; --- No luck there -- allocate a new one ---
+
+10             CMP     R3,#sapph__globMax      ;Are we at the limit?
+               ADRGE   R0,sapph__noGlob        ;Yes -- point to the limit
+               SWIGE   OS_GenerateError        ;And quit the proggy
+
+               ADD     R2,R2,#1                ;Bump the global counter
+               STR     R2,sapph__globCnt       ;Store the counter away
+               STR     R0,[R4,#0]              ;Store the name of this one
+
+               MOV     R3,R1                   ;Get the size in R3 nicely
+               MOV     R0,#2                   ;Allocate a new heap block
+               LDR     R1,sapph_heapBase       ;Load my heap pointer nicely
+               SWI     OS_Heap                 ;Allocate the memory now
+               STR     R2,[R4,#4]              ;Store the pointer for later
+               MOV     R0,R2                   ;Return the pointer now
+
+               LDMFD   R13!,{R1-R4,R12,R14}    ;Return to caller
+               BICS    PC,R14,#C_flag          ;Explaining we had to create
+
+sapph__noGlob  DCD     1
+               DCB     "Too many global areas",0
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+; --- Data relative to R11 ---
+
+               ^       0,R11
+sapph__R11     #       0                       ;Make a symbol for R11
+
+sapph_scratchpad EQU   sapph__R11-0            ;Scratchpad data area
+sapph_workspace EQU    sapph__R11-4            ;Workspace base address
+sapph_stackBase EQU    sapph__R11-8            ;The top of the system stack
+sapph_heapBase  EQU    sapph__R11-12           ;Base address of the heap
+sapph_appName  EQU     sapph__R11-16           ;Pointer to application name
+sapph_clientWS  EQU    sapph__R11-20           ;Address of client's space
+
+sapph__minStack EQU    2048                    ;Minimum acceptable stack
+sapph__globMax  EQU    5                       ;Maximum global areas allowed
+
+               ^       0,R12
+sapph__wStart  #       0
+
+sapph__globCnt  #      4                       ;Number of global areas
+sapph__globals  #      8*sapph__globMax        ;The actual global bits
+
+sapph__wSize   EQU     {VAR}-sapph__wStart
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
+
diff --git a/StraySrc/Libraries/Sapphire/s/keyString b/StraySrc/Libraries/Sapphire/s/keyString
new file mode 100644 (file)
index 0000000..ae2be8a
--- /dev/null
@@ -0,0 +1,603 @@
+;
+; keyString.s
+;
+; Translating key codes to strings (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:msgs
+               GET     sapphire:keyMap
+               GET     sapphire:string
+
+;----- Constants ------------------------------------------------------------
+
+kstr__shift    EQU     (1<<8)
+kstr__ctrl     EQU     (1<<9)
+kstr__keypad   EQU     (1<<10)
+kstr__func     EQU     (1<<11)
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         KENTRY  $char,$shift,$ctrl,$keypad,$func
+$label         DCB     $char
+               DCB     ($shift<<0)+($ctrl<<1)+($keypad<<2)+($func<<3)
+               MEND
+
+;----- KeyString tables -----------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+               ; --- &000 - &00F ---
+
+kstr__lower    KENTRY  ' ',    0,1,0,0
+               KENTRY  'A',    0,1,0,0
+               KENTRY  'B',    0,1,0,0
+               KENTRY  'C',    0,1,0,0
+               KENTRY  'D',    0,1,0,0
+               KENTRY  'E',    0,1,0,0
+               KENTRY  'F',    0,1,0,0
+               KENTRY  'G',    0,1,0,0
+               KENTRY  'H',    0,1,0,0
+               KENTRY  'I',    0,1,0,0
+               KENTRY  'J',    0,1,0,0
+               KENTRY  'K',    0,1,0,0
+               KENTRY  'L',    0,1,0,0
+               KENTRY  'M',    0,1,0,0
+               KENTRY  'N',    0,1,0,0
+               KENTRY  'O',    0,1,0,0
+
+               ; --- &010 - &01F ---
+
+               KENTRY  'P',    0,1,0,0
+               KENTRY  'Q',    0,1,0,0
+               KENTRY  'R',    0,1,0,0
+               KENTRY  'S',    0,1,0,0
+               KENTRY  'T',    0,1,0,0
+               KENTRY  'U',    0,1,0,0
+               KENTRY  'V',    0,1,0,0
+               KENTRY  'W',    0,1,0,0
+               KENTRY  'X',    0,1,0,0
+               KENTRY  'Y',    0,1,0,0
+               KENTRY  'Z',    0,1,0,0
+               KENTRY  &01B,   0,0,0,0
+               KENTRY  &01C,   0,0,0,0
+               KENTRY  &01D,   0,0,0,0
+               KENTRY  &01E,   0,0,0,0
+               KENTRY  &07F,   0,1,0,0
+
+               ; --- &100 - &10F ---
+
+kstr__upper    KENTRY  ' ',    1,1,0,0
+               KENTRY  'A',    1,1,0,0
+               KENTRY  'B',    1,1,0,0
+               KENTRY  'C',    1,1,0,0
+               KENTRY  'D',    1,1,0,0
+               KENTRY  'E',    1,1,0,0
+               KENTRY  'F',    1,1,0,0
+               KENTRY  'G',    1,1,0,0
+               KENTRY  'H',    1,1,0,0
+               KENTRY  'I',    1,1,0,0
+               KENTRY  'J',    1,1,0,0
+               KENTRY  'K',    1,1,0,0
+               KENTRY  'L',    1,1,0,0
+               KENTRY  'M',    1,1,0,0
+               KENTRY  'N',    1,1,0,0
+               KENTRY  'O',    1,1,0,0
+
+               ; --- &110 - &11F ---
+
+               KENTRY  'P',    1,1,0,0
+               KENTRY  'Q',    1,1,0,0
+               KENTRY  'R',    1,1,0,0
+               KENTRY  'S',    1,1,0,0
+               KENTRY  'T',    1,1,0,0
+               KENTRY  'U',    1,1,0,0
+               KENTRY  'V',    1,1,0,0
+               KENTRY  'W',    1,1,0,0
+               KENTRY  'X',    1,1,0,0
+               KENTRY  'Y',    1,1,0,0
+               KENTRY  'Z',    1,1,0,0
+               KENTRY  &01B,   1,0,0,0
+               KENTRY  &01C,   1,0,0,0
+               KENTRY  &01D,   1,0,0,0
+               KENTRY  &01E,   1,0,0,0
+               KENTRY  &07F,   1,1,0,0
+
+               ; --- &120 - &12F ---
+
+               KENTRY  ' ',    1,0,0,0
+               KENTRY  '/',    0,1,1,0
+               KENTRY  '*',    0,1,1,0
+               KENTRY  '#',    0,1,1,0
+               KENTRY  '-',    0,1,1,0
+               KENTRY  '+',    0,1,1,0
+               KENTRY  &01D,   0,1,1,0
+               KENTRY  '.',    0,1,1,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  '[',    0,1,0,0
+               KENTRY  '\',    0,1,0,0
+               KENTRY  ']',    0,1,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  '-',    0,1,0,0
+
+               ; --- &130 - &13F ---
+
+               KENTRY  '0',    0,1,0,0
+               KENTRY  '1',    0,1,0,0
+               KENTRY  '2',    0,1,0,0
+               KENTRY  '3',    0,1,0,0
+               KENTRY  '4',    0,1,0,0
+               KENTRY  '5',    0,1,0,0
+               KENTRY  '6',    0,1,0,0
+               KENTRY  '7',    0,1,0,0
+               KENTRY  '8',    0,1,0,0
+               KENTRY  '9',    0,1,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  &01B,   0,1,0,0
+               KENTRY  &01C,   0,1,0,0
+               KENTRY  &01D,   0,1,0,0
+               KENTRY  &01E,   0,1,0,0
+               KENTRY  0,      0,0,0,0
+
+               ; --- &140 - &14F ---
+
+               KENTRY  0,      0,0,0,0
+               KENTRY  '/',    1,1,1,0
+               KENTRY  '*',    1,1,1,0
+               KENTRY  '#',    1,1,1,0
+               KENTRY  '-',    1,1,1,0
+               KENTRY  '+',    1,1,1,0
+               KENTRY  &01D,   1,1,1,0
+               KENTRY  '.',    1,1,1,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  '[',    1,1,0,0
+               KENTRY  '\',    1,1,0,0
+               KENTRY  ']',    1,1,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  '-',    1,1,0,0
+
+               ; --- &150 - &15F ---
+
+               KENTRY  '0',    1,1,0,0
+               KENTRY  '1',    1,1,0,0
+               KENTRY  '2',    1,1,0,0
+               KENTRY  '3',    1,1,0,0
+               KENTRY  '4',    1,1,0,0
+               KENTRY  '5',    1,1,0,0
+               KENTRY  '6',    1,1,0,0
+               KENTRY  '7',    1,1,0,0
+               KENTRY  '8',    1,1,0,0
+               KENTRY  '9',    1,1,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  &01B,   1,1,0,0
+               KENTRY  &01C,   1,1,0,0
+               KENTRY  &01D,   1,1,0,0
+               KENTRY  &01E,   1,1,0,0
+               KENTRY  0,      0,0,0,0
+
+               ; --- &160 - &16F ---
+
+               KENTRY  0,      0,0,0,0
+               KENTRY  '/',    0,0,1,0
+               KENTRY  '*',    0,0,1,0
+               KENTRY  '#',    0,0,1,0
+               KENTRY  '-',    0,0,1,0
+               KENTRY  '+',    0,0,1,0
+               KENTRY  &01D,   0,0,1,0
+               KENTRY  '.',    0,0,1,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+
+               ; --- &170 - &17F ---
+
+               KENTRY  0,      0,0,0,0
+               KENTRY  '/',    1,0,1,0
+               KENTRY  '*',    1,0,1,0
+               KENTRY  '#',    1,0,1,0
+               KENTRY  '-',    1,0,1,0
+               KENTRY  '+',    1,0,1,0
+               KENTRY  &01D,   1,0,1,0
+               KENTRY  '.',    1,0,1,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  0,      0,0,0,0
+               KENTRY  &07F,   1,0,0,0
+
+               ; --- &180 - &18F ---
+
+               KENTRY  0,      0,0,0,1
+               KENTRY  1,      0,0,0,1
+               KENTRY  2,      0,0,0,1
+               KENTRY  3,      0,0,0,1
+               KENTRY  4,      0,0,0,1
+               KENTRY  5,      0,0,0,1
+               KENTRY  6,      0,0,0,1
+               KENTRY  7,      0,0,0,1
+               KENTRY  8,      0,0,0,1
+               KENTRY  9,      0,0,0,1
+               KENTRY  13,     0,0,0,1
+               KENTRY  14,     0,0,0,1
+               KENTRY  15,     0,0,0,1
+               KENTRY  16,     0,0,0,1
+               KENTRY  17,     0,0,0,1
+               KENTRY  18,     0,0,0,1
+
+               ; --- &190 - &19F ---
+
+               KENTRY  0,      1,0,0,1
+               KENTRY  1,      1,0,0,1
+               KENTRY  2,      1,0,0,1
+               KENTRY  3,      1,0,0,1
+               KENTRY  4,      1,0,0,1
+               KENTRY  5,      1,0,0,1
+               KENTRY  6,      1,0,0,1
+               KENTRY  7,      1,0,0,1
+               KENTRY  8,      1,0,0,1
+               KENTRY  9,      1,0,0,1
+               KENTRY  13,     1,0,0,1
+               KENTRY  14,     1,0,0,1
+               KENTRY  15,     1,0,0,1
+               KENTRY  16,     1,0,0,1
+               KENTRY  17,     1,0,0,1
+               KENTRY  18,     1,0,0,1
+
+               ; --- &1A0 - &1AF ---
+
+               KENTRY  0,      0,1,0,1
+               KENTRY  1,      0,1,0,1
+               KENTRY  2,      0,1,0,1
+               KENTRY  3,      0,1,0,1
+               KENTRY  4,      0,1,0,1
+               KENTRY  5,      0,1,0,1
+               KENTRY  6,      0,1,0,1
+               KENTRY  7,      0,1,0,1
+               KENTRY  8,      0,1,0,1
+               KENTRY  9,      0,1,0,1
+               KENTRY  13,     0,1,0,1
+               KENTRY  14,     0,1,0,1
+               KENTRY  15,     0,1,0,1
+               KENTRY  16,     0,1,0,1
+               KENTRY  17,     0,1,0,1
+               KENTRY  18,     0,1,0,1
+
+               ; --- &1B0 - &1BF ---
+
+               KENTRY  0,      1,1,0,1
+               KENTRY  1,      1,1,0,1
+               KENTRY  2,      1,1,0,1
+               KENTRY  3,      1,1,0,1
+               KENTRY  4,      1,1,0,1
+               KENTRY  5,      1,1,0,1
+               KENTRY  6,      1,1,0,1
+               KENTRY  7,      1,1,0,1
+               KENTRY  8,      1,1,0,1
+               KENTRY  9,      1,1,0,1
+               KENTRY  13,     1,1,0,1
+               KENTRY  14,     1,1,0,1
+               KENTRY  15,     1,1,0,1
+               KENTRY  16,     1,1,0,1
+               KENTRY  17,     1,1,0,1
+               KENTRY  18,     1,1,0,1
+
+               ; --- &1C0 - &1CF ---
+
+               KENTRY  '0',    0,0,1,0
+               KENTRY  '1',    0,0,1,0
+               KENTRY  '2',    0,0,1,0
+               KENTRY  '3',    0,0,1,0
+               KENTRY  '4',    0,0,1,0
+               KENTRY  '5',    0,0,1,0
+               KENTRY  '6',    0,0,1,0
+               KENTRY  '7',    0,0,1,0
+               KENTRY  '8',    0,0,1,0
+               KENTRY  '9',    0,0,1,0
+               KENTRY  10,     0,0,0,1
+               KENTRY  11,     0,0,0,1
+               KENTRY  12,     0,0,0,1
+               KENTRY  19,     0,0,0,1
+               KENTRY  20,     0,0,0,1
+               KENTRY  21,     0,0,0,1
+
+               ; --- &1D0 - &1DF ---
+
+               KENTRY  '0',    1,0,1,0
+               KENTRY  '1',    1,0,1,0
+               KENTRY  '2',    1,0,1,0
+               KENTRY  '3',    1,0,1,0
+               KENTRY  '4',    1,0,1,0
+               KENTRY  '5',    1,0,1,0
+               KENTRY  '6',    1,0,1,0
+               KENTRY  '7',    1,0,1,0
+               KENTRY  '8',    1,0,1,0
+               KENTRY  '9',    1,0,1,0
+               KENTRY  10,     1,0,0,1
+               KENTRY  11,     1,0,0,1
+               KENTRY  12,     1,0,0,1
+               KENTRY  19,     1,0,0,1
+               KENTRY  20,     1,0,0,1
+               KENTRY  21,     1,0,0,1
+
+               ; --- &1E0 - &1EF ---
+
+               KENTRY  '0',    0,1,1,0
+               KENTRY  '1',    0,1,1,0
+               KENTRY  '2',    0,1,1,0
+               KENTRY  '3',    0,1,1,0
+               KENTRY  '4',    0,1,1,0
+               KENTRY  '5',    0,1,1,0
+               KENTRY  '6',    0,1,1,0
+               KENTRY  '7',    0,1,1,0
+               KENTRY  '8',    0,1,1,0
+               KENTRY  '9',    0,1,1,0
+               KENTRY  10,     0,1,0,1
+               KENTRY  11,     0,1,0,1
+               KENTRY  12,     0,1,0,1
+               KENTRY  19,     0,1,0,1
+               KENTRY  20,     0,1,0,1
+               KENTRY  21,     0,1,0,1
+
+               ; --- &1F0 - &1FF ---
+
+               KENTRY  '0',    1,1,1,0
+               KENTRY  '1',    1,1,1,0
+               KENTRY  '2',    1,1,1,0
+               KENTRY  '3',    1,1,1,0
+               KENTRY  '4',    1,1,1,0
+               KENTRY  '5',    1,1,1,0
+               KENTRY  '6',    1,1,1,0
+               KENTRY  '7',    1,1,1,0
+               KENTRY  '8',    1,1,1,0
+               KENTRY  '9',    1,1,1,0
+               KENTRY  10,     1,1,0,1
+               KENTRY  11,     1,1,0,1
+               KENTRY  12,     1,1,0,1
+               KENTRY  19,     1,1,0,1
+               KENTRY  20,     1,1,0,1
+               KENTRY  21,     1,1,0,1
+
+;----- Main code ------------------------------------------------------------
+
+; --- keyString ---
+;
+; On entry:    R0 == key number, from Straylight extended keymap
+;              R1 == 0 => return full shortcuts (for e.g. writable icons)
+;                    1 => return abbreviated shortcuts (for e.g. menus)
+;
+; On exit:     CS if key number was recognised, and
+;                R0 == pointer to short cut string
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Translates a key number into a string suitable for
+;              displaying to a user, and returns a pointer to the
+;              translated string.
+
+               EXPORT  keyString
+keyString      ROUT
+
+               BIC     R14,R14,#C_flag
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+
+               ; --- Find the correct entry in the tables ---
+
+               CMP     R0,#' '                 ;Is it a control key?
+               ADRLT   R2,kstr__lower          ;Yes -- point to low table
+               ADDLT   R2,R2,R0,LSL #1         ;And find the entry
+               BLT     %10keyString            ;Skip ahead after this
+
+               CMP     R0,#&FF                 ;Is it in the upper half?
+               ADRGT   R2,kstr__upper          ;Yes -- point to high table
+               BICGT   R0,R0,#&100             ;Chop off the top bit
+               ADDGT   R2,R2,R0,LSL #1         ;And find the entry again
+               BGT     %10keyString            ;Skip ahead after this
+
+               CMP     R0,#&7F                 ;Is it a delete?
+               ADREQ   R2,kstr__delete         ;Yes -- point to delete entry
+               LDMNEFD R13!,{R1-R5,PC}^        ;No -- return to caller
+
+               ; --- Load the entry from the table ---
+
+10keyString    AND     R14,R2,#3               ;Get bottom two bits of R2
+               LDR     R2,[R2,-R14]            ;Load the word properly
+               MOV     R14,R14,LSL #3          ;Get the correct shift value
+               MOV     R2,R2,LSR R14           ;And shift R2 nicely
+
+               TST     R2,#&FF                 ;Make sure bottom byte non-0
+               TSTEQ   R2,#kstr__func          ;Or is it a function key?
+               LDMEQFD R13!,{R1-R5,PC}^        ;Return to caller if neither
+
+               ; --- Find the base key name ---
+
+               TST     R2,#kstr__func          ;Is it really a function key?
+               BEQ     %20keyString            ;No -- skip this bit
+               AND     R4,R2,#&ff              ;Get the key byte out
+               CMP     R4,#12                  ;Is it F12?
+               LDMEQFD R13!,{R1-R5,PC}^        ;Yes -- always ignore F12
+
+               ADR     R3,kstr__fkeys          ;Point to key names table
+               LDR     R0,[R3,R4,LSL #2]       ;Get the correct entry out
+               CMP     R0,#0                   ;Is it a null pointer?
+               BLNE    msgs_lookup             ;No -- lookup message
+               BNE     %30keyString            ;And skip ahead nicely
+
+               ADR     R0,kstr__fmsg           ;Point to `kstrF:F%i2'
+               BL      msgs_lookup             ;Lookup the message
+               ADD     R1,R11,#50              ;Point to scratchpad
+               BL      str_subst               ;And fill the string in
+               B       %30keyString            ;Now do the rest of it all
+
+kstr__delete   KENTRY  &7F,    0,0,0,0         ;Dummy entry for delete
+
+kstr__fkeys    DCD     kstr__print
+               DCD     0,0,0,0,0,0
+               DCD     0,0,0,0,0,0
+               DCD     kstr__tab
+               DCD     kstr__copy
+               DCD     kstr__left
+               DCD     kstr__right
+               DCD     kstr__down
+               DCD     kstr__up
+               DCD     kstr__insert
+               DCD     kstr__pageDown
+               DCD     kstr__pageUp
+
+kstr__fmsg     DCB     "kstrF",0
+kstr__print    DCB     "kstrPRT",0
+kstr__tab      DCB     "kstrTAB",0
+kstr__copy     DCB     "kstrCOPY",0
+kstr__left     DCB     "kstrLEFT",0
+kstr__right    DCB     "kstrRIGHT",0
+kstr__down     DCB     "kstrDOWN",0
+kstr__up       DCB     "kstrUP",0
+kstr__insert   DCB     "kstrINS",0
+kstr__pageDown DCB     "kstrPDN",0
+kstr__pageUp   DCB     "kstrPUP",0
+
+               ; --- Handle strange keys in lower map ---
+
+20keyString    AND     R4,R2,#&ff              ;Get the key byte out
+               CMP     R4,#key_Return          ;Is it the return code?
+               BNE     %21keyString            ;No -- skip
+               TST     R2,#kstr__keypad        ;Is it on the keypad?
+               BNE     %22keyString            ;Yes -- handle it
+
+21keyString    CMP     R4,#key_Delete          ;Is it a delete key?
+               BEQ     %23keyString            ;Yes -- handle that too
+               CMP     R4,#' '                 ;Is it a space?
+               BEQ     %24keyString            ;Yes -- handle that too
+               SUB     R14,R4,#&1B             ;Is it a strange one?
+               CMP     R14,#4                  ;Is it one of the four?
+               BLO     %25keyString            ;Yes -- handle that
+
+               ADD     R0,R11,#50              ;Point to spare bit of buffer
+               STRB    R4,[R0,#0]              ;Store character in buffer
+               MOV     R3,#0                   ;Terminate the string
+               STRB    R3,[R0,#1]              ;Store that in buffer too
+               B       %30keyString            ;Skip to final processing
+
+               ; --- Handle various special cases ---
+
+22keyString    BIC     R2,R2,#kstr__keypad     ;Yes -- remove keypad flag
+               ADR     R0,kstr__enter          ;Yes -- point to string
+               BL      msgs_lookup             ;Translate it as usual
+               B       %30                     ;We've got a base string
+
+kstr__enter    DCB     "kstrENTER",0
+
+23keyString    ADR     R0,kstr__delmsg         ;Point to the string
+               BL      msgs_lookup             ;Translate it as usual
+               B       %30                     ;We've got a base string
+
+kstr__delmsg   DCB     "kstrDEL",0
+
+24keyString    ADR     R0,kstr__space          ;Point to the string
+               BL      msgs_lookup             ;Translate it as usual
+               B       %30                     ;We've got a base string
+
+kstr__space    DCB     "kstrSPC",0
+
+25keyString    ADR     R0,kstr__lowtbl         ;Point to the table
+               LDR     R0,[R0,R14,LSL #2]      ;Load the correct entry
+               BL      msgs_lookup             ;Translate it as usual
+               B       %30                     ;We've got a base string
+
+kstr__lowtbl   DCD     kstr__escape
+               DCD     kstr__backspc
+               DCD     kstr__return
+               DCD     kstr__home
+
+kstr__escape   DCB     "kstrESC",0
+kstr__backspc  DCB     "kstrBSP",0
+kstr__return   DCB     "kstrRET",0
+kstr__home     DCB     "kstrHOME",0
+
+               ; --- Finally, handle modifier strings ---
+
+30keyString    MOV     R5,R0                   ;Keep pointer to base key
+               LDR     R4,[R13,#0]             ;Get shortcut style wanted
+               MOV     R0,R11                  ;Point to the scratchpad
+
+               TST     R2,#kstr__shift         ;Is shift held down?
+               MOVNE   R1,#'\8b'                 ;Yes -- short character
+               ADRNE   R3,kstr__shmod          ;And long message
+               BLNE    %80keyString            ;Sort everything out
+
+               TST     R2,#kstr__ctrl          ;Is shift held down?
+               MOVNE   R1,#'^'                 ;Yes -- short character
+               ADRNE   R3,kstr__ctmod          ;And long message
+               BLNE    %80keyString            ;Sort everything out
+
+               TST     R2,#kstr__keypad        ;Is shift held down?
+               MOVNE   R1,#'k'                 ;Yes -- short character
+               ADRNE   R3,kstr__kpmod          ;And long message
+               BLNE    %80keyString            ;Sort everything out
+
+               MOV     R1,R5                   ;Point to base string
+               BL      str_cpy                 ;Copy the last string in
+               MOV     R0,R11                  ;Point to string in buffer
+               LDMFD   R13!,{R1-R5,R14}        ;Load the registers
+               ORRS    PC,R14,#C_flag          ;We handled it (eventually)
+
+kstr__shmod    DCB     "kstrSH",0
+kstr__ctmod    DCB     "kstrCTL",0
+kstr__kpmod    DCB     "kstrKPD",0
+
+               ; --- Work out what a modifier should look like ---
+
+80keyString    CMP     R4,#0                   ;Do we want short mod chars?
+               STRNEB  R1,[R0],#1              ;Yes -- store char nicely
+               MOVNES  PC,R14                  ;And return to caller
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R3                   ;Point to message tag
+               BL      msgs_lookup             ;Translate the string
+               MOV     R1,R0                   ;Keep pointer to message
+               LDMFD   R13!,{R0}               ;Restore a register
+               BL      str_cpy                 ;Attach string to end
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/libOpts b/StraySrc/Libraries/Sapphire/s/libOpts
new file mode 100644 (file)
index 0000000..66d42ae
--- /dev/null
@@ -0,0 +1,142 @@
+;
+; libOpts.s
+;
+; Allow options for library units to be declared
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:sapphire
+               GET     sapphire:suballoc
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- libOpts_register ---
+;
+; On entry:    R0 == address of an options block
+;
+; On exit:     --
+;
+; Use:         Adds the block given to the library options.
+
+               EXPORT  libOpts_register
+libOpts_register ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers
+               WSPACE  lo__wSpace              ;Locate my workspace
+
+               BL      sub_init                ;Awaken suballoc just in case
+               MOV     R1,R0                   ;Look after the block addr
+               MOV     R0,#8                   ;Allocate a small link block
+               BL      sub_alloc               ;Try to allocate memory
+               LDMVSFD R13!,{R0,R1,R12,PC}^    ;If it failed, don't bother
+
+               STR     R1,[R0,#0]              ;Remember this block pointer
+               LDR     R14,lo__head            ;Load the current list head
+               STR     R14,[R0,#4]             ;Save this as the next link
+               STR     R0,lo__head             ;And save new list head
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- libOpts_find ---
+;
+; On entry:    R0 == magic marker word
+;
+; On exit:     CS if found, and
+;                R0 == address of options block
+;              else CC, and
+;                R0 corrupted
+;
+; Use:         Tries to find an option with the given marker, which will
+;              normally be a four-character text string.  The first match
+;              found will be returned.  The options blocks are searched in
+;              reverse order of registration (i.e. blocks registered later
+;              will override blocks registered reviously).
+
+               EXPORT  libOpts_find
+libOpts_find   ROUT
+
+               STMFD   R13!,{R1-R3,R12,R14}    ;Save some registers away
+               WSPACE  lo__wSpace              ;Find my workspace
+               MOV     R2,R0                   ;Look after the marker
+               LDR     R1,lo__head             ;Load the list head block
+
+               ; --- Scan through the list ---
+
+10libOpts_find CMP     R1,#0                   ;Reached the end yet?
+               BEQ     %50libOpts_find         ;Yes -- return to caller
+               LDMIA   R1,{R0,R1}              ;Load the block ptr and link
+
+               ; --- See if we can find it in here ---
+
+20libOpts_find LDMIA   R0!,{R3,R14}            ;Load marker and size word
+               CMP     R2,R3                   ;Does this match up?
+               BEQ     %40libOpts_find         ;Yes -- found it then
+               CMP     R3,#-1                  ;Is this the block end?
+               ADDNE   R0,R0,R14               ;No -- move on to next item
+               BNE     %20libOpts_find         ;And loop round again
+               B       %10libOpts_find         ;Try the next options block
+
+               ; --- Found a match ---
+
+40libOpts_find LDMFD   R13!,{R1-R3,R12,R14}    ;Restore registers
+               ORRS    PC,R14,#C_flag          ;Return successfully
+
+               ; --- Failed to find a match ---
+
+50libOpts_find LDMFD   R13!,{R1-R3,R12,R14}    ;Restore registers
+               BICS    PC,R14,#C_flag          ;Return unsuccessfully
+
+               LTORG
+
+lo__wSpace     DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+lo__wStart     #       0
+
+lo__head       #       4                       ;Base of the options list
+
+lo__wSize      EQU     {VAR}-lo__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     lo__wSize
+               DCD     lo__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/listbox b/StraySrc/Libraries/Sapphire/s/listbox
new file mode 100644 (file)
index 0000000..a07927e
--- /dev/null
@@ -0,0 +1,1672 @@
+;
+; listbox.s
+;
+; Nice listbox handling routines (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:fastMove
+               GET     sapphire:idle
+               GET     sapphire:divide
+               GET     sapphire:pane
+               GET     sapphire:resspr
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+               GET     sapphire:tspr
+               GET     sapphire:win
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- lb_create ---
+;
+; On entry:    R0 == pointer to list manager description block
+;              R1 == pointer to the list
+;              R2 == pointer to a width function
+;              R3 == The height of each item
+;              R4 == parent window handle or
+;                    pointer to window block if R5 == -1
+;              R5 == parent icon handle or -1 if not a pane
+;
+; On exit:     R0 == listbox handle
+;              R1 == window handle of list box
+;              May return an error (R1 corrupted)
+
+               EXPORT  lb_create
+lb_create      ROUT
+
+               STMFD   R13!,{R2,R3,R10,R14}    ;Stack some registers
+
+               ; --- First, create the block ---
+
+               MOV     R10,R0                  ;Preserve R0
+               MOV     R0,#lb__size            ;The structure size
+               BL      alloc                   ;Get the block
+               BLCS    alloc_error             ;Get a message if no memory
+               BCS     %99lb_create            ;Return on error
+
+               MOV     R14,R10                 ;Do a swap type thing
+               MOV     R10,R0                  ;Point to the block
+               MOV     R0,R14                  ;Confused yet?
+               STMIA   R10,{R0-R5}             ;Store information in block
+               MOV     R0,#0                   ;No flags set yet
+               STR     R0,[R10,#lb__flags]     ;Store this word
+               STR     R0,[R10,#lb__handler]   ;No handler either
+               BL      lb__getMaxWidth         ;Find length of longest item
+
+               ; --- Calculate the minimum width and height of the box ---
+
+               CMP     R5,#-1                  ;Is this a pane listbox?
+               BNE     %10lb_create            ;No -- use icon then
+
+               MOV     R14,#176                ;A minimum height
+               STR     R14,[R10,#lb__height]   ;Store the width
+               LDR     R0,[R4,#0]              ;Load the minimum x position
+               LDR     R14,[R4,#8]             ;Load the maximum x position
+               SUB     R0,R14,R0               ;Get the initial width
+               STR     R0,[R10,#lb__width]     ;Store the width
+               B       %20lb_create            ;And jump ahead a bit
+
+10lb_create    SUB     R13,R13,#40             ;Get another block
+               STR     R4,[R13,#0]             ;Store parent window handle
+               STR     R5,[R13,#4]             ;And icon handle
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetIconState       ;Get the icon's state
+
+               LDR     R2,[R1,#16]             ;Get the x1 coord
+               LDR     R14,[R1,#8]             ;And x0 coord
+               SUB     R2,R2,R14               ;Calculate the icon width
+               STR     R2,[R10,#lb__width]     ;Store the width
+               LDR     R2,[R1,#20]             ;Get the y1 coord
+               LDR     R14,[R1,#12]            ;And y0 coord
+               SUB     R2,R2,R14               ;Calculate the icon height
+               STR     R2,[R10,#lb__height]    ;Store the height
+               ADD     R13,R13,#40             ;Get the block back
+
+               ; --- Now create the window ---
+
+20lb_create    SUB     R13,R13,#88             ;Get a block
+               MOV     R0,R13                  ;Point to it
+               CMP     R5,#-1                  ;Is this a pane listbox?
+               ADRNE   R1,lb__windowDef        ;No -- point to my window def
+               MOVEQ   R1,R4                   ;Yes -- use theirs then
+               MOV     R2,#lb__defSize         ;Copy this much
+               BL      fastMove                ;Copy the definition across
+               LDR     R1,[R10,#lb__height]    ;y0
+               RSB     R1,R1,#0                ;Negate it
+               LDR     R2,[R10,#lb__width]     ;x1
+               ADD     R14,R13,#44             ;The workarea extent block
+               STMIA   R14,{R1,R2}             ;Store the desired extent
+               BL      resspr_area             ;Find the sprite area
+               STR     R0,[R13,#64]            ;Store this in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_CreateWindow       ;Try to create the window
+               ADD     R13,R13,#88             ;Get the stack back
+               BVS     %98lb_create            ;Return on error
+               STR     R0,[R10,#lb__wHandle]   ;Store my window handle
+
+               ; --- Set up the event handler ---
+
+               ADR     R1,lb__eventHandler     ;Point to the event handler
+               MOV     R2,R10                  ;R10 value to call with
+               MOV     R3,#0                   ;R12 value to call with
+               BL      win_eventHandler        ;Add in the event handler
+
+               ; --- Add it as a pane to the parent (if we need to) ---
+
+               MOV     R2,R0                   ;The window handle
+               MOV     R0,R4                   ;Parent window handle
+               MOVS    R1,R5                   ;Parent icon handle
+               BLPL    pane_add                ;Register the pane (if reqd)
+
+               ; --- Add scroll bars if we need too ---
+
+               ORR     R10,R10,#(1<<31)        ;Don't open the window
+               BL      lb__rescanSize          ;Re-scan the size nicely
+               BIC     R10,R10,#(1<<31)        ;Clear silly bit again
+               BVS     %98lb_create            ;Return om error
+
+               LDR     R1,[R10,#lb__wHandle]   ;Return window handle in R1
+               MOV     R0,R10                  ;Return the listbox handle
+               B       %99lb_create            ;Return to caller
+
+98lb_create    MOV     R0,R10                  ;Point to the allocated block
+               BL      free                    ;Free the block
+99lb_create    LDMFD   R13!,{R2,R3,R10,R14}    ;Get registers back
+               ORRVSS  PC,R14,#V_flag          ;And return either with...
+               BICVCS  PC,R14,#V_flag          ;...or without error
+
+               LTORG
+
+lb__windowDef  DCD     320,256,960,768
+               DCD     0,0
+               DCD     -1
+               DCD     &80000122
+               DCB     7,2,7,255,3,1,12,0
+               DCD     0,0,0,0
+               DCD     &39,10<<12
+               DCD     0,0
+               DCB     "ListBox",0,0
+               DCD     0
+
+lb__defSize    EQU     {PC}-lb__windowDef
+
+; --- lb__rescanSize ---
+;
+; On entry:    R10 == pointer to listbox
+;                Bit 31 == don't call open the window
+;
+; On exit:     VS and R0 == pointer to error or
+;              VC and R0 == window handle
+;
+; Use:         Scans the list, and adds/removes scroll bars if necessary
+
+lb__rescanSize ROUT
+
+               STMFD   R13!,{R1-R10,R14}       ;Stack some registers
+               BIC     R10,R10,#(1<<31)        ;Clear the top bit
+
+               ; --- First get the window state of the current window ---
+
+               SUB     R13,R13,#36             ;Get a block
+               LDR     R0,[R10,#lb__wHandle]   ;Get the window handle
+               STR     R0,[R13,#0]             ;Store in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window state
+               LDR     R6,[R1,#32]             ;Get the window flags
+               ADD     R13,R13,#36             ;Get the block back again
+               LDR     R9,[R10,#lb__descriptor] ;Point to descriptor block
+               LDR     R0,[R10,#lb__list]      ;Point to the list itself
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R9,#lb_items         ;Call the function
+               LDR     R7,[R10,#lb__iHeight]   ;The height of each item
+               MUL     R7,R1,R7                ;The required box y extent
+               LDR     R4,[R10,#lb__width]     ;Overall box width
+               LDR     R5,[R10,#lb__height]    ;Overall box height
+               BL      tspr_borderWidths       ;Get the border widths
+               BL      screen_getInfo          ;Get pixel sizes
+               LDR     R14,[R0,#screen_dx]     ;x pixel size
+               SUB     R4,R4,R14,LSL#1         ;Correct overall width
+               ADD     R1,R1,R14               ;Set up border width
+               LDR     R14,[R0,#screen_dy]     ;y pixel size
+               SUB     R5,R5,R14,LSL#1         ;Correct overall height
+               SUB     R2,R2,R14               ;Set up border height
+               LDR     R14,[R10,#lb__pIHandle] ;Get the parent icon handle
+               CMP     R14,#-1                 ;Is this a pane dialogue?
+               BEQ     %50lb__rescanSize       ;Yes -- jump ahead then
+
+               ; --- Which scroll bars do we want? ---
+
+               MOV     R14,#0                  ;No flags so far
+               LDR     R0,[R10,#lb__maxWidth]  ;Get the width required
+               CMP     R0,R4                   ;Is width>overall?
+               ORRGT   R14,R14,#(1<<30)        ;Yes -- we need horz. scr bar
+               SUBGT   R5,R5,R2                ;Reduce overall height
+
+               CMP     R7,R5                   ;Do we need a vertical bar?
+               ORRGT   R14,R14,#(1<<28)        ;Yes -- make a note of this
+               SUBGT   R4,R4,R1                ;Reduce overall width
+
+               TST     R14,#(1<<30)            ;Do we have a horz. bar?
+               BNE     %00lb__rescanSize       ;Yes -- jump ahead
+               CMP     R0,R4                   ;Is width>overall?
+               ORRGT   R14,R14,#(1<<30)        ;Yes -- we need horz. scr bar
+               SUBGT   R5,R5,R2                ;Reduce overall height
+
+               ; --- Do we need to add/remove scroll bars? ---
+
+00             AND     R0,R6,#&50000000        ;The scroll bars we have
+               CMP     R0,R14                  ;Are the flags the same
+               BEQ     %50lb__rescanSize       ;Yes -- jump ahead
+
+               ; --- Now we need to recreate the window ---
+
+               BIC     R6,R6,#&50000000        ;No scroll bars at all
+               ORR     R6,R6,R14               ;Just the ones we want please
+
+               ; --- Now create the new window ---
+
+               SUB     R13,R13,#88             ;Get a block
+               MOV     R0,R13                  ;Point to it
+               ADR     R1,lb__windowDef        ;Point to window definition
+               MOV     R2,#lb__defSize         ;Copy this much
+               BL      fastMove                ;Copy the definition across
+               RSB     R1,R7,#0                ;y0
+               LDR     R2,[R10,#lb__maxWidth]  ;x1
+               ADD     R14,R13,#44             ;The workarea extent block
+               STMIA   R14,{R1,R2}             ;Store the desired extent
+               STR     R6,[R13,#28]            ;Store the flags word
+               BL      resspr_area             ;Find the sprite area
+               STR     R0,[R13,#64]            ;Store this in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_CreateWindow       ;Try to create the window
+               ADD     R13,R13,#88             ;Get the block back
+               LDRVS   R0,[R10,#lb__pWHandle]  ;On error, get window handle
+               LDRVS   R1,[R10,#lb__pIHandle]  ;...get the icon handle
+               BLVS    pane_remove             ;...remove the pane
+               BVS     %99lb__rescanSize       ;...and Barf with error
+
+               MOV     R1,R0                   ;Look after the window handle
+               LDR     R0,[R10,#lb__wHandle]   ;Load the old handle
+               BL      win_swapWindow          ;Tell win the handle changed
+               MOV     R2,R1                   ;Look after new handle
+               ADD     R1,R10,#lb__wHandle     ;Point to the old handle
+               SWI     Wimp_DeleteWindow       ;Destroy the old window
+               STR     R2,[R10,#lb__wHandle]   ;Store the new window handle
+
+               LDR     R0,[R10,#lb__pWHandle]  ;Parent window handle
+               LDR     R1,[R10,#lb__pIHandle]  ;Parent icon handle
+               BL      pane_swap               ;Swap the pane
+               B       %50lb__rescanSize       ;Jump ahead a little
+
+50             ; --- Work out the correct extents ---
+
+               BL      screen_getInfo          ;Get pixel sizes
+               LDR     R14,[R0,#screen_dx]     ;x pixel size
+               ADD     R4,R4,R14,LSL#1         ;Correct overall width
+
+               CMP     R7,R5                   ;Is required<overall height?
+               MOVLT   R7,R5                   ;Yes -- make them the same
+               LDR     R3,[R10,#lb__maxWidth]  ;Get the width required
+               CMP     R3,R4                   ;Is required<overall width?
+               MOVLT   R3,R4                   ;Yes -- make them the same
+               SUB     R13,R13,#16             ;Get a small block
+               MOV     R1,#0                   ;x0 extent
+               RSB     R2,R7,#0                ;y0 extent
+               MOV     R4,#0                   ;y1 extent
+               STMIA   R13,{R1-R4}             ;Store the required extent
+               MOV     R1,R13                  ;Point to the block
+               LDR     R5,[R10,#lb__wHandle]   ;Load the window handle
+               MOV     R0,R5                   ;Put it in R0
+               SWI     Wimp_SetExtent          ;Set the window extent
+               ADD     R13,R13,#16             ;Reclaim the block again
+
+               LDR     R14,[R13,#36]           ;Load R10 value
+               TST     R14,#(1<<31)            ;Should we return here
+               BNE     %90lb__rescanSize       ;Yes -- return then
+               LDR     R14,[R10,#lb__pIHandle] ;Get the parent icon
+               CMP     R14,#-1                 ;Is the listbox attached?
+               STREQ   R5,[R13,#-36]!          ;Yes -- store window handle
+               MOVEQ   R1,R13                  ;Point at the block
+               SWIEQ   Wimp_GetWindowState     ;Find the current position
+               SWIEQ   Wimp_OpenWindow         ;And open it again
+               ADDEQ   R13,R13,#36             ;Restore the stack
+               LDRNE   R0,[R10,#lb__pWHandle]  ;Parent window handle
+               BLNE    pane_open               ;Open the listbox cunningly
+90             MOV     R0,R5                   ;Get the window handle back
+
+               ; --- Return to caller ---
+
+99             LDMFD   R13!,{R1-R10,R14}       ;Load registers
+               ORRVSS  PC,R14,#V_flag          ;And return with...
+               BICVCS  PC,R14,#V_flag          ;...or without error
+
+               LTORG
+
+; --- lb_destroy ---
+;
+; On entry:    R0 == listbox handle
+;
+; On exit:     --
+;
+; Use:         Destroys the given listbox.
+
+               EXPORT  lb_destroy
+lb_destroy     ROUT
+
+               STMFD   R13!,{R0-R3,R10,R14}    ;Stack some registers
+               MOV     R10,R0                  ;Keep the pointer
+               ADD     R1,R10,#lb__wHandle     ;Point to the window handle
+               SWI     XWimp_CloseWindow       ;Close the window
+               SWI     Wimp_DeleteWindow       ;And the delete it
+
+               ; --- Remove the pane attachment ---
+
+               LDR     R0,[R10,#lb__pWHandle]  ;Get the parent window handle
+               LDR     R1,[R10,#lb__wHandle]   ;Get the listbox window hnd
+               BL      pane_remove             ;Remove the pane
+
+               ; --- Remove the event handler ---
+
+               MOV     R0,R1                   ;The window handle
+               BL      win_windowDeleted       ;Remove the handler
+
+               ; --- Finally, free the block ---
+
+               MOV     R0,R10                  ;Point to the block
+               BL      free                    ;Free it
+
+               LDMFD   R13!,{R0-R3,R10,PC}^    ;Return to caller
+
+; --- lb_eventHandler ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == handler function
+;              R2 == R10 value to pass
+;              R3 == R12 value to pass
+;
+; On exit:     --
+;
+; Use:         Registers an event handler for the given listbox.
+
+               EXPORT  lb_eventHandler
+lb_eventHandler        ROUT
+
+               STMFD   R13!,{R14}              ;Stack some registers
+               ADD     R14,R0,#lb__handler     ;Point to nice block
+               STMIA   R14,{R1-R3}             ;Store the information
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- lb__getMaxWidth ---
+;
+; On entry:    R10 == pointer to listbox structure
+;
+; On exit:     R0 == longest item width in the list
+
+lb__getMaxWidth        ROUT
+
+               STMFD   R13!,{R1-R7,R14}        ;Stack some registers
+
+               MOV     R4,#0                   ;The longest width so far
+               LDR     R5,[R10,#lb__widthFun]  ;Get the width function ptr
+               LDR     R6,[R10,#lb__descriptor] ;Point to the descriptor blk
+               LDR     R0,[R10,#lb__list]      ;Get the list head
+               MOV     R1,#0                   ;From the first item
+               MOV     R2,#0                   ;No mask word
+               MOV     R3,#0                   ;Or test word
+00             MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R6,#lb_enumerate     ;Get a list item
+               BCC     %99lb__getMaxWidth      ;No more items -- return
+               MOV     R7,R1                   ;Remember the R1 value
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R5                   ;Call the width function
+               CMP     R1,R4                   ;Is the the longest width?
+               MOVGT   R4,R1                   ;Yes -- remember this fact
+               MOV     R1,R7                   ;Put R1 back again
+               B       %00lb__getMaxWidth      ;Check other items
+
+99             MOV     R0,R4                   ;Put width in R0
+               STR     R0,[R10,#lb__maxWidth]  ;And store in the listbox
+               LDMFD   R13!,{R1-R7,PC}^        ;And return to caller
+
+               LTORG
+
+; --- lb__eventHandler ---
+;
+; On entry:    R0 == event type
+;              R1 == pointer to event block
+;
+; On exit:     --
+;
+; Use:         Called to deal with events on the listbox window
+
+lb__eventHandler ROUT
+
+               CMP     R0,#1                   ;Is it a redraw event?
+               BEQ     lb__redraw              ;Yes -- handle it then
+               CMP     R0,#3                   ;Is it a close event?
+               BEQ     lb__close               ;Yes -- report it then
+               CMP     R0,#10                  ;Scroll request?
+               BEQ     lb__scroll              ;Yes -- let's hope we cope
+               CMP     R0,#6                   ;Is it a click event?
+               BEQ     lb__click               ;Yes -- handle that
+               CMP     R0,#17                  ;Is it a message (normal)?
+               CMPNE   R0,#18                  ;Or a rubber message?
+               BEQ     lb__message             ;Yes -- handle it then
+
+               BICS    PC,R14,#C_flag          ;Return -- didn't understand
+
+               LTORG
+
+; --- lb__dispatch ---
+;
+; On entry:    R0 == a list box event code
+;              R1-R8 == arguments for the client's event handler
+;              R10 == list box handle
+;
+; On exit:     CC or CS, from the event handler
+;
+; Use:         Sends an event to the user event handler for the list box.
+
+lb__dispatch   ROUT
+
+               STMFD   R13!,{R9,R10,R12,R14}   ;Save some useful registers
+               ADD     R14,R10,#lb__handler    ;Point to the handler stuff
+               LDMIA   R14,{R9,R10,R12}        ;Load the appropriate bits
+               ADDS    R0,R0,#0                ;Clear the carry flag
+               TEQ     R9,#0                   ;Is there a handler defined?
+               MOV     R14,PC                  ;Set up a return address
+               MOVNE   PC,R9                   ;Yes -- call the handler
+               LDMFD   R13!,{R9,R10,R12,R14}   ;Unstack the registers again
+               BICCCS  PC,R14,#C_flag          ;If C clear then clear C
+               ORRCSS  PC,R14,#C_flag          ;If C set then set C
+
+               LTORG
+
+; --- lb__message ---
+;
+; On entry:    R0 == message type (17 or 18)
+;              R1 == event block
+;
+; On exit:     --
+;
+; Use:         Called when the listbox recieves a message
+
+lb__message    ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Stack some messages
+               LDR     R0,[R1,#16]             ;Get the message type
+               CMP     R0,#1                   ;Is it a save message?
+               CMPNE   R0,#3                   ;Or a load message?
+               BEQ     %10lb__message          ;Yes -- handle them the same
+               LDR     R14,=&502               ;The help message code
+               CMP     R0,R14                  ;Is that the message?
+               BEQ     %05lb__message          ;Yes -- deal with it
+
+               ; --- Check for mode/font changes ---
+
+               CMP     R0,R14                  ;Are they the same
+               LDRNE   R14,=&400CF             ;Also get a FontChange msg
+               CMPNE   R0,R14                  ;Does this match?
+               BLEQ    lb__getMaxWidth         ;Yes -- calculate max width
+               BLEQ    lb__rescanSize          ;...and rescan the size
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               ; --- Handle a help request ---
+
+05lb__message  ADD     R1,R1,#20               ;Point to mouse info
+               BL      lb__getItem             ;Get the item under pointer
+               MOV     R0,#lbEvent_help        ;Set up the event type
+               BL      lb__dispatch            ;Dispatch the event
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+               ; --- Handle data saves and loads ---
+
+10lb__message  CMP     R0,#1                   ;Is it a save message?
+               MOVEQ   R5,#lbDrop_save         ;Set up the subreason code
+               MOVNE   R5,#lbDrop_load
+
+               MOV     R6,R1                   ;Remember the block pointer
+               SUB     R13,R13,#52             ;Get a nice block
+               MOV     R1,R13                  ;Point to it
+               SWI     Wimp_GetPointerInfo     ;Get pointer information
+               BL      lb__getItem             ;Get the item under pointer
+               ADD     R13,R13,#52             ;Get the stack back
+
+               LDR     R2,[R6,#40]             ;Load the file type
+               ADD     R3,R6,#44               ;Point to the filename
+               LDR     R4,[R6,#36]             ;Load the estimated size
+               MOV     R0,#lbEvent_drop        ;The event type
+               BL      lb__dispatch            ;Dispatch the event
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+               LTORG
+
+; --- lb__getItem ---
+;
+; On entry:    R1 == pointer to a mouse info block
+;              R10 == pointer to the listbox
+;
+; On exit:     R1 == the item
+;
+; Use:         Returns the item the pointer is over
+
+lb__getItem    ROUT
+
+               STMFD   R13!,{R0,R2-R4,R9,R14}  ;Stack some registers
+               MOV     R9,R1                   ;Keep the mouse info block
+               SUB     R13,R13,#36             ;Get me a nice block
+               LDR     R0,[R9,#12]             ;The window handle
+               STR     R0,[R13,#0]             ;Store it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window state
+
+               LDR     R2,[R13,#16]            ;y1 coord
+               LDR     R14,[R13,#24]           ;Scroll y position
+               SUB     R2,R2,R14               ;Screen coord of origin
+               LDR     R14,[R9,#4]             ;Mouse y position
+               SUB     R2,R14,R2               ;Window relative position
+               ADD     R13,R13,#36             ;Get stack back
+               BL      screen_getInfo          ;Get screen information
+               LDR     R14,[R0,#screen_dy]     ;Get y pixel size
+               ADD     R0,R2,R14               ;Prepare for division
+               LDR     R1,[R10,#lb__iHeight]   ;By the item height
+               RSB     R1,R1,#0                ;Negate it
+               BL      divide                  ;Perform the division
+               MOV     R1,R0                   ;Put index in R1
+               LDR     R0,[R10,#lb__list]      ;And list head in R0
+               LDR     R4,[R10,#lb__descriptor] ;Get the descriptor block
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R4,#lb_indexToItem   ;Get the item itself
+               LDMFD   R13!,{R0,R2-R4,R9,PC}^  ;Return to caller
+
+               LTORG
+
+; --- lb__redraw ---
+;
+; On entry:    R1 == pointer to a window handle
+;
+; On exit:     CS
+;
+; Use:         Redraws a list box, by sending redraw events to the client.
+
+lb__redraw     ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Save masses of registers
+
+               ; --- Start a redraw job ---
+
+               SWI     Wimp_RedrawWindow       ;Start the redraw
+               CMP     R0,#0                   ;Is there anything to do?
+               BEQ     %90lb__redraw           ;No -- don't do it then
+
+               ; --- Do some setting up ---
+
+               ADD     R14,R1,#16              ;Point to the top edge
+               LDMIA   R14,{R0,R9,R14}         ;Load that and the scroll pos
+               SUB     R7,R0,R14               ;Work out the y origin pos
+
+               ; --- Get the left and right sides set up ---
+
+               LDR     R4,[R10,#lb__maxWidth]  ;Get the width of the items
+               LDR     R14,[R10,#lb__width]    ;Get the window width
+               CMP     R14,R4                  ;Is the window width bigger?
+               MOVGT   R4,R14                  ;Yes -- use that instead
+
+               LDR     R9,[R10,#lb__descriptor] ;Load his list descriptor
+               LDR     R8,[R10,#lb__list]      ;Find the list block
+
+               ; --- Work out which bits need drawing ---
+
+10lb__redraw   LDR     R6,[R1,#40]             ;Load the top y coordinate
+               SUB     R6,R6,R7                ;Convert to window coords
+               LDR     R14,[R10,#lb__iHeight]  ;Get the item height
+               ADD     R6,R6,R14               ;Get height thingy value
+
+               MOV     R5,#0                   ;Top of the first item
+               MOV     R1,#0                   ;Start at item -1 (sort of)
+
+               ; --- Get items until one is visible ---
+
+15lb__redraw   MOV     R0,R8                   ;Point to the list block
+               MOV     R2,#0                   ;Don't care about the flags
+               MOV     R3,#0                   ;I *really* don't care at all
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R9,#lb_enumerate     ;Get a new item in R1
+               BCC     %70lb__redraw           ;Run out -- 76 for 3
+
+               CMP     R5,R6                   ;Is this item visible?
+               LDRGT   R14,[R10,#lb__iHeight]  ;No -- get the item height
+               SUBGT   R5,R5,R14               ;Move to the next one down
+               BGT     %15lb__redraw           ;And find one that is then
+
+               ; --- Now draw items until they stop being visible ---
+
+               LDR     R6,[R13,#4]             ;Get the redraw block pointer
+               LDR     R6,[R6,#32]             ;Load the bottom y coordinate
+               SUB     R6,R6,R7                ;And convert to window coords
+
+               ; --- The main plotting loop ---
+
+20lb__redraw   CMP     R5,R6                   ;Is this one visible?
+               BLE     %80lb__redraw           ;No -- then stop plotting
+
+               MOV     R0,#lbEvent_redraw      ;Send a redraw event on
+               LDR     R14,[R10,#lb__iHeight]  ;Get the item height
+               SUB     R3,R5,R14               ;Get the item bottom bit
+               MOV     R2,#0                   ;Left hand side is at 0
+               BL      lb__dispatch            ;Send the event on then
+
+               MOV     R5,R3                   ;Move to the next item down
+               MOV     R0,R8                   ;Point to the list block
+               MOV     R2,#0                   ;Don't care about the flags
+               MOV     R3,#0                   ;I *really* don't care at all
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R9,#lb_enumerate     ;Get a new item in R1
+               BCS     %20lb__redraw           ;More to do -- go round again
+
+               ; --- Fill in the rest in grey ---
+
+               CMP     R5,R6                   ;Do we really have to draw it
+               BLE     %80lb__redraw           ;No -- then stop plotting
+
+70lb__redraw   MOV     R0,#1                   ;The background colour
+               SWI     Wimp_SetColour          ;Set the colour up
+               ADD     R2,R5,R7                ;Get the top of the area
+               BL      screen_getInfo          ;Read some screen information
+               MOV     R14,#1                  ;This will be shifty
+               LDR     R0,[R0,#screen_yEig]    ;Load the y eigen factor
+               SUB     R2,R2,R14,LSL R0        ;S*dding thing's exclusive
+               LDR     R3,[R13,#4]             ;Load the redraw block addr
+               LDR     R1,[R3,#28]             ;Load the left hand side
+               MOV     R0,#4                   ;Move cursor absolute
+               SWI     OS_Plot                 ;Do the plotting bit
+               MOV     R0,#101                 ;Rectangle fill absolute
+               LDR     R1,[R3,#36]             ;Get the right hand side
+               LDR     R2,[R3,#32]             ;And the bottom edge
+               SWI     OS_Plot                 ;Fill in the remaining bit
+
+               ; --- Go round and get another rectangle ---
+
+80lb__redraw   LDR     R1,[R13,#4]             ;Get the redraw block pointer
+               SWI     Wimp_GetRectangle       ;Get the next rectangle
+               CMP     R0,#0                   ;Is there more to draw?
+               BNE     %10lb__redraw           ;Yes -- go round again
+
+               ; --- We finished at last ---
+
+90lb__redraw   LDMFD   R13!,{R0-R9,R14}        ;Unstack the registers again
+               ORRS    PC,R14,#C_flag          ;More redraws cause flicker
+
+               LTORG
+
+; --- lb__close ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Informs the user when the listbox has been closed.
+
+lb__close      ROUT
+
+               STMFD   R13!,{R0,R14}           ;Stack some register
+               MOV     R0,#lbEvent_close       ;Send this event code
+               BL      lb__dispatch            ;And dispatch the event
+               LDMFD   R13!,{R0,PC}            ;Return to caller
+
+               LTORG
+
+; --- lb__scroll ---
+;
+; On entry:    R0 == 10
+;              R1 == event block
+;
+; On exit:     --
+
+lb__scroll     ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+               MOV     R4,R1                   ;Keep the block pointer
+
+               ; --- First, try to scroll vertically ---
+
+               LDR     R0,[R4,#24]             ;Load the y scroll offset
+               ADD     R14,R4,#8               ;Find the bottom edge
+               LDMIA   R14,{R2,R3,R14}         ;Load the y positions
+               SUB     R3,R14,R2               ;R3 is the window height now
+               LDR     R2,[R10,#lb__iHeight]   ;Get the item height
+
+               LDR     R14,[R1,#36]            ;Get vertical scroll value
+               ADD     R14,R14,#1              ;Convert into range -1..3
+               ADD     PC,PC,R14,LSL #2        ;And jump to right routine
+
+               B       %10lb__scroll           ;Y scroll page down
+               B       %20lb__scroll           ;Y scroll line down
+               B       %50lb__scroll           ;No y scrolling
+               B       %40lb__scroll           ;Y scroll line up
+               B       %30lb__scroll           ;Y scroll page up
+
+               ; --- Do a y scroll page down ---
+
+10lb__scroll   SUB     R0,R0,R3                ;Find the window bottom
+               MOV     R1,R2                   ;Now prepare to divide by it
+               SUB     R0,R0,R2                ;Make it round towards 0
+               BL      divide                  ;Get the quotient value
+               MUL     R0,R2,R0                ;And multiply it up again
+               ADD     R0,R0,R2,LSL #1         ;Find the appropriate top
+               STR     R0,[R4,#24]             ;Store the scroll offset back
+               B       %50lb__scroll           ;And now do the x bit
+
+               ; --- Do a y scroll line down ---
+
+20lb__scroll   SUB     R0,R0,R3                ;Find the window bottom
+               MOV     R1,R2                   ;Now prepare to divide by it
+               SUB     R0,R0,R2                ;Make it round towards 0
+               BL      divide                  ;Get the quotient value
+               MUL     R0,R2,R0                ;And multiply it up again
+               ADD     R0,R0,R3                ;Find the appropriate top
+               STR     R0,[R4,#24]             ;Store the scroll offset back
+               B       %50lb__scroll           ;And now do the x bit
+
+               ; --- Do a y scroll page up ---
+
+30lb__scroll   MOV     R1,R2                   ;Now prepare to divide by it
+               ADD     R0,R0,#1                ;Make it round towards 0
+               BL      divide                  ;Get the quotient value
+               MUL     R0,R2,R0                ;And multiply it up again
+               ADD     R0,R0,R3                ;Scroll the whole window up
+               SUB     R0,R0,R2,LSL #1         ;And scroll back two items
+               STR     R0,[R4,#24]             ;Store the scroll offset back
+               B       %50lb__scroll           ;And now do the x bit
+
+               ; --- Do a y scroll line up ---
+
+40lb__scroll   MOV     R1,R2                   ;Now prepare to divide by it
+               ADD     R0,R0,#1                ;Make it round towards 0
+               BL      divide                  ;Get the quotient value
+               MUL     R0,R2,R0                ;And multiply it up again
+               STR     R0,[R4,#24]             ;Store the scroll offset back
+               B       %50lb__scroll           ;And now do the x bit
+
+               ; --- Now do the x scrolling ---
+
+50lb__scroll   LDR     R0,[R4,#20]             ;Load the x scroll offset
+               ADD     R14,R4,#4               ;Find the left hand side
+               LDMIA   R14,{R2,R3,R14}         ;Load the x positions
+               SUB     R3,R14,R2               ;Get the current window width
+
+               LDR     R14,[R4,#32]            ;Get horizontal scroll value
+               CMP     R14,#-2                 ;Scroll left by a page?
+               SUBEQ   R0,R0,R3                ;Yes -- do it then
+               CMP     R14,#-1                 ;Scroll left by a column?
+               SUBEQ   R0,R0,#32               ;Yes -- do it then
+               CMP     R14,#1                  ;Scroll right by a column?
+               ADDEQ   R0,R0,#32               ;Yes -- do it then
+               CMP     R14,#2                  ;Scroll right by a page?
+               ADDEQ   R0,R0,R3                ;Yes -- do it then
+               STR     R0,[R4,#20]             ;Save the x scroll offset
+
+99lb__scroll   MOV     R1,R4                   ;Point to the block again
+               SWI     Wimp_OpenWindow         ;Actually do the scrolling
+               LDMFD   R13!,{R0-R4,R14}        ;Return to caller
+               ORRS    PC,R14,#C_flag
+
+               LTORG
+
+; --- lb_plotString ---
+;
+; On entry:    R0 == pointer to a string
+;              R1 == pointer to the list item
+;              R2-R5 == window coordinates to plot it
+;              R10 == pointer to the listbox
+;
+; On exit:     --
+;
+; Use:         Plots a list item consisting of a single string.  It assumes
+;              the default selection model.
+
+               EXPORT  lb_plotString
+lb_plotString  ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save a lot of registers
+               SUB     R13,R13,#32             ;Make an icon block
+               STMIA   R13,{R2-R5}             ;Save the coordinates in it
+               MOV     R2,#-1                  ;No validation string
+               MOV     R3,#1                   ;Put in a silly buffer size
+               ADD     R14,R13,#20             ;Point to icon data section
+               STMIA   R14,{R0,R2,R3}          ;Save the icon data away
+               LDR     R4,[R10,#lb__descriptor] ;Get the descriptor block
+               LDR     R0,[R10,#lb__list]      ;Point to the list head
+               MOV     R2,#0                   ;Don't alter the flags
+               MOV     R3,#0                   ;Don't alter them at all
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R4,#lb_setFlags      ;Read the item's flags
+               LDR     R0,=&07000131           ;Set up default flags
+               TST     R2,#3                   ;Is it selected?
+               ORRNE   R0,R0,#&00200000        ;Yes -- set the selected bit
+               STR     R0,[R13,#16]            ;Store the flags in the blk
+               MOV     R1,R13                  ;Point to the icon block
+               SWI     Wimp_PlotIcon           ;Plot the icon then
+               ADD     R13,R13,#32             ;Recover the icon block
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- lb_update ---
+;
+; On entry:    R0 == listbox handle
+;
+; On exit:     May return an error
+;
+; Use:         Updates the entire listbox prettily
+
+               EXPORT  lb_update
+lb_update      ROUT
+
+               STMFD   R13!,{R0-R4,R10,R14}    ;Stack sonme registers
+
+               MOV     R10,R0                  ;Put list box handle in R10
+               BL      lb__getMaxWidth         ;Get the maximum width
+               BL      lb__rescanSize          ;Ensure windows right size
+               BVS     %90lb_update            ;Barf on error
+               LDR     R0,[R10,#lb__wHandle]   ;Get the window handle
+               MOV     R1,#0                   ;x0
+               LDR     R2,[R10,#lb__height]    ;Overall height
+               RSB     R2,R2,#0                ;Negate it
+               LDR     R3,[R10,#lb__width]     ;Overall width -- x1
+               LDR     R14,[R10,#lb__maxWidth] ;And the widest item width
+               CMP     R14,R3                  ;Which one is bigger?
+               MOVGT   R3,R14                  ;Make R3 biggest
+               MOV     R4,#0                   ;y1
+               SWI     Wimp_ForceRedraw        ;Force a redraw
+
+               LDMFD   R13!,{R0-R4,R10,PC}^    ;Return to caller
+
+90lb_update    ADD     R13,R13,#4              ;Point past R0
+               LDMFD   R13!,{R1-R4,R10,R14}    ;Get back some registers
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- lb_updateItem ---
+;
+; On entry:    R0 == list box handle
+;              R1 == list item handle
+;
+; On exit:     --
+;
+; Use:         Redraws a list item to reflect a change in its state.
+
+               EXPORT  lb_updateItem
+lb_updateItem  ROUT
+
+               STMFD   R13!,{R0-R5,R10,R14}    ;Save a load of registers
+
+               ; --- Find the item's index ---
+
+               MOV     R10,R0                  ;Keep the list box handle
+               LDR     R0,[R10,#lb__list]      ;Find the list block
+               LDR     R2,[R10,#lb__descriptor] ;Find the list descriptor
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R2,#lb_itemToIndex   ;Get the item's index
+
+               ; --- Now set up the update block ---
+
+               SUB     R13,R13,#44             ;Make space for update blk
+               LDR     R0,[R10,#lb__wHandle]   ;Get the window handle
+               LDR     R14,[R10,#lb__iHeight]  ;Get the item height
+               RSB     R14,R14,#0              ;Negate it
+               MUL     R5,R14,R1               ;Get the top of the item
+               ADD     R3,R5,R14               ;And get the bottom too
+               MOV     R2,#0                   ;Redraw from left hand side
+               LDR     R4,[R10,#lb__width]     ;Load the window width
+               LDR     R14,[R10,#lb__maxWidth] ;And the widest item width
+               CMP     R14,R4                  ;Which one is bigger?
+               MOVGT   R4,R14                  ;Use the biggest one
+               STMIA   R13,{R0,R2-R5}          ;Save them in the block
+
+               ; --- Update the item ---
+
+               MOV     R1,R13                  ;Point to the window block
+               SWI     Wimp_UpdateWindow       ;Start doing the update
+               CMP     R0,#0                   ;Is there anything to do?
+               BEQ     %90lb_updateItem        ;No -- skip it all then
+
+10lb_updateItem        MOV     R0,#lbEvent_redraw      ;Send out a redraw event
+               LDR     R1,[R13,#48]            ;Get the item handle
+               BL      lb__dispatch            ;Give the user an event
+               MOV     R1,R13                  ;Point to the update block
+               SWI     Wimp_GetRectangle       ;Get another rectangle
+               CMP     R0,#0                   ;Was that the last one?
+               BNE     %10lb_updateItem        ;No -- do another one then
+
+               ; --- Tidy up and go home again ---
+
+90lb_updateItem        ADD     R13,R13,#44             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;And return to the caller
+
+               LTORG
+
+; --- lb_select ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == item handle
+;              R2 == 0 to unselect, 1 to select, or 2 to toggle
+;
+; On exit:     --
+;
+; Use:         Selects or deselects a listbox item, nicely and without
+;              flickering it.
+
+               EXPORT  lb_select
+lb_select      ROUT
+
+               CMP     R1,#0                   ;Is there actually an item?
+               MOVEQS  PC,R14                  ;No -- then do nothing here
+
+               STMFD   R13!,{R0-R5,R10,R14}    ;Save some registers away
+               MOV     R10,R0                  ;Get the listbox handle
+
+               ; --- Read the current flags ---
+
+               LDR     R4,[R10,#lb__descriptor] ;Find the list definition
+               MOV     R5,R2                   ;And look after argument
+               MOV     R3,#0                   ;Want to read the flags
+               MOV     R2,#0                   ;Oh, yes I do
+               LDR     R0,[R10,#lb__list]      ;Load the list block
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R4,#lb_setFlags      ;And read the current flags
+
+               ; --- Work out new flags ---
+
+               AND     R2,R2,#1                ;Only leave selected flag
+               CMP     R5,#1                   ;What is the operation?
+               MOVLT   R3,#0                   ;Clear -- clear the flag
+               MOVEQ   R3,#1                   ;Set -- set the flag
+               EORGT   R3,R2,#1                ;Toggle -- toggle the flag
+               CMP     R3,R2                   ;Have we made a difference?
+               LDMEQFD R13!,{R0-R5,R10,PC}^    ;No -- return now then
+
+               ; --- Set the new flags ---
+
+               MOV     R2,#1                   ;Clear the selected bit
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R4,#lb_setFlags      ;Set the new flags nicely
+               MOV     R0,R10                  ;Get handle in R0
+               BL      lb_updateItem           ;And redraw the list item
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;And return to caller
+
+               LTORG
+
+; --- lb_isSelected ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == item handle
+;
+; On exit:     CS if item is selected, else CC
+;
+; Use:         Informs you whether an item is selected.
+
+               EXPORT  lb_isSelected
+lb_isSelected  ROUT
+
+               CMP     R1,#0                   ;Is there an icon?
+               BICEQS  PC,R14,#C_flag          ;No -- not selected then
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R2,#0                   ;Don't clear any flags
+               MOV     R3,#0                   ;Don't toggle any either
+               LDR     R4,[R0,#lb__descriptor] ;Find the list block
+               LDR     R0,[R0,#lb__list]       ;Find the list base
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R4,#lb_setFlags      ;Read the current flags
+               TST     R2,#1                   ;Is it selected then?
+               LDMFD   R13!,{R0-R4,R14}        ;Restore caller's registers
+               ORRNES  PC,R14,#C_flag          ;If selected, return C set
+               BICEQS  PC,R14,#C_flag          ;Otherwise clear C on exit
+
+               LTORG
+
+; --- lb__click ---
+;
+; On entry:    R1 == pointer to event block
+;
+; On exit:     CS
+;
+; Use:         Dispatches click events on the list box
+
+lb__click      ROUT
+
+               ORR     R14,R14,#C_flag         ;Set the carry flag
+               STMFD   R13!,{R0-R4,R9,R14}     ;Stack some registers
+               MOV     R9,R1                   ;Keep a pointer to the block
+
+               BL      lb__getItem             ;Get item pointer is over
+
+               LDR     R3,[R9,#8]              ;Get the mouse button status
+               TST     R3,#&5                  ;Double select or ajdust
+               TSTEQ   R3,#&500                ;No -- just select or adjust?
+               BNE     %10lb__click            ;Yes -- handle it then
+               TST     R3,#&50                 ;Drag with select or adjust?
+               BNE     %20lb__click            ;Yes -- deal with that
+               TST     R3,#&2                  ;Is it menu click?
+               LDMEQFD R13!,{R0-R3,R9,PC}^     ;no -- return then
+
+               ; --- Deal with menu clicks ---
+
+               MOV     R0,#lbEvent_menu        ;The event type
+               BL      lb__dispatch            ;Dispatch the event
+               B       %99lb__click            ;And return to caller
+
+               ; --- Click or double click on an item ---
+
+10             MOV     R0,#lbEvent_click       ;The event type
+               BL      lb__dispatch            ;Dispatch the event
+               B       %99lb__click            ;And return to caller
+
+               ; --- There was a drag event ---
+
+20             MOV     R0,#lbEvent_drag        ;The event type
+               BL      lb__dispatch            ;Dispatch the event
+               B       %99lb__click            ;And return to caller
+
+99             LDMFD   R13!,{R0-R4,R9,PC}^     ;Return to caller
+
+               LTORG
+
+; --- lb_clearSelection ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == item handle of item to ignore (or 0 for none)
+;
+; On exit:     --
+;
+; Use:         Deselects all items in the listbox.
+
+               EXPORT  lb_clearSelection
+lb_clearSelection ROUT
+
+               STMFD   R13!,{R0-R6,R10,R14}    ;Stack some registers
+               MOV     R10,R0                  ;Get the listbox handle
+               LDR     R6,[R10,#lb__list]      ;And load the list pointer
+               MOV     R5,R1                   ;Remember this item
+               LDR     R4,[R10,#lb__descriptor] ;Point to the descriptor blk
+
+               MOV     R1,#0                   ;Start with the first item
+00             MOV     R0,R6                   ;Get the list handle
+               MOV     R2,#1                   ;Only read selected items
+               MOV     R3,#1                   ;Don't want the others
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R4,#lb_enumerate     ;Read the item and flags
+               BCC     %90                     ;No more items -- skip
+
+               CMP     R1,R5                   ;Is this the special item?
+               BEQ     %b00                    ;Yes -- ignore it then
+               MOV     R0,R10                  ;No -- get the list handle
+               MOV     R2,#0                   ;Deselect it please
+               BL      lb_select               ;And unselect the item
+               B       %b00                    ;And loop back again
+
+90             LDMFD   R13!,{R0-R6,R10,PC}^    ;Return to caller
+
+               LTORG
+
+; --- lb_clickS ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == pointer to list item
+;              R3 == mouse button status
+;
+; On exit:     --
+;
+; Use:         Provides a default action for clicking on an item in a
+;              list box.
+;
+;              Only one selection is possible at any one time.
+
+               EXPORT  lb_clickS
+lb_clickS      ROUT
+
+               STMFD   R13!,{R0,R2,R14}        ;Stack some registers
+               BL      lb_clearSelection       ;Clear all the other items
+               TST     R3,#&100                ;Is it an adjust click?
+               TSTEQ   R3,#&001                ;Better check the double too
+               MOVNE   R2,#2                   ;Yes -- then toggle the item
+               MOVEQ   R2,#1                   ;Otherwise just select
+               BL      lb_select               ;Go and select the item
+               LDMFD   R13!,{R0,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- lb_clickM ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == pointer to list item
+;              R3 == mouse button status
+;
+; On exit:     --
+;
+; Use:         Provides a default action for clicking on an item in a
+;              list box.
+;
+;              The multiple selection model is used.
+
+               EXPORT  lb_clickM
+lb_clickM      ROUT
+
+               STMFD   R13!,{R0,R2,R14}        ;Stack some registers
+               TST     R3,#&100                ;Is it an adjust click?
+               TSTEQ   R3,#&001                ;Better check the double too
+               BEQ     %50lb_clickM            ;No -- then deal elsewhere
+               MOV     R2,#2                   ;Just toggle the item
+               BL      lb_select               ;Do the selecting bit
+               B       %90lb_clickM            ;And skip onwards
+50lb_clickM    BL      lb_isSelected           ;Is the item selected?
+               BLCC    lb_clearSelection       ;No -- then clear the others
+               MOVCC   R2,#1                   ;Select this item
+               BLCC    lb_select               ;Go and do that
+90lb_clickM    LDMFD   R13!,{R0,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- lb__idleHandler ---
+;
+; On entry:    R10 == listbox handle
+;              R12 == workspace pointer                                        ;
+; On exit:     --
+;
+; Use:         Called on NULL events during a drag
+
+lb__idleHandler        ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Stack some registers
+
+               SUB     R13,R13,#56             ;Get a block
+               MOV     R1,R13                  ;Point to it
+               SWI     Wimp_GetPointerInfo     ;Get pointer position
+               LDR     R0,[R10,#lb__wHandle]   ;Get the window handle
+               STR     R0,[R13,#20]            ;Store in the block
+               ADD     R1,R13,#20              ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window state
+               LDR     R9,[R13,#36]            ;Get the y1 coordinate
+               LDR     R14,[R13,#44]           ;The scroll coordinate
+               SUB     R9,R9,R14               ;Window origin
+               LDR     R14,[R13,#4]            ;Mouse y position
+               SUB     R9,R14,R9               ;Make it window relative
+
+               BL      screen_getInfo          ;Get screen information
+               LDR     R14,[R0,#screen_dy]     ;Get y pixel size
+               ADD     R0,R9,R14               ;Prepare for division
+               LDR     R1,[R10,#lb__iHeight]   ;By the item height
+               RSB     R1,R1,#0                ;Negate it
+               BL      divide                  ;Perform the division
+               CMP     R0,#0                   ;Is index negative?
+               MOVLT   R0,#0                   ;Yes -- make it 0
+
+               LDR     R6,ws__dragItem         ;Get start drag index
+               LDR     R3,ws__dragLast         ;And last drag position
+               MOV     R8,R0                   ;Copy index into R1
+               MOV     R7,R0                   ;And R7
+               MOV     R5,R0                   ;And R5
+
+               ; --- Find minimum and maximum values ---
+
+               CMP     R7,R6                   ;R0>R2?
+               MOVGT   R7,R6                   ;Yes == R0:=R2
+               CMP     R7,R3                   ;R0>R3?
+               MOVGT   R7,R3                   ;Yes == R0:=R3
+
+               CMP     R8,R6                   ;R0<R2?
+               MOVLT   R8,R6                   ;Yes == R0:=R2
+               CMP     R8,R3                   ;R0<R3?
+               MOVLT   R8,R3                   ;Yes == R0:=R3
+
+               ; --- Summary ---
+               ;
+               ; R5 == the current index
+               ; R6 == the initial index
+               ; R7 == minimum of current,last and initial drag indicies
+               ; R8 == maximum of current,last and initial drag indicies
+               ; R9 == window relative position of the mouse position
+
+               STMFD   R13!,{R12}              ;We need this -- blurgg!!
+               LDR     R12,[R10,#lb__descriptor] ;Point to descriptor block
+               MOV     R4,#-1                  ;Current item index (i)
+               MOV     R3,#-1                  ;The selection type
+               LDR     R0,[R10,#lb__list]      ;Get the list head
+               MOV     R1,#0                   ;Start from the first item
+
+00             STMFD   R13!,{R3}               ;Preserve R3 over call
+               MOV     R2,#0                   ;Interested in all items
+               MOV     R3,#0                   ;Interested in all items
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R12,#lb_enumerate    ;Call enumeration function
+               LDMFD   R13!,{R3}               ;Get R3 back again
+               BCC     %50lb__idleHandler      ;No more -- exit the loop
+               ADD     R4,R4,#1                ;Increment index count
+
+               CMP     R4,R7                   ;i == start index?
+               MOVEQ   R3,#0                   ;Yes -- sel=0
+               CMP     R6,R5                   ;Initial index<index
+               BGT     %20lb__idleHandler      ;No -- jump ahead then
+
+               CMP     R4,R6                   ;i=initial index?
+               MOVEQ   R3,#1                   ;Yes -- sel=1
+               CMP     R4,R5                   ;i>current index?
+               MOVGT   R3,#0                   ;Yes -- sel=0
+               B       %30lb__idleHandler      ;Jump ahead a bit
+
+20             CMP     R4,R5                   ;i=current index?
+               MOVEQ   R3,#1                   ;Yes -- sel=1
+               CMP     R4,R6                   ;i>initial index?
+               MOVGT   R3,#0                   ;Yes -- sel=0
+               B       %30lb__idleHandler      ;Jump ahead a bit
+
+30             CMP     R4,R8                   ;Are we at the end?
+               BGT     %50lb__idleHandler      ;Yes -- jump out of loop
+
+               ; --- Redraw the item if we need to ---
+
+               CMP     R3,#-1                  ;Do we need to do anything?
+               BEQ     %00lb__idleHandler      ;No -- keep going round
+               STMFD   R13!,{R0-R4}            ;Stack some registers
+               LDR     R0,[R10,#lb__list]      ;Get the list head
+               MOV     R4,R3                   ;Look after thing in R3
+               MOV     R2,#0                   ;Read the flags
+               MOV     R3,#0                   ;No writing here
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R12,#lb_setFlags     ;Read the flags
+               ORR     R3,R2,R2,LSR#1          ;Is bit 0 or 1 set?
+               AND     R3,R3,#1                ;Just interested in this bit
+               CMP     R3,R4                   ;Is there a change to be made
+               BEQ     %40lb__idleHandler      ;No -- keep on looping then
+               ANDS    R2,R2,#1                ;Just get selected bit
+               BEQ     %35lb__idleHandler      ;If its clear -- jump ahead
+               CMP     R2,R4                   ;Is this the same?
+               BNE     %40lb__idleHandler      ;No -- return
+35             MOV     R2,#2                   ;Just alter this bit
+               MOV     R3,R4,LSL#1             ;Set or clear appropriately
+               LDR     R0,[R10,#lb__list]      ;Get the list head
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R12,#lb_setFlags     ;Set the flags
+               MOV     R0,R10                  ;Put listbox handle in R0
+               BL      lb_updateItem           ;Update the item
+
+40             LDMFD   R13!,{R0-R4}            ;Restore registers
+               B       %00lb__idleHandler      ;Keep going round
+
+50             LDMFD   R13!,{R12}              ;Get R12 back again
+               STR     R5,ws__dragLast         ;Store last item visited
+
+               ; --- Scroll the window nicely ---
+
+               LDR     R0,[R13,#44]            ;Get the y scroll position
+               CMP     R9,R0                   ;Is mouse y>y scroll?
+               MOVGT   R0,R9                   ;Yes -- y scroll=mouse y
+               BGT     %55lb__idleHandler      ;...and jump ahead
+               LDR     R2,[R13,#36]            ;Get y1 coordinate
+               LDR     R3,[R13,#28]            ;Get y0 coordinate
+               SUB     R3,R2,R3                ;Get window height
+               ADD     R9,R9,R3                ;Add on mouse position
+               CMP     R9,R0                   ;Is it less than y scroll pos
+               MOVLT   R0,R9                   ;Yes -- use y scroll pos
+55             STR     R0,[R13,#44]            ;Store new scroll position
+               ADD     R1,R13,#20              ;Point to the block
+               SWI     Wimp_OpenWindow         ;Open the window
+
+99             ADD     R13,R13,#56             ;Reclaim the stack
+99             LDMFD   R13!,{R0-R9,PC}^        ;Return to caller
+
+               LTORG
+
+; --- lb__unknownHandler ---
+;
+; On entry:    R0 == event type
+;              R1 == event block
+;              R10 == listbox handle
+;              R12 == workspace pointer
+;
+; On exit:     --
+;
+; Use:         Called when the drag is ended
+
+
+lb__unknownHandler ROUT
+
+               CMP     R0,#7                   ;Are we interested?
+               MOVNES  PC,R14                  ;No -- return PDQ
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+
+               ; --- First get rid of the idle claimer ---
+
+               MOV     R0,#0                   ;Call very frequently
+               ADR     R1,lb__idleHandler      ;Call this routine
+               MOV     R2,R10                  ;Call with this R10 handle
+               MOV     R3,R12                  ;And this R12 value
+               BL      idle_removeHandler      ;Add in the handler
+
+               ; --- Now this  unknown handler ---
+
+               ADR     R0,lb__unknownHandler   ;Call this routine
+               MOV     R1,#0                   ;R4 value
+               MOV     R2,R10                  ;Call with this R10 handle
+               MOV     R3,R12                  ;And this R12 value
+               BL      win_removeUnknownHandler ;Add in the handler
+
+               ; --- Make temporary selections permanant ---
+
+               LDR     R4,[R10,#lb__descriptor] ;Point to descriptor block
+               LDR     R0,[R10,#lb__list]      ;Get the list head
+               MOV     R1,#0                   ;Start from the top
+00             MOV     R2,#2                   ;Just interested in this bit
+               MOV     R3,#2                   ;And it must be set
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R4,#lb_enumerate     ;Enumerate the list
+               BCC     %99lb__unknownHandler   ;No more -- return
+
+               LDR     R0,[R10,#lb__list]      ;Get the list head
+               MOV     R2,#3                   ;Clear these bits
+               MOV     R3,#1                   ;And set this one
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R4,#lb_setFlags      ;And set the flags
+               B       %00lb__unknownHandler   ;Keep going round for more
+
+99             LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- lb_drag ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == pointer to list item
+;              R3 == mouse button status
+;
+; On exit:     --
+;
+; Use:         Starts a drag operation to allow for easy multiple
+;              selection.
+
+               EXPORT  lb_drag
+lb_drag                ROUT
+
+               STMFD   R13!,{R0-R3,R10,R12,R14} ;Stack some registers
+               WSPACE  lb__wSpace              ;Locate my workspace
+               MOV     R10,R0                  ;Move listbox handle into R10
+
+               LDR     R0,[R10,#lb__list]      ;Point to the list head
+               LDR     R2,[R10,#lb__descriptor] ;Point to descriptor block
+               CMP     R1,#0                   ;Is there an item
+               MOVEQ   R3,#lb_items            ;No -- use the item count
+               MOVNE   R3,#lb_itemToIndex      ;Yes -- find its index
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R2,R3                ;Convert item to an index
+               STR     R1,ws__dragItem         ;The start drag item
+               STR     R1,ws__dragLast         ;Last item visited
+
+               ; --- First we must start the drag box ---
+
+               SUB     R13,R13,#40             ;Get me a block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetPointerInfo     ;Get mouse position
+               LDR     R0,[R1,#0]              ;Get mouse x position
+               LDR     R1,=&9001               ;Parent y0
+               MOV     R2,R0                   ;Parent x1
+               LDR     R3,=&6FFE               ;Parent Parent y1
+               ADD     R14,R13,#24             ;Point to right place
+               STMIA   R14,{R0-R3}             ;Store parent coords
+               MOV     R0,#7                   ;The drag type
+               STR     R0,[R13,#4]             ;Store nicely in block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_DragBox            ;Start the drag
+
+               ; --- Set up the idle event handler ---
+
+               MOV     R0,#0                   ;Call very frequently
+               ADR     R1,lb__idleHandler      ;Call this routine
+               MOV     R2,R10                  ;Call with this R10 handle
+               MOV     R3,R12                  ;And this R12 value
+               BL      idle_handler            ;Add in the handler
+
+               ; --- Set up the unknown handler ---
+
+               ADR     R0,lb__unknownHandler   ;Call this routine
+               MOV     R1,#0                   ;R4 value
+               MOV     R2,R10                  ;Call with this R10 handle
+               MOV     R3,R12                  ;And this R12 value
+               BL      win_unknownHandler      ;Add in the handler
+
+               ; --- Now return to the caller ---
+
+               ADD     R13,R13,#40             ;Reclaim the stack
+               LDMFD   R13!,{R0-R3,R10,R12,PC}^ ;Return to caller
+
+               LTORG
+
+; --- lb_inserted ---
+;
+; On entry:    R0 == pointer to the listbox
+;              R1 == pointer to the new item
+;
+; On exit:     --
+;
+; Use:         Informs the listbox that an item has been inserted,
+;              and causes a flicker free insert to occur if possible.
+
+               EXPORT  lb_inserted
+lb_inserted    ROUT
+
+               STMFD   R13!,{R0-R8,R10,R14}    ;Stack some registers
+
+               MOV     R10,R0                  ;Put listbox handle in R10
+               MOV     R7,R1                   ;Look after item
+               BL      lb__getMaxWidth         ;Get the maximum width
+               LDR     R2,[R10,#lb__wHandle]   ;Get the old window handle
+               BL      lb__rescanSize          ;Ensure windows right size
+               CMP     R2,R0                   ;Has the window changed?
+               BNE     %99lb_inserted          ;Yes -- return
+
+               ; --- Now do the block copy ---
+
+               LDR     R0,[R10,#lb__list]      ;Get the list head
+               LDR     R2,[R10,#lb__descriptor] ;Get the descriptor
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R2,#lb_itemToIndex   ;Convert item to index
+
+               LDR     R8,[R10,#lb__iHeight]   ;Get the item height
+               RSB     R8,R8,#0                ;Negate it
+               MUL     R4,R8,R1                ;Get top of item
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R2,#lb_items         ;Get the item count
+               MUL     R2,R1,R8                ;The overall height
+               LDR     R0,[R10,#lb__wHandle]   ;Get the window handle
+               MOV     R1,#0                   ;The minimum x coord
+               LDR     R3,[R10,#lb__width]     ;Load the window width
+               LDR     R6,[R10,#lb__maxWidth]  ;And the widest item width
+               CMP     R6,R3                   ;Which one is bigger?
+               MOVGT   R3,R6                   ;Use the biggest one
+               MOV     R5,#0                   ;x coord to move to
+               ADD     R6,R2,R8                ;y coord to move to
+               SWI     Wimp_BlockCopy          ;Do a block copy
+
+               ; --- Finally, update the new item ---
+
+               MOV     R0,R10                  ;Point to the listbox
+               MOV     R1,R7                   ;Put item pointer in R1
+               BL      lb_updateItem           ;Update the item
+
+99lb_inserted  LDMFD   R13!,{R0-R8,R10,PC}^    ;Return to caller
+
+               LTORG
+
+; --- lb_removed ---
+;
+; On entry:    R0 == pointer to the listbox
+;              R1 == index of item removed
+;
+; On exit:     --
+;
+; Use:         Informs the listbox that an item has been removed, and
+;              causes a flicker free remove to occur, if possible.
+
+               EXPORT  lb_removed
+lb_removed     ROUT
+
+               STMFD   R13!,{R0-R8,R10,R14}    ;Stack some registers
+
+               MOV     R10,R0                  ;Put listbox handle in R10
+               MOV     R7,R1                   ;Look after item
+               BL      lb__getMaxWidth         ;Get the maximum width
+               LDR     R2,[R10,#lb__wHandle]   ;Get the old window handle
+               BL      lb__rescanSize          ;Ensure windows right size
+               CMP     R2,R0                   ;Has the window changed?
+               BNE     %99lb_removed           ;Yes -- return
+
+               ; --- Now do the block copy ---
+
+               LDR     R2,[R10,#lb__descriptor] ;Get the descriptor block
+               LDR     R8,[R10,#lb__iHeight]   ;Get the item height
+               RSB     R8,R8,#0                ;Negate it
+               MUL     R4,R8,R1                ;Get top of item
+               ADD     R4,R4,R8                ;Now get the bottom of it
+               LDR     R0,[R10,#lb__list]      ;Get the list head
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R2,#lb_items         ;Get the item count
+               MUL     R2,R1,R8                ;The overall height
+               LDR     R3,[R10,#lb__height]    ;Get overall window height
+               SUB     R2,R2,R3                ;Subtract that for luck
+               LDR     R0,[R10,#lb__wHandle]   ;Get the window handle
+               MOV     R1,#0                   ;The minimum x coord
+               LDR     R3,[R10,#lb__width]     ;Load the window width
+               LDR     R6,[R10,#lb__maxWidth]  ;And the widest item width
+               CMP     R6,R3                   ;Which one is bigger?
+               MOVGT   R3,R6                   ;Use the biggest one
+               MOV     R5,#0                   ;x coord to move to
+               SUB     R6,R2,R8                ;y coord to move to
+               SWI     Wimp_BlockCopy          ;Do a block copy
+
+99lb_removed   LDMFD   R13!,{R0-R8,R10,PC}^    ;Return to caller
+
+               LTORG
+
+; --- lb_window ---
+;
+; On entry:    R0 == listbox handle
+;
+; On exit:     R0 == window handle
+;
+; Use:         Returns the window handle of the listbox
+
+               EXPORT  lb_window
+lb_window      ROUT
+
+               LDR     R0,[R0,#lb__wHandle]    ;Load the window handle
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- lb_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the listbox unit.
+
+               EXPORT  lb_init
+lb_init                ROUT
+
+               STMFD   R13!,{R12,R14}          ;Stack some registers
+               WSPACE  lb__wSpace              ;Locate my workspace
+
+               ; --- Ensure that we are not already initialised ---
+
+               LDR     R14,ws__flags           ;Get the flags word
+               TST     R14,#wsFlag__inited     ;Are we initialised?
+               BNE     %99lb_init              ;Yes -- return
+               ORR     R14,R14,#wsFlag__inited ;We are initialised now
+               STR     R14,ws__flags           ;Store back modified flags
+
+               ; --- Return to caller ---
+
+99lb_init      LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+lb__wSpace     DCD     0
+
+;----- List events ----------------------------------------------------------
+
+               ^       0
+lbEvent_close  #       1                       ;Listbox has been closed
+
+lbEvent_redraw #       1                       ;Redraw a list item
+                                               ;R1 == pointer to list item
+                                               ;R2-R5 == window coords
+lbEvent_click  #       1                       ;Click/Double on listbox
+                                               ;R1 == pointer to list item
+                                               ;R2 == window relative y pos
+                                               ;R3 == button type (10)
+lbEvent_menu   #       1                       ;Menu click
+                                               ;R1 == pointer to list item
+                                               ;R2 == window relative y pos
+                                               ;R3 == button type (10)
+lbEvent_drag   #       1                       ;Drag on listbox
+                                               ;R1 == pointer to list item
+                                               ;R2 == window relative y pos
+                                               ;R3 == button type (10)
+lbEvent_help   #       1                       ;R1 == pointer to list item
+lbEvent_drop   #       1                       ;R1 == pointer to list item
+                                               ;R2 == filetype
+                                               ;R3 == pointer to filename
+                                               ;R4 == estimated file size
+                                               ;R5 == subreason cde
+
+               ^       0
+lbDrop_load    #       1
+lbDrop_save    #       1
+
+;----- Workspace layout -----------------------------------------------------
+
+; --- listbox block descriptor ---
+
+               ^       0
+
+lb_itemToIndex #       4                       ;Item to index routine
+lb_indexToItem #       4                       ;Index to item routine
+lb_enumerate   #       4                       ;Enumeration function
+lb_items       #       4                       ;Function to return items
+lb_setFlags    #       4                       ;Function to set/read flags
+
+; --- listbox individual layout ---
+
+               ^       0
+
+lb__descriptor #       4                       ;Pointer to descriptor above
+lb__list       #       4                       ;The list itself
+lb__widthFun   #       4                       ;Function to return width
+lb__iHeight    #       4                       ;Height of each item
+lb__pWHandle   #       4                       ;Parent window handle
+lb__pIHandle   #       4                       ;Parent icon handle
+lb__handler    #       4                       ;The handler function
+lb__R10                #       4                       ;The R10 value to pass
+lb__R12                #       4                       ;The R12 value to pass
+lb__width      #       4                       ;Overall box width
+lb__height     #       4                       ;Overall box height
+lb__flags      #       4                       ;Listbox flags
+lb__wHandle    #       4                       ;The listbox window handle
+lb__maxWidth   #       4                       ;The maximum item width
+lb__size       #       4                       ;Size of this structure
+
+; --- Main workspace ---
+
+               ^       0,R12
+
+ws__flags      #       4                       ;The flags word
+ws__dragItem   #       4                       ;Item from which drag starts
+ws__dragLast   #       4                       ;Last drag item visited
+
+ws__size       EQU     {VAR}-ws__flags         ;The size of the workspace
+
+wsFlag__inited EQU     (1<<0)                  ;We are initialised
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     ws__size
+               DCD     lb__wSpace
+               DCD     0
+               DCD     lb_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/llistMan b/StraySrc/Libraries/Sapphire/s/llistMan
new file mode 100644 (file)
index 0000000..0e23bc3
--- /dev/null
@@ -0,0 +1,673 @@
+;
+; llistMan.s
+;
+; Linked List Management (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:fastMove
+               GET     sapphire:sapphire
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- llist_create ---
+;
+; On entry:    R0 == pointer to 12 byte list head to fill in
+;              R1 == sort routine to use (0 for none)
+;
+; On exit:     List head filled in appropriately
+;
+; Use:         This call set up list. It must be made just once, before
+;              and other list alls are made. On entry, R0 must point to
+;              12 bytes in memory, which is filled in by this call.
+;              Example code may look like:
+;
+;                      ADR     R0,myList
+;                      LDR     R1,=myStrCmp
+;                      BL      llist_create
+;
+;                        .
+;                         .
+;                        .
+;
+;                      mylist  DCD     0,0
+
+               EXPORT  llist_create
+llist_create   ROUT
+
+               STMFD   R13!,{R12,R14}          ;Stack some registers
+               WSPACE  llist__wSpace           ;Locate my workspace
+
+               ADR     R14,ws__z               ;Point to list terminator
+               STR     R14,[R0,#ll__first]     ;Store in the list head
+               STR     R1,[R0,#ll__sort]       ;The sort routine
+               MOV     R14,#0                  ;Number of items so far
+               STR     R14,[R0,#ll__items]     ;Stor that in the block
+
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+; --- llist_destroy ---
+;
+; On entry:    R0 == pointer to list head
+;
+; On exit:     R0 corrupted
+;
+; Use:         Destroys the given list.
+
+               EXPORT  llist_destroy
+llist_destroy  ROUT
+
+               STMFD   R13!,{R1,R2,R12,R14}    ;Stack registers
+               WSPACE  llist__wSpace           ;Locate my workspace
+               ADR     R1,ws__z                ;Point to terminator
+
+               LDR     R0,[R0,#ll__first]      ;Get the first item
+00llist_destroy        LDR     R2,[R0,#ll__next]       ;Get the next item
+               CMP     R0,R1                   ;Are we at the end?
+               BLNE    free                    ;No -- free item
+               MOVNE   R0,R2                   ;Get the next item
+               BNE     %00llist_destroy        ;And destroy that too
+
+               LDMFD   R13!,{R1,R2,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- llist__insert ---
+;
+; On entry:    R0 == pointer to the list head
+;              R1 == pointer to the item (user data)
+;
+; On exit:     --
+;
+; Use:         Insert the given item into the list, assuming that the list
+;              is already sorted.
+
+llist__insert  ROUT
+
+               STMFD   R13!,{R0-R5,R12,R14}    ;Stack some registers
+               WSPACE  llist__wSpace           ;Find workspace
+               ADR     R2,ws__z                ;The list terminator
+
+               LDR     R5,[R0,#ll__sort]       ;The sort routine
+               MOV     R3,R0                   ;The previous item
+
+               ; --- Scan through the items, until comparison is GT ---
+
+00llist__insert        MOV     R4,R3                   ;The previous item
+               LDR     R3,[R3,#ll__next]       ;Get the next item
+               CMP     R3,R2                   ;Is there one?
+               BEQ     %20llist__insert        ;No -- insert at end
+               ADD     R0,R3,#ll__blockSize    ;Point to user data
+               CMP     R5,#0                   ;Is there a sort routine?
+               CMPEQ   R0,R0                   ;No -- make LE condition
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               MOVNE   PC,R5                   ;...and branch to sort routn
+               BLE     %00llist__insert        ;Keep looking
+
+               ; --- Insert the item ---
+
+20llist__insert        SUB     R1,R1,#ll__blockSize    ;Point to full item desc
+               STR     R1,[R4,#ll__next]       ;Store in previous next ^
+               STR     R3,[R1,#ll__next]       ;Update this next pointer
+               STR     R1,[R3,#ll__prev]       ;Update next previous pointer
+               STR     R4,[R1,#ll__prev]       ;Update this previous pointer
+
+                ; --- Return to the caller ---
+
+99llist__insert        LDMFD   R13!,{R0-R5,R12,PC}^    ;Return
+
+               LTORG
+
+; --- llist_addItem ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == pointer to user data (or 0 if none to copy)
+;              R2 == size of user data
+;
+; On exit:     R0 preserved
+;              R1 == pointer to the new user data
+;              May return an error
+;
+; Use:         This call will add an item to a list. Notice that the
+;              item is entirely allocated by the list manager, it does not
+;              point to the data that you supply it, instead it
+;              copies the data into the newly created item. For this reason
+;              if 0 is supplied as the user data, nothing is copied.
+;              It is the returned user data pointer, that must be
+;              used to reference the item in other llist calls.
+
+               EXPORT  llist_addItem
+llist_addItem  ROUT
+
+               BIC     R14,R14,#V_flag         ;No error yet
+               STMFD   R13!,{R0,R2,R3,R12,R14} ;Stack some registers
+               WSPACE  llist__wSpace           ;Locate workspace
+
+               MOV     R3,R2                   ;Size of user data
+               ADD     R2,R2,#ll__blockSize+3  ;The blocksize required
+               BIC     R2,R2,#3                ;Word align
+               MOV     R0,R2                   ;Allocate this much
+               BL      alloc                   ;Try to allocate the block
+               BCS     alloc_error             ;No memory? Get message
+               BVS     %99llist_addItem        ;And return with error
+
+               STR     R2,[R0,#ll__size]       ;Store the item size
+               MOV     R2,R3                   ;Just copy this much
+               MOV     R3,R0                   ;Remember this pointer
+               ADD     R0,R0,#ll__blockSize    ;Point to user data
+               CMP     R1,#0                   ;Any data supplied?
+               BLNE    fastMove                ;Yes -- copy it over
+               MOV     R2,#0                   ;The flags word
+               STR     R2,[R3,#ll__flags]      ;Store them nicely
+               BEQ     %10llist_addItem        ;...and insert at beginning
+               MOV     R1,R0                   ;Point to the list item block
+               LDMIA   R13,{R0}                ;Get list head back
+               BL      llist__insert           ;Insert the item in the list
+               LDR     R2,[R0,#ll__items]      ;Get the item count
+               ADD     R2,R2,#1                ;Increment it
+               STR     R2,[R0,#ll__items]      ;Store it back again
+               B       %99llist_addItem        ;Return to caller
+
+               ; --- Just insert at the beginning ---
+
+10llist_addItem        MOV     R1,R0                   ;Point to the item data
+               SUB     R0,R0,#ll__blockSize    ;Point to full item desc
+               LDMIA   R13,{R2}                ;Get list head back
+               STR     R2,[R0,#ll__prev]       ;Store head in item
+               LDR     R14,[R2,#ll__first]     ;Get the first item
+               STR     R14,[R0,#ll__next]      ;Store this as second item
+               STR     R0,[R2,#ll__first]      ;Store this as first item
+               STR     R0,[R14,#ll__prev]      ;Finish off the insertion
+               LDR     R14,[R2,#ll__items]     ;Get the item count
+               ADD     R14,R14,#1              ;Increment it
+               STR     R14,[R2,#ll__items]     ;Store it back again
+
+99llist_addItem        LDMFD   R13!,{R0,R2,R3,R12,R14} ;Get registers back
+               ORRVSS  PC,R14,#V_flag          ;Return either with...
+               BICVCS  PC,R14,#V_flag          ;...or without error
+
+               LTORG
+
+; --- llist__removeItem ---
+;
+; On entry:    R1 == pointer to item to remove (as returned by addItem)
+;
+; On exit:     --
+;
+; Use:         This call removes the item from the given list. The
+;              item in question is not freed.
+
+llist__removeItem ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stack some registers
+
+               SUB     R1,R1,#ll__blockSize    ;Point to the real item block
+               LDR     R2,[R1,#ll__next]       ;Get next item in list
+               LDR     R14,[R1,#ll__prev]      ;And the previous item
+               STR     R2,[R14,#ll__next]      ;Update previous next pointer
+               STR     R14,[R2,#ll__prev]      ;Update next previous pointer
+
+               LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- llist_removeItem ---
+;
+; On entry:    R0 == list head pointer
+;              R1 == pointer to item to remove (as returned by addItem)
+;
+; On exit:     --
+;
+; Use:         This call removes the item from the given list. All
+;              memory taken up by the item is freed. If the value
+;              passed in R1 is not an item in the list, then all hell is
+;              likely to break loose, so I don't advise making this mistake.
+
+               EXPORT  llist_removeItem
+llist_removeItem ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Stack some registers
+
+               BL      llist__removeItem       ;Remove the item
+               LDR     R14,[R0,#ll__items]     ;Get the item count
+               SUB     R14,R14,#1              ;Reduce it
+               STR     R14,[R0,#ll__items]     ;Store it back again
+               SUB     R1,R1,#ll__blockSize    ;Point to the allocated block
+               MOV     R0,R1                   ;Point to item to remove
+               BL      free                    ;Free it nicely
+
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- llist_reinsert ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == item to reinsert
+;
+; On exit:     --
+;
+; Use:         Reinserts the given item into the list. This call is
+;              used if the item is updated in such a way that its
+;              position in the list may change.
+
+               EXPORT  llist_reinsert
+llist_reinsert ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               BL      llist__removeItem       ;Remove the item from list
+               BL      llist__insert           ;Insert it into the list
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- llist_setFlags ---
+;
+; On entry:    R1 == pointer to list item
+;              R2 == BIC word
+;              R3 == EOR word
+;
+; On exit:     R2 == the new flags word
+;
+; Use:         Sets the flags associated with the given item. If you
+;              just wish to read them, set R2 and R3 to 0.
+
+               EXPORT  llist_setFlags
+llist_setFlags ROUT
+
+               STMFD   R13!,{R0,R14}           ;Stack registers
+               SUB     R0,R1,#ll__blockSize    ;Point to real item
+               LDR     R14,[R0,#ll__flags]     ;Get the flags word
+               BIC     R14,R14,R2              ;Do the BIC operation
+               EOR     R14,R14,R3              ;Now the EOR op
+               STR     R14,[R0,#ll__flags]     ;Set the flags word
+               MOV     R2,R14                  ;Return these flags
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+; --- llist_items ---
+;
+; On entry:    R0 == pointer to list head
+;
+; On exit:     R1 == number of items in list
+;
+; Use:         Returns the number of items in the list given. This is
+;              a cached value, and so is very fast.
+
+               EXPORT  llist_items
+llist_items    ROUT
+
+               LDR     R1,[R0,#ll__items]      ;Get the number of items
+               MOVS    PC,R14                  ;And return
+
+; --- llist_enumerate ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == pointer to item (0 for first)
+;              R2 == mask word
+;              R3 == test word
+;
+; On exit:     CS and R1 == next item that matches
+;              CC and R1 corrupted if no more items
+;
+; Use:         This calls return each item in the list, one at a time,
+;              as long as the item matches the pattern given.
+
+               EXPORT  llist_enumerate
+llist_enumerate        ROUT
+
+               STMFD   R13!,{R4,R12,R14}       ;Stack some registers
+               WSPACE  llist__wSpace           ;Locate my workspace
+               ADR     R4,ws__z                ;The last item in list
+
+               ; --- Find first item to search from ---
+
+               CMP     R1,#0                   ;Is this the first call?
+               LDREQ   R1,[R0,#ll__first]      ;Yes -- get first item
+               LDRNE   R1,[R1,#ll__next-ll__blockSize] ;No -- get the next
+
+               ; --- Keep looking for an item that matches ---
+
+00             CMP     R1,R4                   ;Are we at the end
+               BEQ     %95llist_enumerate      ;Yes -- return failure
+               LDR     R14,[R1,#ll__flags]     ;Get the flags word
+               AND     R14,R14,R2              ;Clear un-interesting bits
+               CMP     R14,R3                  ;Is this a match?
+               BEQ     %90llist_enumerate      ;Yes -- return it then
+               LDR     R1,[R1,#ll__next]       ;Get the next item in list
+               B       %00llist_enumerate      ;No -- test it then
+
+               ;--- We have found an item which matches ---
+
+90             ADD     R1,R1,#ll__blockSize    ;Point to user data
+               LDMFD   R13!,{R4,R12,R14}       ;Get registers back
+               ORRS    PC,R14,#C_flag          ;Return with carry set
+
+               ; --- There are no more matching items ---
+
+95             LDMFD   R13!,{R4,R12,R14}       ;Get registers back
+               BICS    PC,R14,#C_flag          ;Return with carry clear
+
+               LTORG
+
+; --- llist_itemToIndex ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == point to the item
+;
+; On exit:     R1 == index of the item, -1 if it's not there
+;
+; Use:         Returns the index of the item given, indexed from 0.
+
+               EXPORT  llist_itemToIndex
+llist_itemToIndex ROUT
+
+               STMFD   R13!,{R2,R3,R12,R14}    ;Stack some registers
+               WSPACE  llist__wSpace           ;Find my workspace
+               ADR     R14,ws__z               ;Terminator -- (I'll be back)
+
+               SUB     R2,R1,#ll__blockSize    ;Point to real item
+               MOV     R1,#0                   ;Index so far
+               MOV     R3,R0                   ;Start from here
+00             LDR     R3,[R3,#ll__next]       ;The next item in the list
+               CMP     R3,R2                   ;Is this the one we want?
+               BEQ     %99llist_itemToIndex    ;Yes -- return
+               CMP     R3,R14                  ;Are we at the end?
+               MOVEQ   R1,#-1                  ;Yes -- no valid index then
+               BEQ     %99llist_itemToIndex    ;...and return
+               ADD     R1,R1,#1                ;Increment index
+               B       %00llist_itemToIndex    ;Keep on looking
+
+99             LDMFD   R13!,{R2,R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- llist_indexToItem ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == point to the index (indexed from 0)
+;
+; On exit:     R1 == the item itself, or 0 if index doesn't exist
+;
+; Use:         Returns the index of the item given, indexed from 0.
+
+               EXPORT  llist_indexToItem
+llist_indexToItem ROUT
+
+               STMFD   R13!,{R2,R3,R12,R14}    ;Stack some registers
+
+               LDR     R2,[R0,#ll__items]      ;The number ot items in list
+               CMP     R1,R2                   ;How do they compare?
+               MOVGE   R1,#0                   ;No such index -- return 0
+               BGE     %99llist_indexToItem    ;And actually return
+
+               MOV     R2,R1                   ;Get the index in R2
+               LDR     R1,[R0,#ll__first]      ;The first item
+               CMP     R2,#0                   ;Is this the one we want?
+               BEQ     %98llist_indexToItem    ;Yes -- return
+00             LDR     R1,[R1,#ll__next]       ;Get the next in the list
+               SUBS    R2,R2,#1                ;Decrement the index
+               BNE     %00llist_indexToItem    ;And keep looking
+
+98             ADD     R1,R1,#ll__blockSize
+99             LDMFD   R13!,{R2,R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- llist__merge ---
+;
+; On entry:    R1 == sort routine
+;              R2 == list a
+;              R3 == list b
+;              R8 == z
+;              R9 == list c
+;
+; On exit:     c^.next = merge of a and b
+;              R9 == last item in list
+;
+; Use:         Used in the mergesort routine to merge two lists.
+
+llist__merge   ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Stack some registers
+
+               MOV     R5,R1                   ;Keep pointer to sort routine
+               MOV     R4,R8                   ;c:=z
+
+               ; --- The main loop ---
+
+00llist__merge ADD     R0,R2,#ll__blockSize    ;Point to user data for a
+               ADD     R1,R3,#ll__blockSize    ;Point to user data for b
+               CMP     R5,#0                   ;Is there a sort routine?
+               CMPEQ   R0,R0                   ;No -- make LE condition
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               MOVNE   PC,R5                   ;...and branch to sort routn
+               BGT     %10llist__merge         ;If a^.key>b^.key
+
+               STR     R2,[R4,#ll__next]       ;c^.next=a
+               STR     R4,[R2,#ll__prev]       ;a^.prev=c
+               MOV     R4,R2                   ;c:=a
+               LDR     R2,[R2,#ll__next]       ;a:=a^.next
+               B       %20llist__merge         ;Jump ahead
+
+10llist__merge STR     R3,[R4,#ll__next]       ;c^.next=b
+               STR     R4,[R3,#ll__prev]       ;b^.prev=c
+               MOV     R4,R3                   ;c:=b
+               LDR     R3,[R3,#ll__next]       ;b:=b^.next
+
+20llist__merge CMP     R4,R8                   ;c=z?
+               BNE     %00llist__merge         ;No -- keep looping
+
+               LDR     R14,[R8,#ll__next]      ;z^.next
+               STR     R14,[R9,#ll__next]      ;Update next for 'entry c'
+               LDR     R9,[R4,#ll__prev]       ;Return last item
+               STR     R8,[R8,#ll__next]       ;z^.next:=z
+
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+               LTORG
+
+; --- llist__mergeSort ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == pointer to sort routine
+;
+; On exit:     --
+;
+; Use:         Sort the given list very quickly. Ref Sedgewick P.170
+
+llist__mergeSort ROUT
+
+               STMFD   R13!,{R0-R10,R12,R14}   ;Stack some registers
+               WSPACE  llist__wSpace           ;Find my workspace
+
+               ; --- Initialise some variables ---
+
+               ADR     R8,ws__z                ;The terminator
+               MOV     R7,#1                   ;N:=1
+
+               ; --- The outer loop ---
+
+00             LDR     R5,[R0,#ll__next]       ;todo:=head^.next
+               MOV     R9,R0                   ;c:=head
+
+               ; --- The inner loop ---
+
+10             MOV     R4,R5                   ;t:=todo
+               MOV     R2,R4                   ;a:=t
+               SUB     R10,R7,#1               ;R10=N-1
+
+               MOV     R6,#1                   ;i:=1
+15             CMP     R6,R10                  ;Do an iteration?
+               LDRLE   R4,[R4,#ll__next]       ;Yes -- t:=t^.next
+               ADDLE   R6,R6,#1                ;...i:=i+1
+               BLE     %15llist__mergeSort     ;...continue the loop
+
+               LDR     R3,[R4,#ll__next]       ;b:=t^.next
+               STR     R8,[R4,#ll__next]       ;t^.next=z
+               MOV     R4,R3                   ;t:=b
+
+               MOV     R6,#1                   ;i:=1
+20             CMP     R6,R10                  ;Do an iteration?
+               LDRLE   R4,[R4,#ll__next]       ;Yes -- t:=t^.next
+               ADDLE   R6,R6,#1                ;...i:=i+1
+               BLE     %20llist__mergeSort     ;...continue the loop
+
+               LDR     R5,[R4,#ll__next]       ;todo:=t^.next
+               STR     R8,[R4,#ll__next]       ;t^.next=z
+
+               BL      llist__merge            ;c^.next:=merge(a,b)
+                                               ;c points to last item
+
+               CMP     R5,R8                   ;todo=z?
+               BNE     %10llist__mergeSort     ;No -- keep looping
+
+               ADD     R7,R7,R7                ;N:=N+N
+
+               LDR     R14,[R0,#ll__next]      ;head^.next
+               CMP     R14,R2                  ;a=head^.next?
+               BNE     %00llist__mergeSort     ;No -- keep looping
+
+               LDMFD   R13!,{R0-R10,R12,PC}^   ;Return to caller
+
+               LTORG
+
+; --- llist_registerSort ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == pointer to new sort routine
+;
+; On exit:     --
+;
+; Use:         Registers a new sort routine to be used on the given
+;              list. This call will also cause a complete resort
+;              of the given list using a mergesort algorithm -- O(n log n).
+
+               EXPORT  llist_registerSort
+llist_registerSort ROUT
+
+               STMFD   R13!,{R12,R14}          ;Stack registers
+               WSPACE  llist__wSpace           ;Locate my workspace
+
+               STR     R1,[R0,#ll__sort]       ;Store the sort routine
+               CMP     R1,#0                   ;Is there one now?
+               LDMEQFD R13!,{R12,PC}^          ;No -- return
+               LDR     R14,[R0,#ll__items]     ;Get number of items in list
+               CMP     R14,#2                  ;2 or more items?
+               BLGE    llist__mergeSort        ;Yes -- do the merge sort
+
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+; --- llist_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the llistMan unit.
+
+               EXPORT  llist_init
+llist_init     ROUT
+
+               STMFD   R13!,{R12,R14}          ;Stack some registers
+               WSPACE  llist__wSpace           ;Locate my workspace
+
+               ; --- Ensure that we are not already initialised ---
+
+               LDR     R14,ws__flags           ;Get the flags word
+               TST     R14,#wsFlag__inited     ;Are we initialised?
+               BNE     %99llist_init           ;Yes -- return
+               ORR     R14,R14,#wsFlag__inited ;We are initialised now
+               STR     R14,ws__flags           ;Store back modified flags
+
+               ; --- Set up the workspace ---
+
+               ADR     R14,ws__z               ;Point to terminating item
+               STR     R14,[R14,#ll__next]     ;Set up the next field
+
+               ; --- Return to caller ---
+
+99llist_init   LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+llist__wSpace  DCD     0
+
+;----- Workspace layout -----------------------------------------------------
+
+; --- The list head description ---
+
+               ^       0
+
+ll__first      #       4                       ;The first item
+ll__sort       #       4                       ;The sort routine
+ll__items      #       4                       ;The number of items
+
+; --- The list item description ---
+
+               ^       0
+
+ll__next       #       4                       ;The next item in the list
+ll__prev       #       4                       ;The previous item in list
+ll__flags      #       4                       ;Various item flags
+ll__size       #       4                       ;Total size of this item
+ll__blockSize  #       0                       ;Size without user data
+ll__userData   #       4                       ;The user data itself
+
+; --- The workspace ---
+
+               ^       0,R12
+
+ws__start      #       0                       ;Workspace start
+
+ws__flags      #       4                       ;The flags word
+ws__z          #       8                       ;The end node of a list
+
+ws__size       EQU     {VAR}-ws__start         ;The workspace size
+
+wsFlag__inited EQU     (1<<0)                  ;We have been initialised
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     ws__size
+               DCD     llist__wSpace
+               DCD     0
+               DCD     llist_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/llistStub b/StraySrc/Libraries/Sapphire/s/llistStub
new file mode 100644 (file)
index 0000000..67bf5c7
--- /dev/null
@@ -0,0 +1,53 @@
+;
+; llistStub.s
+;
+; The llist description block
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+               MACRO
+$label         BT      $l
+$label
+               IMPORT  $l
+               B       $l
+               MEND
+
+; --- llist_desc ---
+;
+; A llist decription for use with listbox
+
+               EXPORT  llist_desc
+llist_desc     BT      llist_itemToIndex
+               BT      llist_indexToItem
+               BT      llist_enumerate
+               BT      llist_items
+               BT      llist_setFlags
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
+
+
diff --git a/StraySrc/Libraries/Sapphire/s/mbox b/StraySrc/Libraries/Sapphire/s/mbox
new file mode 100644 (file)
index 0000000..004c8bb
--- /dev/null
@@ -0,0 +1,120 @@
+;
+; mbox.s
+;
+; Handling for monologue boxes (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:help
+               GET     sapphire:msgs
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- mbox ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to help message tag for dialogue box
+;              R2 == icon handle for embedded title
+;
+; On exit:     --
+;
+; Use:         Displays a `monologue' box (i.e. a dialogue box which just
+;              displays information to the user) on the screen and sets up
+;              an event handler for it.  The dialogue box is destroyed when
+;              it is closed.
+;
+;              If the dialogue box does not have a title bar (read by
+;              dbox_hasTitle) then R2 is used to give the monologue box
+;              an embedded title.  R2 is not used otherwise, and thus may
+;              safely contain any old rubbish.
+
+               EXPORT  mbox
+mbox           ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Save some registers
+               BL      dbox_hasTitle           ;Does it have a title bar?
+               MOVCC   R1,R2                   ;Yes -- move icon number in
+               BLCC    dbox_setEmbeddedTitle   ;Give dbox embedded title
+               BLCC    dbox_setClickDrag       ;And make clicks move it
+               LDR     R3,[R13,#0]             ;Pass help message in R12
+               MOV     R2,R0                   ;Pass dbox handle in R10
+               ADR     R1,mbox__handler        ;Point to event handler
+               BL      dbox_eventHandler       ;Register my event handler
+               MOV     R1,#dbOpen_pointer :OR: dbOpen_trans
+               BL      dbox_open               ;Open as transient dialogue
+               LDMFD   R13!,{R1-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- mbox__handler ---
+;
+; On entry:    R0 == dialogue box event code
+;              R1-R9 == dependent on event type
+;              R10 == dialogue box handle
+;              R12 == pointer to help message for the dialogue box
+;
+; On exit:     --
+;
+; Use:         Handles events for a monologue box window.
+
+mbox__handler  ROUT
+
+               ; --- Return unknown events very quickly ---
+
+               CMP     R0,#dbEvent_close       ;Is the window closing?
+               BEQ     %00mbox__handler        ;Yes -- jump round to it
+               CMPNE   R0,#dbEvent_help        ;Or is the user wanting help?
+               MOVNES  PC,R14                  ;Neither -- ignore it
+
+               ; --- User wants some help on the dbox ---
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R12                  ;Find the help message
+               BL      msgs_lookup             ;Translate it nicely
+               BL      help_add                ;Add it to the help message
+               BL      dbox_help               ;Read help from the window
+               LDMFD   R13!,{R0,R14}           ;Restore the registers
+               ORRS    PC,R14,#C_flag          ;I handled the event
+
+               ; --- Something closed the window ---
+
+00mbox__handler        STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R10                  ;Get the dialogue box handle
+               BL      dbox_destroy            ;Get rid of the dialogue
+               LDMFD   R13!,{R0,R14}           ;Restore the registers
+               ORRS    PC,R14,#C_flag          ;I handled the event again
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/mem b/StraySrc/Libraries/Sapphire/s/mem
new file mode 100644 (file)
index 0000000..4ad86fa
--- /dev/null
@@ -0,0 +1,86 @@
+;
+; mem.s
+;
+; Operations on memory blocks (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+;
+; None.
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- mem_set ---
+;
+; On entry:    R0 == pointer to a block of memory (word-aligned)
+;              R1 == size of the block
+;              R2 == word value to store in the block
+;
+; On exit:     --
+;
+; Use:         Initialises a block by filling every word within it with the
+;              same value.  This is normally 0, although maybe MOVS PC,#0
+;              might be useful too.
+
+               EXPORT  mem_set
+mem_set                ROUT
+
+               STMFD   R13!,{R0-R8,R14}        ;Stack registers away
+
+               ; --- Set up seed value in lots of registers ---
+
+               MOV     R3,R2
+               MOV     R4,R2
+               MOV     R5,R2
+               MOV     R6,R2
+               MOV     R7,R2
+               MOV     R8,R2
+               MOV     R14,R2
+
+               ; --- Do the copy ---
+
+00mem_set      SUBS    R1,R1,#32               ;Is there enough for fastblat
+               STMGEIA R0!,{R2-R8,R14}         ;Yes -- *blat*
+               BGE     %00mem_set
+
+               ; --- Now to word blats ---
+
+               ADD     R1,R1,#32               ;How much left to do?
+01mem_set      SUBS    R1,R1,#4                ;Enough for a word?
+               STRGE   R14,[R0],#4             ;Yes -- store it
+               BGE     %01mem_set              ;And go round again
+
+               LDMFD   R13!,{R0-R8,PC}^        ;Return to caller
+
+               LTORG
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/menu b/StraySrc/Libraries/Sapphire/s/menu
new file mode 100644 (file)
index 0000000..c4fcbce
--- /dev/null
@@ -0,0 +1,1249 @@
+;
+; menu.s
+;
+; RISC OS menu handling facilities (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:event
+               GET     sapphire:libOpts
+               GET     sapphire:sapphire
+               GET     sapphire:string
+               GET     sapphire:fastMove
+               GET     sapphire:msgs
+               GET     sapphire:help
+
+;----- Useful values --------------------------------------------------------
+
+mFlag_tearoff  EQU     (1<<1)                  ;Menu has a tearoff bar
+mFlag_makeMe   EQU     (1<<2)                  ;Recreate menu on adjust
+mFlag_maxHeight        EQU     (1<<3)                  ;Menu has a maximum height
+
+mFlag_indirect EQU     (1<<0)                  ;Item text is indirected
+mFlag_shortcut EQU     (1<<1)                  ;Item has a keyboard shortcut
+mFlag_iShortcut        EQU     (1<<2)                  ;Item has an indirected S/C
+mFlag_shade    EQU     (1<<3)                  ;Item is shadable
+mFlag_iShade   EQU     (1<<4)                  ;Item is inverse shadable
+mFlag_switch   EQU     (1<<5)                  ;Item is a switch
+mFlag_radio    EQU     (1<<6)                  ;Item is a radio item
+mFlag_sprite   EQU     (1<<7)                  ;Menu item has a sprite
+mFlag_halfSize EQU     (1<<8)                  ;Sprite is halfsize
+mFlag_subWarn  EQU     (1<<9)                  ;Warn client if submenu warn
+mFlag_subMenu  EQU     (1<<10)                 ;Item has menu to be opened
+
+mFlag_R12      EQU     (1<<16)                 ;Use R12 for runtime data
+mFlag_noWarn   EQU     (1<<17)                 ;Don't warn on shaded items
+mFlag_ruleOff  EQU     (1<<18)                 ;Put a ruleoff after item
+mFlag_noTrans  EQU     (1<<19)                 ;Don't translate messages
+
+mFlag_end      EQU     (1<<31)                 ;No more items
+
+; --- Event types ---
+
+mEvent_select  EQU     0                       ;Normal menu selection
+                                               ;  R1 == index of item
+mEvent_arrow   EQU     1                       ;Sub menu warning
+                                               ;  R1 == index of item
+mEvent_deleted EQU     2                       ;Menu has been deleted
+mEvent_help    EQU     3                       ;Menu help requested
+                                               ;  R1 == ndex of item
+                                               ;  R2 == ptr to packed itmdef
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- menu__createTitle ---
+;
+; On entry:    R0 == pointer to menu title definition
+;              R1 == event handler to use (not used here)
+;              R2 == R10 value to use
+;              R3 == R12 value to use
+;              R4 == pointer to menu stack area
+;              R5 == pointer into stack to build definition
+;              R9 == workspace pointer
+;
+; On exit:     R0 == points to first word after table
+;              R1-R4 == preserved
+;              R5 == next free word in stack after defintion
+;
+; Use:         This call creates the title part of a WIMP menu from
+;              a menu definition table (assuming that it has a menu
+;              title definition).
+
+menu__createTitle ROUT
+
+               STMFD   R13!,{R1-R4,R6-R8,R14}  ;Stack some registers
+
+               STMDB   R4,{R0-R3}              ;Store information in stack
+               LDR     R7,[R0],#4              ;Get flags
+               MOV     R8,R2                   ;Use R10 for runtime data
+               TST     R7,#mFlag_R12           ;Should we use R12?
+               MOVNE   R8,R3                   ;Yes, set R8 = R3 then
+               TST     R7,#mFlag_indirect      ;Is the title indirected
+               LDRNE   R6,[R0],#4              ;Yes -- load the offset
+               LDRNE   R6,[R6,R8]              ;...find new pointer
+               BNE     %05                     ;...and jump the next bit
+
+               MOV     R6,R0                   ;Get the text pointer
+00             LDRB    R8,[R0],#1              ;Get a byte
+               CMP     R8,#0                   ;Was it the last character?
+               BNE     %00                     ;No -- keep looking
+               ADD     R0,R0,#3                ;Word align
+               BIC     R0,R0,#3                ;Oh yes indeedy
+
+05             MOV     R2,R0                   ;Remember this pointer
+               MOV     R0,R6                   ;Point to the message
+               TST     R7,#mFlag_noTrans       ;Do we translate the string?
+               BLEQ    msgs_lookup             ;Yes -- lookup the message
+               MOV     R6,R0                   ;Remember new pointer
+               BL      str_len                 ;Get the length of the text
+               STRGT   R0,menu__maxLen         ;Yes -- store new length
+               TST     R7,#mFlag_makeMe        ;Is the menu recreatable?
+               LDMNEIA R2!,{R8}                ;Yes -- read it
+               TST     R7,#mFlag_maxHeight     ;Is there a maximum height
+               LDMNEIA R2!,{R8}                ;Yes -- read it
+
+               ; --- Now enter data into stack ---
+
+               BL      menu__checkOverflow     ;Make sure there's room
+               MOV     R0,R5                   ;Copy to here...
+               MOV     R1,R6                   ;...this string
+               BL      str_cpy                 ;Do the copy
+               ADD     R5,R5,#12               ;Point past 12 bytes
+               MOV     R0,R2                   ;Get the pointer back
+               LDR     R4,=&00070207           ;Colours
+               MOV     R6,#40                  ;Don't know width yet
+               MOV     R7,#44                  ;Item height
+               MOV     R8,#0                   ;Gap between items
+               STMIA   R5!,{R4,R6-R8}          ;Store information
+
+               ; --- Return thankfully ---
+
+               LDMFD   R13!,{R1-R4,R6-R8,PC}^
+
+               LTORG
+
+; --- menu_create ---
+;
+; On entry:    R0 == pointer to menu definition table
+;              R1 == event handler to use
+;              R2 == R10 value for handler
+;              R3 == R12 value for handler
+;
+; On exit:     --
+;
+; Use:         Creates a menu from the given menu definition
+;              table. If this call is called more than once before
+;              a menu is opened then the menu definiton are concatenated
+;              into a large menu. Only the first menu title read is
+;              taken notice of. Notice therefore, that the call doesn't
+;              actually open a menu.
+
+               EXPORT  menu_create
+menu_create    ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Stack some registers
+               WSPACE  menu__wSpace,R9         ;Find my workspace
+
+               MOV     R12,#0                  ;Number of items so far
+
+               ; --- Do we need to read the menu title? ---
+
+               LDR     R4,menu__flags          ;Get the flags word
+               TST     R4,#mFlag__creating     ;Is this the first menu
+               BEQ     %00menu_create          ;Yes -- set up things
+
+               ; --- We are already creating a menu ---
+
+               LDR     R6,menu__begin          ;Get beginning of real menu
+               TST     R4,#mFlag__tOnly        ;Has just the title been done
+               SUBNE   R4,R6,#24               ;Yes -- block already there
+               LDR     R5,menu__end            ;Get the end marker
+               LDMNEIA R13,{R0-R3}             ;Reclaim useful values
+               STMNEFD R13!,{R0}               ;Pointer to item definitions
+               BNE     %05menu_create          ;Now read the items
+
+               SUB     R1,R6,#4                ;Copy from here..
+               ADD     R0,R1,#20               ;...to here
+               SUB     R2,R5,R1                ;...this much
+               BL      fastMove                ;Do the copy
+               ADD     R5,R5,#20               ;Increment end pointer
+               MOV     R4,R1                   ;Write header here
+               ADD     R6,R6,#20               ;The new beginning
+               STR     R6,menu__begin          ;Store new value
+               LDMIA   R13,{R0-R3}             ;Reclaim useful values
+               STMFD   R13!,{R0}               ;Pointer to item definitions
+               B       %05menu_create          ;Go through the items
+
+               ; --- We are creating a new menu ---
+
+00menu_create  STR     R12,menu__maxLen        ;Max length so far
+               TST     R4,#mFlag__wasSub       ;Was last event a submenu?
+               LDREQ   R4,menu__stack          ;No -- Get the stack address
+               LDRNE   R4,menu__prevMenu       ;Yes - start of previous menu
+               LDRNE   R5,[R4]                 ;...get length of menu
+               ADDNE   R4,R4,R5                ;Start new menu here
+               STR     R4,menu__start          ;The menu start (incl. defn)
+
+               ADD     R5,R4,#44               ;Where to start adding defns
+               ADD     R4,R4,#20               ;Where to write the header
+               MOV     R6,#0                   ;The last header marker
+               STR     R6,[R5,#-4]             ;Store it nicely
+               STR     R5,menu__begin          ;Store the begin pointer
+               BL      menu__createTitle       ;Create the title
+               STMFD   R13!,{R0}               ;Pointer to item definitions
+
+               ; --- Now go through the menu items ---
+               ;
+                ; At this point, R4 points to the menu header to write to,
+                ; R5 points into the stack at the position that the next
+                ; items should be written to. R0 points to the next menu
+                ; item.
+
+05menu_create  LDR     R7,[R0],#4              ;Get flags
+               TST     R7,#mFlag_end           ;Any more items?
+               BNE     %40menu_create          ;Nope -- branch ahead
+               MOV     R8,R2                   ;Use R10 for runtime data
+               TST     R7,#mFlag_R12           ;Should we use R12?
+               MOVNE   R8,R3                   ;Yes, set R8 = R3 then
+               TST     R7,#mFlag_indirect      ;Is the text indirected
+               LDRNE   R6,[R0],#4              ;Yes -- load the offset
+               LDRNE   R6,[R6,R8]              ;...find new pointer
+               BNE     %07menu_create          ;...and jump the next bit
+
+               MOV     R6,R0                   ;Point to the string
+06menu_create  LDRB    R1,[R0],#1              ;Get a byte
+               CMP     R1,#0                   ;Was it the last character?
+               BNE     %06menu_create          ;No -- keep looking
+               ADD     R0,R0,#3                ;Word align
+               BIC     R0,R0,#3                ;Oh yes indeedy
+
+               ; --- So, we have an item ---
+
+07menu_create  MOV     R2,R0                   ;Remember this pointer
+               MOV     R0,R6                   ;Point to the message
+               TST     R7,#mFlag_noTrans       ;Do we translate the string?
+               BLEQ    msgs_lookup             ;Yes -- lookup the message
+               MOV     R6,R0                   ;Remember new pointer
+               BL      str_len                 ;Get the length of the text
+               TST     R7,#mFlag_sprite        ;Is there a sprite too?
+               ADDNE   R0,R0,#2                ;Yes -- add 42 to the length
+               LDR     R1,menu__maxLen         ;Get maximum length so far
+               CMP     R0,R1                   ;Is new text longer?
+               STRGT   R0,menu__maxLen         ;Yes -- store new length
+               MOV     R0,R2                   ;Get the offset back
+               MOV     R1,#24                  ;The WIMP item flags so far
+               LDR     R2,=&7000131            ;The icon flags so far
+
+               TST     R7,#mFlag_shade         ;Is it shadable?
+               BEQ     %10menu_create          ;No -- jump this code
+               BL      %99                     ;Do a bit specification
+               ORRCS   R2,R2,#(1<<22)          ;Set the 'shaded' bit
+
+10menu_create  TST     R7,#mFlag_iShade        ;Is it inverse shadable?
+               BEQ     %15menu_create          ;No -- jump this code
+               BL      %99                     ;Do a bit specification
+               ORRCC   R2,R2,#(1<<22)          ;Set the 'shaded' bit
+
+15menu_create  TST     R7,#mFlag_switch        ;Is it a switch?
+               BEQ     %20menu_create          ;No -- jump this code
+               BL      %99                     ;Do a bit specification
+               ORRCS   R1,R1,#1                ;Set the tick flag
+
+20menu_create  TST     R7,#mFlag_radio         ;Is is a radio type?
+               BEQ     %23menu_create          ;No -- try next type
+               LDMIA   R0!,{R10,R14}           ;Get offset and selector
+               ADD     R10,R10,R8              ;Get real offset
+               LDR     R10,[R10]               ;Get the word there
+               CMP     R10,R14                 ;It is the same as selector?
+               ORREQ   R1,R1,#1                ;Yes -- set the tick flag
+
+23menu_create  TST     R7,#mFlag_sprite        ;Does item contain a sprite?
+               BEQ     %25menu_create          ;No -- try next type
+               LDR     R10,[R0],#4             ;Get the sprite name pointer
+               ORR     R2,R2,#2                ;Set the 'sprite' bit
+               STR     R10,menu__sprite        ;Store the sprite pointer
+
+25menu_create  TST     R7,#mFlag_halfSize      ;Make sprite half size?
+               ORRNE   R2,R2,#(1<<11)          ;Yeap -- set the bit
+
+               TST     R7,#mFlag_noWarn        ;Don't open subs if shaded?
+               BICNE   R1,R1,#16               ;Clear relevant bit
+
+               TST     R7,#mFlag_ruleOff       ;Put a rule off here?
+               ORRNE   R1,R1,#2                ;Yes -- set the bit up
+
+               ; --- Now store this information in the block ---
+
+               BL      menu__checkOverflow     ;Make sure there's room
+               MOV     R10,R2                  ;Put the icon flags in R10
+               MOV     R2,#-1                  ;No submenu yet
+               TST     R7,#mFlag_subMenu       ;Automatic sub menu?
+               LDMNEIA R0!,{R2,R14}            ;Yes -- get menu pointer
+               TST     R7,#mFlag_subWarn       ;Submenu warning required
+               MOVNE   R2,#1                   ;Yeap -- put non -1 value in
+               STMIA   R5!,{R1,R2,R10}         ;Splodge!
+               TST     R10,#2                  ;Is the sprite bit set?
+               MOVEQ   R10,#-1                 ;No -- no validation
+               LDRNE   R10,menu__sprite        ;Yes -- point to sprite name
+               MOV     R14,#255                ;Buffer length
+               STMIA   R5!,{R6,R10,R14}        ;Icon data -- splodge!
+
+               ; --- Now, keep searching for icons ---
+
+               ADD     R12,R12,#1              ;Increment item count
+               ADD     R1,R13,#8               ;Point to useful values
+               LDMIA   R1,{R1-R3}              ;Load back useful values
+               B       %05menu_create          ;Keep looking
+
+               ; --- All the icons have been found, tidy up ---
+
+40menu_create  LDR     R0,menu__flags          ;Get my flags word
+               CMP     R12,#0                  ;Did we create any items?
+               ORREQ   R0,R0,#mFlag__tOnly     ;Yes -- set the flag
+               BICNE   R0,R0,#mFlag__tOnly     ;No -- clear the flag
+               ORR     R0,R0,#mFlag__creating  ;We are creating a menu
+               STR     R0,menu__flags          ;Store updated flags
+               STR     R12,[R4],#4             ;Store number of items
+               STR     R5,menu__end            ;The end pointer
+               LDR     R6,menu__start          ;Get the start
+               SUB     R7,R5,R6                ;Get the length
+               STR     R7,[R6]                 ;Store in the header
+               LDMFD   R13!,{R5}               ;First item pointer
+               LDMFD   R13!,{R0-R3}            ;Load some stuff
+               MOV     R14,R0                  ;Remember user R0
+               MOV     R0,R5                   ;Pointer to first item defn
+               STMIA   R4!,{R0-R3}             ;Store them in the header
+               MOV     R0,R14                  ;Preserve R0
+
+               ; --- And return to the client ---
+
+               LDMFD   R13!,{R4-R12,PC}^       ;Return to client
+
+               ; --- Do a bit specification ---
+
+99             STMFD   R13!,{R14}              ;Save a register
+               LDR     R10,[R0],#4             ;Get the next word
+               ADD     R14,R8,R10,LSR#5        ;Get the offset
+               LDR     R14,[R14]               ;And the byte there
+               AND     R10,R10,#31             ;Clear bit we don't want
+               ADD     R10,R10,#1              ;Correct for shifting
+               MOVS    R14,R14,LSR R10         ;Shift that bit into carry
+               LDMFD   R13!,{PC}               ;And return to caller
+
+               LTORG
+
+; --- menu__checkOverflow ---
+;
+; On entry:    R5 == offset in menu stack for creating next item
+;
+; On exit:     --
+;
+; Use:         Checks to see if there's enough room in the menu stack for
+;              a new menu item or header.
+
+menu__checkOverflow ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+               LDR     R14,menu__stackEnd      ;Find the end of the stack
+               SUB     R14,R14,#64             ;Allow a nice bit of space
+               CMP     R14,R5                  ;Do we have enough space?
+               LDMGEFD R13!,{PC}^              ;Yes -- return then
+
+               LDR     R14,menu__flags         ;Get my flags word
+               AND     R14,R14,#mFlag__inited  ;Reset all the flags
+               STR     R14,menu__flags         ;Store updated flags
+               MOV     R1,#-1                  ;An invalid menu pointer
+               SWI     XWimp_CreateMenu        ;Close the current menu tree
+               ADR     R0,menu__noMem          ;Point to error message
+               BL      msgs_error              ;Translate the error message
+               SWI     OS_GenerateError        ;And generate the error
+
+menu__noMem    DCD     1
+               DCB     "mSOVF",0
+
+               LTORG
+
+; --- menu__recreate ---
+;
+; On entry:    R1 == pointer to list of menu hits
+;              R9 == pointer to workspace
+;
+; On exit:     --
+;
+; Use:         Called to recreate the menu definition after an adjust
+;              click was made on a menu.
+
+menu__recreate ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Stack some registers
+
+               MOV     R10,R1                  ;We need this list
+               LDR     R12,menu__stack         ;Point to first menu header
+00             LDR     R0,[R10],#4             ;Load a menu hit (ignore 1st)
+               CMP     R0,#-1                  ;Is this the end?
+               BEQ     %90                     ;Yes -- finish
+
+               LDR     R0,[R12,#4]             ;Get the title defn pointer
+               LDR     R2,[R0],#4              ;Get the flags word
+               MOV     R6,R0                   ;Point to the text
+               TST     R2,#mFlag_R12           ;Do we use R12?
+               LDREQ   R7,[R12,#12]            ;No -- use R10 value
+               LDRNE   R7,[R12,#16]            ;Yes -- use R12 value
+
+               TST     R2,#mFlag_indirect      ;Is the text indirected?
+               LDRNE   R6,[R0]                 ;Yes -- get the offset
+               LDRNE   R6,[R7,R6]              ;...load indirected pointer
+               BL      menu__skipText          ;Skip past the text
+               STMFD   R13!,{R10}              ;Save this R10 value
+               TST     R2,#mFlag_makeMe        ;Is it a 'makeme' type
+               BEQ     %01                     ;No -- skip this bit
+               LDR     R5,[R10]                ;Get the next hit
+               CMP     R5,#-1                  ;Are we at the last menu
+               BNE     %01                     ;No -- ignore this function
+               LDR     R5,[R0],#4              ;Get the 'make me' function
+
+               ; --- Recreate the menu over the top of the old one ---
+
+               MOV     R6,#0                   ;Set the new length
+               STR     R6,[R12]                ;Store this length in field
+               LDR     R6,menu__flags          ;Get my flags word
+               ORR     R6,R6,#mFlag__wasSub    ;Fool menu_create
+               STR     R6,menu__flags          ;Store the modified flags
+               STR     R12,menu__prevMenu      ;Make this the previous menu
+               MOV     R14,PC                  ;Set up the return address
+               MOV     PC,R5                   ;Branch to the function
+               ORR     R6,R6,#mFlag__recreating ;We're recreating
+               STR     R6,menu__flags          ;Store the modified flags
+               STR     R12,menu__start         ;Update this menu
+               MOV     R2,R6                   ;Put the flags in R2
+               BL      menu__open              ;Set the menu up properley
+               BIC     R6,R6,#mFlag__creating  ;We're not really creating
+               STR     R6,menu__flags          ;Store the modified flags
+               B       %90                     ;Tidy up and return
+
+01             MOV     R0,R6                   ;Point to the text
+               TST     R2,#mFlag_noTrans       ;Do we translate the string?
+               BLEQ    msgs_lookup             ;Yes -- lookup the message
+               MOV     R6,R0                   ;Remember new pointer
+               BL      str_len                 ;Get the length of the text
+               STR     R0,menu__maxLen         ;Store max length
+
+               ; --- Go through the items changing the flags ---
+               ;
+               ; We have to use three pointers, one to keep track of
+               ; the real WIMP icon so that we can alter it, one
+               ; to keep track of our position in the users block, and
+               ; one to keep track of which header we are using!
+
+               ; --- Find the first real item ---
+
+               MOV     R0,R12                  ;Point to menu defn
+               BL      menu__locateFirst       ;Locate the first item
+               MOV     R3,R0                   ;Use R3 instead
+               STMFD   R13!,{R3}               ;Stack this pointer
+               SUB     R0,R3,#28               ;Point the the menu header
+               MOV     R1,R6                   ;The text string
+               BL      str_cpy                 ;Copy the title across
+               MOV     R14,#7                  ;Might have trashed colour
+               STRB    R14,[R3,#12-28]         ;So store colour back ;-)
+
+               ; --- Set up the pointer to the first header ---
+
+               ADD     R1,R12,#20              ;Point to first header
+05             LDR     R8,[R1,#12]             ;Get the R10 value
+               LDR     R10,[R1,#16]            ;Get the R12 value
+
+               ; --- Finally locate the users definition ---
+
+               LDR     R0,[R1,#4]              ;Get the pointer
+
+               ; --- Now go through the list ---
+
+06             LDR     R2,[R0],#4              ;Get the flags word
+               TST     R2,#mFlag_end           ;No more items?
+               BNE     %20                     ;No -- try for more
+               LDR     R4,[R3,#0]              ;Load the item flags
+               MOV     R7,R8                   ;Use R10 value
+               TST     R2,#mFlag_R12           ;Do we use R12?
+               MOVNE   R7,R10                  ;Yes -- set up R7
+               MOV     R5,R0                   ;Pointer to the text
+               TST     R2,#mFlag_indirect      ;Is the text indirected?
+               LDRNE   R0,[R0]                 ;Yes -- get the offset
+               LDRNE   R0,[R7,R0]              ;...load indirected pointer
+               TST     R2,#mFlag_noTrans       ;Do we translate the string?
+               BLEQ    msgs_lookup             ;Yes -- lookup the message
+               STR     R0,[R3,#12]             ;Store the new text pointer
+               BL      str_len                 ;Get the length
+               TST     R2,#mFlag_sprite                ;Is there a sprite?
+               ADDNE   R0,R0,#2                ;Yes -- allow for it
+               LDR     R6,menu__maxLen         ;Get the current max length
+               CMP     R0,R6                   ;Is new length longer?
+               STRGT   R0,menu__maxLen         ;Yes, store this
+               MOV     R0,R5                   ;Get current offset back
+               BL      menu__skipText          ;Skip the text part
+07             TST     R2,#mFlag_shade         ;Is it shadable?
+               BEQ     %10                     ;No -- jump this code
+               BL      %99                     ;Do a bit specification
+               LDR     R5,[R3,#8]              ;Get the icon flags
+               ORRCS   R5,R5,#(1<<22)          ;Set the 'shaded' bit
+               BICCC   R5,R5,#(1<<22)          ;Or maybe clear it
+               STR     R5,[R3,#8]              ;Put them back
+
+10             TST     R2,#mFlag_iShade        ;Is it inverse shadable?
+               BEQ     %11                     ;No -- jump this code
+               BL      %99                     ;Do a bit specification
+               LDR     R5,[R3,#8]              ;Get the icon flags
+               ORRCC   R5,R5,#(1<<22)          ;Set the 'shaded' bit
+               BICCS   R5,R5,#(1<<22)          ;Or maybe clear it
+               STR     R5,[R3,#8]              ;Put them back
+
+11             TST     R2,#mFlag_switch        ;Is it a switch
+               BEQ     %12                     ;No -- jump this code
+               BL      %99                     ;Do a bit specification
+               ORRCS   R4,R4,#1                ;Set the tick flag
+               BICCC   R4,R4,#1                ;Or maybe clear it
+
+12             TST     R2,#mFlag_radio         ;Is is a radio type?
+               BEQ     %13                     ;No -- jump this code
+               LDMIA   R0!,{R5,R6}             ;Get offset and selector
+               ADD     R5,R5,R7                ;Get real offset
+               LDR     R5,[R5]                 ;Get the word there
+               CMP     R5,R6                   ;It is the same as selector?
+               ORREQ   R4,R4,#1                ;Yes -- set the tick flag
+               BICNE   R4,R4,#1                ;No -- clear it
+
+13             TST     R2,#mFlag_sprite        ;Is there a sprite?
+               ADDNE   R0,R0,#4                ;Yes -- skip the pointer
+
+               TST     R2,#mFlag_subMenu       ;Automatic submenu?
+               ADDNE   R0,R0,#8                ;Yes -- skip those fields
+
+               STR     R4,[R3,#0]              ;Store the item flags back
+               ADD     R3,R3,#24               ;Point to next real icon
+               B       %06                     ;Try another icon
+
+               ; --- Try more items from next header ---
+
+20             ADD     R1,R1,#20               ;Point to next header
+               LDR     R0,[R1]                 ;Get the item count
+               CMP     R0,#0                   ;Is there one?
+               BNE     %05                     ;...and do it
+
+               ; --- Now move onto next menu ---
+
+               LDMFD   R13!,{R3}               ;Get the first item pointer
+               LDR     R0,menu__maxLen         ;Get the menu with
+               ADD     R0,R0,#1                ;Add a character width
+               MOV     R0,R0,LSL#4             ;Multiply width by 16
+               STR     R0,[R3,#-12]            ;Store in menu width field
+               LDR     R0,[R12]                ;Get the length
+               ADD     R12,R12,R0              ;Point to the next menu
+               LDMFD   R13!,{R10}              ;Load menu hit pointer
+               B       %00                     ;And keep looking
+
+               ; --- We have apparently finished now ---
+
+90             LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               ; --- Calculate a bit specification ---
+
+99             LDR     R5,[R0],#4              ;Get the next word
+               ADD     R6,R7,R5,LSR#5          ;Get the offset
+               LDR     R6,[R6]                 ;And the byte there
+               AND     R5,R5,#31               ;Clear bits we don't want
+               ADD     R5,R5,#1                ;Correct for shifting
+               MOVS    R6,R6,LSR R5            ;Shift that bit into carry
+               MOV     PC,R14                  ;Return from subroutine
+
+               LTORG
+
+; --- menu__locateFirst ---
+;
+; On entry:    R0 == pointer to my menu defn
+;
+; On exit:     R0 == pointer to first item in menu
+;              R1 == Number of items in menu
+;
+; Use:         Given a pointer to a menu definition (my type, not
+;              WIMP), it returns a pointer to the first item, and
+;              a count of the number of items in the menu.
+
+menu__locateFirst
+               ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack some registers
+
+               MOV     R1,#0                   ;Item count
+               ADD     R0,R0,#20               ;Point past length/re-create
+00             LDMIA   R0!,{R2,R3,R4,R5,R6}    ;Load menu data
+               CMP     R2,#0                   ;Is this the last item?
+               ADDNE   R1,R1,R2                ;No -- increment item count
+               BNE     %00                     ;Keep searching
+               ADD     R0,R0,#12               ;Point to the first item
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- menu__height ---
+;
+; On entry:    R1 == pointer to real menu block
+;
+; On exit:     R0 == height of menu
+;
+; Use:         Calculates the height of a WIMP menu, from its data structure
+
+menu__height   ROUT
+
+               STMFD   R13!,{R1-R2,R14}        ;Stack some registers
+
+               MOV     R0,#0                   ;The height so far
+               ADD     R1,R1,#28               ;Point to the first item
+00             ADD     R0,R0,#44               ;Increment the height
+               LDR     R2,[R1]                 ;Get the flags word
+               TST     R2,#2                   ;Is there a dotted line?
+               ADDNE   R0,R0,#24               ;Yes -- add 24 to height
+               TST     R2,#&80                 ;Is this the last item?
+               ADDEQ   R1,R1,#24               ;No -- point to next item
+               BEQ     %00                     ;...and keep counting
+
+               LDMFD   R13!,{R1-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- menu__open ---
+;
+; On entry:    R2 == modules flags word
+;              R9 == workspace pointer
+;
+; On exit:     --
+;
+; Use:         Opens the next menu in the right place
+
+menu__open     ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+
+               LDR     R0,menu__start          ;Point to current menu
+               BL      menu__locateFirst       ;Find the first item
+               SUB     R1,R1,#1                ;0 index item count
+               MOV     R1,R1,LSL#3             ;Multiple no. of items by 8
+               RSB     R1,R1,R1,LSL#2          ;And the by 3
+               ADD     R1,R0,R1                ;Point to last item
+               LDR     R3,[R1]                 ;Load the flags word
+               ORR     R3,R3,#&80              ;Set 'Last item' bit
+               BIC     R3,R3,#2                ;No ruleoff here
+               STR     R3,[R1]                 ;Store the flags back
+
+               SUB     R1,R0,#28               ;Point to real menu structure
+               LDR     R0,menu__maxLen         ;Get the longest text length
+               MOV     R0,R0,LSL#4             ;Multiply by 16
+               ADD     R0,R0,#16               ;Add one for luck
+               STR     R0,[R1,#16]             ;Store the width
+               MOV     R4,R2                   ;Remember flags word
+               TST     R4,#mFlag__recreating   ;Are we recreating a menu
+               LDMNEFD R13!,{R0-R4,PC}^        ;Yes -- Return
+               ADR     R2,menu__coords         ;Point to coords block
+               LDMIA   R2,{R2,R3}              ;Get the x and y coords
+
+               ; --- Ensure Y position is correct on icon bar ---
+
+               TST     R4,#mFlag__iBar         ;Was it on the icon bar?
+               BLNE    menu__height            ;Calculate the menu height
+               ADDNE   R3,R0,#96               ;This is the Y position
+
+               TST     R4,#mFlag__wasSub       ;Is it a submenu?
+               BEQ     %90                     ;No -- create a normal menu
+               LDR     R0,menu__prevMenu       ;Get menu from which it came
+               ADD     R0,R0,#20               ;Point to the first header
+50menu__open   LDR     R14,[R0],#4             ;Get the number of items
+               CMP     R14,#0                  ;Any more headers?
+               ADDNE   R0,R0,#16               ;Yes -- point to next one
+               BNE     %50menu__open           ;...and keep looking
+               ADD     R0,R0,#28               ;Point to first item
+               LDR     R14,menu__prevItem      ;Get the previous item hit
+               MOV     R14,R14,LSL#3           ;Multiply item hit by 8
+               RSB     R14,R14,R14,LSL#2       ;And then by 3
+               ADD     R0,R0,R14               ;Point to the item
+               STR     R1,[R0,#4]              ;Store pointer in menu field
+               SWI     Wimp_CreateSubMenu      ;Create sub menu
+               LDMFD   R13!,{R0-R4,PC}^        ;Return
+
+90menu__open   SUB     R2,R2,#64               ;No -- correct X position
+               SWI     Wimp_CreateMenu         ;...create the menu
+               ORR     R4,R4,#mFlag__opened    ;Set the opened bit
+               STR     R4,menu__flags          ;Store the modified flags
+               LDMFD   R13!,{R0-R4,PC}^        ;Return
+
+               LTORG
+
+; --- menu__skipText ---
+;
+; On entry:    R0 == pointer to text field
+;              R2 == item flags for this item
+;
+; On exit:     R0 == pointer to first data field after the text
+;
+; Use:         Skips text part of an icon definition
+
+menu__skipText ROUT
+
+               STMFD   R13!,{R14}              ;Stack registers
+
+               TST     R2,#mFlag_indirect      ;Is it indirected?
+               ADDNE   R0,R0,#4                ;Yes -- just skip a word
+               LDMNEFD R13!,{PC}^              ;And return
+
+00             LDRB    R14,[R0],#1             ;Get a character
+               CMP     R14,#0                  ;Is it a NULL
+               BNE     %00                     ;No, keep looking
+               ADD     R0,R0,#3                ;Word align R0
+               BIC     R0,R0,#3                ;Complete aligning
+               LDMFD   R13!,{PC}^              ;And return
+
+               LTORG
+
+; --- menu__findItem ---
+;
+; On entry:    R0 == pointer to menu definition (my kind)
+;              R1 == Item number to locate
+;
+; On exit:     R0 == pointer to the item definition
+;              R1 == pointer to header entry for this item
+;              R2 == index for this item (to pass to handler)
+;
+; Use:         Locates the given item from a created menu definition,
+;              and also finds the header entry for it
+
+menu__findItem ROUT
+
+               STMFD   R13!,{R3,R4,R14}        ;Stack some registers
+
+               ADD     R0,R0,#20               ;Point to first header
+               MOV     R2,#0                   ;Item so far
+00             LDR     R3,[R0]                 ;Number of items header's for
+               MOV     R4,R2                   ;Number so far
+               ADD     R2,R2,R3                ;Increment my count
+               CMP     R1,R2                   ;Is this the relevant header?
+               ADDGE   R0,R0,#20               ;No -- point to next header
+               BGE     %00                     ;...and keep looking
+
+               ; --- We have located the relevant header ---
+
+               SUBS    R3,R1,R4                ;Calculate item index
+               STMFD   R13!,{R3}               ;Store it on the stack
+               MOV     R1,R0                   ;Point to header for user
+               LDR     R0,[R1,#4]              ;Find definition pointer
+10             LDMEQFD R13!,{R2-R4,PC}^        ;Yes -- return to caller
+               LDR     R2,[R0],#4              ;Load the flags
+               BL      menu__skipText          ;Skip the text
+               TST     R2,#mFlag_shade         ;Is there a shade field
+               ADDNE   R0,R0,#4                ;Yes -- skip it
+               TST     R2,#mFlag_iShade        ;Is there a ishade field
+               ADDNE   R0,R0,#4                ;Yes -- skip it
+               TST     R2,#mFlag_switch        ;Is there a switch field
+               ADDNE   R0,R0,#4                ;Yes -- skip it
+               TST     R2,#mFlag_radio         ;Are there radio fields
+               ADDNE   R0,R0,#8                ;Yes -- skip them
+               TST     R2,#mFlag_sprite        ;Is there a sprite pointer?
+               ADDNE   R0,R0,#4                ;Yes -- skip it
+               TST     R2,#mFlag_subMenu       ;Automatic submenu?
+               ADDNE   R0,R0,#8                ;Yes -- skip fields
+               SUBS    R3,R3,#1                ;Decrement the count
+               B       %10                     ;Keep searching
+
+               LTORG
+
+; --- menu__dispatch ---
+;
+; On entry:    R0 == event type to send
+;              R1 == pointer to menu hits
+;
+; On exit:     --
+;
+; Use:         Called to dispatch a menu hit event
+
+menu__dispatch ROUT
+
+               STMFD   R13!,{R0-R3,R10,R12,R14}
+
+               MOV     R3,R0                   ;Remember event to send
+               LDR     R0,menu__stack          ;Point to first menu header
+00             LDR     R2,[R1,#4]!             ;Load a menu hit (ignore 1st)
+               CMP     R2,#-1                  ;Is this the end?
+               BEQ     %10                     ;Yes -- branch ahead
+               LDR     R2,[R0]                 ;Get the length
+               ADD     R0,R0,R2                ;Point to the next menu
+               B       %00                     ;And keep looking
+10             LDR     R1,[R1,#-4]             ;Get the item number
+               BL      menu__findItem          ;Point to item and header
+               MOV     R14,R0                  ;Keep the item pointer
+               ADD     R1,R1,#8                ;Point to the event handler
+               MOV     R0,R3                   ;Get the event type
+               LDMFD   R1,{R3,R10,R12}         ;Get the values
+               MOV     R1,R2                   ;The indexed item number
+               MOV     R2,R14                  ;Pass item address in R2
+               CMP     R3,#0                   ;Sanity check
+               MOV     R14,PC                  ;Set up return address
+               MOVNE   PC,R3                   ;Jump to the event handler
+
+               LDMFD   R13!,{R0-R3,R10,R12,PC}^ ;Return
+
+               LTORG
+
+; --- menu__preFilter ---
+;
+; On entry:    R0 == event mask and flags
+;              R1 == pointer to block to use
+;              R2 == earliest time to return with NULL event
+;              R3 == pointer to poll word
+;
+; On exit:     --
+;
+; Use:         Call as an event pre-filter. Its purpose is to open
+;              a previously created menu in the right place.
+
+menu__preFilter        ROUT
+
+               STMFD   R13!,{R0-R2,R9,R14}     ;Stack some registers
+               MOV     R9,R12                  ;Get workspace pointer in R9
+
+               LDR     R2,menu__flags          ;Get my flags word
+               TST     R2,#mFlag__creating     ;Are we creating a menu?
+               BEQ     %90menu__preFilter      ;No -- return then
+               TST     R2,#mFlag__wasSub       ;Is this from a sub menu?
+               BNE     %70menu__preFilter      ;Yes -- just open the menu
+
+               ; --- Set up menu coordinates and things ---
+
+               BL      event_last              ;Get the last event
+               CMP     R0,#6                   ;Mouse click?
+               BEQ     %50menu__preFilter      ;Yes -- deal with it
+
+               ; --- Open over the mouse pointer then ---
+
+               MOV     R14,R2                  ;Preserve flags word
+               SUB     R13,R13,#20             ;Get a block for me
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetPointerInfo     ;Get pointer information
+               LDMIA   R1,{R0,R1}              ;Get coords out of block
+               ADR     R2,menu__coords         ;Point to coords block
+               STMIA   R2,{R0,R1}              ;Store them in the block
+               ADD     R13,R13,#20             ;Get stack back
+               MOV     R2,R14                  ;Get flags back
+               B       %70menu__preFilter      ;Open the menu
+
+               ; --- Deal with button click ---
+
+50             MOV     R14,R2                  ;Preserve flags word
+               LDR     R0,[R1,#12]             ;Get the window handle
+               CMP     R0,#-2                  ;Is it the icon bar
+               BNE     %60menu__preFilter      ;No -- jump
+               ORR     R14,R14,#mFlag__iBar    ;Set relevent bit
+               STR     R14,menu__flags         ;Store the flags back
+60             ADR     R2,menu__coords         ;Point to coords block
+               LDMIA   R1,{R0,R1}              ;Get x and y coords
+               STMIA   R2,{R0,R1}              ;Store them in the block
+               MOV     R2,R14                  ;Get flags word back
+
+               ; --- Open the menu,then ---
+
+70             BL      menu__open              ;Yes -- open the menu
+90             LDR     R2,menu__flags          ;Get new flags
+               AND     R2,R2,#mFlag__inited+mFlag__opened
+               STR     R2,menu__flags          ;Store the new flags
+               LDMFD   R13!,{R0-R2,R9,PC}^     ;Return to caller
+
+               LTORG
+
+; --- menu__postFilter ---
+;
+; On entry:    R0 == wimp event
+;              R1 == pointer to block
+;
+; On exit:     --
+;
+; Use:         Called as an event post filter to catch menu related events
+
+menu__postFilter
+               ROUT
+
+               ; --- Are we at all interested? ---
+
+               STMFD   R13!,{R9,R14}           ;Store R9 value
+               MOV     R9,R12                  ;Get the workspace pointer
+               LDR     R14,menu__flags         ;Get the menu flags
+               TST     R14,#mFlag__opened      ;Do we have a menu open?
+               LDMEQFD R13!,{R9,PC}^           ;No -- ignore it then
+
+               CMP     R0,#9                   ;Menu click?
+               BEQ     %20                     ;Yes -- deal with that
+               CMP     R0,#17                  ;User_Message
+               CMPNE   R0,#18                  ;User_Message_Recorded
+               BNE     %90                     ;No -- tidy up a bit
+
+               ; --- It was a message, are we interested? ---
+               ;
+               ; Note that we are allowed to corrupt R12
+
+               STMFD   R13!,{R0-R2}            ;Stack some registers
+               LDR     R0,=&400C0              ;Menu warning
+               LDR     R12,[R1,#16]            ;Get the message type
+               CMP     R0,R12                  ;Is it menu warning?
+               BEQ     %05                     ;Yes -- deal with it
+               LDR     R0,=&400C9              ;Menus deleted
+               CMP     R0,R12                  ;Is that the message?
+               BEQ     %03                     ;Yes -- deal with it
+               LDR     R0,=&502                ;Help request
+               CMP     R0,R12                  ;Is that the message?
+               LDMNEFD R13!,{R0-R2}            ;No -- Get registers
+               BNE     %90                     ;...and tidy up a bit
+
+               ; --- There was a help request ---
+
+               STMFD   R13!,{R3,R10,R12}       ;We need these
+               SUB     R13,R13,#40             ;Get a buffer
+               MOV     R0,#1                   ;Get state give window/icon
+               ADD     R1,R1,#32               ;Point to window/icon handle
+               LDMIA   R1,{R2,R3}              ;Get them
+               LDR     R14,menu__twin          ;Get the dbmn address
+               LDR     R14,[R14,#twin_trans]   ;Get the transient dbox
+               CMP     R14,R2                  ;Are they the same
+               BEQ     %02                     ;Yes -- forget it
+               MOV     R1,R13                  ;Use this buffer
+               SWI     XWimp_GetMenuState      ;Get the menu state
+               BVS     %02                     ;If failed, return
+               LDR     R0,[R1,#0]              ;First first menu index
+               CMP     R0,#-1                  ;Is it on our menu?
+               BEQ     %02                     ;No -- skip forward
+               MOV     R0,#mEvent_help         ;Set the event type
+               BL      menu__dispatch          ;Dispatch the event
+
+               ; --- Return to caller ---
+
+02             ADD     R13,R13,#40             ;Reclaim my stack
+               LDMFD   R13!,{R3,R10,R12}       ;Get these values back
+               LDMFD   R13!,{R0-R2}            ;Get registers
+               B       %90                     ;...and tidy up a bit
+
+               ; --- There was a menus deleted message ---
+
+03             STMFD   R13!,{R10,R12}          ;We need these
+               LDR     R0,menu__flags          ;Get the flags word
+               BIC     R0,R0,#mFlag__opened    ;Well,it's closed now
+               STR     R0,menu__flags          ;Store the flags back
+               LDR     R0,menu__stack          ;Find the top level menu
+               ADD     R0,R0,#8                ;Point to the handler
+               LDMIA   R0,{R2,R10,R12}         ;Get handler and R10/R12
+               MOV     R0,#mEvent_deleted      ;Set the event type
+               CMP     R2,#0                   ;Sanity check
+               MOV     R14,PC                  ;Set the return address
+               MOVNE   PC,R2                   ;Call the handler
+04             LDMFD   R13!,{R10,R12}          ;Get these values back
+               LDMFD   R13!,{R0-R2}            ;Get registers
+               B       %90                     ;...and tidy up a bit
+
+               ; --- It was a submenu warning ---
+
+05             LDR     R0,menu__flags          ;Get the flags
+               ORR     R0,R0,#mFlag__wasSub    ;It was a menu warning
+               STR     R0,menu__flags          ;Put the flags back
+               ADR     R0,menu__coords         ;Point to my coords block
+               ADD     R1,R1,#24               ;Point to the (x,y) to use
+               LDMIA   R1!,{R2,R12}            ;Load x and y
+               STMIA   R0,{R2,R12}             ;And store them usefully
+
+               ; --- We now need to find the menu in question ---
+
+               LDR     R0,menu__stack          ;Point to first menu header
+05             LDR     R2,[R1,#4]!             ;Load a menu hit (ignore 1st)
+               CMP     R2,#-1                  ;Is this the end?
+               BEQ     %10                     ;Yes -- branch ahead
+               LDR     R2,[R0]                 ;Get the length
+               ADD     R0,R0,R2                ;Point to the next menu
+               B       %05                     ;And keep looking
+10             STR     R0,menu__prevMenu       ;Store this pointer
+               LDR     R1,[R1,#-4]             ;Get the item number
+               STR     R1,menu__prevItem       ;Store the item number
+
+               ; --- Now we need to create the submenu if we need to ---
+
+               BL      menu__findItem          ;Point to the item definition
+               LDR     R2,[R0],#4              ;Get the flags word
+               TST     R2,#mFlag_subMenu       ;Automatic menu?
+               BNE     %15                     ;Yes -- deal with it
+
+               ; --- Here we must just tell the user ---
+               ;
+               ; R0 == pointer to the menu item definition+4
+               ; R1 == pointer to the menu header for this item
+               ; R2 == item flags
+
+               MOV     R0,#mEvent_arrow        ;Set the event type
+               LDR     R1,[R13,#4]             ;Get the message block
+               ADD     R1,R1,#32               ;Point to the menu hit list
+               BL      menu__dispatch          ;Dispatch the event
+               LDMFD   R13!,{R0-R2,R9,PC}^     ;Return to caller
+
+               ; --- We must automatically open the menu ---
+
+15             BL      menu__skipText          ;Skip the item text
+               TST     R2,#mFlag_switch        ;Is there a switch field
+               ADDNE   R0,R0,#4                ;Yes -- skip it
+               TST     R2,#mFlag_shade         ;Is there a shade field
+               ADDNE   R0,R0,#4                ;Yes -- skip it
+               TST     R2,#mFlag_iShade        ;Is there a ishade field
+               ADDNE   R0,R0,#4                ;Yes -- skip it
+               TST     R2,#mFlag_radio         ;Are there radio fields
+               ADDNE   R0,R0,#8                ;Yes -- skip them
+               TST     R2,#mFlag_sprite        ;Is there a sprite?
+               ADDNE   R0,R0,#4                ;Yes -- skip pointer
+               ADD     R1,R1,#12               ;Point to R10,R12 for item
+               LDMIA   R1,{R2,R3}              ;Use these values again
+               LDMIA   R0,{R0,R1}              ;Get menu pointer & handler
+               BL      menu_create             ;Create this menu
+
+               LDMFD   R13!,{R0-R2,R9,PC}^     ;Return to caller
+
+               ; --- Deal with menu selection ---
+
+20             STMFD   R13!,{R0-R2}            ;Stack some registers
+               BIC     R14,R14,#mFlag__opened  ;Say the menu just closed
+               STR     R14,menu__flags         ;Save these flags back
+
+               ; --- Set up the dbmn flag word ---
+
+               LDR     R2,menu__twin           ;Locate dbmn area
+               LDR     R14,[R2,#twin_flags]    ;Get the flags word
+               ORR     R14,R14,#twinFlag_recrt ;We are going to recreate it
+               STR     R14,[R2,#twin_flags]    ;Store the flags back
+
+               ; --- Dispatch the event ---
+
+               MOV     R0,#mEvent_select       ;Set the event type
+               BL      menu__dispatch          ;Dispatch the event
+
+               LDR     R14,[R2,#twin_flags]    ;Get the flags word back
+               TST     R14,#twinFlag_recrt     ;Do we still need to recreate
+               LDMEQFD R13!,{R0-R2}            ;No -- get registers back
+               BEQ     %90                     ;...and tidy up
+
+               ; --- Recreate the menu if we need to ---
+
+               SUB     R13,R13,#20             ;Get a block
+               MOV     R1,R13                  ;Point to it
+               SWI     Wimp_GetPointerInfo     ;Get pointer information
+               LDR     R1,[R1,#8]              ;Get the button state
+               TST     R1,#1                   ;Was Adjust clicked?
+               ADD     R13,R13,#20             ;Get the stack back
+               LDMEQFD R13!,{R0-R2}            ;No -- get registers back
+               BEQ     %90                     ;...and tidy up
+               LDMIB   R13,{R1}                ;Get the menu hit list back
+               BL      menu__recreate          ;Recreate the menu
+               LDR     R1,menu__stack          ;Get the stack pointer
+               ADD     R1,R1,#20               ;Point to the first header
+25             LDR     R0,[R1],#4              ;Get the number of items
+               CMP     R0,#0                   ;Any more headers?
+               ADDNE   R1,R1,#16               ;Yes -- point to next one
+               BNE     %25                     ;...and keep looking
+               SWI     Wimp_CreateMenu         ;Recreate the menu
+               LDR     R14,menu__flags         ;Load the menu flags again
+               ORR     R14,R14,#mFlag__opened  ;The menu is still open
+               STR     R14,menu__flags         ;Save the flags back
+
+               LDMFD   R13!,{R0-R2}            ;Get registers back
+               B       %90                     ;And tidy up
+
+               ; --- Tidy up on a non-submenu warning event ---
+
+90             LDR     R12,menu__flags         ;Get the flags
+               BIC     R12,R12,#mFlag__wasSub  ;It was not a menu warning
+               STR     R12,menu__flags         ;Put the flags back
+               LDMFD   R13!,{R9,PC}^           ;Return to caller
+
+               LTORG
+
+; --- menu_help ---
+;
+; On entry:    R0 == pointer to base message tag
+;              R1 == index of menu item
+;
+; On exit:     --
+;
+; Use:         Adds a string to the help message found by adding the menu
+;              item number to the base message tag.
+
+               EXPORT  menu_help
+menu_help      ROUT
+
+               CMP     R1,#0                   ;Is the menu item sane?
+               MOVLTS  PC,R14                  ;No -- don't trust Tim
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R1,R0                   ;Point to base message tag
+               MOV     R0,R11                  ;Point to scratchpad
+               BL      str_cpy                 ;Add the string in there
+               MOV     R1,R0                   ;Point to terminating null
+               MOV     R2,#25                  ;Should be 25 bytes left over
+               LDR     R0,[R13,#4]             ;Get his item number
+               SWI     OS_ConvertInteger4      ;Tack it on the end
+               MOV     R0,R11                  ;Point to the message tag
+               BL      msgs_lookup             ;Translate it nicely
+               BL      help_add                ;Add it to the help string
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- menu_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the menu system.
+
+               EXPORT  menu_init
+menu_init      ROUT
+
+               STMFD   R13!,{R0-R3,R9,R14}     ;Stack some registers
+               WSPACE  menu__wSpace,R9         ;Locate my workspace
+
+               ; --- Are we already initialised? ---
+
+               LDR     R0,menu__flags          ;Get my flags
+               TST     R0,#mFlag__inited       ;Are we initialised?
+               LDMNEFD R13!,{R0-R3,R9,PC}^     ;Yes -- return
+
+               ORR     R0,R0,#mFlag__inited    ;Set initialised flag
+               STR     R0,menu__flags          ;And store them back
+
+               ; --- Ensure that event is initialised ---
+
+               BL      event_init              ;Initialise it
+
+               ; --- Set up my menu stack ---
+
+               LDR     R0,menu__optName        ;Get the option block name
+               BL      libOpts_find            ;Try to find the block
+               LDRCS   R3,[R0,#0]              ;If found, load stack size
+               MOVCC   R3,#2048                ;Otherwise use default 2K
+               MOV     R0,#2                   ;Allocate memory
+               BL      sapphire_heapAddr       ;Find the heap address
+               SWI     OS_Heap                 ;Allocate the stack
+               STR     R2,menu__stack          ;Store this value
+               ADD     R3,R3,R2                ;The end of the menu stack
+               STR     R3,menu__stackEnd       ;The menu stack end
+
+               ; --- Set up the filters ---
+
+               ADR     R0,menu__preFilter      ;Point to the filter
+               MOV     R1,R9                   ;Use this workspace
+               BL      event_preFilter         ;Add the pre filter
+
+               ADR     R0,menu__postFilter     ;Point to the filter
+               MOV     R1,R9                   ;Use this workspace
+               BL      event_postFilter        ;Add the post filter
+
+               ; --- Locate the TWIN global area ---
+
+               LDR     R0,menu__TWIN           ;Load the global area name
+               MOV     R1,#twin_size           ;Load the area's size
+               BL      sapphire_global         ;Find the area's address
+               STR     R0,menu__twin           ;Store the address away
+
+               MOVCC   R1,#0                   ;Clear the global area
+               MOVCC   R2,#0
+               MOVCC   R14,#0
+               STMCCIA R0,{R1,R2,R14}          ;Store zeroes all over it
+
+               ; --- And return peacefully ---
+
+               LDMFD   R13!,{R0-R3,R9,PC}^     ;Return to caller
+
+menu__optName  DCB     "MENU"
+menu__TWIN     DCB     "TWIN"
+
+               LTORG
+
+menu__wSpace   DCD     0
+
+;----- Global area layouts --------------------------------------------------
+
+; --- TWIN global area ---
+;
+; See transWin for more details
+
+               ^       0
+twin_flags     #       4                       ;Various flags for things
+twin_trans     #       4                       ;Handle of transient window
+twin_tmsHook   #       4                       ;Hook for TMS
+twin_size      #       4
+
+twinFlag_recrt EQU     (1<<0)                  ;Do we want to recreate?
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R9
+menu__wStart   #       0
+
+menu__flags    #       4                       ;Flags word
+
+mFlag__inited  EQU     (1<<0)                  ;We are initialised
+mFlag__creating        EQU     (1<<1)                  ;We are creating a menu
+mFlag__wasSub  EQU     (1<<2)                  ;Last event was sub menu warn
+mFlag__tOnly   EQU     (1<<4)                  ;Only the title has been done
+mFlag__iBar    EQU     (1<<5)                  ;The click was on icon bar
+mFlag__recreating EQU  (1<<6)                  ;We are recreating a menu
+mFlag__opened  EQU     (1<<7)                  ;I have a menu opened
+
+menu__stack    #       4                       ;Pointer to the menu stack
+menu__stackEnd #       4                       ;The end of the menu stack
+menu__start    #       4                       ;Start of current menu defn
+menu__begin    #       4                       ;Pointer to real menu
+menu__end      #       4                       ;The end of the menu
+
+menu__maxLen   #       4                       ;Maximum length of items
+menu__sprite   #       4                       ;Pointer to a sprite name
+menu__coords   #       8                       ;(x,y) coords to open menu at
+menu__prevMenu #       4                       ;Menu from which warning came
+menu__prevItem #       4                       ;Menu from which warning came
+menu__twin     #       4                       ;Pointer to DBMN global area
+
+menu__wSize    EQU     {VAR}-menu__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     menu__wSize             ;Workspace size
+               DCD     menu__wSpace            ;Workspace pointer
+               DCD     0                       ;Scratchpad size
+               DCD     menu_init               ;Initialisation
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/msgs b/StraySrc/Libraries/Sapphire/s/msgs
new file mode 100644 (file)
index 0000000..bf0e857
--- /dev/null
@@ -0,0 +1,466 @@
+;
+; msgs.s
+;
+; Message file handling (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:sapphire
+               GET     sapphire:string
+               GET     sapphire:res
+               GET     sapphire:resources
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- msgs_load ---
+;
+; On entry:    R0 == pointer to filename
+;
+; On exit:     May return an error
+;
+; Use:         Reads in the given messages file.
+
+               EXPORT  msgs_load
+msgs_load      ROUT
+
+               STMFD   R13!,{R0-R5,R12,R14}    ;Stack some registers
+               WSPACE  msgs__wSpace            ;Find my workspace
+
+               ; --- How big is the file? ---
+
+               MOV     R1,R0                   ;Point to the filename
+               MOV     R0,#17                  ;File info please
+               SWI     XOS_File                ;Get the info
+               BVS     %99msgs_load            ;Make the error if not OK
+               TST     R0,#1                   ;Is it a file?
+               BEQ     %80msgs_load            ;No -- ignore it then
+
+               ; --- Allocate a heap block for it ---
+
+               ADD     R3,R4,#1+8              ;Get file size + 1 +size word
+               MOV     R0,R3                   ;Get the size
+               BL      alloc                   ;Try to allocate the block
+               BLCS    alloc_error             ;If failed, find error
+               BCS     %99msgs_load            ;And handle it
+               MOV     R2,R0                   ;Get the pointer safely
+
+               ; --- Remember block position ---
+
+               LDR     R14,msgs__list          ;Find old list head
+               STR     R14,[R2,#0]             ;Save that here
+               STR     R2,msgs__list           ;Store this block away
+               ADD     R3,R2,R3                ;Get pointer to end of block
+               STR     R3,[R2,#4]              ;And save it
+               ADD     R2,R2,#8                ;Point to file space
+               STMFD   R13!,{R2,R3}            ;Save these registers
+
+               ; --- Load the messages file into buffer ---
+
+               MOV     R0,#16                  ;Load file into memory
+               MOV     R3,#0                   ;Load into my buffer
+               SWI     XOS_File                ;Load the file now
+               BVS     %98msgs_load            ;If error, then free block
+
+               ; --- Scan through the messages, and NULL terminate them ---
+
+               LDMFD   R13!,{R2,R3}            ;Get the start/end of mesgs
+               SUBS    R3,R3,R2                ;Get the length
+               MOV     R1,#0                   ;The NULL byte
+10msgs_load    LDRB    R0,[R2]                 ;Get a character
+               CMP     R0,#' '                 ;Is it a control character
+               STRLTB  R1,[R2]                 ;Yes, NULL terminate it
+               SUBS    R3,R3,#1                ;Decrement counter
+               ADDGT   R2,R2,#1                ;Increase index
+               BGT     %10msgs_load            ;And keep looping
+               STRB    R1,[R2]                 ;Put NULL at end
+
+               ; --- Return to the user ---
+
+80msgs_load    LDMFD   R13!,{R0-R5,R12,R14}    ;Get registers
+               BICS    PC,R14,#V_flag          ;And return without error
+
+               ; --- Free memory on error ---
+
+98msgs_load    MOV     R5,R10                  ;Keep hold of error pointer
+               LDMFD   R13!,{R2,R3}            ;Restore old registers
+               LDR     R14,[R2,#0]             ;Load next link
+               STR     R14,msgs__list          ;Store back as list head
+               MOV     R0,R2                   ;Free memory from heap
+               BL      free                    ;Free the block
+               MOV     R0,R5                   ;Restore the error pointer
+
+               ; --- Report the error ---
+
+99msgs_load    ADD     R2,R0,#4                ;Point to error message
+               ADR     R0,msgs__loadError      ;Point to error skeleton
+               BL      msgs_error              ;Create the error message
+               ADD     R13,R13,#4              ;Don't restore R0
+               LDMFD   R13!,{R1-R5,R12,R14}    ;Restore other registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+msgs__loadError        DCD     1
+               DCB     "msgsMLE:Error loading messages file: %0",0
+
+               LTORG
+
+; --- msgs_build ---
+;
+; On entry:    R0 == pointer to a message string
+;              R1 == pointer to output buffer
+;
+; On exit:     R0 == pointer to buffer (R1 on entry)
+;              R1 == pointer to terminating null
+;
+; Use:         Builds a message string, by substituting message references
+;              by their values.  Each reference of the form `$tag' (or
+;              optionally `$(tag)', to avoid having to have a trailing)
+;              space is replaced by the actual message.  A literal `$' sign
+;              may be represented as `$$'.
+
+               EXPORT  msgs_build
+msgs_build     ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Save some registers
+               MOV     R2,R0                   ;Remember this pointer
+
+05msgs_build   LDRB    R14,[R2],#1             ;Load the next character
+               CMP     R14,#'$'                ;Is it a message reference?
+               BEQ     %f00                    ;Yes -- handle it then
+10msgs_build   CMP     R14,#&20                ;Is it the end of the line?
+               MOVCC   R14,#0                  ;Yes -- store a zero then
+               STRB    R14,[R1],#1             ;Store in output buffer
+               BCS     %05msgs_build           ;And keep on going
+               SUB     R1,R1,#1                ;Point back to the null
+               LDMFD   R13!,{R0,R2-R4,PC}^     ;And return to caller
+
+               ; --- Handle a dollar sign ---
+
+00             LDRB    R14,[R2],#1             ;Load the next character
+               CMP     R14,#'$'                ;Is this a literal dollar?
+               CMPNE   R14,#&1F                ;Or maybe a control character
+               BLS     %10msgs_build           ;Yes -- then ignore this
+               CMP     R14,#'('                ;Is the reference bracketted?
+               MOVEQ   R3,#')'                 ;Yes -- remember this char
+               MOVNE   R3,#' '                 ;Otherwise, use a space
+               LDREQB  R14,[R2],#1             ;Load next char if `(`
+               MOV     R4,R1                   ;Remember this output place
+
+00             CMP     R14,R3                  ;Is this the end char?
+               CMPNE   R14,#&1F                ;Or a control character?
+               STRHIB  R14,[R4],#1             ;Write the character out
+               LDRHIB  R14,[R2],#1             ;Load the next one maybe
+               BHI     %b00                    ;And keep going until done
+
+               MOV     R0,#0                   ;A nice zero word
+               STRB    R0,[R4],#1              ;Store the word away nicely
+               CMP     R14,#' '                ;Is this a space character?
+               SUBLS   R2,R2,#1                ;Yes -- move back one space
+
+               MOV     R0,R1                   ;Point to the tag start
+               BL      msgs_lookup             ;Translate the message
+00             LDRB    R14,[R0],#1             ;Load a byte from here
+               CMP     R14,#&20                ;Finished here yet?
+               STRCSB  R14,[R1],#1             ;No -- store the byte
+               BCS     %b00                    ;And keep on going
+               B       %05msgs_build           ;Go back to the main loop
+
+               LTORG
+
+; --- msgs_error ---
+;
+; On entry:    R0 == pointer to an error skeleton string:
+;                      R0+0 == error number
+;                      R0+4 == message tag-and-default (null-terminated)
+;              R2-R11 == filler strings (not message tags)
+;
+; On exit:     R0 == pointer to translated error message (in error buffer)
+;              R1 == pointer to null terminator of message
+;
+; Use:         Performs string sustitution on an error message (as done by
+;              str_subst), but translating the error string.
+
+               EXPORT  msgs_error
+msgs_error     ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+
+               ; --- First, translate the message ---
+
+               ADD     R0,R0,#4                ;Point to the message tag
+               BL      msgs_lookup             ;Translate the tag
+
+               ; --- Perform the substitution ---
+
+               SUB     R0,R0,#4                ;Create a dummy error number
+               BL      str_error               ;So the real work
+
+               ; --- Now copy the error number over ---
+
+               LDR     R14,[R13],#4            ;Get the initial error ptr
+               LDR     R14,[R14,#0]            ;Get the user's error number
+               STR     R14,[R0,#0]             ;Store in substituted error
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- msgs_lookup ---
+;
+; On entry:    R0 == message tag (and default message)
+;
+; On exit:     R0 == pointer to located message
+;
+; Use:         Returns the real message from its tag. If the tag does not
+;              exist, then the default message is used. If that is not
+;              supplied, then the tag name itself is returned (ie. R0
+;              is preserved).
+
+               EXPORT  msgs_lookup
+msgs_lookup    ROUT
+
+               STMFD   R13!,{R1-R6,R12,R14}    ;Stack some registers
+               WSPACE  msgs__wSpace            ;Load pointer
+
+               LDR     R14,msgs__flags         ;Load my flags word
+               TST     R14,#msFlag__inited     ;Are we initialised?
+               BEQ     %60msgs_lookup          ;No -- handle specially
+
+               LDR     R6,msgs__list           ;Find message block list
+
+               ; --- Loop through the message lists ---
+
+10msgs_lookup  CMP     R6,#-1                  ;Is this the very end?
+               BEQ     %90msgs_lookup          ;Yes -- return default then
+               MOVS    R4,R6                   ;Reached the end yet?
+               ADREQ   R14,msgs__global        ;Otherwise find shared msgs
+               LDMEQIA R14,{R4,R5}             ;Load those out please
+               MOVEQ   R6,#-1                  ;And stop next time
+               LDMNEIA R4!,{R1,R5}             ;Load data from block
+               MOVNE   R6,R1                   ;Set up the link
+
+               ; --- Try matching the next message ---
+
+20msgs_lookup  MOV     R1,R0                   ;Remember start of tag
+               CMP     R4,R5                   ;Finished yet?
+               BCS     %10msgs_lookup          ;Yes -- move to next block
+               LDRB    R2,[R1],#1              ;Load next byte from tag
+               LDRB    R3,[R4],#1              ;And one from the message
+
+               ; --- Handle a comment ---
+
+               CMP     R3,#';'                 ;Is it a semicolon?
+               CMPNE   R3,#'#'                 ;Or a hash?
+               CMPNE   R3,#'|'                 ;Or a vertical bar?
+               BEQ     %50msgs_lookup          ;Yes -- skip on to next msg
+
+               ; --- Main comparison loop ---
+
+00             CMP     R2,#0                   ;End of tag?
+               CMPNE   R2,#':'                 ;Could have a default
+               CMPNE   R3,#'*'                 ;Or is tag wildcarded?
+               BEQ     %f00                    ;Yes -- investigate then
+               CMP     R3,#0                   ;End of message?
+               CMPNE   R3,#'/'                 ;End of alternative?
+               BEQ     %20msgs_lookup          ;Yes -- retry from here
+               CMPNE   R3,#':'                 ;End of message tags?
+               BEQ     %50msgs_lookup          ;Move to next message then
+               CMP     R2,R3                   ;Do the two match at all?
+               CMPNE   R3,#'?'                 ;Allow a wildcard here
+               BNE     %30msgs_lookup          ;No -- move to next message
+               LDRB    R2,[R1],#1              ;Load next byte from tag
+               LDRB    R3,[R4],#1              ;And one from the message
+               B       %b00                    ;And keep on looping
+
+               ; --- Investigate a possible match ---
+
+00             CMP     R3,#':'                 ;End of message's tag?
+               CMPNE   R3,#'/'                 ;End of this alternative?
+               CMPNE   R3,#'*'                 ;Or just a wildcard?
+               BNE     %30msgs_lookup          ;No -- try next message
+
+00             CMP     R3,#0                   ;End of message?
+               SUBEQ   R4,R4,#1                ;Yes -- backtrack one then
+               CMPNE   R3,#':'                 ;Found the message text yet?
+               LDRNEB  R3,[R4],#1              ;No -- skip on then
+               BNE     %b00                    ;Loop till we find it
+               MOV     R0,R4                   ;Point to the message
+               LDMFD   R13!,{R1-R6,R12,PC}^    ;Return to caller OK
+
+               ; --- Skip on to next alternative ---
+
+30msgs_lookup  CMP     R3,#0                   ;End of message?
+               CMPNE   R3,#'/'                 ;Or of the alternative?
+               LDRNEB  R3,[R4],#1              ;No -- move on then
+               BNE     %b30                    ;And loop round
+
+               B       %20msgs_lookup          ;Try the next message now
+
+               ; --- Skip on to next message ---
+
+50msgs_lookup  CMP     R3,#0                   ;End of message?
+               LDRNEB  R3,[R4],#1              ;No -- move on then
+               BNE     %b50                    ;And loop round
+
+               B       %20msgs_lookup          ;Try the next message now
+
+               ; --- Not yet initialised ---
+               ;
+               ; This is a bit of an odd circumstance, but people can have
+               ; errors at all sorts of times.  We should try to translate
+               ; the message using the [Sapphire.Resources] DLL, although
+               ; not be overly upset if this isn't possible -- either the
+               ; default message (English) will be used, or maybe
+
+60msgs_lookup  MOV     R6,R0                   ;Look after this for a while
+               MOV     R0,#rsType_message      ;Request a message resource
+               BL      resources_find          ;Find the resource please
+               MOVCC   R0,R6                   ;Failed -- refind tag pointer
+               BCC     %90msgs_lookup          ;And return tag as
+               MOV     R4,R0                   ;Point to message block base
+               MOV     R5,R1                   ;Point to the block limit
+               MOV     R0,R6                   ;Point to the tag again
+               MOV     R6,#-1                  ;Stop after scanning please
+               B       %20msgs_lookup          ;Now search default messages
+
+               ; --- No luck at all ---
+
+90msgs_lookup  MOV     R1,R0                   ;Look after tag pointer
+00             LDRB    R14,[R1],#1             ;Load next byte
+               CMP     R14,#':'                ;Is it a tag separator?
+               MOVEQ   R0,R1                   ;Yes -- return this string
+               CMPNE   R14,#0                  ;Or is it the end?
+               BNE     %b00                    ;No -- keep on going then
+
+               LDMFD   R13!,{R1-R6,R12,PC}^    ;Return to caller with that
+
+               LTORG
+
+; --- msgs_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the message system.
+
+               EXPORT  msgs_init
+msgs_init      ROUT
+
+               STMFD   R13!,{R0-R5,R12,R14}    ;Stack some registers
+               WSPACE  msgs__wSpace            ;Get workspace (silly billy)
+
+               ; --- Return if we are already initialised ---
+
+               LDR     R0,msgs__flags          ;Are we initialised
+               TST     R0,#msFlag__inited      ;Test the bit
+               LDMNEFD R13!,{R0-R5,R12,PC}^    ;Yes -- return
+
+               ORR     R0,R0,#msFlag__inited   ;Set the initialised bit
+               STR     R0,msgs__flags          ;Store the flags back
+
+               ; --- Initialise properly ---
+
+               LDR     R0,[R13]                ;Get the app name
+               BL      res_init
+
+               ; --- Set up fallback position ---
+
+               MOV     R0,#rsType_message      ;Find message resource
+               BL      resources_find          ;Find the resource please
+               MOVCC   R0,#0                   ;Not there -- remember this
+               MOVCC   R1,#0                   ;We get base and limit
+               ADR     R14,msgs__global        ;Find the global block
+               STMIA   R14,{R0,R1}             ;Store them away nicely
+
+               ; --- Load messages file ---
+
+               MOV     R14,#0                  ;Clear the messages list
+               STR     R14,msgs__list          ;Store that over now
+
+               SUB     R13,R13,#16             ;Make some space available
+               MOV     R0,R13                  ;Point at this buffer
+               BL      res_country             ;Read the country name
+               BL      %10msgs_init            ;Try to load that file
+               ADRCC   R0,msgs__ukName         ;Failed -- try UK in case
+               BLCC    %10msgs_init            ;Try that quickly too
+               ADRCC   R0,msgs__fileName       ;Failed -- use normal name
+               BLCC    %10msgs_init            ;Try that quickly too
+               ADD     R13,R13,#16             ;Restore my buffer now
+               LDMFD   R13!,{R0-R5,R12,PC}^
+
+               ; --- Look up a name, and load if it is a file ---
+
+10msgs_init    STMFD   R13!,{R14}              ;Save a register
+               MOV     R1,R11                  ;Point to a buffer
+               BL      res_find                ;Try to find the file
+               MOV     R1,R0                   ;Point to the name
+               MOV     R0,#17                  ;Read file information
+               SWI     XOS_File                ;Get the info on it
+               MOVVS   R0,#0                   ;If failed, say not there
+               CMN     R0,#0                   ;Clear V flag and others
+               MOVS    R0,R0,LSR #1            ;Is it a file?
+               MOV     R0,R1                   ;Point to the name again
+               BLCS    msgs_load               ;If able, load the file
+               SWIVS   OS_GenerateError        ;If failed, be unhappy
+               LDMFD   R13!,{PC}               ;And return C state
+
+msgs__fileName DCB     "Messages",0
+msgs__ukName   DCB     "UK",0
+
+               LTORG
+
+msgs__wSpace   DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+msgs__wStart   #       0
+
+msgs__flags    #       4                       ;Flags word
+msgs__list     #       4                       ;Linked list of messages
+msgs__global   #       8                       ;Shared resource messages
+
+msgs__wSize    EQU     {VAR}-msgs__wStart
+
+msFlag__inited EQU     (1<<0)                  ;Has been initialised
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     msgs__wSize             ;Workspace size
+               DCD     msgs__wSpace            ;Workspace pointer
+               DCD     256                     ;Scratchpad size
+               DCD     msgs_init               ;Initialisation
+
+;----- That's all folks -----------------------------------------------------
+
+               END
+
+
diff --git a/StraySrc/Libraries/Sapphire/s/nopoll b/StraySrc/Libraries/Sapphire/s/nopoll
new file mode 100644 (file)
index 0000000..cda131e
--- /dev/null
@@ -0,0 +1,434 @@
+;
+; nopoll.s
+;
+; Handling nonpolling dialogue boxes (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Some notes before we start -------------------------------------------
+;
+; This is utterly different to the STEEL nopoll.  It nabs a prehandler, and
+; then uses it to direct fake events at the nonpolling window, which it then
+; can pick up and do whatever it wants with.  Fake events generated so far:
+;
+;   Click -- for any click on an icon
+;   Key -- for *only* Escape and Return -- we can't risk people using
+;      Wimp_ProcessKey or strange caret-moving calls
+;   Redraw -- when the thing gets opened, we fake a redraw for it, so that
+;      it gets painted nicely on the screen
+;
+; Basically, you get much more control over the dialogue box than you would
+; with STEEL, but at the small price of a little more responsibility for
+; what actually happens.  So your nonpolling dialogue boxes can be that much
+; cleverer!
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:defHandler
+               GET     sapphire:event
+               GET     sapphire:hour
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- nopoll_open ---
+;
+; On entry:    R0 == a window handle to take over
+;
+; On exit:     --
+;
+; Use:         Sets up the window with the given handle to be a nonpolling
+;              dialogue box.  The window must already be open on the screen.
+;              This call will force it to be painted on the screen, and
+;              then start faking events for it.
+
+               EXPORT  nopoll_open
+nopoll_open    ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  nopoll__wSpace          ;Load my workspace pointer
+
+               ; --- Make sure there's only one window ---
+
+               LDR     R14,nopoll__window      ;Load the nonpolling window
+               CMP     R14,#0                  ;Is it nonzero?
+               LDMNEFD R13!,{R12,PC}^          ;Yes -- ignore the new one
+
+               ; --- Remember this window handle ---
+
+               STR     R0,nopoll__window       ;Store this handle away
+               LDR     R14,nopoll__flags       ;Load my flags word
+               ORR     R14,R14,#npFlag__redraw ;Window needs painting
+               STR     R14,nopoll__flags       ;Store flags away again
+               TST     R0,#1<<31               ;Is the top bit set?
+               LDMNEFD R13!,{R12,PC}^          ;Yes -- do nothing else
+
+               ; --- Now read the initial mouse state ---
+
+               STMFD   R13!,{R0-R6}            ;Save some more registers
+               SWI     OS_Mouse                ;Read the mouse position
+               STR     R2,nopoll__buttons      ;Store the button state away
+
+               ; --- Read the window position ---
+
+               LDR     R0,[R13,#0]             ;Reread the window handle
+               SUB     R13,R13,#36             ;Make space for window blk
+               STR     R0,[R13,#0]             ;Store handle in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window information
+
+               ; --- Remember the origin position ---
+
+               LDMIB   R13,{R1-R6}             ;Load the coordinates out
+               SUB     R5,R1,R5                ;Get the x origin position
+               SUB     R6,R4,R6                ;Get the y origin position
+               ADR     R14,nopoll__ox          ;Point to the origin cache
+               STMIA   R14,{R5,R6}             ;Store these values away
+
+               ; --- Constrain the mouse ---
+
+               BL      screen_getInfo          ;Get the screen information
+               ADD     R0,R0,#screen_dx        ;Point to the pixel sizes
+               LDMIA   R0,{R5,R6}              ;Load the pixel sizes
+               SUB     R1,R1,R5                ;Knock a pixel off the left
+               SUB     R2,R2,R6                ;And off the bottom
+
+               ; --- Build the constrain block ---
+               ;
+               ; We build the parameter block in registers using lots of
+               ; barrel shifting and then stuff it in the stack.  This is
+               ; much quicker and also takes less space.  We assume that
+               ; all the coordinates are two bytes wide already.
+
+               MOV     R0,#1                   ;Subreason code
+               ORR     R0,R0,R1,LSL #8         ;Move in left hand side
+               ORR     R0,R0,R2,LSL #24        ;Move in the bottom byte
+               MOV     R1,R2,LSR #8            ;Get top byte of bottom edge
+               ORR     R1,R1,R3,LSL #8         ;Get right hand side in
+               ORR     R1,R1,R4,LSL #24        ;Get bottom byte of top edge
+               MOV     R2,R4,LSR #8            ;And the top byte of top edge
+               STMFD   R13!,{R0-R2}            ;Save them on the stack
+               MOV     R0,#21                  ;OS_Word mouse operations
+               MOV     R1,R13                  ;Point to the block
+               SWI     XOS_Word                ;Perform the constrain
+
+               ADD     R13,R13,#48             ;Return the block nicely
+               LDMFD   R13!,{R0-R6,R12,PC}^    ;Return to caller now
+
+               LTORG
+
+; --- nopoll_close ---
+;
+; On entry:    R0 == return value for nopoll_process (can be anything)
+;
+; On exit:     --
+;
+; Use:         Tells nopoll that the nonpolling window has been killed,
+;              and hence that polling can return to normal again.  You can
+;              specify a return value to give from nopoll_process (if that
+;              system is being used).
+
+               EXPORT  nopoll_close
+nopoll_close   ROUT
+
+               STMFD   R13!,{R0-R4,R12,R14}    ;Save some registers
+               WSPACE  nopoll__wSpace          ;Find my workspace
+               STR     R0,nopoll__return       ;Save the return value away
+
+               ; --- Clear the window handle ---
+
+               LDR     R0,nopoll__window       ;Load the old window
+               MOV     R14,#0                  ;No nonpolling window
+               STR     R14,nopoll__window      ;Store it over the window
+               TST     R0,#1<<31               ;Is the top bit set?
+               LDMNEFD R13!,{R0-R4,R12,PC}^    ;Yes -- do nothing else then
+
+               ; --- Now release the mouse pointer ---
+
+               BL      screen_getInfo          ;Read the screen information
+               ADD     R0,R0,#screen_width     ;Point to the right bit
+               LDMIA   R0,{R1-R4}              ;Load screen and pixel sizes
+               SUB     R3,R1,R3                ;Reduce screen width by 1
+               SUB     R4,R2,R4                ;Reduce screen height by 1
+
+               MOV     R0,#&00000001           ;Bottom word for constrain
+               MOV     R1,R3,LSL #8            ;Shift the width word in
+               ORR     R1,R1,R4,LSL #24        ;Move bottom byte of width in
+               MOV     R2,R4,LSR #8            ;And get top byte in R2
+               STMFD   R13!,{R0-R2}            ;Create the block on stack
+               MOV     R1,R13                  ;Point to the block
+               MOV     R0,#21                  ;Reason code
+               SWI     XOS_Word                ;Do the constraining
+
+               ADD     R13,R13,#12             ;Skip past the OS_Word block
+               LDMFD   R13!,{R0-R4,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- nopoll_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises nopoll so it can be used.
+
+               EXPORT  nopoll_init
+nopoll_init    ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers
+
+               ; --- Make sure I'm not already going ---
+
+               WSPACE  nopoll__wSpace          ;Load my workspace pointer
+               LDR     R14,nopoll__flags       ;Load my flags word
+               TST     R14,#npFlag__inited     ;Am I initialised yet?
+               MOV     R0,#0                   ;Zero window handle
+               STR     R0,nopoll__window       ;No nonpolling window yet
+               LDMNEFD R13!,{R0,R1,R12,PC}^    ;Yes -- return right now
+
+               ; --- Register my prefilter nicely ---
+
+               BL      event_init              ;Initialise the event system
+               ADR     R0,nopoll__filter       ;Point to my filter routine
+               MOV     R1,R12                  ;Pass my workspace pointer
+               BL      event_preFilter ;Register the prefilter
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to caller
+
+nopoll__wSpace DCD     0
+
+               LTORG
+
+; --- nopoll__filter ---
+;
+; On entry:    R0 == an event mask
+;              R1 == pointer to event block
+;              R2 == earliest time to return with null event
+;              R3 == pointer to poll word if any
+;
+; On exit:     Carry clear and registers preserved, or carry set and:
+;
+;              R0 == WIMP event code
+;              R1 preserved, block updated
+;
+; Use:         Generates WIMP-like events from the nonpolling window.
+
+nopoll__filter ROUT
+
+               ; --- Pass on quickly if nothing to do ---
+
+               STMFD   R13!,{R14}              ;Just save the link register
+               LDR     R14,nopoll__window      ;Is there a nonpolling window
+               CMP     R14,#0                  ;Just check it's nonzero
+               LDMEQFD R13!,{PC}^              ;No -- return right now
+
+               ; --- Now dispatch redraw events if necessary ---
+
+               STMFD   R13!,{R10}              ;Save another register
+               BIC     R10,R14,#1<<31          ;Look after the window handle
+               LDR     R14,nopoll__flags       ;Load my flags word
+               TST     R14,#npFlag__redraw     ;Do I have to fake a redraw?
+               BEQ     %00nopoll__filter       ;No -- skip ahead
+
+               BIC     R14,R14,#npFlag__redraw ;Clear the flag
+               STR     R14,nopoll__flags       ;Store the new flags word
+               MOV     R0,#1                   ;Pass a redraw reason code
+               STR     R10,[R1,#0]             ;Store window handle in block
+               LDMFD   R13!,{R10,R14}          ;Load the registers back
+               ORRS    PC,R14,#C_flag          ;Return the fake event
+
+               ; --- Find out if a key was pressed ---
+
+00             STMFD   R13!,{R1-R7}            ;Save some more registers
+
+               SUB     R13,R13,#8              ;Make space for hourglass blk
+               MOV     R0,R13                  ;Point to the block
+               BL      hour_suspend            ;Turn hourglass off a while
+
+01             MOV     R0,#&81                 ;Read keyboard status
+               MOV     R1,#0                   ;No delay on key reading
+               MOV     R2,#0                   ;No delay on key reading
+               SWI     OS_Byte                 ;Read the key value
+               CMP     R1,#&0D                 ;Was Return pressed?
+               CMPNE   R1,#&1B                 ;Or was it Escape?
+               BNE     %10nopoll__filter       ;No -- handle mouse buttons
+
+               ; --- Build a dummy caret record in the block ---
+
+               MOV     R0,R13                  ;Point to hourglass block
+               BL      hour_resume             ;Restore old hourglass state
+               ADD     R13,R13,#8              ;And restore the stack ptr
+
+               MOV     R0,R1
+               LDMFD   R13!,{R1}               ;Restore the Wimp block ptr
+               STR     R10,[R1,#0]             ;Store window handle away
+               STR     R0,[R1,#24]             ;Save the key number too
+                                               ;Don't bother with the rest
+               MOV     R0,#8                   ;Fake a key event
+               LDMFD   R13!,{R2-R7,R10,R14}    ;Restore registers
+               ORRS    PC,R14,#C_flag          ;And fake the event
+
+               ; --- Read the mouse status ---
+
+10             SWI     OS_Mouse                ;Read the mouse status
+               LDR     R14,nopoll__buttons     ;Read the old button state
+               STR     R2,nopoll__buttons      ;Store new button state
+               BIC     R2,R2,R14               ;Leave only newly clicked
+               BICS    R2,R2,#2                ;And clear the menu button
+               BEQ     %01nopoll__filter       ;If nothing clicked, loop
+
+               LDR     R4,[R13,#8]             ;Load the Wimp block pointer
+               STMIA   R4,{R0-R2,R10,R12,R14}  ;Save the registers away
+
+               ; --- Now find which icon got clicked ---
+
+               ADR     R14,nopoll__ox          ;Point to the origin coords
+               LDMIA   R14,{R6,R7}             ;Load them into registers
+               SUB     R6,R0,R6                ;Convert mouse coords to...
+               SUB     R7,R1,R7                ;... window-relative ones
+               SUB     R13,R13,#40             ;Create an icon block
+               STR     R10,[R13,#0]            ;Save the window handle in it
+               MOV     R10,#-1                 ;No icons found yet
+               MOV     R5,#0                   ;Start searching from icon 0
+
+               ; --- Loop through the icons nicely now ---
+
+20             STR     R5,[R13,#4]             ;Store it in the block
+               MOV     R1,R13                  ;Point to my icon block
+               SWI     Wimp_GetIconState       ;Get the icon information
+               LDR     R14,[R13,#24]           ;Load the icon flags out
+               CMP     R14,#&00800000          ;Is it deleted-only?
+               BEQ     %30nopoll__filter       ;Yes -- we've scanned 'em all
+               EOR     R14,R14,#&00DF0000      ;Toggle deleted, shaded, ESG
+               TST     R14,#&00800000          ;Is it deleted?
+               TSTNE   R14,#&00400000          ;Is it shaded?
+               TSTNE   R14,#&001F0000          ;Or is the ESG all 1s?
+               ADDEQ   R5,R5,#1                ;Check the next icon along
+               BEQ     %20nopoll__filter       ;Yes -- skip this icon
+
+               ADD     R1,R13,#8               ;Point to icon coordinates
+               LDMIA   R1,{R0-R3}              ;Load the icon coordinates
+               CMP     R0,R6
+               CMPLE   R1,R7
+               CMPLE   R6,R2
+               CMPLT   R7,R3
+               MOVLT   R10,R5                  ;If over icon, remember no.
+
+               ADD     R5,R5,#1                ;Check the next icon along
+               B       %20nopoll__filter       ;And carry on
+
+               ; --- Return a fake mouse click event ---
+
+30             ADD     R13,R13,#40             ;Recover the icon block
+               MOV     R0,R13                  ;Point to hourglass block
+               BL      hour_resume             ;Restore hourglass state
+               ADD     R13,R13,#8              ;And restore stack block
+               STR     R10,[R4,#16]            ;Store the icon number away
+               MOV     R0,#6                   ;Fake a mouse click event
+               LDMFD   R13!,{R1-R7,R10,R14}    ;Restore loads of registers
+               ORRS    PC,R14,#C_flag          ;Return to caller at last
+
+               LTORG
+
+; --- nopoll_process ---
+;
+; On entry:    --
+;
+; On exit:     R0 == value passed to nopoll_close
+;
+; Use:         Processes a nonpolling window until it calls nopoll_close.
+;              It then returns the value passed to nopoll_close in R0,
+;              which can be defined in any way you want.
+;
+;              Some notes on the use of this routine:
+;
+;              * It calls event_poll, so any functions that get called
+;                after the normal event_poll don't get called.  Since the
+;                Wimp isn't actually being polled at all, this isn't a
+;                real problem as long as your handlers are registered at the
+;                event filter level or higher (e.g. win event handlers or
+;                even dbox handlers).
+;
+;              * It uses up an extra 256 bytes of stack for a poll block.
+;                If you think you might miss this stack space, then you'd
+;                better not use this routine.
+;
+;              * It isn't reentrant, but then again, nor is the rest of the
+;                nopoll system -- you can only have one nonpolling box open
+;                at a time.
+
+               EXPORT  nopoll_process
+nopoll_process ROUT
+
+               STMFD   R13!,{R1-R3,R12,R14}    ;Save some registers
+               WSPACE  nopoll__wSpace          ;Locate my workspace
+               SUB     R13,R13,#256            ;Make a poll block (!)
+
+00             LDR     R14,nopoll__window      ;Is there a nonpolling window
+               CMP     R14,#0                  ;Quick check...
+               BEQ     %10nopoll_process       ;No -- jump ahead then
+               MOV     R1,R13                  ;Point to the poll block
+               BL      event_poll              ;Get a dodgy event back
+               BLCC    defHandler              ;If not handled, handle it
+               B       %00nopoll_process       ;And loop back again
+
+10             LDR     R0,nopoll__return       ;Load the return value
+               ADD     R13,R13,#256            ;Restore the stack pointer
+               LDMFD   R13!,{R1-R3,R12,PC}^    ;Return to caller again
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+nopoll__wStart #       0
+
+nopoll__flags  #       4                       ;Various interesting flags
+nopoll__window #       4                       ;The nonpolling window handle
+nopoll__buttons        #       4                       ;Button state for icons
+nopoll__ox     #       4                       ;Window origin x position
+nopoll__oy     #       4                       ;Window origin y position
+nopoll__return #       4                       ;nopoll_process return value
+
+nopoll__wSize  EQU     {VAR}-nopoll__wStart    ;My workspace size
+
+npFlag__inited EQU     (1<<0)                  ;Am I initialised yet?
+npFlag__redraw EQU     (1<<1)                  ;Does window need redrawing?
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     nopoll__wSize
+               DCD     nopoll__wSpace
+               DCD     0
+               DCD     nopoll_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/note b/StraySrc/Libraries/Sapphire/s/note
new file mode 100644 (file)
index 0000000..70c5ef0
--- /dev/null
@@ -0,0 +1,147 @@
+;
+; note.s
+;
+; Handling of a Note box (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:errorBox
+               GET     sapphire:msgs
+               GET     sapphire:nopoll
+               GET     sapphire:sapphire
+               GET     sapphire:string
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- note ---
+;
+; On entry:    R0 == pointer to a piece of text to display
+;
+; On exit:     --
+;
+; Use:         Displays some text in a small window.
+
+               EXPORT  note
+note           ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               ADR     R0,note__dbName         ;Point to the dialogue name
+               BL      dbox_create             ;Create the dialogue box
+               BVS     %90note                 ;If it failed, skip ahead
+               MOV     R4,R0                   ;Look after the handle
+
+               ; --- Set up the window title bar ---
+
+               BL      sapphire_appName        ;Get the application's name
+               MOV     R2,R0                   ;Put it in another register
+               BL      str_buffer              ;Point to a buffer
+               ADR     R0,note__from           ;Point to title skeleton
+               BL      msgs_lookup             ;Translate the message
+               BL      str_subst               ;Fill in the string nicely
+               MOV     R2,R0                   ;Point to the title string
+               MOV     R1,#-1                  ;Set the window title
+               MOV     R0,R4                   ;Get the dialogue handle
+               BL      dbox_setField           ;Fill in the window title
+
+               ; --- Set up the other bits of the dialogue ---
+
+               LDR     R2,[R13,#0]             ;Get the caller's string
+               MOV     R1,#nIcon__text         ;Get the icon handle
+               BL      dbox_setField           ;Fill in the icon nicely
+               MOV     R1,#nIcon__title        ;Get the pseudotitle icon
+               BL      dbox_setEmbeddedTitle   ;Write the title string here
+               ADR     R1,note__handler        ;Point to my handler routine
+               MOV     R2,R0                   ;Pass dialogue handle in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      dbox_eventHandler       ;Register my event handler
+
+               ; --- Display the dialogue box ---
+
+               MOV     R1,#dbOpen_pointer+dbOpen_persist+dbOpen_nonSub
+               BL      dbox_open               ;Open the dialogue box
+               BL      dbox_window             ;Get the dialogue's window
+               BL      nopoll_open             ;Let nopoll take over now
+               BL      nopoll_process          ;Wait until it's over
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               ; --- Not enough memory or something ---
+               ;
+               ; We display the message in an error box and put up with it.
+
+90note         LDR     R0,[R13,#0]             ;Get the caller's string
+               SUB     R0,R0,#4                ;Make a fake error number
+               MOV     R1,#1                   ;Just an OK button please
+               BL      errorBox                ;Display the error message
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+note__dbName   DCB     "note",0
+note__from     DCB     "noteFROM",0
+
+               LTORG
+
+; --- note__handler ---
+;
+; On entry:    R0 == dialogue event code
+;              R1-R9 == something weird
+;
+; On exit:     --
+;
+; Use:         Handles events for note dialogue boxes
+
+note__handler  ROUT
+
+               CMP     R0,#dbEvent_OK          ;Is it a return keypress?
+               CMPNE   R0,#dbEvent_cancel      ;Or an escape keypress?
+               CMPNE   R0,#nIcon__ok           ;Or a click on OK?
+               MOVNES  PC,R14                  ;None of these -- return
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               MOV     R0,R10                  ;Get the dialogue handle
+               MOV     R1,#nIcon__ok           ;Get the OK icon number
+               BL      dbox_slab               ;Slab the button in
+               BL      dbox_close              ;Close the window
+               BL      dbox_unslab             ;Unslab the button quietlike
+               BL      nopoll_close            ;Stop nopoll being silly
+               BL      dbox_destroy            ;Zap the dialogue box
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller happy
+
+               LTORG
+
+;----- Icon numbers ---------------------------------------------------------
+
+nIcon__text    EQU     0
+nIcon__ok      EQU     1
+nIcon__title   EQU     2
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/pane b/StraySrc/Libraries/Sapphire/s/pane
new file mode 100644 (file)
index 0000000..8851b22
--- /dev/null
@@ -0,0 +1,590 @@
+;
+; pane.s
+;
+; Pane handling facilities (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:event
+               GET     sapphire:screen
+               GET     sapphire:sapphire
+               GET     sapphire:suballoc
+               GET     sapphire:tspr
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- pane_add ---
+;
+; On entry:    R0 == window handle of parent window
+;              R1 == icon handle in parent window
+;              R2 == window handle of pane window
+;
+; On exit:     May return an error
+;
+; Use:         This call registers a pane to be associated with the given
+;              window. The pane is always opened to fit exactly within
+;              the given icon -- border widths are taken into account
+;              if there are scroll bars etc.
+;
+;              You must call pane_closed if the parent window is closed,
+;              since there is no way for pane to trap this occurence.
+
+               EXPORT  pane_add
+pane_add       ROUT
+
+               STMFD   R13!,{R0-R4,R12,R14}    ;Stack some registers
+               WSPACE  pane__wSpace            ;Locate my workspace
+
+               ; --- First, we must scan to see if the parent
+               ;     window is already registered
+
+               MOV     R4,R0                   ;Preserve parent handle
+               BL      pane__windowBlock       ;Find the window block
+               CMP     R0,#0                   ;Is there one?
+               MOVNE   R3,R0                   ;Yes -- point to it
+               BNE     %50pane_add             ;And add in the pane
+
+               ; --- The window isn't registered ---
+
+10             MOV     R0,#wl__size            ;Allocate this much memory
+               BL      sub_alloc               ;Get it then
+               SWIVS   OS_GenerateError        ;...and generate error
+               LDR     R3,ws__wList            ;Load first window defn
+               STR     R3,[R0,#wl__next]       ;Store as next pointer
+               CMP     R3,#0                   ;Is there any more?
+               STRNE   R0,[R3,#wl__prev]       ;Yes -- update prev pointer
+               MOV     R3,#0                   ;A NULL pointer
+               STR     R3,[R0,#wl__prev]       ;No previous for new block
+               STR     R3,[R0,#wl__pList]      ;No pane list yet
+               MOV     R3,R0                   ;Put pointer in R3
+               STR     R4,[R3,#wl__wHandle]    ;Store parent window handle
+               STR     R3,ws__wList            ;Store at list head
+
+               ; --- R3 points to the window list block ---
+
+50             MOV     R0,#pl__size            ;Allocate this much memory
+               BL      sub_alloc               ;Go on then
+               SWIVS   OS_GenerateError        ;...and generate error
+               LDR     R4,[R3,#wl__pList]      ;Load first pane defn
+               STR     R4,[R0,#pl__next]       ;Store as next pointer
+               CMP     R4,#0                   ;Is there any more?
+               STRNE   R0,[R4,#pl__prev]       ;Yes -- update prev pointer
+               MOV     R14,#0                  ;A NULL pointer
+               STR     R14,[R0,#pl__prev]      ;No previous for new block
+               STR     R1,[R0,#pl__iHandle]    ;Store the icon handle
+               STR     R2,[R0,#pl__wHandle]    ;Store the window handle
+               STR     R0,[R3,#wl__pList]      ;Store at list head
+
+               ; --- Return to caller ---
+
+               LDMFD   R13!,{R0-R4,R12,PC}^    ;Return
+
+               LTORG
+
+; --- pane_remove ---
+;
+; On entry:    R0 == window handle for which pane was registered
+;              R1 == window handle of the pane window itself
+;
+; On exit:     --
+;
+; Use:         Removes the pane from the given window. This call will
+;              close the given pane, but will not actually delete it
+;              (ie. with a Wimp_DeleteWindow).
+
+               EXPORT  pane_remove
+pane_remove    ROUT
+
+               STMFD   R13!,{R0-R5,R12,R14}    ;Stack some registers
+               WSPACE  pane__wSpace            ;Locate my workspace
+
+               BL      pane__windowBlock       ;Find the window block
+               CMP     R0,#0                   ;Is there one?
+               BEQ     %90pane_remove          ;No -- remove
+               MOV     R3,R0                   ;Put pointer in R3
+
+               ; --- Remove the pane from the window list ---
+
+50             LDR     R4,[R3,#wl__pList]      ;Get the first entry
+55             CMP     R4,#0                   ;Is there a pane definition?
+               BEQ     %90pane_remove          ;No -- return
+               LDR     R5,[R4,#pl__wHandle]    ;Get the pane handle
+               CMP     R5,R1                   ;Is this the one we want
+               LDRNE   R4,[R4,#wl__next]       ;No -- get next in list
+               BNE     %55pane_remove          ;...and keep looking
+
+               ; --- We have now found the pane block ---
+
+               ADD     R1,R4,#pl__wHandle      ;Point to the window handle
+               SWI     XWimp_CloseWindow       ;Close the window
+               LDR     R1,[R4,#pl__prev]       ;Get the previous pointer
+               LDR     R2,[R4,#pl__next]       ;And the next pointer
+               CMP     R2,#0                   ;Is there a next field?
+               STRNE   R1,[R2,#pl__prev]       ;Yes -- update previous
+               CMP     R1,#0                   ;Is there a previous field
+               STRNE   R2,[R1,#pl__next]       ;Yes -- update next field
+               STREQ   R2,[R3,#wl__pList]      ;No -- store next as head
+
+               MOV     R0,R4                   ;Point to the block
+               MOV     R1,#pl__size            ;It's this big
+               BL      sub_free                ;Free the block
+               LDR     R1,[R3,#wl__pList]      ;Get the pane list
+               CMP     R1,#0                   ;Is there one?
+               MOVEQ   R0,R3                   ;No -- point to window block
+               BLEQ    pane__removeWindow      ;...remove the definition
+
+               ; --- Return to caller ---
+
+90             LDMFD   R13!,{R0-R5,R12,PC}^    ;Return
+
+               LTORG
+
+; --- pane__removeWindow ---
+;
+; On entry:    R0 == pointer to window block
+;
+; On exit:     --
+;
+; Use:         Removes the give window block from the list. All associated
+;              panes are removed too.
+
+pane__removeWindow ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+
+               MOV     R3,R0                   ;Keep a pointer to this block
+               LDR     R2,[R3,#wl__pList]      ;Get the first pane block
+               CMP     R2,#0                   ;Is there one?
+               BEQ     %10pane__removeWindow   ;No -- free window block
+00             ADD     R1,R2,#pl__wHandle      ;Point to the window handle
+               MOV     R14,R2                  ;Get block pointer in R14
+               LDR     R2,[R2,#pl__next]       ;Get next pointer
+               SWI     XWimp_CloseWindow       ;Close the window
+               MOV     R0,R14                  ;Block pointer in R0
+               MOV     R1,#pl__size            ;It's this big
+               BL      sub_free                ;Free the block
+               CMP     R2,#0                   ;Are there more blocks?
+               BNE     %00pane__removeWindow   ;Yes -- remove next pane too
+
+               ; --- Remove the window block ---
+
+10             LDR     R1,[R3,#wl__prev]       ;Get the previous pointer
+               LDR     R2,[R3,#wl__next]       ;And the next pointer
+               CMP     R2,#0                   ;Is there a next field?
+               STRNE   R1,[R2,#wl__prev]       ;Yes -- update previous
+               CMP     R1,#0                   ;Is there a previous field
+               STRNE   R2,[R1,#wl__next]       ;Yes -- update next field
+               STREQ   R2,ws__wList            ;No -- store next as head
+               MOV     R0,R3                   ;Point to the block
+               MOV     R1,#wl__size            ;It's this big
+               BL      sub_free                ;And free it
+
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- pane_closed ---
+;
+; On entry:    R0 == window handle of parent
+;
+; On exit:     --
+;
+; Use:         Informs pane that a parent window has closed.
+;              All associated panes are then closed.
+
+               EXPORT  pane_closed
+pane_closed    ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Stacks some registers
+               WSPACE  pane__wSpace            ;Locate workspace
+
+               BL      pane__windowBlock       ;Find the block
+               CMP     R0,#0                   ;Is there one?
+               BEQ     %90pane_closed          ;No -- return
+
+               LDR     R2,[R0,#wl__pList]      ;Get the first pane pointer
+00pane_closed  ADD     R1,R2,#pl__wHandle      ;Point to the window handle
+               SWI     XWimp_CloseWindow       ;Close the window
+               LDR     R2,[R2,#pl__next]       ;Get the next pane
+               CMP     R2,#0                   ;Is there one?
+               BNE     %00pane_closed          ;Yes -- close it then
+
+90pane_closed  LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- pane_deleted ---
+;
+; On entry:    R0 == window handle of parent
+;
+; On exit:     --
+;
+; Use:         Informs pane that a parent window has been deleted.
+;              All associated panes are then closed, and there
+;              registration with the pane library module is
+;              terminated.
+
+               EXPORT  pane_deleted
+pane_deleted   ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Stacks some registers
+               WSPACE  pane__wSpace            ;Locate workspace
+
+               BL      pane__windowBlock       ;Find the block
+               CMP     R0,#0                   ;Is there one?
+               BLNE    pane__removeWindow      ;Yes -- remove definitions
+
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- pane__windowBlock ---
+;
+; On entry:    R0 == window handle
+;
+; On exit:     R0 == pointer to window block
+;
+; Use:         Find the window block associated with the given
+;              window handle. If it is not found, 0 is returned.
+
+pane__windowBlock ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stack some registers
+
+               MOV     R1,R0                   ;Keep the window handle
+               LDR     R0,ws__wList            ;Load first window defn
+00             CMP     R0,#0                   ;Is there one?
+               BEQ     %90pane__windowBlock    ;No -- return
+               LDR     R2,[R0,#wl__wHandle]    ;Get the window handle
+               CMP     R2,R1                   ;Is this the one we want?
+               BEQ     %90pane__windowBlock    ;Yes -- return
+               LDR     R0,[R0,#wl__next]       ;Get the next in list
+               B       %00pane__windowBlock    ;And keep looking
+
+90             LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- pane_swap ---
+;
+; On entry:    R0 == window handle of parent window
+;              R1 == icon handle within parent window
+;              R2 == window handle of new pane
+;
+; On exit:     --
+;
+; Use:         This call will replace the pane in associated with icon R1
+;              in window R0, with the pane in R2.
+;
+;              The exisiting pane is closed, and the new pane is
+;              opened in it's place. No error is generated if the existing
+;              pane does not exist; this allows the caller to delete the
+;              window before doing the swap.
+
+               EXPORT  pane_swap
+pane_swap      ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Stack some registers
+               WSPACE  pane__wSpace            ;Locate my workspace
+
+               BL      pane__windowBlock       ;Find the window block
+               CMP     R0,#0                   ;Is there one?
+               BEQ     %90pane_swap            ;No -- return
+
+               ; --- Find the pane in the pane window list ---
+
+               LDR     R3,[R0,#wl__pList]      ;Get the first entry
+00             CMP     R3,#0                   ;Is there a pane definition?
+               BEQ     %90pane_swap            ;No -- return
+               LDR     R14,[R3,#pl__iHandle]   ;Get the icon handle
+               CMP     R14,R1                  ;Is this the one we want
+               LDRNE   R3,[R3,#wl__next]       ;No -- get next in list
+               BNE     %00pane_swap            ;...and keep looking
+
+               ; --- Do the swap ---
+
+               MOV     R14,R0                  ;Preserve R0
+               ADD     R1,R3,#pl__wHandle      ;Point to the window handle
+               SWI     XWimp_CloseWindow       ;Close it
+               STR     R2,[R3,#pl__wHandle]    ;Store the new window handle
+               SUB     R13,R13,#36             ;Get a block
+               LDR     R0,[R14,#wl__wHandle]   ;Get parent handle
+               STR     R0,[R13,#0]             ;Store it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window state
+               MOV     R2,R1                   ;Put state in R2
+               MOV     R0,R14                  ;The window block
+               MOV     R1,R3                   ;Point to the pane block
+               MOV     R3,R2                   ;Now put state in R3
+               BL      pane__open              ;Open the new pane
+               ADD     R13,R13,#36             ;Reclaim my stack
+
+90pane_swap    LDMFD   R13!,{R0-R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- pane_open ---
+;
+; On entry:    R0 == window handle
+;
+; On exit:     --
+;
+; Use:         Opens all the panes associated with the given window.
+
+               EXPORT  pane_open
+pane_open      ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Stack some registers
+               WSPACE  pane__wSpace            ;Load my workspace pointer
+
+               BL      pane__windowBlock       ;Find the window block
+               CMP     R0,#0                   ;Is there one?
+               BEQ     %90pane_open            ;No -- return
+
+               ; --- Find the pane in the pane window list ---
+
+               SUB     R13,R13,#36             ;Get a block
+               LDR     R14,[R0,#wl__wHandle]   ;Get the window handle
+               STR     R14,[R13,#0]            ;Store in the block
+               MOV     R1,R13                  ;Point to the block
+               MOV     R2,R0                   ;Preserve R0
+               SWI     Wimp_GetWindowState     ;Get the window state
+               MOV     R0,R2                   ;Get R0 back
+               MOV     R3,R1                   ;Put state in R3
+
+               LDR     R1,[R0,#wl__pList]      ;Get the first entry
+00pane_open    BL      pane__open              ;Open the pane
+               LDR     R1,[R1,#pl__next]       ;Get next pane
+               CMP     R1,#0                   ;Is there one?
+               BNE     %00pane_open            ;Yes -- keep looping
+               ADD     R13,R13,#36             ;Get stack back
+
+90pane_open    LDMFD   R13!,{R0-R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- pane__open ---
+;
+; On entry:    R0 == pointer to window block
+;              R1 == pointer to pane block
+;              R3 == pointer to parent window state
+;
+; On exit:     --
+;
+; Use:         Opens the pane in the right place.
+
+pane__open     ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Stack some more registers
+
+               MOV     R4,R0                   ;Preserve window block
+               MOV     R6,R1                   ;Preserve R1
+               BL      screen_justChangedMode  ;Due to a mode change?
+               MOVCS   R1,R3                   ;Point to open window block
+               BLCS    tspr_adjustBox          ;Adjust the box
+
+               LDR     R5,[R3,#28]             ;Get the back value
+               CMP     R5,#-2                  ;Opening at the back?
+               MOVEQ   R1,R3                   ;Yes -- point to the block
+               SWIEQ   Wimp_OpenWindow         ;Open the window
+               SWIEQ   Wimp_GetWindowState     ;Get the window state
+
+               MOV     R2,R6                   ;Get R1 back again
+               SUB     R13,R13,#36             ;Get me a block
+               LDR     R14,[R2,#pl__wHandle]   ;Get pane window handle
+               STR     R14,[R13,#0]            ;Store in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window state
+               LDR     R9,[R13,#32]            ;Load the window's flags
+               SUB     R13,R13,#40             ;Get another block
+               LDR     R14,[R4,#wl__wHandle]   ;Get parent handle
+               STR     R14,[R13,#0]            ;Store the handle
+               LDR     R14,[R2,#pl__iHandle]   ;Get the icon handle
+               STR     R14,[R13,#4]            ;Store that too
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetIconState       ;Get the icon state
+               ADD     R1,R13,#8               ;Point to coordinates
+               LDMIA   R1,{R5-R8}              ;Get the icon coordinates
+               ADD     R13,R13,#40             ;Point at window state
+               LDR     R0,[R3,#4]              ;Visible area x0 coord
+               LDR     R1,[R3,#16]             ;Visible area y1 coord
+               ADD     R5,R0,R5                ;Make icon coords screen rel.
+               ADD     R6,R1,R6
+               ADD     R7,R0,R7
+               ADD     R8,R1,R8
+
+               STMFD   R13!,{R2-R4}            ;Preserve registers
+               BL      screen_getInfo          ;Get screen information
+               ADD     R0,R0,#screen_dx        ;Point to the pixel sizes
+               LDMIA   R0,{R3,R4}              ;Load the pixel sizes
+               BL      tspr_borderWidths       ;Get the border widths
+               TST     R9,#&0f000000           ;Is there a title bar?
+               SUBNE   R8,R8,R0                ;Yes -- correct y1 coord
+               SUBEQ   R8,R8,R4                ;No -- subtract pixel size
+               TST     R9,#&10000000           ;Is there a vertical bar?
+               SUBNE   R7,R7,R1                ;Yes -- correct x1 coord
+               SUBEQ   R7,R7,R3                ;No -- subtract pixel size
+               TST     R9,#&40000000           ;Is there a horizontal bar?
+               ADDNE   R6,R6,R2                ;Yes -- correct y0 coord
+               ADDEQ   R6,R6,R4                ;No -- add pixel size
+               ADD     R5,R5,R3                ;Add pixel size to x0
+               LDMFD   R13!,{R2-R4}            ;Get registers back again
+
+10pane__open   STMIB   R13,{R5-R8}             ;Store new coorinates
+               LDR     R5,[R3,#28]             ;Get behind value to use
+               LDR     R6,[R13,#0]             ;And the pane handle
+               CMP     R6,R5                   ;Are they the same?
+               STRNE   R5,[R13,#28]            ;No -- Store it in the block
+               STR     R6,[R3,#28]             ;New behind for parent window
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_OpenWindow         ;Open the pane window
+
+               ADD     R13,R13,#36             ;Reclaim stack
+               LDMFD   R13!,{R0-R9,PC}^        ;Return to caller
+
+               LTORG
+
+; --- pane__fakeHandler ---
+;
+; On entry:    R0 == event type
+;              R1 == event block
+;
+; On exit:     CC
+;
+; Use:         Although this is called as a fake handler, it does not
+;              generate fake event. Instead, it is used to trap
+;              open window event before any handler can claim them. This
+;              allows the panes to be moved automatically.
+
+pane__fakeHandler ROUT
+
+               TEQ     R0,#2                   ;Open window request?
+               MOVNES  PC,R14                  ;No -- return PDQ
+
+               STMFD   R13!,{R0,R14}           ;Stack some registers
+               LDR     R0,[R1,#0]              ;Get the window handle
+               BL      pane__windowBlock       ;Find out if it's registered
+               CMP     R0,#0                   ;Is there a block
+               LDMEQFD R13!,{R0,PC}^           ;No -- return
+
+               ; --- We are moving a window with panes in it ---
+
+               STMFD   R13!,{R1,R3}            ;Stack some more registers
+               MOV     R3,R1                   ;Put window state in R3
+               LDR     R1,[R0,#wl__pList]      ;Get the first pane
+00             BL      pane__open              ;Open the given pane
+
+               ; --- Keep looking for more panes ---
+
+               LDR     R1,[R1,#pl__next]       ;Get the next pane
+               CMP     R1,#0                   ;Is there one?
+               BNE     %00pane__fakeHandler    ;Yes -- move it then
+
+               LDMFD   R13!,{R1,R3}            ;Get back first lot
+               LDMFD   R13!,{R0,PC}^           ;And return
+
+               LTORG
+
+; --- pane_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the pane unit.
+
+               EXPORT  pane_init
+pane_init      ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Stack some registers
+               WSPACE  pane__wSpace            ;Locate my workspace
+
+               ; --- Set up a fake handler ---
+
+               BL      event_init              ;Initialise event
+               ADR     R0,pane__fakeHandler    ;Call this routine
+               MOV     R1,R12                  ;With this R12 value
+               BL      event_fakeHandler       ;Add in the handler
+
+               ; --- Initalise some workspace ---
+
+               MOV     R0,#0                   ;A nice NULL word
+               STR     R0,ws__wList            ;No window list yet
+
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to caller
+
+               LTORG
+
+pane__wSpace   DCD     0
+
+;----- Workspace layout -----------------------------------------------------
+
+; --- Window list ---
+
+               ^       0
+
+wl__next       #       4                       ;The next window in list
+wl__prev       #       4                       ;The previous window in list
+wl__wHandle    #       4                       ;The window handle
+wl__pList      #       4                       ;List of panes
+wl__size       #       0                       ;The size of this structure
+
+; --- Pane list ---
+
+               ^       0
+
+pl__next       #       4                       ;The next pane in the list
+pl__prev       #       4                       ;The previous pane in list
+pl__wHandle    #       4                       ;The window handle of pane
+pl__iHandle    #       4                       ;Icon handle in window
+pl__size       #       0                       ;The size of this structure
+
+; --- The workspace ---
+
+               ^       0,R12
+
+ws__start      #       0                       ;Workspace start
+
+ws__wList      #       4                       ;The window list
+
+ws__size       EQU     {VAR}-ws__start         ;Workspace size
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     ws__size                ;Workspace size
+               DCD     pane__wSpace            ;Workspace pointer
+               DCD     0                       ;Scratchpad size
+               DCD     pane_init               ;Initialisation code
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/progInfo b/StraySrc/Libraries/Sapphire/s/progInfo
new file mode 100644 (file)
index 0000000..d447bb2
--- /dev/null
@@ -0,0 +1,107 @@
+;
+; progInfo.s
+;
+; The `About this program' box (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:mbox
+               GET     sapphire:sapphire
+
+;----- Icon numbers ---------------------------------------------------------
+
+piIcon__title  EQU     0
+piIcon__name   EQU     7
+piIcon__purpose        EQU     5
+piIcon__author EQU     3
+piIcon__version        EQU     1
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- progInfo ---
+;
+; On entry:    R0 == pointer to purpose string
+;              R1 == pointer to author string
+;              R2 == pointer to version string
+;
+; On exit:     May return an error
+;
+; Use:         Displays an `About this program' dialogue box on the screen.
+
+               EXPORT  progInfo
+progInfo       ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Create the dialogue box ---
+
+               ADR     R0,pi__dbName           ;Point to the name string
+               BL      dbox_create             ;Create the dialogue box
+               ADDVS   R13,R13,#4              ;If error, don't restore R0
+               LDMVSFD R13!,{R1-R3,PC}         ;Return any errors here
+               MOV     R3,R0                   ;Save the dialogue handle
+
+               ; --- Fill in the various fields ---
+
+               BL      sapphire_appName        ;Find the application's name
+               MOV     R2,R0                   ;Move pointer around nicely
+               MOV     R0,R3                   ;Get the dialogue handle
+               MOV     R1,#piIcon__name        ;The `Name' icon
+               BL      dbox_setField           ;Fill it in
+               LDR     R2,[R13,#0]             ;Get the purpose string
+               MOV     R1,#piIcon__purpose     ;The `Purpose' icon
+               BL      dbox_setField           ;Fill it in
+               LDR     R2,[R13,#4]             ;Get the author string
+               MOV     R1,#piIcon__author      ;The `Author' icon
+               BL      dbox_setField           ;Fill that in too
+               LDR     R2,[R13,#8]             ;Get the version string
+               MOV     R1,#piIcon__version     ;The `Version' icon
+               BL      dbox_setField           ;And fill that one in
+
+               ; --- Display the dialogue box and return ---
+
+               ADR     R1,pi__dbHelp           ;Point to the help string
+               MOV     R2,#piIcon__title       ;The embedded title icon
+               BL      mbox                    ;Handle the dialogue box
+               LDMFD   R13!,{R0-R3,R14}        ;Restore the registers
+               BICS    PC,R14,#V_flag          ;Return without error
+
+pi__dbName     DCB     "progInfo",0
+pi__dbHelp     DCB     "piHELP"
+
+;----- Workspace ------------------------------------------------------------
+;
+; None.
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/ptr b/StraySrc/Libraries/Sapphire/s/ptr
new file mode 100644 (file)
index 0000000..bb42b6c
--- /dev/null
@@ -0,0 +1,663 @@
+;
+; ptr.s
+;
+; Pointer changing and caret blinking (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:event
+               GET     sapphire:except
+               GET     sapphire:idle
+               GET     sapphire:resspr
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+               GET     sapphire:sprite
+               GET     sapphire:string
+               GET     sapphire:wimp
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+;----- Pointer shape changing -----------------------------------------------
+
+; --- ptr_setShape ---
+;
+; On entry:    R0 == sprite name
+;              R1 == x offset of hot spot
+;              R2 == y offset of hot spot
+;
+; On exit:     --
+;
+; Use:         Set the pointer sprite to the given name. The sprite area
+;              used is that returned from resspre_area.
+
+               EXPORT  ptr_setShape
+ptr_setShape   ROUT
+
+               STMFD   R13!,{R0-R7,R12,R14}    ;Stack some registers
+               WSPACE  ptr__wSpace             ;Get my workspace
+
+               ; --- Try to find a good match for the mode ---
+
+               MOV     R1,R0                   ;Get name in R1
+               BL      screen_getInfo          ;Get mode information block
+               MOV     R7,R0                   ;Remember its position
+               MOV     R0,R11                  ;Put my buffer in R0
+               BL      str_cpy                 ;Copy the string across
+
+               MOV     R4,#'0'                 ;For ASCII conversion
+               LDR     R1,[R7,#screen_dx]      ;Get x pixel size
+               ADD     R1,R4,R1                ;Convert to ASCII pix size
+               STRB    R1,[R0],#1              ;Store it in the buffer
+               LDR     R1,[R7,#screen_dy]      ;Get y pixel size
+               ADD     R1,R4,R1                ;Convert to ASCII pix size
+               STRB    R1,[R0],#1              ;Store it in the buffer
+               MOV     R1,#0
+               STRB    R1,[R0]                 ;Stick a NULL on the end
+
+               ; --- Does sprite exist (sprite call corrupts R0-R6) ---
+
+               MOV     R0,#40                  ;Read sprite information
+               MOV     R2,R11                  ;Pointer to sprite name
+               BL      sprite_op               ;Does the sprite exist
+
+               LDMIA   R13,{R2,R4,R5}          ;Get users name, x and y
+               BVS     %10ptr_setShape         ;If sprite didn't exist...
+
+               ; --- Now use the new sprite ---
+
+               MOV     R2,R11                  ;Use this sprite name
+
+               ; --- Alter the x and y offsets for new resolution ---
+
+               LDR     R0,[R7,#screen_xEig]    ;Get the screen xEig
+               MOV     R4,R4,LSL #1            ;Multiply by 2
+               MOV     R4,R4,LSR R0            ;And shift down by xEig
+               LDR     R0,[R7,#screen_yEig]    ;Get the screen yEig
+               MOV     R5,R5,LSL #2            ;Multiply by 4
+               MOV     R5,R5,LSR R0            ;And shift down by yEig
+
+10ptr_setShape MOV     R0,#36                  ;Set pointer shape
+               MOV     R3,#2                   ;Pointer shape number
+               MOV     R6,#0                   ;Scale factors
+               MOV     R7,#0                   ;Pixel translation
+
+               BL      sprite_op               ;Do the correct SpriteOp
+
+               ; --- Alter my flags ---
+
+               LDR     R0,ptr__flags           ;Get my flags
+               ORR     R0,R0,#ptr__USERSET+ptr__NOTDEFAULT
+               STR     R0,ptr__flags           ;Store the flags back
+
+               ; --- Return to caller ---
+
+               LDMFD   R13!,{R0-R7,R12,PC}^    ;Return to user
+
+               LTORG
+
+; --- ptr_resetShape ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Resets the pointer shape to the default.
+
+               EXPORT  ptr_resetShape
+ptr_resetShape ROUT
+
+               STMFD   R13!,{R0,R12,R14}       ;Save some registers
+               WSPACE  ptr__wSpace             ;Get my workspace
+
+               ; --- Is the default pointer already on? ---
+
+               LDR     R0,ptr__flags           ;Get my flags
+               TST     R0,#ptr__NOTDEFAULT     ;Are we using default
+               LDMEQFD R13!,{R0,R12,PC}^       ;Yes, return
+
+               ; --- Alter the flags ---
+
+               BIC     R0,R0,#ptr__NOTDEFAULT+ptr__USERSET
+               STR     R0,ptr__flags           ;Store the flags
+
+               ; --- Now reset the shape using *pointer (Yuck) ---
+
+               ADR     R0,ptr__pointer         ;Point to command
+               SWI     OS_CLI                  ;Execute it
+
+               LDMFD   R13!,{R0,R12,PC}^       ;Return to user
+
+               LTORG
+
+ptr__pointer   DCB     "Pointer",0             ;*Pointer command string
+
+;----- Automatic pointer changing -------------------------------------------
+
+; --- ptr__idles ---
+;
+; On entry:    R12 == pointer to my workspace
+;
+; On exit:     --
+;
+; Use:         Called on idle events to try to change the pointer
+;              shape if it needs to.
+
+ptr__idles     ROUT
+
+               STMFD   R13!,{R0-R7,R14}        ;Stack some registers
+
+               LDR     R0,ptr__flags           ;Get my flags
+               TST     R0,#ptr__USERSET        ;Are we using user ptr?
+               LDMNEFD R13!,{R0-R7,PC}^        ;Yes, return
+
+               ; --- Is the pointer over an icon? ---
+
+               MOV     R1,R11                  ;Use the scratch pad
+               SWI     Wimp_GetPointerInfo     ;Get pointer info
+               LDR     R0,[R1,#16]             ;Get icon under pointer
+               LDR     R2,ptr__oldIcon         ;What were we over before?
+               STR     R0,ptr__oldIcon         ;This is now previous icon
+               CMP     R2,R0                   ;Are they the same
+               LDMEQFD R13!,{R0-R7,PC}^        ;Yes -- return
+               CMP     R0,#-1                  ;Is it the window background?
+               BEQ     %90ptr__idles           ;Yes -- skip to the end
+
+               ; --- Is this icon interesting? ---
+
+               STR     R0,[R1,#4]              ;Store the icon number
+               LDR     R2,[R1,#12]             ;Get the returned window hnd
+               STR     R2,[R1,#0]              ;Store it at beginning
+               SWI     Wimp_GetIconState       ;Get the state of the icon
+               LDR     R2,[R1,#24]             ;Get the icon flags
+
+               MOV     R7,R2,LSR#12            ;Get the button type
+               AND     R7,R7,#15               ;...only
+
+               TST     R2,#&100                ;Is it indirected?
+               TSTNE   R2,#&01                 ;Is it a text icon?
+               BEQ     %90ptr__idles           ;Not both -- return
+               AND     R2,R2,#&1f0000          ;Get the ESG number
+               CMP     R2,#&1f0000             ;Is it 31?
+               BEQ     %90ptr__idles           ;Yes -- it's shaded
+
+               LDR     R2,[R1,#32]             ;Get the validation string
+               CMP     R2,#-1                  ;Does it exist?
+               BEQ     %90ptr__idles           ;No -- return
+
+               ; --- Now parse validation string for xp<name>,<x>,<y> ---
+               ;
+               ; This is based on a state drive parser with the following
+               ; defined states:
+               ;
+               ;       0 == not in anything useful
+               ;       1 == looking for xp
+               ;       2 == reading sprite name
+               ;       3 == reading x value
+               ;       4 == reading y value
+               ;       5 == finished
+
+               MOV     R0,#1                   ;Set the current state to 1
+               ADD     R3,R11,#20              ;Use this buffer
+               MOV     R5,#0                   ;Current x value
+               MOV     R6,#0                   ;Current y value
+
+               ; --- All cases return to here ---
+
+00ptr__idles   CMP     R0,#5                   ;Are we in state 5?
+               BEQ     %70ptr__idles           ;Yes -- we're finished
+               LDRB    R1,[R2],#1              ;Get a character
+               CMP     R1,#31                  ;Is it a terminator
+               BLE     %70ptr__idles           ;Yes -- we're finished
+
+               ; --- case '\' ---
+
+               CMP     R1,#'\'                 ;Is it the escape character?
+               BNE     %10ptr__idles           ;No -- try next case
+               LDRB    R4,[R2]                 ;Get the next byte
+               CMP     R4,#31                  ;Is it a terminator
+               MOVGT   R1,R4                   ;No -- use this
+               ADDGT   R2,R2,#1                ;...and increment pointer
+               CMP     R0,#1                   ;Are we in state 1?
+               MOVEQ   R0,#0                   ;Yes -- go into state 0
+               CMP     R0,#2                   ;Are we in state 2
+               STREQB  R1,[R3],#1              ;Yes -- store the character
+               B       %00ptr__idles           ;break
+
+               ; --- case ';' ---
+
+10ptr__idles   CMP     R1,#';'                 ;Is it a new command?
+               BNE     %20ptr__idles           ;No -- try next case
+               CMP     R0,#1                   ;Is the state greater than 1?
+               MOVGT   R0,#5                   ;Yes -- state = 5
+               MOVLE   R0,#1                   ;No -- state = 1
+               B       %00ptr__idles           ;break
+
+               ; --- case 'X' / 'x' ---
+
+20ptr__idles   CMP     R1,#'X'                 ;Is is an 'X'?
+               CMPNE   R1,#'x'                 ;Or an 'x'?
+               BNE     %30ptr__idles           ;No -- try next case
+               CMP     R0,#1                   ;Are we in state 1?
+               BNE     %21ptr__idles           ;No -- go ahead a bit
+               LDRB    R4,[R2]                 ;Get next character
+               CMP     R4,#'P'                 ;Is it a 'P'?
+               CMPNE   R4,#'p'                 ;Or a 'p'?
+               ADDEQ   R2,R2,#1                ;Yes -- increment pointer
+               MOVEQ   R0,#2                   ;...and set state to 2
+               B       %00ptr__idles           ;break
+
+21ptr__idles   CMP     R0,#2                   ;Are we in state 2?
+               STREQB  R1,[R3],#1              ;Yes -- store the character
+               B       %00ptr__idles           ;break
+
+               ; --- case ',' ---
+
+30ptr__idles   CMP     R1,#','                 ;Is it a ,?
+               BNE     %40ptr__idles           ;No -- try next case
+               CMP     R0,#2                   ;Are we in state 2?
+               MOVEQ   R4,#0                   ;Yes -- get the NULL byte
+               STREQB  R4,[R3],#1              ;... store it at end of name
+               CMPNE   R0,#3                   ;Or state 3?
+               CMPNE   R0,#4                   ;Or state 4?
+               ADDEQ   R0,R0,#1                ;If any, increment the state
+               B       %00ptr__idles           ;break
+
+               ; --- default ---
+
+40ptr__idles   CMP     R0,#1                   ;Are we in state 1?
+               MOVEQ   R0,#0                   ;Yes -- put it in state 0
+               BEQ     %00ptr__idles           ;break
+               CMP     R0,#2                   ;State 2?
+               STREQB  R1,[R3],#1              ;Yes -- store the character
+               BEQ     %00ptr__idles           ;break
+               CMP     R0,#3                   ;Are we in state 3?
+               CMPNE   R0,#4                   ;Or 4?
+               BNE     %00ptr__idles           ;No -- break
+               CMP     R1,#'0'                 ;Is it less than '0'
+               BLT     %00ptr__idles           ;Yes -- break
+               CMP     R1,#'9'                 ;Is it greater than '9'
+               BGT     %00ptr__idles           ;Yes -- break
+               SUB     R1,R1,#'0'              ;Turn it into a number
+               MOV     R4,#10                  ;A useful number
+               CMP     R0,#3                   ;Are we reading x?
+               MLAEQ   R5,R4,R5,R1             ;Yes -- calculate new x
+               MLANE   R6,R4,R6,R1             ;No -- calculate new y
+               B       %00ptr__idles           ;break
+
+               ; --- We have finished parsing the string ---
+
+70ptr__idles   CMP     R0,#1                   ;Is the state > 1?
+               BLE     %80ptr__idles           ;No -- try default case
+               ADD     R0,R11,#20              ;Point to sprite name
+               MOV     R1,R5                   ;The x value
+               MOV     R2,R6                   ;The y value
+               BL      ptr_setShape            ;Set the pointer shape
+               LDR     R14,ptr__flags          ;Get the new flags
+               BIC     R14,R14,#ptr__USERSET   ;The user didn't set it
+               STR     R14,ptr__flags          ;Store them again
+               LDMFD   R13!,{R0-R7,PC}^        ;Return
+
+               ; --- If the button type was writable, use caret_ptr ---
+
+80ptr__idles   CMP     R7,#14                  ;Writable?
+               CMPNE   R7,#15
+               BNE     %90ptr__idles           ;Return
+               ADR     R0,ptr__caretPtr        ;The sprite name
+               MOV     R1,#4                   ;X offset
+               MOV     R2,#5                   ;Y Offset
+               BL      ptr_setShape            ;Set the pointer shape
+               LDR     R14,ptr__flags          ;Get the new flags
+               BIC     R14,R14,#ptr__USERSET   ;The user didn't set it
+               STR     R14,ptr__flags          ;Store them again
+               LDMFD   R13!,{R0-R7,PC}^        ;Return
+
+               ; --- Return to the user ---
+
+90ptr__idles   BL      ptr_resetShape          ;Reset the pointer
+               LDMFD   R13!,{R0-R7,PC}^        ;...and return
+
+               LTORG
+
+; --- ptr__postFilter ---
+;
+; On entry:    R0 == event code returned
+;              R1 == pointer to block returned
+;              R12 == pointer to my workspace
+;
+; On exit:     --
+;
+; Use:         Called as a post-filter to trap pointer entering/leaving
+;              events, so that idles may be added for pointer
+;              changing.
+
+ptr__postFilter        ROUT
+
+               ; --- Ensure that we want this event ---
+
+               CMP     R0,#4                   ;Pointer leaving?
+               BEQ     %50ptr__postFilter      ;Yes -- handle that
+               CMPNE   R0,#5                   ;Or entering?
+               MOVNES  PC,R14                  ;Neither, return now
+
+               ; --- Pointer is entering one of tasks windows ---
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+               MOV     R0,#2                   ;Call it this frequently
+               ADR     R1,ptr__idles           ;Call this on idle events
+               MOV     R2,#0                   ;Our user handle
+               MOV     R3,R12                  ;Put our workspace in R12
+               BL      idle_handler            ;Add the idle handler
+               MOV     R0,#-1                  ;Set up previous icon number
+               STR     R0,ptr__oldIcon         ;...to a non positive value
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               ; --- Pointer is leaving a window ---
+
+50             STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+               MOV     R0,#2                   ;Call it this frequently
+               ADR     R1,ptr__idles           ;Call this on idle events
+               MOV     R2,#0                   ;Our user handle
+               MOV     R3,R12                  ;Put our workspace in R12
+               BL      idle_removeHandler      ;Remove the handler routine
+               LDR     R14,ptr__flags          ;Load my flags word
+               TST     R14,#ptr__USERSET       ;Is it the user's pointer?
+               BLEQ    ptr_resetShape          ;No -- clear pointer shape
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+ptr__caretPtr  DCB     "ptr_caret",0
+
+;----- Caret blinking -------------------------------------------------------
+
+; --- ptr__doCaret ---
+;
+; On entry:    R0 == flags word
+;              R1 == pointer to block to use
+;
+; On exit:     --
+;
+; Use:         Turn the caret on or off, according to the relevent bit
+;              in the flags word.
+
+ptr__doCaret   ROUT
+
+               MOV     R5,R0                   ;Remember flags word
+               SWI     Wimp_GetCaretPosition   ;Get the caret position
+               LDR     R0,[R1,#0]              ;Window handle
+               LDR     R2,[R1,#8]              ;X offset
+               LDR     R3,[R1,#12]             ;Y offset
+               LDR     R4,[R1,#16]             ;Caret height and flags
+
+               ; --- Set or clear the 'invisible' bit ---
+
+               TST     R5,#ptr__ON             ;Turn the caret on?
+               ORREQ   R4,R4,#1<<25            ;No, set the 'invisible' bit
+               BICNE   R4,R4,#1<<25            ;No, clear 'invisible' bit
+
+               ; --- Set the caret position ---
+
+               LDR     R5,[R1,#20]             ;Index into string
+               LDR     R1,[R1,#4]              ;Icon handle
+
+               SWI     Wimp_SetCaretPosition   ;Put back invisible caret
+
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- ptr__blinkCaret ---
+;
+; On entry:    R12 == workspace pointer
+;
+; On exit:     --
+;
+; Use:         Called by an alarm to flash the caret.
+
+ptr__blinkCaret        ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Stack some registers
+
+               ; --- Do I own the task the carets in? ---
+
+               MOV     R1,R11                  ;Point to scratchpad
+               SWI     Wimp_GetCaretPosition   ;Get the caret position
+               LDR     R2,[R1,#0]              ;Get window handle
+               CMP     R2,#-1                  ;Is it in a window?
+               BEQ     %00                     ;No -- set up alarm, return
+
+               ; --- Send a acknowledgement message around ---
+
+               MOV     R0,#20                  ;Message size
+               STR     R0,[R1,#0]              ;Store in message block
+               MOV     R0,#0                   ;Your ref
+               STR     R0,[R1,#0]              ;Store in message block
+               MOV     R0,#19                  ;Send message_acknowlegde
+               SWI     Wimp_SendMessage        ;Send the message
+
+               ; --- My task handle is now in R2 ---
+
+               BL      wimp_taskHandle         ;Get the actual task handle
+               CMP     R0,R2                   ;Do we own caret?
+               BNE     %00                     ;No -- set up alarm, return
+
+               ; --- Mess about withe my flags, and blink caret ---
+
+               LDR     R0,ptr__flags           ;Get my flags word
+               TST     R0,#ptr__ON             ;Is the caret on?
+               BICNE   R0,R0,#ptr__ON          ;The caret is now off
+               ORREQ   R0,R0,#ptr__ON          ;The caret is now on
+               STR     R0,ptr__flags           ;Store flags back
+
+               BL      ptr__doCaret            ;Blink the caret
+
+               ; --- Prepare another alarm ---
+
+00             BL      ptr__setUpAlarm         ;Prepare to flash again
+
+               ; --- And return to caller ---
+
+               LDMFD   R13!,{R0-R5,PC}^        ;Stack some registers
+
+               LTORG
+
+; --- ptr__setUpAlarm ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets up an alarm to blink the caret
+
+ptr__setUpAlarm        ROUT
+
+               STMFD   R13!,{R14}              ;Stack return address
+               SWI     OS_ReadMonotonicTime    ;Get the current time
+               ADD     R0,R0,#25               ;Add 1/25 of a second
+               ADR     R1,ptr__blinkCaret      ;Call this routine
+               ADR     R2,ptr__setUpAlarm      ;My private handle
+               MOV     R3,R12                  ;Pass this for R12
+               BL      idle_setAlarm           ;Set up the alarm
+               LDMFD   R13!,{PC}               ;Return to caller
+
+               LTORG
+
+; --- ptr_blinkOn ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Makes the caret blink while it is in a window owned by your
+;              application.
+
+               EXPORT  ptr_blinkOn
+ptr_blinkOn    ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Stack some registers
+               WSPACE  ptr__wSpace             ;Point to my workspace
+
+               ; --- Turn on caret blinking ---
+
+               LDR     R14,ptr__flags          ;Get my flags
+               TST     R14,#ptr__BLINKING      ;Is blinking on?
+               LDMNEFD R13!,{R0-R3,R12,PC}^    ;Yes -- return
+
+               ORR     R14,R14,#ptr__BLINKING  ;Set the 'is blinking' bit
+               STR     R14,ptr__flags          ;Store the flags word
+
+               BL      ptr__setUpAlarm         ;Set up the blinking alarm
+
+               ; --- Return to client ---
+
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;And return
+
+               LTORG
+
+; --- ptr_blinkOff ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Turns the caret blinking off.
+
+               EXPORT  ptr_blinkOff
+ptr_blinkOff   ROUT
+
+               STMFD   R13!,{R0-R5,R12,R14}    ;Stack some registers
+               WSPACE  ptr__wSpace             ;Point to my workspace
+
+               ; --- Is blinking already off? ---
+
+               LDR     R14,ptr__flags          ;Get my flags
+               TST     R14,#ptr__BLINKING      ;Is blinking on?
+               LDMEQFD R13!,{R0-R5,R12,PC}^    ;Yes -- return
+
+               BIC     R14,R14,#ptr__BLINKING  ;Clear the 'is blinking' bit
+               STR     R14,ptr__flags          ;Store the flags word
+
+               ; --- Remove any blink alarms already set up ---
+
+               ADR     R0,ptr__setUpAlarm      ;My private handle
+               BL      idle_removeAllAlarms    ;Remove all alarms I own
+
+               ; --- Update my flags appropriately ---
+
+               LDR     R0,ptr__flags           ;Get my flags word
+               ORR     R0,R0,#ptr__ON          ;Caret is on
+               STR     R0,ptr__flags           ;Store the flags back
+               MOV     R1,R11                  ;Point to scratchpad
+               BL      ptr__doCaret            ;Turn the caret off
+
+               ; --- Return to client ---
+
+               LDMFD   R13!,{R0-R5,R12,PC}^    ;And return
+
+               LTORG
+
+;----- Initialisation -------------------------------------------------------
+
+; --- ptr_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the ptr system.
+
+               EXPORT  ptr_init
+ptr_init       ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Stack some registers
+               WSPACE  ptr__wSpace             ;Get my workspace
+
+               ; --- Are we already initialised? ---
+
+               LDR     R0,ptr__flags           ;Get my flags
+               TST     R0,#ptr__INITED         ;Are we initialised?
+               LDMNEFD R13!,{R0,R9,PC}^        ;Yes -- return
+
+               ORR     R0,R0,#ptr__INITED+ptr__ON ;Set flags
+               STR     R0,ptr__flags           ;And store them back
+
+               ; --- Ensure that the event system is initialised ---
+
+               BL      event_init
+
+               ; --- And set up a post-filter for pointer changing ---
+
+               ADR     R0,ptr__postFilter      ;Address of routine to call
+               MOV     R1,R12                  ;Call with my workspace
+               BL      event_postFilter        ;And add to the post filters
+
+               ; --- Set up exit handler ---
+
+               BL      except_init             ;Make sure except is awake
+               ADR     R0,ptr_resetShape       ;Make pointer normal on exit
+               MOV     R1,R12                  ;Pass workspace in R12
+               BL      except_atExit           ;Register the routine
+
+               ; --- That's it now ---
+
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return
+
+               LTORG
+
+ptr__wSpace    DCD     0                       ;My workspace pointer
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+ptr__wStart    #       0
+
+ptr__flags     #       4                       ;Flags
+
+ptr__INITED    EQU     (1<<0)                  ;I've been initialised
+ptr__BLINKING  EQU     (1<<1)                  ;Caret blinking is on
+ptr__ON                EQU     (1<<2)                  ;Caret is on
+ptr__NOTDEFAULT        EQU     (1<<3)                  ;We're not using default ptr
+ptr__USERSET   EQU     (1<<4)                  ;The user set the pointer
+
+ptr__oldIcon   #       4                       ;Icon we were previously over
+
+ptr__wSize     EQU     {VAR}-ptr__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     ptr__wSize              ;Workspace size
+               DCD     ptr__wSpace             ;Workspace pointer
+               DCD     40                      ;Scratchpad size
+               DCD     ptr_init                ;Initialisation code
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/rand b/StraySrc/Libraries/Sapphire/s/rand
new file mode 100644 (file)
index 0000000..2a15d5d
--- /dev/null
@@ -0,0 +1,200 @@
+;
+; rand.s
+;
+; Generating random numbers
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:divide
+               GET     sapphire:sapphire
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- rand ---
+;
+; On entry:    --
+;
+; On exit:     R0 == a pseudorandom number between 0 and &7FFFFFFF
+;
+; Use:         Returns a pseudorandom number.  The algorithm used is the
+;              additive generator found in Knuth.  The table is generated
+;              from the current monotonic time using a linear congruential
+;              generator.  Randomness is fairly good, and it's very quick.
+
+               EXPORT  rand
+rand           ROUT
+
+               STMFD   R13!,{R1-R3,R12,R14}    ;Save some registers
+               WSPACE  rand__wSpace            ;Find my workspace address
+               LDMIB   R12,{R1,R2}             ;Load the table indices
+               ADR     R3,rand__table          ;Find the ring buffer
+               LDR     R0,[R3,R1,LSL #2]       ;Load the value x[n-24]
+               LDR     R14,[R3,R2,LSL #2]      ;Load the value x[n-55]
+               ADD     R0,R0,R14               ;And form the new number
+               STR     R0,[R3,R2,LSL #2]       ;Store new number in buffer
+               SUBS    R1,R1,#1                ;Decrement x-24 index
+               MOVLT   R1,#54                  ;If too small, wrap it round
+               SUBS    R2,R2,#1                ;Decrement x-55 index
+               MOVLT   R2,#54                  ;If too small, wrap it round
+               STMIB   R12,{R1,R2}             ;Save the indices back again
+               BIC     R0,R0,#&80000000        ;Clear the top bit (positive)
+               LDMFD   R13!,{R1-R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- rand_setSeed ---
+;
+; On entry:    R0 == a pseudorandom seed
+;
+; On exit:     --
+;
+; Use:         Sets up the random number generator (rand) to the given start
+;              position.  The table of values is initialised from the seed
+;              in a psuedorandom manner, using a linear congruential
+;              generator.
+
+               EXPORT  rand_setSeed
+rand_setSeed   ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers
+               WSPACE  rand__wSpace            ;Find my workspace address
+
+               ; --- Reset the indices ---
+
+               MOV     R1,#23                  ;Start 24-index at 24-1
+               MOV     R2,#54                  ;Start 55-index at 55-1
+               STMIB   R12,{R1,R2}             ;Save them away
+
+               ; --- Now start populating the table ---
+
+               ADR     R1,rand__table          ;Point to the ring buffer
+               MOV     R2,#55                  ;Counter for the items
+
+00rand_setSeed ADD     R14,R0,R0,LSR #16       ;Mangle the seed a little
+               STR     R14,[R1],#4             ;Save it in the table
+
+               ADD     R14,R0,R0,LSL #2        ;Do multiply op in generator
+               RSB     R14,R14,R14,LSL #4
+               RSB     R0,R0,R14,LSL #2
+               RSB     R0,R0,R0,LSL #3
+               ADD     R0,R0,R0,LSL #5
+
+               ADD     R0,R0,#&66000000        ;Do add op in generator
+               ADD     R0,R0,#&00D60000
+               ADD     R0,R0,#&00001900
+               ADD     R0,R0,#&000000E1
+
+               SUBS    R2,R2,#1                ;Decrement the counter
+               BGT     %00rand_setSeed         ;If not finished, go again
+
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- rnd ---
+;
+; On entry:    R0 == start value (inclusive)
+;              R1 == end value (inclusive)
+;
+; On exit:     R0 == random number between the boundaries given
+;
+; Use:         Returns a random integer between the boundaries given.
+;              The distribution is slightly skewed towards lower numbers,
+;              but there's not a lot I can do about this, folks.
+
+               EXPORT  rnd
+rnd            ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save a bunch of registers
+               MOV     R2,R0                   ;Look after the start value
+               SUB     R1,R1,R0                ;Subtract the initial value
+               ADD     R1,R1,#1                ;Make it inclusive nicely
+               BL      rand                    ;Get a random number
+               BL      divide                  ;Force it to be in range
+               ADD     R0,R1,R2                ;And add the start value
+               LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- rand_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialise the random number table.
+
+               EXPORT  rand_init
+rand_init      ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save a register or two
+               WSPACE  rand__wSpace            ;Find my workspace
+               LDR     R14,rand__flags         ;Load my flags word
+               TST     R14,#rFlag__inited      ;Am I initialised yet?
+               LDMNEFD R13!,{R12,PC}^          ;Yes -- don't do it again
+
+               ORR     R14,R14,#rFlag__inited  ;Set the flag then
+               STR     R14,rand__flags         ;And save back the new flags
+               STMFD   R13!,{R0}               ;Save another register
+               SWI     OS_ReadMonotonicTime    ;Load the current time
+               BL      rand_setSeed            ;Set up the random table
+               LDMFD   R13!,{R0,R12,PC}^       ;And return to caller
+
+               LTORG
+
+rand__wSpace   DCD     0
+
+;------ Workspace -----------------------------------------------------------
+
+               ^       0,R12
+rand__wStart   #       0
+
+rand__flags    #       4                       ;Various flaglike objects
+
+rand__24       #       4                       ;Offset to item 24 in buffer
+rand__55       #       4                       ;Offset to item 55 in buffer
+
+rand__table    #       55*4                    ;The random number table
+
+rand__wSize    EQU     {VAR}-rand__wStart
+
+rFlag__inited  EQU     (1<<0)                  ;Am I initialised yet?
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     rand__wSize
+               DCD     rand__wSpace
+               DCD     0
+               DCD     rand_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/repeater b/StraySrc/Libraries/Sapphire/s/repeater
new file mode 100644 (file)
index 0000000..8886cbe
--- /dev/null
@@ -0,0 +1,319 @@
+;
+; repeater.s
+;
+; Handles things that should auto-repeat
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:divide
+               GET     sapphire:idle
+               GET     sapphire:sapphire
+               GET     sapphire:win
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- repeater ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R10 value to pass to routine
+;              R2 == R12 value to pass to routine
+;
+; On exit:     --
+;
+; Use:         Calls a routine (a) immediately, (b) after the configured
+;              keyboard delay rate and (c) repeatedly after the configured
+;              keyboard repeat rate.  Calls stop when the user stops
+;              pressing the mouse button.
+;
+;              The routine is called with R0 containing either the number
+;              of missed calls since the last one (normally this is 1) --
+;              this is intended to be used to implement a kind of buffering
+;              of repeats if the operation being performed is a lengthy one
+;              -- and with 0 to indicate that the operation is now
+;              completed.
+
+               EXPORT  repeater
+repeater       ROUT
+
+               STMFD   R13!,{R0-R4,R12,R14}    ;Save some registers
+               WSPACE  rpt__wSpace             ;Locate my workspace nicely
+
+               ; --- Set up the workspace ---
+
+               STMIA   R12,{R0-R2}             ;Save the call information
+               MOV     R0,#1                   ;This is the first call
+               BL      rpt__call               ;Call the user's routine
+
+               ; --- Now we have to work out the repeat times ---
+
+               MOV     R0,#196                 ;Read keybd repeat and delay
+               MOV     R1,#0                   ;Set up registers to read...
+               MOV     R2,#255                 ;... without corrupting
+               SWI     OS_Byte                 ;Read the autorepeat info
+               STR     R2,rpt__repeat          ;Save repeat rate in wspace
+               MOVS    R4,R1                   ;Look after delay time
+
+               MOVEQ   R0,#0                   ;If no delay, end op now
+               BLEQ    rpt__call               ;Tell client it's over
+               BEQ     %90repeater             ;And exit nicely
+
+               ; --- Set up the drag box ---
+               ;
+               ; We do this for several reasons:
+               ;
+               ; * It informs us when the mouse button is finally released.
+               ;
+               ; * It keeps the mouse pointer bounded for the duration.
+               ;
+               ; * It stops things going wrong if for some reason the mouse
+               ;   gets unbounded (e.g. by doing a Wimp_SetMode).
+
+               SUB     R13,R13,#56             ;Get a drag box block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetPointerInfo     ;Get the current mouse state
+               LDMIA   R13,{R2,R3}             ;Read mouse position
+               MOV     R1,#7                   ;This drag is a user type
+               STMIA   R13,{R0,R1}             ;Save them in the block
+               ADD     R14,R13,#24             ;Point to parent rectangle
+               STMIA   R14!,{R2,R3}            ;Save the current mouse...
+               STMIA   R14!,{R2,R3}            ;... posn to lock in place
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_DragBox            ;Start the drag operation
+               ADD     R13,R13,#56             ;Restore the stack now
+
+               ; --- Now set up the unknown handler to catch the drag ---
+
+               ADR     R0,rpt__ukEvents        ;Point to my handler routine
+               MOV     R1,#0                   ;Don't care about R4
+               MOV     R2,#0                   ;Nothing to pass in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_unknownHandler      ;Add the handler
+               BVS     %90repeater             ;If it failed, skip to end
+
+               ; --- Set up the alarm for the first repeat ---
+
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               ADD     R0,R4,R0                ;Add time to keyboard delay
+               STR     R0,rpt__alarm           ;Store the time of the alarm
+               STR     R0,rpt__last            ;And this is correct time
+               ADR     R1,rpt__alarms          ;Point to my alarm handler
+               MOV     R2,#0                   ;Nothing to pass in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      idle_setAlarm           ;Set the alarm call then
+
+90repeater     LDMFD   R13!,{R0-R4,R12,PC}^    ;Return to caller if all OK
+
+               LTORG
+
+; --- rpt__call ---
+;
+; On entry:    R0 == value to pass client in R0
+;
+; On exit:     --
+;
+; Use:         Calls client routine.
+
+rpt__call      ROUT
+
+               STMFD   R13!,{R1,R10,R12,R14}   ;Save some registers
+               LDMIA   R12,{R1,R10,R12}        ;Load client's routine data
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R1                   ;And call the routine
+               LDMFD   R13!,{R1,R10,R12,PC}^   ;And return to caller
+
+               LTORG
+
+; --- rpt__alarms ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Handles alarms while a repeater is in operation.
+
+rpt__alarms    ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+
+               LDR     R0,rpt__routine         ;Load the current addr
+               CMP     R0,#-1                  ;Have we ended?
+               BEQ     %70rpt__alarms          ;Yes -- do special things
+
+               ; --- Things go odd if zero repeat rate set up ---
+
+               LDR     R2,rpt__repeat          ;Load current repeat rate
+               CMP     R2,#0                   ;Is it currently zero?
+               BEQ     %50rpt__alarms          ;Yes -- handle specially
+
+               ; --- Work out how many we missed ---
+               ;
+               ; We also add in the next alarm, and resynch to the
+               ; expected time.
+
+               SWI     OS_ReadMonotonicTime    ;Get the current time
+               MOV     R4,R0                   ;Look after this value
+               LDR     R3,rpt__last            ;Get the time I was expecting
+               SUB     R0,R4,R3                ;Find how late I was called
+               MOV     R1,R2                   ;Get the repeat rate ready
+               BL      divide                  ;Find out how many I missed
+               ADD     R0,R0,#1                ;Add in one extra repeat
+               BL      rpt__call               ;Call client code again
+               SUB     R14,R2,R1               ;Work out next repeat time
+               ADD     R0,R4,R14               ;Add that to current time
+               STR     R0,rpt__last            ;This is the new alarm time
+
+               SWI     OS_ReadMonotonicTime    ;Get the current time
+               MOV     R4,R0                   ;Look after this now
+               SUB     R0,R4,R3                ;Find how late I was called
+               MOV     R1,R2                   ;Get the repeat rate ready
+               BL      divide                  ;Find out how many I missed
+               SUB     R14,R2,R1               ;Work out next repeat time
+               ADD     R0,R4,R14               ;Add that to current time
+               STR     R0,rpt__alarm           ;This is the new alarm time
+
+               ADR     R1,rpt__alarms          ;Point to me again
+               MOV     R2,R10                  ;Pass the dialogue handle
+               MOV     R3,R12                  ;And my workspace pointer
+               BL      idle_setAlarm           ;Add in next alarm handler
+
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               ; --- If no repeat rate, stop the whole operation ---
+
+50rpt__alarms  MOV     R0,#1                   ;Just send one call
+               BL      rpt__call               ;Send that off to the client
+               MOV     R1,#-1                  ;Tell Wimp to stop dragging
+               SWI     Wimp_DragBox            ;Send that off nicely
+               ADR     R0,rpt__ukEvents        ;Point to the unknown handler
+               MOV     R1,#0                   ;I'm passing 0 in R4
+               MOV     R2,#0                   ;And 0 in R10 too
+               MOV     R3,R12                  ;But R12 is my workspace
+               BL      win_removeUnknownHandler ;Remove it from the list
+               MOV     R0,#0                   ;Tell client it's all over
+               BL      rpt__call               ;Finish that off nicely
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               ; --- The repeater was ended before its time ---
+               
+70rpt__alarms  MOV     R1,#-1                  ;Tell Wimp to stop dragging
+               SWI     Wimp_DragBox            ;Send that off nicely
+               ADR     R0,rpt__ukEvents        ;Point to the unknown handler
+               MOV     R1,#0                   ;I'm passing 0 in R4
+               MOV     R2,#0                   ;And 0 in R10 too
+               MOV     R3,R12                  ;But R12 is my workspace
+               BL      win_removeUnknownHandler ;Remove it from the list
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rpt_end ---
+;
+; On entry:    --
+;
+; On exit:     --
+;               
+; Use:         Ends a repeater before the drag is released. No final
+;              0 is sent to the handler.
+
+               EXPORT  rpt_end
+rpt_end                ROUT
+
+               STMFD   R13!,{R12,R14}          ;Stack registers
+               WSPACE  rpt__wSpace             ;Locate my workspace nicely
+               MOV     R14,#-1                 ;Get a silly routine value
+               STR     R14,rpt__routine        ;Store in routine address
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+               
+               LTORG
+
+; --- rpt__ukEvents ---
+;
+; On entry:    R0 == event code
+;              R1 == pointer to event information
+;
+; On exit:     --
+;
+; Use:         Picks up end-of-drag events from the WindowMangler and
+;              diables the alarm for the repeat op.
+
+rpt__ukEvents  ROUT
+
+               CMP     R0,#7                   ;Is this a drag event?
+               MOVNES  PC,R14                  ;No -- return right away
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers away
+
+               ; --- Remove the alarm and unknown handlers ---
+
+               LDR     R0,rpt__alarm           ;Get the time it's due for
+               ADR     R1,rpt__alarms          ;Point to my alarms routine
+               MOV     R2,#0                   ;I passed 0 as it's R10
+               MOV     R3,R12                  ;Get its R12 value
+               BL      idle_removeAlarm        ;And remove it from the list
+               ADR     R0,rpt__ukEvents        ;Point to the unknown handler
+               MOV     R1,#0                   ;I'm passing 0 in R4
+               BL      win_removeUnknownHandler ;Remove it from the list
+
+               ; --- Tell the client it's over ---
+
+               MOV     R0,#0                   ;Say this is it then
+               BL      rpt__call               ;Send the event over
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+rpt__wSpace    DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+rpt__wStart    #       0
+
+rpt__routine   #       4                       ;Client routine to call
+rpt__R10       #       4                       ;R10 value to pass routine
+rpt__R12       #       4                       ;R12 value to pass routine
+rpt__repeat    #       4                       ;Current autorepeat rate
+rpt__alarm     #       4                       ;Time for next alarm pop
+rpt__last      #       4                       ;When last pop expected
+
+rpt__wSize     EQU     {VAR}-rpt__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     rpt__wSize
+               DCD     rpt__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/report b/StraySrc/Libraries/Sapphire/s/report
new file mode 100644 (file)
index 0000000..f2c7b08
--- /dev/null
@@ -0,0 +1,219 @@
+;
+; report.s
+;
+; A simple report box handler (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:buttons
+               GET     sapphire:errorBox
+               GET     sapphire:except
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:seh
+               GET     sapphire:string
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- report_register ---
+;
+; On entry:    R0 == pointer to routine to use
+;              R1 == R12 to pass to the routine
+;              R2 == stack pointer to set when it gets control
+;
+; On exit:     --
+;
+; Use:         Registers a resume point so that the application can recover
+;              from errors.  Error messages are reported using errorBox.
+
+               EXPORT  report_register
+report_register        ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers
+               WSPACE  report__wspace          ;Get my workspace pointer
+               STMIA   R12,{R0,R1}             ;Save these for later
+               ADR     R0,report__report       ;Point to my own resumer
+               MOV     R1,R12                  ;And set up my workspace
+               BL      except_returnPt         ;Set this up as the handler
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to the caller
+
+; --- report__report ---
+;
+; On entry:    R0 == pointer to an error block
+;
+; On exit:     R0 == pointer to user-supplied resume point
+;              R1 == value of R12 to pass to the resume point
+;
+; Use:         Pops up an error box reporting the error in a `OK to
+;              continue, Cancel to cancel program' type way.
+
+report__report ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+               BL      report_error            ;Ask the user about quitting
+               LDMIA   R12,{R0,R1}             ;Get the resume point out
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- report_catchAll ---
+;
+; On entry:    --
+;
+; On exit:     R13 modified
+;
+; Use:         Sets up an exception handler to catch errors and other SEH
+;              exceptions.  Errors are reported in the usual way, and the
+;              user is given the option to close the application.  Other
+;              exceptions are reported as errors.
+
+               EXPORT  report_catchAll
+report_catchAll        ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save some registers
+report__resume MOV     R12,R13                 ;Remember where this lot is
+               ADR     R0,report__catch        ;Point to the try block
+               BL      seh_try                 ;Register it with SEH
+               LDMIA   R12,{R0-R12,PC}^        ;And return to caller
+
+report__catch  MOVS    PC,R14
+               DCW     &FFFF,1
+               B       report__catchErr
+               DCD     -1
+               B       report__catchUK
+               DCD     0
+
+report__catchUK        ADR     R0,report__special      ;Point to emergency try block
+               BL      seh_try                 ;Register that nicely
+               MOV     R2,R0                   ;Put the exception in R2
+               ADR     R0,report__ukExc        ;Point to error skeleton
+               BL      msgs_error              ;Translate the message
+               MOV     R1,R0                   ;And move error to R1
+               B       %f00                    ;Skip emergency handler
+
+report__catchErr
+               ADR     R0,report__special      ;Point to emergency try block
+               BL      seh_try                 ;Register that nicely
+00             MOV     R0,R1                   ;Point to the error block
+               BL      report_error            ;Report it to the user
+               BL      seh_unTry               ;Remove emergency handler
+               B       report__resume          ;And resume the application
+
+report__ukExc  DCD     1
+               DCB     "rptUKEXC",0
+
+report__special        MOVS    PC,R14
+               DCD     -1
+               B       report__abort
+               DCD     0
+
+report__abort  ADR     R0,report__badExc       ;Point to the error message
+               B       except_fatal            ;And report it, and die
+
+report__badExc DCD     &80000000
+               DCB     "Fatal error: couldn't recover from error",0
+
+               LTORG
+
+; --- report_error ---
+;
+; On entry:    R0 == pointer to error
+;
+; On exit:     --
+;
+; Use:         Prompts the user about quitting the application in response
+;              to a really bad error.  If the user decides to quit, we
+;              quit.  Otherwise we return.
+
+               EXPORT  report_error
+report_error   ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save lots of registers
+
+               ; --- Set up the message to display in the box ---
+
+               ADD     R3,R0,#4                ;Point to error message
+               LDR     R4,[R0,#-4]             ;Get PC when error happened
+               BIC     R4,R4,#&FC000003        ;Clear off nasty PSR bits
+               LDR     R2,sapph_appName        ;Keep this name pointer
+               ADR     R0,report__msg1         ;Point to the error skeleton
+               BL      msgs_error              ;Construct the error message
+
+               ; --- Display the message and get a response ---
+
+               ADR     R1,report__buttons      ;Point to buttons block
+               BL      errorBox                ;Do all the real business
+               BCS     %10report_error         ;If OK, skip ahead
+
+               ; --- If the user pressed Cancel, we give another go ---
+
+               ADR     R0,report__msg2         ;Point to confirm message
+               BL      msgs_error              ;Construct the error message
+               ADR     R1,report__buttons      ;Point to buttons block
+               BL      errorBox                ;Get another response
+               SWICC   OS_Exit                 ;If `Quit' then we die
+
+10report_error LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+report__msg1   DCD     1
+               DCB     "rptERR",0
+
+report__msg2   DCD     1
+               DCB     "rptCONF",0
+
+report__buttons        BUTTON  "rptCONT"
+               BCANCEL "rptQUIT"
+               BUTEND
+
+               LTORG
+
+report__wspace DCD     0                       ;Workspace pointer
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+report_wstart  #       0
+
+report_routine #       4                       ;Pointer to resume routine
+report_R12     #       4                       ;Value of R12 it wants
+
+report_wsize   EQU     {VAR}-report_wstart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     report_wsize            ;Workspace size I want
+               DCD     report__wspace          ;Pointer to my pointer :-/
+               DCD     0                       ;No scratchpad required
+               DCD     0                       ;No initialisation either
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/res b/StraySrc/Libraries/Sapphire/s/res
new file mode 100644 (file)
index 0000000..8125c86
--- /dev/null
@@ -0,0 +1,314 @@
+;
+; res.s
+;
+; Locating resources (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:string
+               GET     sapphire:sapphire
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- res_exists ---
+;
+; On entry:    R0 == pointer to pathname
+;
+; On exit:     CS if the file exists, CC otherwise
+;
+; Use:         Tries to find the named file.  The file is deemed to exist
+;              if OS_File can return a valid object type for it (i.e. not
+;              `non-existant object' or actually raising errors).
+
+               EXPORT  res_exists
+res_exists     ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Stack some registers
+               MOV     R1,R0                   ;Point to the filename
+               MOV     R0,#17                  ;Find information about file
+               SWI     XOS_File                ;Try to find the file
+               MOVVS   R0,#0                   ;If error, say didn't exist
+               CMP     R0,#0                   ;Is it a nonexistant thing?
+               LDMFD   R13!,{R0-R5,R14}        ;Restore the registers
+               ORRNES  PC,R14,#C_flag          ;If it is there, set C
+               BICEQS  PC,R14,#C_flag          ;Otherwise clear it
+
+               LTORG
+
+; --- res__trySuffix ---
+;
+; On entry:    R0 == pointer to pathname to try
+;              R1 == pointer to end of pathname
+;
+; On exit:     R0 == pointer to pathname start (same as entry)
+;              R1 == pointer to pathname end (may be different)
+;              If C is set on exit, the pathname is updated to show the
+;                suffix which was found successfully.
+;
+; Use:         Tries to find a named file with either a suffix
+;              (Wimp_ReadSysInfo-style) or no suffix with the given
+;              basename.
+
+res__trySuffix ROUT
+
+               STMFD   R13!,{R0,R2-R4,R14}     ;Stack some registers again
+
+               ; --- Try to read the suffix string ---
+
+               MOV     R4,R1                   ;Keep end pointer
+               MOV     R3,R0                   ;Keep start pointer too!
+               MOV     R0,#-1                  ;Use the current mode
+               MOV     R1,#5                   ;Read the y-EIG factor
+               SWI     OS_ReadModeVariable     ;Read that then, please
+               CMP     R2,#2                   ;Is this a low-res mode?
+               ADRCS   R1,res__lowRes          ;Yes -- point to the suffix
+               ADRCC   R1,res__hiRes           ;No -- point to other suffix
+
+               ; --- Tack the suffix on the end of the string ---
+
+               MOV     R0,R4                   ;Point to the main string
+               BL      str_cpy                 ;Copy the suffix on
+
+               ; --- Find out whether the file exists ---
+
+               MOV     R1,R0                   ;Point to null terminator
+               MOV     R0,R3                   ;Point to the string base
+               BL      res_exists              ;Does it exist?
+               LDMCSFD R13!,{R0,R2-R4,PC}      ;Yes -- return with C set
+               MOV     R0,#0                   ;Chop off terminator again
+               STRB    R0,[R4,#0]              ;Store it on the end
+
+               ; --- See if the basic file exists ---
+
+               MOV     R0,R3                   ;Point to the base name
+               MOV     R1,R4                   ;Point to the terminator
+               LDMFD   R13!,{R0,R2-R4,R14}     ;Unstack all the registers
+               B       res_exists              ;And see if it exists
+
+res__lowRes    DCB     "24",0
+res__hiRes     DCB     "22",0
+
+               LTORG
+
+; --- res_country ---
+;
+; On entry:    R0 == pointer to a buffer to use
+;
+; On exit:     R0 == pointer to country name (may not be in the buffer)
+;
+; Use:         Reads the name of the current country.  If no name can be
+;              found, it returns a pointer to the string `UK' which should
+;              do as a suitable default
+
+               EXPORT  res_country
+res_country    ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save loads of registers
+
+               ; --- Read the country number ---
+
+               MOV     R0,#240                 ;Read country number
+               MOV     R1,#0                   ;Read, don't write
+               MOV     R2,#255                 ;Read, don't write
+               SWI     OS_Byte                 ;Find the country number
+
+               ; --- Now get someone to translate it for us ---
+
+               MOV     R3,R1                   ;Get the country number
+               MOV     R1,#&43                 ;Service_International
+               MOV     R2,#2                   ;The magic reason code
+               LDR     R4,[R13],#4             ;Get the buffer pointer
+               MOV     R5,#20                  ;A fair size for the name
+               SWI     OS_ServiceCall          ;Try to find the name
+
+               CMP     R1,#0                   ;Was the service call claimed
+               ADRNE   R0,res__uk              ;No -- point to `UK'
+               STREQB  R1,[R4,R5]              ;Yes -- null terminate string
+               MOVEQ   R0,R4                   ;... and point to the name
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to the caller
+
+res__uk                DCB     "UK",0
+
+               LTORG
+
+; --- res_find ---
+;
+; On entry:    R0 == pointer to resource filename
+;              R1 == pointer to buffer to build filename in
+;
+; On exit:     R0 == pointer to start of full pathname (R1 on entry)
+;              R1 == pointer to terminating null character
+;              CS if the file could actually be found, CC otherwise
+;
+; Use:         Locates a resource file.  It searches, in order:
+;
+;              * resPrefix.Resources.leaf[suffix]
+;              * resPrefix.Resources.country.leaf[suffix]
+;              * resPrefix.leaf[suffix]
+;
+;              returning the last if none of them could be found.  Note
+;              that `country' here is the currently configured country
+;              setting, and `suffix' is the WIMP mode aspect ratio suffix
+;              for the current mode (RISC OS 3 only).
+
+               EXPORT  res_find
+res_find       ROUT
+
+               STMFD   R13!,{R7-R10,R12,R14}   ;Save some registers
+
+               ; --- First build the resource prefix ---
+
+               WSPACE  res_wspace              ;Find the workspace
+               MOV     R10,R1                  ;Keep buffer pointer
+               MOV     R7,R0                   ;Keep leafname pointer
+               MOV     R0,R1                   ;Point to the buffer
+               ADR     R1,res_prefix           ;Point to resource root
+               BL      str_cpy                 ;Copy it over
+
+               ; --- Now build resPrefix.Resources.leaf ---
+
+               MOV     R1,#'.'                 ;Put a dot in there
+               STRB    R1,[R0],#1              ;Insert after res prefix
+               MOV     R9,R0                   ;Keep this pointer
+               ADR     R1,res__resources       ;Point to `Resources'
+               BL      str_cpy                 ;Copy it over
+               MOV     R8,R0                   ;Keep this pointer for later
+               MOV     R1,R7                   ;Point to leafname pointer
+               BL      str_cpy                 ;Copy it over
+               MOV     R1,R0                   ;Keep terminator pointer
+               MOV     R0,R10                  ;Point to buffer
+               BL      res__trySuffix          ;Try adding a suffix then
+               BCS     %10res_find             ;If it's there return
+
+               ; --- Try resPrefix.Resources.country.leaf ---
+
+               SUB     R13,R13,#20             ;Drop the stack a bit
+               MOV     R0,R13                  ;Point to this new buffer
+               BL      res_country             ;Read the country name
+               MOV     R1,R0                   ;Keep the pointer
+               MOV     R0,R8                   ;We remembered this pointer
+               BL      str_cpy                 ;Copy the country name over
+               ADD     R13,R13,#20             ;Reclaim the stack
+               MOV     R1,#'.'                 ;Put a dot in there
+               STRB    R1,[R0],#1              ;Insert after country name
+               MOV     R1,R7                   ;Point to leafname
+               BL      str_cpy                 ;Copy it over
+               MOV     R1,R0                   ;Keep the end pointer
+               MOV     R0,R10                  ;Point to buffer
+               BL      res__trySuffix          ;Try adding a suffix then
+               BCS     %10res_find             ;If it's there return
+
+               ; --- Try resPrefix.Resources.UK.leaf ---
+
+               MOV     R0,R8                   ;We remembered this pointer
+               ADR     R1,res__uk              ;Point to the UK string
+               BL      str_cpy                 ;Copy the country name over
+               MOV     R1,#'.'                 ;Put a dot in there
+               STRB    R1,[R0],#1              ;Insert after country name
+               MOV     R1,R7                   ;Point to leafname
+               BL      str_cpy                 ;Copy it over
+               MOV     R1,R0                   ;Keep the end pointer
+               MOV     R0,R10                  ;Point to buffer
+               BL      res__trySuffix          ;Try adding a suffix then
+               BCS     %10res_find             ;If it's there return
+
+               ; --- No joy so just build resPrefix.leafname and quit ---
+
+               MOV     R0,R9                   ;We remembered this point
+               MOV     R1,R7                   ;Point to the leafname
+               BL      str_cpy                 ;Copy it over
+               MOV     R1,R0                   ;Keep the end pointer
+               MOV     R0,R10                  ;Point to buffer
+               BL      res__trySuffix          ;Try adding a suffix then
+               BCS     %10res_find             ;If it's there return
+
+               ; --- Couldn't find it at all -- return with C clear ---
+
+               LDMFD   R13!,{R7-R10,R12,R14}   ;Unstack loads of registers
+               BICS    PC,R14,#C_flag          ;Return with C clear
+
+               ; --- We found a resource name -- return with C set ---
+
+10res_find     LDMFD   R13!,{R7-R10,R12,R14}   ;Unstack loads of registers
+               ORRS    PC,R14,#C_flag          ;Return with C set
+
+res__resources DCB     "Resources.",0
+
+               LTORG
+
+; --- res_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Initialises the resource prefix to <appname$Dir>
+
+               EXPORT  res_init
+res_init       ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers
+               WSPACE  res_wspace              ;Get my workspace pointer
+               LDR     R14,res_wstart          ;Get the first word
+               CMP     R14,#0                  ;Are we initialised?
+               LDMNEFD R13!,{R0-R2,R12,PC}^    ;Yes -- return
+               MOV     R2,R0                   ;Point to application name
+               ADR     R1,res_prefix           ;Point to my buffer
+               ADR     R0,res__skeleton        ;Point to skeleton for this
+               BL      str_subst               ;Build the string up
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller
+
+res__skeleton  DCB     "<%0$Dir>",0
+
+               LTORG
+
+res_wspace     DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+res_wstart     #       0
+
+res_prefix     #       40                      ;Prefix string
+
+res_wsize      EQU     {VAR}-res_wstart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     res_wsize
+               DCD     res_wspace
+               DCD     0
+               DCD     res_init
+
+;----- That's all, folks ----------------------------------------------------
+
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/resources b/StraySrc/Libraries/Sapphire/s/resources
new file mode 100644 (file)
index 0000000..748fe7a
--- /dev/null
@@ -0,0 +1,172 @@
+;
+; resources.s
+;
+; Access to shared resource DLL (MDW)
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:except
+               GET     sapphire:sapphire
+
+rsc__version   EQU     100
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- resources_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the shared resource system, setting up the
+;              link to the SapphRes DLL.  Note that this initialisation is
+;              /not/ performed automatically.
+
+               EXPORT  resources_init
+resources_init ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers
+               WSPACE  rsc__wSpace             ;Find my workspace
+               LDR     R14,rsc__find           ;Locate the function pointer
+               CMP     R14,#0                  ;Have I set it up?
+               LDMNEFD R13!,{R0,R1,R12,PC}^    ;I guess so then
+               MOV     R14,#0                  ;A nice null pointer
+               STR     R14,rsc__dllHandle      ;Resource DLL not found yet
+
+               ; --- Save the application handle
+
+               SWI     XDLL_SaveHandle         ;Find my current app handle
+               BVS     %90resources_init       ;Failed -- return now then
+               STR     R0,rsc__appHandle       ;Save that away
+
+               ; --- Now do the dynamic linking ---
+
+               ADR     R0,rsc__dllName         ;Point to the DLL name
+               LDR     R1,=rsc__version        ;Load the resource version
+               SWI     XDLL_Find               ;Try to find the version
+               STRVC   R0,rsc__dllHandle       ;Store the DLL handle
+               ADRVC   R1,rsc__findRsc         ;Point to routine name
+               SWIVC   XDLL_FindEntry          ;Try to find the entry
+               STRVC   R0,rsc__find            ;Store this away nicely
+
+               ; --- Initialise things which we need ---
+
+               BL      except_init             ;We need to finalise properly
+
+               ; --- Set up the finalisation ---
+
+               ADR     R0,rsc__closeDown       ;Point to the exit handler
+               MOV     R1,R12                  ;Pass it my workspace
+               BL      except_atExit           ;And register the handler
+
+90             LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to caller when done
+
+rsc__dllName   DCB     "[Sapphire.Resources]",0
+rsc__findRsc   DCB     "sapphRes_find",0
+
+               LTORG
+
+; --- resources_find ---
+;
+; On entry:    R0 == resource code
+;              R1 == pointer to name (only for rsType_template)
+;
+; On exit:     CS if found, and
+;                R0 == pointer to resource
+;                R1 == pointer to resource limit (only for rsType_message)
+;              else CC and
+;                R0,R1 preserved
+;
+; Use:         Locates resources in the shared resource DLL.
+
+               EXPORT  resources_find
+resources_find ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  rsc__wSpace             ;Locate my workspace address
+               LDR     R12,rsc__find           ;Load the routine pointer
+               CMP     R12,#0                  ;Have we found the DLL?
+               BEQ     %90resources_find       ;No -- skip
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R12                  ;Call the routine
+               LDMFD   R13!,{R12,R14}          ;Restore caller's registers
+               ORRCSS  PC,R14,#C_flag          ;Set C if C must be set
+               BICCCS  PC,R14,#C_flag          ;Clear C if C must be clear
+
+90             LDMFD   R13!,{R12,R14}          ;Restore caller's registers
+               BICS    PC,R14,#C_flag          ;Couldn't find the resource
+
+               LTORG
+
+; --- rsc__closeDown ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Closes down the shared resource DLL.
+
+rsc__closeDown ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               LDR     R0,rsc__appHandle       ;Load my application handle
+               SWI     XDLL_RestoreHandle      ;Set that up nicely
+               LDR     R0,rsc__dllHandle       ;Recover the DLL handle
+               SWI     XDLL_Lose               ;No longer need this
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               LTORG
+
+rsc__wSpace    DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+rsc__wStart    #       0
+
+rsc__find      #       4                       ;Address of sapphRes_find
+rsc__appHandle #       4                       ;Our application handle
+rsc__dllHandle #       4                       ;SapphRes's DLL handle
+
+rsc__wSize     EQU     {VAR}-rsc__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     rsc__wSize
+               DCD     rsc__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/resspr b/StraySrc/Libraries/Sapphire/s/resspr
new file mode 100644 (file)
index 0000000..355a615
--- /dev/null
@@ -0,0 +1,232 @@
+;
+; resspr.s
+;
+; Handling of the application's private sprite area (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:msgs
+               GET     sapphire:res
+               GET     sapphire:resources
+               GET     sapphire:sapphire
+               GET     sapphire:string
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- resspr_load ---
+;
+; On entry:    R0 == pointer to filename
+;
+; On exit:     May return an error
+;
+; Use:         Loads a sprite file into memory and allows it to be
+;              referenced through resspr_area.  Note that Straylight's
+;              Sprinkle module must be loaded if more than one sprite file
+;              is to be used for resources.
+
+               EXPORT  resspr_load
+resspr_load    ROUT
+
+               STMFD   R13!,{R0-R6,R12,R14}    ;Stack some registers
+               WSPACE  resspr__wSpace          ;Find my workspace
+
+               ; --- Find out how big the sprite file is ---
+
+               MOV     R1,R0                   ;Point to the filename
+               MOV     R0,#17                  ;Find information about file
+               SWI     XOS_File                ;Get information about it
+               BVS     %99resspr_load          ;If it failed, go ahead
+
+               ; --- Allocate a buffer for it ---
+
+               ADD     R3,R4,#12+3             ;Add 12 byte overhead and...
+               BIC     R3,R3,#3                ;... word align
+               MOV     R0,R3                   ;Get the size
+               BL      alloc                   ;Allocate the memory
+               BLCS    alloc_error             ;If it failed, get error
+               BCS     %99resspr_load          ;And go tidy up
+               MOV     R6,R0                   ;Remember the address
+
+               ; --- Set up the sprite area and load the file ---
+
+               STR     R3,[R0,#0]              ;Store size in first word
+               MOV     R0,#16                  ;Load the file into memory
+               ADD     R2,R6,#12               ;Point past first word
+               MOV     R3,#0                   ;Load where I want it
+               SWI     XOS_File                ;Load the file
+               BVS     %98resspr_load          ;If it failed, tidy up
+
+               ; --- Now set up the sprite area ---
+
+               ADD     R14,R6,#12              ;Point to sprite block base
+               LDMIA   R14,{R0-R2}             ;Load those out nicely
+               ADD     R1,R1,#8                ;Grow the extension words
+               ADD     R2,R2,#8                ;Allow 8 more bytes here
+               LDR     R3,resspr__splk         ;Get magic word for SprLink
+               LDR     R4,resspr__last         ;Find the list terminator
+               ADD     R14,R6,#4               ;Point to appropriate place
+               STMIA   R14,{R0-R4}             ;Store all that lot away
+
+               ; --- Link this into the list ---
+
+               LDR     R14,resspr__listEnd     ;Find the list end
+               STR     R6,[R14,#20]            ;Store that away nicely
+               STR     R6,resspr__listEnd      ;This is now the last block
+
+               LDMFD   R13!,{R0-R6,R12,R14}    ;Restore all registers
+               BICS    PC,R14,#V_flag          ;And return to caller
+
+               ; --- It couldn't load -- tidy up ---
+
+98resspr_load  MOV     R5,R0                   ;Keep error pointer safe
+               MOV     R0,R6                   ;Find the heap block
+               BL      free                    ;Free the block now
+               MOV     R0,R5                   ;Restore error pointer
+
+               ; --- Something went wrong -- make an error ---
+
+99resspr_load  ADD     R2,R0,#4                ;Point to error string
+               ADR     R0,resspr__err          ;Point to error skeleton
+               BL      msgs_error              ;Build the error up
+               ADD     R13,R13,#4              ;Move stack pointer past R0
+               LDMFD   R13!,{R1-R6,R12,R14}    ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+resspr__splk   DCB     "SPLK"                  ;SprLink's magic number
+
+resspr__err    DCD     1
+               DCB     "rsprSLE",0
+
+               LTORG
+
+; --- resspr_area ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to application's sprite area
+;
+; Use:         Locates the application's `Sprites' resource in memory and
+;              returns a pointer to it.  If the resource has not been
+;              loaded, 1 is returned, to indicate to use the WIMP area.
+;              If multiple sprite files have been loaded, this call returns
+;              the address of the first: they will have been linked together
+;              so that Sprinkle will treat them as one big area.
+
+               EXPORT  resspr_area
+resspr_area    ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R0,resspr__wSpace       ;Find my workspace
+               LDR     R14,sapph_workspace     ;Find workspace base address
+               LDR     R0,[R0,R14]             ;Locate sprite area
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- resspr_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Initalises resspr, loading the Sprites resource.
+
+               EXPORT  resspr_init
+resspr_init    ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save registers
+               WSPACE  resspr__wSpace          ;Find my workspace
+
+               ; --- Avoid multiple initialisation ---
+
+               LDR     R14,resspr__area        ;Get the area pointer
+               CMP     R14,#0                  ;Is it NULL
+               LDMNEFD R13!,{R0,R1,R12,PC}^    ;No -- we've already done it
+
+               ; --- Fallback position -- use the WIMP area ---
+
+               ADR     R14,resspr__area-20     ;Put obscure address in
+               STR     R14,resspr__listEnd     ;As the list end
+
+               MOV     R14,#1                  ;Use the WIMP area
+               STR     R14,resspr__area        ;Save as sprite area pointer
+
+               ; --- Set up the shared resource sprites ---
+
+               MOV     R0,#rsType_sprite       ;Find the sprite resource
+               BL      resources_find          ;Try to find the resources
+               STRCS   R0,resspr__area         ;It will do as a sprite area
+               MOVCC   R0,#0                   ;Otherwise terminate normally
+               STR     R0,resspr__last         ;Store that as last pointer
+
+               ; --- Now initialise res and load the sprites ---
+
+               LDR     R0,[R13,#0]             ;Find the application name
+               BL      msgs_init               ;This will start up res
+
+               ADR     R0,resspr__sprites      ;Point to the leafnae
+               MOV     R1,R11                  ;Build name in scratchpad
+               BL      res_find                ;Translate the name
+               BLCS    resspr_load             ;If there, load the file
+               SWIVS   OS_GenerateError        ;If failed, there's no hope
+
+               ; --- That's it, then ---
+
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to caller
+
+resspr__sprites        DCB     "Sprites",0
+
+               LTORG
+
+resspr__wSpace DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+resspr__wStart #       0
+
+resspr__area   #       4                       ;Pointer to sprite area
+resspr__listEnd        #       4                       ;Last block in the list
+resspr__last   #       4                       ;Pointer to list terminator
+
+resspr__wSize  EQU     {VAR}-resspr__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     resspr__wSize
+               DCD     resspr__wSpace
+               DCD     256
+               DCD     resspr_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/roVersion b/StraySrc/Libraries/Sapphire/s/roVersion
new file mode 100644 (file)
index 0000000..e55ae35
--- /dev/null
@@ -0,0 +1,122 @@
+;
+; roVersion.s
+;
+; Handling of the RISC OS version (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:sapphire
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- rov_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets up the OS version in a cache.
+
+               EXPORT  rov_init
+rov_init       ROUT
+
+               STMFD   R13!,{R0-R4,R12,R14}    ;Save some registers away
+               WSPACE  rov__wSpace             ;Find my workspace pointer
+               LDR     R14,rov__version        ;Get the cached version
+               CMP     R14,#0                  ;Is it set up yet?
+               LDMNEFD R13!,{R0-R4,R12,PC}^    ;Yes -- return to caller
+
+               ; --- Work out the RISC OS version properly ---
+
+               MOV     R0,#129                 ;Read key (or OS version) :-/
+               MOV     R1,#0                   ;Want OS version
+               MOV     R2,#255                 ;Still want OS version
+               SWI     OS_Byte                 ;Read the version number
+
+               ADR     R2,rov__verTable        ;Point to my version table
+               MOV     R0,#-1                  ;Start off with bad version
+10rov_init     LDMIA   R2!,{R3,R4}             ;Load the version numbers
+               CMP     R3,R1                   ;Does this version match?
+               MOVLE   R0,R4                   ;Yes -- use this version
+               BGT     %10rov_init             ;Otherwise continue search
+
+               STR     R0,rov__version         ;Save this version away
+               LDMFD   R13!,{R0-R4,R12,PC}^    ;Return to caller
+
+rov__verTable  DCD     &A5,350
+               DCD     &A4,310
+               DCD     &A3,300
+               DCD     &A2,201
+               DCD     &A1,200
+               DCD     0,0
+
+rov__wSpace    DCD     0
+
+               LTORG
+
+; --- rov_version ---
+;
+; On entry:    --
+;
+; On exit:     R0 == current RISC OS version
+;
+; Use:         Returns the current operating system version number.
+
+               EXPORT  rov_version
+rov_version    ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R0,rov__wSpace          ;Find my workspace offset
+               LDR     R14,sapph_workspace     ;Find workspace base
+               LDR     R0,[R0,R14]             ;Load version number
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+rov__wStart    #       0
+
+rov__version   #       4                       ;Current OS version number
+
+rov__wSize     EQU     {VAR}-rov__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     rov__wSize
+               DCD     rov__wSpace
+               DCD     0
+               DCD     rov_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/sapphRes b/StraySrc/Libraries/Sapphire/s/sapphRes
new file mode 100644 (file)
index 0000000..107c650
--- /dev/null
@@ -0,0 +1,199 @@
+;
+; sapphRes.s
+;
+; Sapphire shared resources (MDW)
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  |Image$$RO$$Base|
+
+               IMPORT  rsc_sprites
+               IMPORT  rsc_msgBase
+               IMPORT  rsc_msgLimit
+               IMPORT  rsc_tplBase
+               IMPORT  rsc_tplLimit
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Main$$Code|,CODE,READONLY
+
+; --- sapphRes_find ---
+;
+; On entry:    R0 == resource type code
+;              R1 == pointer to resource name (only required for
+;                      srType_template)
+;
+; On exit:     CS if found, and
+;                R0 == address of resource
+;                R1 == limit (for messages)
+;              else CC and
+;                Registers preserved
+;
+; Use:         Looks up the address of a resource in the shared resource
+;              DLL.
+
+               EXPORT  sapphRes_find
+sapphRes_find  ROUT
+
+               CMP     R0,#srType_max          ;Is the type in range?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch it then
+               BICS    PC,R14,#C_flag          ;Otherwise couldn't find it
+
+               B       sr__findSprite          ;Find a sprite resource
+               B       sr__findMessages        ;Find a messages resource
+               B       sr__findTemplate        ;Find a template resource
+
+               LTORG
+
+; --- sr__findSprite ---
+;
+; On entry:    --
+;
+; On exit:     R0 == address of a sprite area
+;
+; Use:         Locates the sprite resource within the DLL.
+
+sr__findSprite ROUT
+
+               LDR     R0,=rsc_sprites         ;Find the sprite area
+               ORRS    PC,R14,#C_flag          ;And return to caller
+
+               LTORG
+
+; --- sr__findMessages ---
+;
+; On entry:    --
+;
+; On exit:     R0 == address of messages base
+;              R1 == address of messages limit
+;
+; Use:         Locates the messages resource within the DLL.
+
+sr__findMessages ROUT
+
+               ADR     R0,sr__msgs             ;Point to messages base/limit
+               LDMIA   R0,{R0,R1}              ;Load them out
+               ORRS    PC,R14,#C_flag          ;And return to caller
+
+sr__msgs       DCD     rsc_msgBase
+               DCD     rsc_msgLimit
+
+               LTORG
+
+; --- sr__findTemplate ---
+;
+; On entry:    R1 == pointer to template name
+;
+; On exit:     CS and R0 == pointer to embedded template block, or CC
+;
+; Use:         Locates a named window defintion.
+
+sr__findTemplate ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Save some registers
+               ADR     R14,sr__tpls            ;Point to base and limit
+               LDMIA   R14,{R2,R3}             ;Load them out
+
+               ; --- Search the template table ---
+
+10             CMP     R2,R3                   ;Have we finished yet?
+               BCS     %90sr__findTemplate     ;Yes -- then we failed
+
+               ; --- Check for a name match ---
+
+               MOV     R4,R1
+00             LDRB    R5,[R4],#1              ;Load first char of name
+               SUB     R14,R5,#'A'             ;Convert to a letter index
+               CMP     R14,#26                 ;Is it in range?
+               ORRCC   R5,R5,#&20              ;Yes -- convert to lowercase
+               CMP     R5,#&20                 ;Is the byte a control char?
+               MOVCC   R5,#0                   ;Yes -- say it's zero
+
+               LDRB    R6,[R2],#1              ;Load first char of name
+               SUB     R14,R6,#'A'             ;Convert to a letter index
+               CMP     R14,#26                 ;Is it in range?
+               ORRCC   R6,R6,#&20              ;Yes -- convert to lowercase
+               CMP     R6,#&20                 ;Is the byte a control char?
+               MOVCC   R6,#0                   ;Yes -- say it's zero
+
+               ; --- Compare the characters
+
+               CMP     R5,R6                   ;Do the chars match?
+               BNE     %50sr__findTemplate     ;No -- move on to next one
+               CMP     R5,#0                   ;Is it the end?
+               BNE     %b00                    ;No -- keep looking
+
+               ; --- Found a match ---
+
+               ADD     R2,R2,#3                ;Word align the output
+               BIC     R2,R2,#3                ;To make sure
+               LDR     R0,[R2,#0]              ;Load the template base
+               LDMFD   R13!,{R2-R6,R14}        ;Restore registers
+               ORRS    PC,R14,#C_flag          ;And return success
+
+               ; --- Failed -- move on to next entry ---
+
+50             CMP     R6,#&20                 ;Reached the end yet?
+               LDRCSB  R6,[R2],#1              ;No -- load next byte
+               BCS     %b50                    ;And keep on looping
+               ADD     R2,R2,#4+3              ;Word align the output
+               BIC     R2,R2,#3                ;To make sure
+               B       %10sr__findTemplate     ;And rejoin the main loop
+
+               ; --- Failed entirely ---
+
+90             LDMFD   R13!,{R2-R6,R14}        ;Restore registers
+               BICS    PC,R14,#C_flag          ;And return to caller
+
+sr__tpls       DCD     rsc_tplBase
+               DCD     rsc_tplLimit
+
+               LTORG
+
+;----- Resource types -------------------------------------------------------
+
+               ^       0
+srType_sprites #       1                       ;Sprite resource, returned as
+                                               ;address of sprite area
+
+srType_messages        #       1                       ;Messages resource, returned
+                                               ;as address of base and limit
+                                               ;pair
+
+srType_template        #       1                       ;Template (window) resource,
+                                               ;returned as address of
+                                               ;embedded template def.
+
+srType_max     #       0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/saveWarn b/StraySrc/Libraries/Sapphire/s/saveWarn
new file mode 100644 (file)
index 0000000..ae6e8fa
--- /dev/null
@@ -0,0 +1,232 @@
+;
+; saveWarn.s
+;
+; Warn the user about saving a document
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:buttons
+               GET     sapphire:errorBox
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:string
+               GET     sapphire:warning
+
+               GET     sapphire:xfer.saveAs
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- saveWarn ---
+;
+; On entry:    R0 == estimated size of data
+;              R1 == file type of the data
+;              R2 == pointer to name of the file
+;              R3 == pointer to handler block
+;              R4 == value to pass to handlers in R10
+;              R5 == value to pass to handlers in R12
+;              R6 == flags (in bottom two bits)
+;
+; On exit:     --
+;
+; Use:         Displays a warning box allowing the user to save a modified
+;              document.  The flags in R6 are as follows:
+;
+;              Bit 0   File is safe; don't give a warning
+;              Bit 1   File's name is sensible; display it in the warning
+;
+;              The handler block is the same as that passed to saveAs (q.v.)
+;              with an extra entry point on the very beginning, which is
+;              expected to remove the document from memory.  This entry
+;              point is not passed any arguments except for R10 and R12.
+;
+;              In order for the system to work, you must call various
+;              saveWarn routines from your saveAs entry points:
+;
+;              saveWarn_saved from saEntry__success
+;              saveWarn_close from saEntry__closed
+
+               EXPORT  saveWarn
+saveWarn       ROUT
+
+               STMFD   R13!,{R0-R5,R12,R14}    ;Save some registers
+               WSPACE  sw__wSpace              ;Find my workspace address
+
+               ; --- Save some data in workspace ---
+
+               MOV     R0,#0                   ;Clear flags word now
+               STMIA   R12,{R0,R3-R5}          ;Save values in workspace
+
+               ; --- Work out whether we need to warn the user ---
+
+               TST     R6,#1                   ;Is the file safe?
+               BNE     %80saveWarn             ;Yes -- just trash it then
+
+               ; --- Give the user a warning ---
+
+               TST     R6,#2                   ;Is the file sensibly named?
+               ADREQ   R0,sw__noName           ;No -- point to general msg
+               ADRNE   R0,sw__named            ;Yes -- point to name msg
+               BL      msgs_lookup             ;Translate the message
+               BLNE    str_buffer              ;Get a nice string buffer
+               BLNE    str_subst               ;And substitute the name
+
+               ADR     R1,sw__warnBlk          ;Point to button definition
+               BL      warning                 ;Ask the big question
+               BCC     %50saveWarn             ;If not `Save...' skip on
+
+               ; --- User wants to try to save the file ---
+
+               LDMIA   R13,{R0-R5}             ;Load saveAs arguments
+               ADD     R3,R3,#4                ;Point past our entry point
+               MOV     R14,#swFlag__saving     ;Just about to open save box
+               STR     R14,sw__flags           ;Save this flags word
+               BL      saveAs                  ;Try to save the file
+               BVC     %90saveWarn             ;If it's OK, return
+
+               MOV     R14,#0                  ;Clear the saving flag
+               STR     R14,sw__flags           ;Save the flags again
+               MOV     R1,#1                   ;Display error with 1 button
+               BL      errorBox                ;Tell user we failed
+               B       %90saveWarn             ;And now return to caller
+
+               ; --- User chose `Cancel' or `Discard' ---
+
+50saveWarn     CMP     R0,#1                   ;Did we choose `Discard'?
+               BNE     %90saveWarn             ;No -- then do nothing at all
+
+80saveWarn     BL      sw__discard             ;Discard the document
+
+90saveWarn     LDMFD   R13!,{R0-R5,R12,PC}^    ;And return to caller
+
+sw__noName     DCB     "swSDC0",0
+sw__named      DCB     "swSDC1",0
+
+sw__warnBlk    BUTTON  "swSAVE"
+               BUTTON  "swDISC"
+               BCANCEL
+               BUTEND
+
+               LTORG
+
+; --- sw__discard ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Discards the document.
+
+sw__discard    ROUT
+
+               STMFD   R13!,{R0,R10,R12,R14}   ;Save some registers
+               LDMIB   R12,{R0,R10,R12}        ;Load user call arguments
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R0                   ;Call discard routine
+               LDMFD   R13!,{R0,R10,R12,PC}^   ;And return to caller
+
+               LTORG
+
+; --- saveWarn_saved ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Informs saveWarn that the document has been saved.  If
+;              saveWarn is not operating, this call is ignored.  You should
+;              only call this routine if the document is *safe*, rather than
+;              RAM transferred to another application, for example.
+
+               EXPORT  saveWarn_saved
+saveWarn_saved ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  sw__wSpace              ;Find my workspace
+               LDR     R14,sw__flags           ;Load the flags word
+               ORR     R14,R14,#swFlag__saved  ;Say that it's been saved
+               STR     R14,sw__flags           ;Save the flags back
+               LDMFD   R13!,{R12,PC}^          ;And return to caller
+
+               LTORG
+
+; --- saveWarn_close ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Informs saveWarn that the save dialogue box has been closed.
+;              If the document is now saved, then it is removed from
+;              memory.
+
+               EXPORT  saveWarn_close
+saveWarn_close ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  sw__wSpace              ;Find my workspace
+               LDR     R14,sw__flags           ;Load the flags word
+               CMP     R14,#3                  ;Are both bits set?
+               BLEQ    sw__discard             ;Yes -- discard the document
+               MOVEQ   R14,#0                  ;Clear the flags
+               STREQ   R14,sw__flags           ;And save them back
+               LDMFD   R13!,{R12,PC}^          ;And return to caller
+
+               LTORG
+
+sw__wSpace     DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+sw__wStart     #       0
+
+sw__flags      #       4                       ;Various useful flags
+sw__table      #       4                       ;Address of client's table
+sw__R10                #       4                       ;Value to pass in R10
+sw__R12                #       4                       ;Value to pass in R12
+
+sw__wSize      EQU     {VAR}-sw__wStart
+
+swFlag__saving EQU     (1<<0)                  ;We have a save box open
+swFlag__saved  EQU     (1<<1)                  ;User has saved the document
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     sw__wSize
+               DCD     sw__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/screen b/StraySrc/Libraries/Sapphire/s/screen
new file mode 100644 (file)
index 0000000..9b6b63c
--- /dev/null
@@ -0,0 +1,261 @@
+;
+; screen.s
+;
+; Screen mode information caching (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:sapphire
+               GET     sapphire:event
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- screen_getInfo ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to screen information block
+;
+; Use:         This call returns a pointer to a block of information
+;              about the current screen modes.  The format of this block
+;              is defined above.
+
+               EXPORT  screen_getInfo
+screen_getInfo ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R0,screen__wSpace       ;Get my workspace offset
+               LDR     R14,sapph_workspace     ;Load workspace base address
+               ADD     R0,R14,R0               ;Find workspace address
+               ADD     R0,R0,#4                ;Point to the data block
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- screen_cache ---
+;
+; On entry:    R12 points to workspace
+;
+; On exit:     --
+;
+; Use:         Caches screen information for the current mode.
+
+               EXPORT  screen_cache
+screen_cache   ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Stack some registers
+
+               ; --- Now read relevent mode variables ---
+
+               MOV     R3,#1                   ;A useful value
+               MOV     R0,#-1                  ;Get info on current mode
+
+               MOV     R1,#4                   ;XEigFactor
+               SWI     OS_ReadModeVariable     ;Read its value
+               MOV     R4,R2                   ;Look after xEig
+               MOV     R9,R3,LSL R4            ;Get dx correctly
+
+               MOV     R1,#5                   ;YEigFactor
+               SWI     OS_ReadModeVariable     ;Read its value
+               MOV     R5,R2                   ;Look after yEig
+               MOV     R10,R3,LSL R5           ;Get dy correctly
+
+               MOV     R1,#9                   ;Log2BPP
+               SWI     OS_ReadModeVariable     ;Read its value
+               MOV     R6,R3,LSL R2            ;Calculate bpp
+
+               MOV     R1,#11                  ;XWindLimit
+               SWI     OS_ReadModeVariable     ;Read its value
+               ADD     R2,R2,#1                ;Calculate screen width
+               MOV     R7,R2,LSL R4            ;width=(XwindLimit+1)<<xEig
+
+               MOV     R1,#12                  ;XWindLimit
+               SWI     OS_ReadModeVariable     ;Read its value
+               ADD     R2,R2,#1                ;Calculate screen width
+               MOV     R8,R2,LSL R5            ;height=(YwindLimit+1)<<yEig
+
+               ; --- Now store the cached information ---
+
+               STMIB   R12,{R4-R10}            ;Store in my workspace
+
+               ; --- And return to caller ---
+
+               LDMFD   R13!,{R0-R10,PC}^       ;Return
+
+               LTORG
+
+; --- screen__postFilter ---
+;
+; On entry:    R0 == wimp event type
+;              R1 == pointer to returned block
+;              R12 == pointer to my workspace
+;
+; On exit:     --
+;
+; Use:         Called as a post filter to cache screen information on
+;              a mode change.
+
+screen__postFilter
+               ROUT
+
+               ; --- Do we want this event ---
+
+               CMP     R0,#2                   ;Open window request?
+               MOVEQS  PC,R14                  ;Yes -- return PDQ
+
+               STMFD   R13!,{R0,R2,R14}        ;Save registers
+               LDR     R2,screen__flags        ;Get the flags word
+               CMP     R0,#17                  ;Is event a message?
+               CMPNE   R0,#18
+               BICNE   R2,R2,#sFlag__newMode   ;No -- clear 'changed mode'
+               STRNE   R2,screen__flags        ;...store back flags
+               LDMNEFD R13!,{R0,R2,PC}^        ;...and return
+
+               ; --- Is it the right message ---
+
+               LDR     R14,[R1,#16]            ;Get the message type
+               LDR     R0,=&400C1              ;Is it a mode change?
+               CMP     R14,R0                  ;Compare the values
+               BICNE   R2,R2,#sFlag__newMode   ;No -- clear 'changed mode'
+               STRNE   R2,screen__flags        ;...store back flags
+               LDMNEFD R13!,{R0,R2,PC}^        ;...and return
+
+               ; --- Cache the mode information ---
+
+               ORR     R2,R2,#sFlag__newMode   ;Set 'changed mode' bit
+               STR     R2,screen__flags        ;Store back flags
+               BL      screen_cache            ;Cache screen info
+
+               ; --- And return ---
+
+               LDMFD   R13!,{R0,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- screen_justChangedMode ---
+;
+; On entry:    --
+;
+; On exit:     CS if last event was a mode change, CC otherwise
+;
+; Use:         Informs the caller if the last event was a mode change.
+;              The system ignores open window requests when making it's
+;              decision.
+
+               EXPORT  screen_justChangedMode
+screen_justChangedMode ROUT
+
+               STMFD   R13!,{R12,R14}          ;Stack some registers
+               WSPACE  screen__wSpace          ;Locate my workspace
+
+               LDR     R14,screen__flags       ;Get the flags word
+               TST     R14,#sFlag__newMode     ;Test relevant bit
+               LDMFD   R13!,{R12,R14}          ;Restore my registers
+               BICEQS  PC,R14,#C_flag          ;It wasn't -- clear carry
+               ORRNES  PC,R14,#C_flag          ;It was -- set carry
+
+               LTORG
+
+; --- screen_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the screen unit.
+
+               EXPORT  screen_init
+screen_init    ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Stack some registers
+               WSPACE  screen__wSpace          ;Get my workspace
+
+               ; --- Are we already initialised? ---
+
+               LDR     R0,screen__flags        ;Get my flags
+               TST     R0,#sFlag__inited       ;Are we initialised?
+               LDMNEFD R13!,{R0,R1,R12,PC}^    ;Yes -- return
+
+               ORR     R0,R0,#sFlag__inited    ;Set flags
+               STR     R0,screen__flags        ;And store them back
+
+               ; --- Now cache the current mode info ---
+
+               BL      screen_cache
+
+               ; --- Ensure that the event system is initialised ---
+
+               BL      event_init
+
+               ; --- Finally, set up a post filter to catch mode changes ---
+
+               ADR     R0,screen__postFilter   ;Routine to call
+               MOV     R1,R12                  ;Put my workspace in R12
+               BL      event_postFilter        ;Add the post filter
+
+               ; --- That's it now ---
+
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return
+
+               LTORG
+
+screen__wSpace DCD     0                       ;My workspace pointer
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+screen__wStart #       0
+
+screen__flags  #       4                       ;Flags
+
+screen__xEig   #       4                       ;X Eig Factor
+screen__yEig   #       4                       ;Y Eig Factor
+screen__bpp    #       4                       ;Bits per pixel
+screen__width  #       4                       ;Current screen width
+screen__height #       4                       ;Current screen height
+screen__dx     #       4                       ;x pixel size
+screen__dy     #       4                       ;y pixel size
+
+screen__wSize  EQU     {VAR}-screen__wStart
+
+sFlag__inited  EQU     (1<<0)                  ;I've been initialised
+sFlag__newMode EQU     (1<<1)                  ;Mode change just happened
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     screen__wSize           ;Workspace size
+               DCD     screen__wSpace          ;Workspace pointer
+               DCD     0                       ;Scratchpad size
+               DCD     screen_init             ;Initialisation code
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/seh b/StraySrc/Libraries/Sapphire/s/seh
new file mode 100644 (file)
index 0000000..b51326b
--- /dev/null
@@ -0,0 +1,274 @@
+;
+; seh.s
+;
+; Structured Exception Handling, the Sapphire way
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:except
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- seh_try ---
+;
+; On entry:    R0 == pointer to catch definition block
+;
+; On exit:     R13 dropped by a (small) amount
+;
+; Use:         Inserts an exception handler at the current position.
+;              Exceptions are matched against those described in the catch
+;              block.  If there is a handler for the exception, the
+;              corresponding handler is called, and expected to resume
+;              normally.  Otherwise the tidy-up routine is called and we
+;              unwind the stack further to find an appropriate handler.
+;
+;              The catch block has the following format:
+;
+;              word    B to tidy-up routine
+;              word    1st exception mask
+;              word    1st B to catch routine
+;              word    2nd exception mask
+;              word    2nd B to catch routine
+;              ...
+;              word    0
+;
+;              An exception mask contains two halfwords.  Bits 16-31 are the
+;              class to match, or -1 for all classes.  Bits 0-15 are the
+;              subtype to match, or -1 for all subtypes.  You can do really
+;              odd things if you set bits 16-31 to -1 and leave 0-15
+;              matching specific subtypes -- do this at your own risk.
+
+               EXPORT  seh_try
+seh_try                ROUT
+
+               SUB     R13,R13,#16             ;Leave space for our record
+               STMFD   R13!,{R0,R12,R14}       ;Save some registers
+
+               ; --- Save caller's R10 and R12 ---
+
+               ADD     R14,R13,#16             ;Point to area in frame
+               STMIA   R14,{R0,R10,R12}        ;Save the registers away
+
+               ; --- Now fiddle with the try list ---
+
+               WSPACE  seh__wSpace             ;Find my workspace
+               LDR     R14,seh__currList       ;Find the current list
+               LDR     R0,[R14,#0]             ;Load the current value
+               STR     R0,[R13,#12]            ;Save that away nicely
+               ADD     R0,R13,#12              ;Point to the frame we made
+               STR     R0,[R14,#0]             ;This is the new list head
+               LDMFD   R13!,{R0,R12,PC}^       ;And return to caller
+
+               LTORG
+
+; --- seh_unTry ---
+;
+; On entry:    --
+;
+; On exit:     R13 moved to position before corresponding seh_try
+;
+; Use:         Removes the try block marker in the stack at the current
+;              position.  Note that the stack will be unwound to where it
+;              was when seh_try was called.
+
+               EXPORT  seh_unTry
+seh_unTry      ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers
+               MOV     R1,R13                  ;Remember this stack frame
+               WSPACE  seh__wSpace             ;Find my workspace
+               LDR     R14,seh__currList       ;Find the current list
+               LDR     R13,[R14,#0]            ;Load the unwound stack ptr
+               LDR     R0,[R13],#16            ;Load the old list position
+               STR     R0,[R14,#0]             ;Store this away nicely
+               LDMIA   R1,{R0,R1,R12,PC}^      ;And return to caller
+
+               LTORG
+
+; --- seh_throw ---
+;
+; On entry:    R0 == exception to match
+;              R1-R3 == useful bits of information
+;
+; On exit:     Doesn't return, unless you've done something /really/ odd
+;
+; Use:         Throws an exception.  The stack is unwound until we find
+;              a handler which can cope.  If there is no handler, we abort
+;              the program.
+
+               EXPORT  seh_throw
+seh_throw      ROUT
+
+               WSPACE  seh__wSpace             ;Find my workspace
+               LDR     R9,seh__currList        ;Find the current list
+
+               ; --- Now go through the list ---
+
+05             LDR     R13,[R9,#0]             ;Get the top try block
+               CMP     R13,#0                  ;Have we run out of trys?
+               BEQ     %90seh_throw            ;Yes -- oh deary me
+               LDR     R14,[R13],#4            ;Load the previous pointer
+               STR     R14,[R9,#0]             ;And store it away
+               LDMIA   R13!,{R8,R10,R12}       ;Load useful things out
+
+               ; --- Now find a matching catch ---
+
+               MOV     R14,#&00FF              ;Build &FFFF
+               ORR     R14,R14,#&FF00          ;Because it's useful
+
+               ADD     R7,R8,#4                ;Skip past tidy-up routine
+01             LDR     R6,[R7],#8              ;Load the exception mask
+               CMP     R6,#0                   ;Have we finished here?
+               BEQ     %10seh_throw            ;Yes -- deal with this then
+               MOV     R5,R6,LSL #16           ;Isolate the bottom half
+               CMP     R5,R14,LSL #16          ;Is it a wildcard?
+               CMPNE   R5,R0,LSL #16           ;Or does it match?
+               BNE     %b01                    ;No -- move on then
+               MOV     R5,R6,LSR #16           ;Isolate the top half
+               CMP     R5,R14                  ;Is it a wildcard?
+               CMPNE   R5,R0,LSR #16           ;Or does it match?
+               BNE     %b01                    ;No -- move on then
+
+               SUB     PC,R7,#4                ;Go and do the exception
+
+10seh_throw    MOV     R14,PC                  ;Set up return address
+               MOV     PC,R8                   ;So call tidy-up code
+               B       %b05                    ;And try another block
+
+               ; --- No catch blocks found ---
+               ;
+               ; Oh dear.  Things go very badly now.
+
+90seh_throw    MOV     R2,R0                   ;Get the exception type
+               LDR     R13,sapph_stackBase     ;Find a stack somewhere
+               ADR     R0,seh__noHandler       ;Point to the error block
+               BL      msgs_error              ;Translate it nicely
+               B       except_fatal            ;Report a fatal error
+
+seh__noHandler DCD     1
+               DCB     "sehNOHND",0
+
+               LTORG
+
+; --- seh_throwErrors ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets up an except-style error handler to throw errors
+;              as SEH exceptions.
+
+               EXPORT  seh_throwErrors
+seh_throwErrors        ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADR     R0,seh__handler         ;Point to the handler
+               MOV     R1,#0                   ;Don't care about R12
+               MOV     R2,#0                   ;Don't even care about R13
+               BL      except_returnPt         ;Register that nicely
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+seh__handler   ADD     R0,PC,#0                ;Point to `resume point'
+               MOVS    PC,R14                  ;And return to except
+
+               ADD     R1,R11,#4               ;Point to error message
+               MOV     R0,#&00010000           ;Exception number for error
+               B       seh_throw               ;Throw it to the handler
+
+               LTORG
+
+; --- seh_setListBase ---
+;
+; On entry:    R0 == pointer to try block list base, or 0 to use global
+;
+; On exit:     --
+;
+; Use:         Sets the try block list base.  This should only be used by
+;              coroutine providers, like coRoutine and thread.
+
+               EXPORT  seh_setListBase
+seh_setListBase        ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  seh__wSpace             ;Find my workspace
+               MOVS    R14,R0                  ;Get the value to save
+               ADREQ   R14,seh__tryList        ;If zero, use our pointer
+               STR     R14,seh__currList       ;Store away in the block
+               LDMFD   R13!,{R12,PC}^          ;And return to caller
+
+               LTORG
+
+; --- seh_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises SEH's facilities.
+
+               EXPORT  seh_init
+seh_init       ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  seh__wSpace             ;Find my workspace
+               ADR     R14,seh__tryList        ;Find the global list
+               STR     R14,seh__currList       ;This is the current one
+               LDMFD   R13!,{R12,PC}^          ;And return to caller
+
+               LTORG
+
+seh__wSpace    DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+seh__wStart    #       0
+
+seh__tryList   #       4                       ;The global try list head
+seh__currList  #       4                       ;Address of current list
+
+seh__wSize     EQU     {VAR}-seh__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     seh__wSize
+               DCD     seh__wSpace
+               DCD     0
+               DCD     seh_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/sprite b/StraySrc/Libraries/Sapphire/s/sprite
new file mode 100644 (file)
index 0000000..0c5455a
--- /dev/null
@@ -0,0 +1,263 @@
+;
+; sprite.s
+;
+; Nice operations on sprites
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:resspr
+               GET     sapphire:screen
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- sprite_op ---
+;
+; On entry:    R0,R2-R7 ==  SpriteOp parameters (R1 set up here)
+;
+; On exit:     Registers and flags altered as for the SpriteOp
+;
+; Use:         Performs an OS_SpriteOp with the given arguments, using
+;              the appication's Sprites resource as the sprite area.
+
+               EXPORT  sprite_op
+sprite_op      ROUT
+
+               STMFD   R13!,{R0,R14}           ;Stack some registers
+
+               ; --- Get the current resource sprite area ---
+
+               BL      resspr_area             ;Get area in R0
+               MOV     R1,R0                   ;Put it in R1
+               LDMFD   R13!,{R0}               ;Get the SpriteOp back
+
+               ; --- Is it the WIMP sprite area (Yrggg...) ---
+
+               CMP     R1,#1                   ;Is it WIMP area?
+               BEQ     %00sprite_op            ;Yes -- deal with it
+
+               ; --- We must be using the user sprite area ---
+
+               ORR     R0,R0,#&100             ;Use user area
+               SWI     XOS_SpriteOp            ;Do the SpriteOp
+               LDMFD   R13!,{PC}               ;And return to the user
+
+               ; --- Use the WIMP sprite area ---
+
+00sprite_op    SWI     XWimp_SpriteOp          ;Do SpriteOp on WIMP area
+               LDMFD   R13!,{PC}               ;And return to the user
+
+               LTORG
+
+; --- sprite_getTable ---
+;
+; On entry:    R0 == pointer to a sprite
+;              R1 == pointer to buffer for translate table
+;
+; On exit:     --
+;
+; Use:         Creates a colour translate table for the given sprite in
+;              the specified buffer.
+;
+;              If you have a sprite name but no pointer, use OS_SpriteOp
+;              24 to find the pointer -- this will make further sprite ops
+;              on the sprite much quicker.
+
+               EXPORT  sprite_getTable
+sprite_getTable        ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Save some registers
+               MOV     R7,R0                   ;Keep the sprite pointer
+               MOV     R8,R1                   ;Keep the buffer pointer
+
+               ; --- Find out how many colours the sprite has ---
+
+               MOV     R2,R7                   ;Get the sprite pointer
+               MOV     R1,#&1000               ;No particular sprite area
+               MOV     R0,#40                  ;Get sprite information
+               ADD     R0,R0,#512              ;Tell it I have a sprite ptr
+               SWI     OS_SpriteOp             ;Read the sprite information
+               MOV     R0,R6                   ;Get the sprite's mode
+               MOV     R1,#3                   ;Read number of colours
+               SWI     OS_ReadModeVariable     ;Read the mode value nicely
+               MOV     R9,R2                   ;Keep number of colours
+
+               ; --- Handle the Wimp palette ---
+                ;
+                ; If the sprite has 16 colours and no palette, we assume it
+                ; should have the Wimp palette, and so use that.
+
+               CMP     R2,#15                  ;Does it have 16 colours?
+               LDREQ   R14,[R7,#32]            ;Get the sprite offset
+               CMPEQ   R14,#44                 ;Is there no palette?
+               BNE     %10sprite_getTable      ;No to either -- skip it out
+
+               ; --- Read the WIMP palette, and use that ---
+
+               SUB     R13,R13,#80             ;Drop the stack pointer
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_ReadPalette        ;Read the Wimp palette
+               MOV     R0,R6                   ;Source mode set up
+               MOV     R2,#-1                  ;Use current mode
+               MOV     R3,#-1                  ;Use current palette too
+               MOV     R4,R8                   ;Create in caller's buffer
+               SWI     ColourTrans_SelectTable ;Set up the table nicely
+               ADD     R13,R13,#80             ;Restore the stack pointer
+               B       %90sprite_getTable      ;And skip to the end
+
+               ; --- Try and use the RISC OS 3 way ---
+
+10             MOV     R0,#&1000               ;No sprite area in particular
+               MOV     R1,R7                   ;Point to my sprite
+               MOV     R2,#-1                  ;Output in current mode
+               MOV     R3,#-1                  ;And into current palette
+               MOV     R4,R8                   ;Into the caller's buffer
+               MOV     R5,#1                   ;And output a sprite table
+               SWI     XColourTrans_SelectTable ;Try and read the table
+               BVC     %90sprite_getTable      ;If it worked, finish
+
+               ; --- If the sprite has no palette, just assume default ---
+
+               CMP     R9,#15                  ;Is the number of colours>16?
+               BGT     %15sprite_getTable      ;Yes -- assume def palette
+               LDR     R14,[R7,#32]            ;Get the sprite offset
+               CMP     R14,#44                 ;Is there a palette?
+               BNE     %20sprite_getTable      ;Yes -- handle it then
+
+15             MOV     R0,R6                   ;Source mode set up
+               MOV     R1,#0                   ;Assume default palette
+               MOV     R2,#-1                  ;Use current mode
+               MOV     R3,#-1                  ;Use current palette too
+               MOV     R4,R8                   ;Create in caller's buffer
+               SWI     ColourTrans_SelectTable ;Set up the table nicely
+               B       %90sprite_getTable      ;And skip to the end
+
+               ; --- Read the palette from the sprite ---
+
+20             ADD     R0,R7,#44               ;Point to first palette entry
+               SUB     R13,R13,R9,LSL #2       ;And make space for palette
+               MOV     R1,R13                  ;Point to palette buffer
+               MOV     R2,R9                   ;Copy the colour count
+
+25             LDR     R14,[R0],#8             ;Load a palette word
+               STR     R14,[R1],#4             ;Save it into the buffer
+               SUBS    R2,R2,#1                ;Decrement the counter
+               BGE     %25sprite_getTable      ;If more to do, go round
+
+               MOV     R0,R6                   ;Source mode set up
+               MOV     R1,R13                  ;Point to my nice palette
+               MOV     R2,#-1                  ;Use current mode
+               MOV     R3,#-1                  ;Use current palette too
+               MOV     R4,R8                   ;Create in caller's buffer
+               SWI     ColourTrans_SelectTable ;Set up the table nicely
+               ADD     R13,R13,R9,LSL #2       ;Reclaim the stack again
+
+               ; --- Return to caller ---
+
+90             LDMFD   R13!,{R0-R9,PC}^        ;Return to caller
+
+               LTORG
+
+; --- sprite_plot ---
+;
+; On entry:    R0 == pointer to a sprite
+;              R1 == x coordinate to plot at
+;              R2 == y coordinate to plot at
+;              R3 == pointer to scale block, or 0 for 1:1
+;
+; On exit:     CS if the sprite was plotted OK, else CC
+;
+; Use:         Plots a sprite on the screen.  The scaling refers to the
+;              sprite proper: /this/ routine takes care of odd pixel
+;              sizes and things, so sprites don't appear squashed or
+;              stretched unless you really want them to.
+;
+;              We return C clear on exit if we couldn't plot the sprite;
+;              typically this would be if the sprite's mode is undefined.
+
+               EXPORT  sprite_plot
+sprite_plot    ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Save some registers
+
+               CMP     R3,#0                   ;Has he given a scaling?
+               ADREQ   R3,sprite__scale        ;No -- use our own one
+               LDMIA   R3,{R5-R8}              ;Load the scaling out
+
+               ; --- Fiddle with the scale factors ---
+
+               MOV     R3,R1                   ;Remember this position
+               MOV     R4,R2                   ;And this one please
+               MOV     R9,R0                   ;Remember the sprite addr
+               BL      screen_getInfo          ;Read the screen info
+               ADD     R14,R0,#screen_xEig     ;Find the EIG factors
+               LDMIA   R14,{R0,R1}             ;Load them out nicely
+               MOV     R7,R7,LSL R0            ;Scale down by this resn
+               MOV     R8,R8,LSL R1            ;So go and do that
+               LDR     R0,[R9,#40]             ;Load the mode gadget
+               MOV     R1,#4                   ;Read the x EIG factor
+               SWI     OS_ReadModeVariable     ;Read that then
+               BCS     %90sprite_plot          ;If it failed, return
+               MOV     R5,R5,LSL R2            ;Bump up the scaling by this
+               MOV     R1,#5                   ;Read the y EIG factor
+               SWI     OS_ReadModeVariable     ;Read that then
+               BCS     %90sprite_plot          ;If it failed, return
+               MOV     R6,R6,LSL R2            ;Bump up the scaling again
+               STMFD   R13!,{R5-R8}            ;Save them away for later
+
+               ; --- Now read the translation table and plot ---
+
+               MOV     R0,R9                   ;Point to the sprite
+               MOV     R1,R11                  ;Build table in R11-space
+               BL      sprite_getTable         ;Go and do that then
+
+               MOV     R0,#52                  ;Put sprite scaled
+               ORR     R0,R0,#512              ;Use my pointed-at sprite
+               MOV     R1,#&1000               ;A bogus sprite area
+               MOV     R2,R9                   ;Point to the sprite
+               MOV     R5,#8                   ;Plot with a mask
+               MOV     R6,R13                  ;Point to scale factors
+               MOV     R7,R11                  ;And to the translate table
+               SWI     XOS_SpriteOp            ;Plot and ignore error
+               ADD     R13,R13,#16             ;Restore stack pointer
+               BVS     %90sprite_plot          ;If it failed, abort
+               LDMFD   R13!,{R0-R9,R14}        ;Restore registers
+               ORRS    PC,R14,#C_flag          ;And return to caller
+
+90sprite_plot  LDMFD   R13!,{R0-R9,R14}        ;Restore registers
+               BICS    PC,R14,#C_flag          ;And return to caller
+
+sprite__scale  DCD     1,1,1,1
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/sqrt b/StraySrc/Libraries/Sapphire/s/sqrt
new file mode 100644 (file)
index 0000000..d572dde
--- /dev/null
@@ -0,0 +1,87 @@
+;
+; sqrt.s
+;
+; Fast square root routines
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- sqrt ---
+;
+; On entry:    R0 == value to square-root
+;
+; On exit:     R0 == the result
+;
+; Use:         Evaluates the square root of the number given.  This routine
+;              is constructed from the information supplied by David Seal,
+;              and is *extremely* fast.
+
+               EXPORT  sqrt
+sqrt           ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack registers
+               MOV     R1,#0                   ;Result so far
+               MOV     R2,#0                   ;Current remainder
+               MOV     R3,#1                   ;A '01' pair
+               MOV     R4,#3                   ;A nice mask
+
+               GBLA    count
+count          SETA    0                       ;Start the count at 30
+
+               WHILE   count<=28               ;Set up the loop condition
+
+               AND     R14,R4,R0,LSR #30-count
+               ORR     R2,R14,R2,LSL #2
+               ORR     R14,R3,R1,LSL #2
+               CMP     R2,R14
+               ADC     R1,R1,R1
+               SUBCS   R2,R2,R14
+
+count          SETA    count+2
+
+               WEND
+
+               AND     R14,R4,R0
+               ORR     R2,R14,R2,LSL #2
+               ORR     R14,R3,R1,LSL #2
+               CMP     R2,R14
+               ADC     R1,R1,R1
+               SUBCS   R2,R2,R14
+
+c              MOV     R0,R1                   ;Put the result in R0
+               LDMFD   R13!,{R1-R4,PC}^        ;Return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/string b/StraySrc/Libraries/Sapphire/s/string
new file mode 100644 (file)
index 0000000..66a4ad9
--- /dev/null
@@ -0,0 +1,466 @@
+;
+; string.s
+;
+; String handling routines (control terminated) (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:sapphire
+
+;----- Main code ------------------------------------------------------------
+;
+; No string routine corrupts the scratchpad.
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- str_cpy ---
+;
+; On entry:    R0 == destination string
+;              R1 == source string
+;
+; On exit:     R0 == pointer to terminator of destination
+;
+; Use:         Copies a string from one block to another.  It leaves the
+;              destination pointer at the end of the string so that any
+;              subsequent copies concatenate other bits on the same string.
+;              Single characters can of course be appended with
+;
+;                      MOV     Rx,#&cc
+;                      STRB    Rx,[R0],#1
+
+               EXPORT  str_cpy
+str_cpy                ROUT
+
+               STMFD   R13!,{R1,R14}           ;Keep return address safe
+00str_cpy      LDRB    R14,[R1],#1             ;Get a byte from source
+               CMP     R14,#' '                ;Is it a control character
+               MOVLT   R14,#0                  ;Yes -- translate to a 0
+               STRB    R14,[R0],#1             ;Store in destination
+               BGE     %00str_cpy              ;No -- copy another byte
+               SUB     R0,R0,#1                ;Point back at terminator
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- str_len ---
+;
+; On entry:    R0 == pointer to string
+;
+; On exit:     R0 == length of the string
+;
+; Use:         Calculates the length of a string.
+
+               EXPORT  str_len
+str_len                ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               MOV     R14,R0                  ;Point to the string
+               MOV     R0,#0                   ;Current length is 0
+00str_len      LDRB    R1,[R14],#1             ;Get a byte from the string
+               CMP     R1,#' '                 ;Is it the end yet?
+               LDMLTFD R13!,{R1,PC}^           ;Yes -- return
+               ADD     R0,R0,#1                ;Bump the length counter
+               B       %00str_len              ;And go back for more
+
+               LTORG
+
+; --- str_cmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         Case-sensitively compares two strings.  You can use the
+;              normal ARM condition codes after the compare, so you can
+;              treat this fairly much like a normal CMP.
+
+               EXPORT  str_cmp
+str_cmp                ROUT
+
+               STMFD   R13!,{R0,R1,R3,R4,R14}
+00str_cmp      LDRB    R3,[R0],#1              ;Get a character from A
+               LDRB    R4,[R1],#1              ;And one from B
+               CMP     R3,#&20                 ;Is that the end of A?
+               MOVLT   R3,#0                   ;Yes -- pretend it's null
+               CMP     R4,#&20                 ;Is that the end of B?
+               MOVLT   R4,#0                   ;Yes -- pretend it's null
+               CMP     R3,R4                   ;How do they match up?
+               LDMNEFD R13!,{R0,R1,R3,R4,PC}   ;If NE, return condition
+               CMP     R3,#0                   ;Is this the end?
+               BNE     %00str_cmp              ;No -- loop again
+               LDMFD   R13!,{R0,R1,R3,R4,PC}   ;Return to caller
+
+; --- str_icmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         As for str_cmp above, but case-insensitive.
+
+               EXPORT  str_icmp
+str_icmp       ROUT
+
+               STMFD   R13!,{R0,R1,R3,R4,R14}
+00str_icmp     LDRB    R3,[R0],#1              ;Get a character from A
+               LDRB    R4,[R1],#1              ;And one from B
+               SUB     R14,R3,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R3,R3,#&20              ;Yes -- convert to upper
+               SUB     R14,R4,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R4,R4,#&20              ;Yes -- convert to upper
+               CMP     R3,#&20                 ;Is that the end of A?
+               MOVLT   R3,#0                   ;Yes -- pretend it's null
+               CMP     R4,#&20                 ;Is that the end of B?
+               MOVLT   R4,#0                   ;Yes -- pretend it's null
+               CMP     R3,R4                   ;How do they match up?
+               LDMNEFD R13!,{R0,R1,R3,R4,PC}   ;If NE, return condition
+               CMP     R3,#0                   ;Is this the end?
+               BNE     %00str_icmp             ;No -- loop again
+               LDMFD   R13!,{R0,R1,R3,R4,PC}   ;Return to caller
+
+               LTORG
+
+; --- str_index ---
+;
+; On entry:    R0 == pointer to name table
+;              R1 == index into name table
+;
+; On exit:     CS if index good, and
+;                R0 == address of R0th string in table
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Finds an indexed string in a table.  The table consists of
+;              ctrl-terminated strings, with no separation.  The table is
+;              terminated by a zero-length entry.
+
+               EXPORT  str_index
+str_index      ROUT
+
+               ORRS    R14,R14,#C_flag         ;Set C initially
+               STMFD   R13!,{R1,R14}           ;Save a register or two
+05             SUBS    R1,R1,#1                ;Decrement the counter
+               LDMCCFD R13!,{R1,PC}^           ;And return to caller
+
+               LDRB    R14,[R0],#1             ;Load byte from string
+               CMP     R14,#&20                ;Is this the end?
+               BCC     %10str_index            ;Yes -- ooops
+00             LDRB    R14,[R0],#1             ;No -- load another
+               CMP     R14,#&20                ;Is this the end?
+               BCS     %b00                    ;No -- loop then
+               B       %b05                    ;Go back to main loop
+
+10str_index    LDMFD   R13!,{R1,R14}           ;And return to caller
+               BICS    PC,R14,#C_flag          ;With a bad result
+
+               LTORG
+
+; --- str_match ---
+;
+; On entry:    R0 == pointer to name table
+;              R1 == string to match in table
+;
+; On exit:     CS if match found, and
+;                R0 == index of string matched
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Looks up a string in a table.  The table consists of
+;              ctrl-terminated strings, with no separation.  The table is
+;              terminated by a zero-length entry.
+
+               EXPORT  str_match
+str_match      ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+               MOV     R2,#0                   ;Index of the current item
+               LDRB    R14,[R1,#0]             ;Load the first byte
+               CMP     R14,#0                  ;Is it a null string?
+               BEQ     %90str_match            ;Yes -- no match then
+
+               ; --- The main loop ---
+
+00str_match    MOV     R3,R1                   ;Point to argument start
+               LDRB    R4,[R0],#1              ;Load a byte from the table
+               LDRB    R5,[R3],#1              ;Load a byte from the arg
+               CMP     R4,#&20                 ;Is this an empty string?
+               BCC     %90str_match            ;Yes -- no match then
+
+               ; --- Try to match a word ---
+
+10str_match    CMP     R5,#&20                 ;End of argument string?
+               BCC     %80str_match            ;Yes -- that's a match then
+               SUB     R14,R4,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R4,R4,#&20              ;Yes -- convert to upper
+               SUB     R14,R5,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R5,R5,#&20              ;Yes -- convert to upper
+               CMP     R4,R5                   ;Do characters match up?
+               LDREQB  R4,[R0],#1              ;Load a byte from the table
+               LDREQB  R5,[R3],#1              ;Load a byte from the arg
+               BEQ     %10str_match            ;Yes -- go round for more
+
+               ; --- Failed -- find end of table entry ---
+
+20str_match    CMP     R4,#&20                 ;End of entry string?
+               LDRCSB  R4,[R0],#1              ;No -- load byte from table
+               BCS     %20str_match            ;And go round again
+               ADD     R2,R2,#1                ;Increment item index
+               B       %00str_match            ;Loop round for next entry
+
+               ; --- Found a match ---
+
+80str_match    MOV     R0,R2                   ;Get the item index
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack the registers
+               ORRS    PC,R14,#C_flag          ;And return with C set
+
+               ; --- No match found ---
+
+90str_match    LDMFD   R13!,{R1-R5,R14}        ;Unstack the registers
+               BICS    PC,R14,#C_flag          ;And return with C clear
+
+               LTORG
+
+; --- str_subst ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R1 == Pointer to output buffer
+;              R2-R11 == Pointer to filler strings (optional)
+;
+; On exit:     R0 == Pointer to start of buffer
+;              R1 == Pointer to terminating null
+;
+; Use:         Performs string substitution, filling in a skeleton string
+;              containing placeholders with `filler' strings.  The
+;              placeholders are actually rather powerful.  The syntax of
+;              these is as follows:
+;
+;                      `%' [<type>] <digit>
+;
+;              (spaces are for clarity -- in fact you must not include
+;              spaces in the format string.)
+;
+;              <digit> is any charater between `0' and `9'.  It refers to
+;              registers R2-R11 (so `0' means R2, `5' is R7 etc.)  How the
+;              value is interpreted is determined by <type>.
+;
+;              <type> is one of:
+;
+;              s       String.  This is the default.  The register is
+;                      considered to be a pointer to an ASCII string
+;                      (control terminated).
+;
+;              i       Integer.  The (signed) decimal representation is
+;                      inserted.  Leading zeros are suppressed.
+;
+;              x       Hex fullword.  The hexadecimal representation of the
+;                      register is inserted.  Leading zeros are included.
+;
+;              b       Hex byte.  The hexadecimal representation of the
+;                      least significant byte is inserted.  Leading zeros
+;                      are included.
+;
+;              c       Character.  The ASCII character corresponding to the
+;                      least significant byte is inserted.
+
+               EXPORT  str_subst
+str_subst      ROUT
+
+               STMFD   R13!,{R1-R11,R14}
+
+               ; --- Move arguments into more amenable registers ---
+
+               MOV     R10,R0                  ;Pointer to skeleton string
+
+               ; --- Main `get a character' loop ---
+
+00str_subst    LDRB    R14,[R10],#1            ;Get an input character
+               CMP     R14,#'%'                ;Is it a `%' sign?
+               BEQ     %01str_subst            ;Yes -- deal with it
+02str_subst    CMP     R14,#&20                ;Is it the end of input?
+               MOVLT   R14,#0                  ;Yes -- null terminate it
+               STRB    R14,[R1],#1             ;Not special, so store it
+               BGE     %00str_subst            ;No -- get another one
+               SUB     R1,R1,#1                ;Point to null terminator
+               LDMFD   R13!,{R0,R2-R11,PC}^    ;And return to caller
+
+               ; --- Found a `%' sign, so find out what to substitute ---
+
+01str_subst    LDRB    R14,[R10],#1            ;Get the next character
+
+               ; --- Now find out what we're substituting ---
+
+               ORR     R9,R14,#&20             ;Convert it to lowercase
+               CMP     R9,#'s'                 ;Is it a string?
+               CMPNE   R9,#'i'                 ;Or an integer?
+               CMPNE   R9,#'x'                 ;Or a fullword hex number?
+               CMPNE   R9,#'b'                 ;Or a single byte in hex?
+               CMPNE   R9,#'c'                 ;Or an ASCII character?
+               LDREQB  R14,[R10],#1            ;And get another character
+
+               ; --- Now find which filler it is ---
+
+               CMP     R14,#'0'                ;Is it a digit?
+               BLT     %02str_subst            ;No -- just ignore the `%'
+               CMP     R14,#'9'                ;Make sure it's small enough
+               BGT     %02str_subst            ;No -- just ignore the `%'
+               SUB     R14,R14,#'0'-1          ;Convert to binary (1..10)
+               LDR     R0,[R13,R14,LSL #2]     ;Load appropriate register
+
+               ; --- Now find out how to substitute this argument ---
+
+               MOV     R2,#256                 ;Buffer size -- saves space
+
+               CMP     R9,#'s'                 ;Is it meant to be a string?
+               BEQ     %03str_subst            ;Yes -- a quick copy loop
+               CMP     R9,#'i'                 ;A decimal integer?
+               BEQ     %04str_subst            ;Yes -- go ahead to convert
+               CMP     R9,#'x'                 ;A hex fullword?
+               BEQ     %05str_subst            ;Yes -- convert that
+               CMP     R9,#'b'                 ;A hex byte?
+               BEQ     %06str_subst            ;Yes -- convert that
+               CMP     R9,#'c'                 ;A character?
+               BEQ     %07str_subst            ;Yes -- convert that
+
+               ; --- String substitution copy-loop ---
+
+03str_subst    LDRB    R14,[R0],#1             ;Get an input byte
+               CMP     R14,#&20                ;Is it the end of the string?
+               BLT     %00str_subst            ;Yes -- read main string
+               STRB    R14,[R1],#1             ;No -- store it in output
+               B       %03str_subst            ;... and get another one
+
+               ; --- Decimal integer conversion ---
+
+04str_subst    SWI     OS_ConvertInteger4      ;Convert and update nicely
+               B       %00str_subst            ;And rejoin the main loop
+
+               ; --- Hexadecimal fullword conversion ---
+
+05str_subst    SWI     OS_ConvertHex8          ;Convert and update nicely
+               B       %00str_subst            ;And rejoin the main loop
+
+               ; --- Hexadecimal byte conversion ---
+
+06str_subst    SWI     OS_ConvertHex2          ;Convert and update nicely
+               B       %00str_subst            ;And rejoin the main loop
+
+               ; --- ASCII character conversion ---
+
+07str_subst    STRB    R0,[R1],#1              ;Store the byte in
+               B       %00str_subst            ;And rejoin the main loop
+
+               LTORG
+
+; --- str_error ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R2-R11 == Pointers to fillin strings
+;
+; On exit:     R0 == Pointer to error in buffer
+;              R1 == Pointer to terminator
+;
+; Use:         Fills in an error skeleton (containing a 4 byte error number
+;              and a control terminated skeleton string as for str_subst)
+;              and returns the address of the filled in error block.  The
+;              error block is stored in a buffer obtained from str_buffer.
+;
+;              Filler strings may be held in the scratchpad.
+
+               EXPORT  str_error
+str_error      ROUT
+
+               STMFD   R13!,{R14}              ;Store the link register
+               BL      str_buffer              ;Find a spare buffer
+               LDR     R14,[R0],#4             ;Get the error number
+               STR     R14,[R1],#4             ;Output it too
+               BL      str_subst               ;Do the string substitution
+               SUB     R0,R0,#4                ;Point to the error start
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+str__wSpace    DCD     0                       ;Pointer to error buffer
+
+; ---- str_buffer ---
+;
+; On entry:    --
+;
+; On exit:     R1 == pointer to the next free buffer
+;
+; Use:         Returns a pointer to a 256-byte buffer.  There are at present
+;              2 buffers, which are returned alternately.
+
+               EXPORT  str_buffer
+str_buffer     ROUT
+
+               STMFD   R13!,{R14}              ;Save a work register
+
+               ; --- Work out which buffer to use ---
+               ;
+               ; This uses some vaguely clever tricks, so watch out  [mdw]
+               ; In fact, the C compiler used exactly the same tricks when
+               ; tried `return (buffer+256*(count^=1))'.
+
+               WSPACE  str__wSpace,R1          ;Find workspace address
+               LDR     R14,[R1,#0]             ;Get the current buffer
+               EOR     R14,R14,#1              ;Toggle the buffer number
+               STR     R14,[R1],#4             ;Store the new one back
+               ADD     R1,R1,R14,LSL #8        ;Point to correct buffer
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+str__buffers   EQU     2                       ;Use two buffers for now
+
+               ^       0                       ;Don't tie it to R12
+str__wStart    #       0
+
+str__buffNum   #       4
+str__buffer    #       256*str__buffers        ;The number of buffers I want
+
+str__wSize     EQU     {VAR}-str__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     str__wSize              ;For the error buffer
+               DCD     str__wSpace             ;Pointer to the pointer
+               DCD     0                       ;Don't use the scratchpad
+               DCD     0                       ;No initialisation reqd.
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/stub b/StraySrc/Libraries/Sapphire/s/stub
new file mode 100644 (file)
index 0000000..c5c44a2
--- /dev/null
@@ -0,0 +1,186 @@
+;
+; stub.s
+;
+; Stub loader for dynamically linked Sapphire
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  sapphire_doInit
+               IMPORT  sapphire_doLibInit
+               IMPORT  sapphire_doDisable
+               IMPORT  except_init
+               IMPORT  except_atExit
+
+               IMPORT  |DLL$$ExternalTable$$Base|,WEAK
+               IMPORT  |DLL$$ExternalTable$$Limit|,WEAK
+
+               IMPORT  |Image$$RW$$Limit|,WEAK
+
+               IMPORT  |Sapphire$$LibData$$Base|,WEAK
+               IMPORT  |Sapphire$$LibData$$Limit|,WEAK
+               IMPORT  |Sapphire$$ClientData$$Base|,WEAK
+               IMPORT  |Sapphire$$ClientData$$Limit|,WEAK
+               IMPORT  |Sapphire$$ExtTable$$Base|,WEAK
+               IMPORT  |Sapphire$$ExtTable$$Limit|,WEAK
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+               EXPORT  |_dll_findall|
+|_dll_findall| EQU     0
+
+; --- sapphire_init ---
+;
+; On entry:    R0 == pointer to application name
+;              R1 == client workspace size
+;              R2 == requested size of stack
+;
+; On exit:     R10 == pointer to heap
+;              R11 == pointer to scratchpad and environment information
+;              R12 == pointer to client workspace
+;              R13 == stack pointer
+;              Other registers corrupted
+;
+; Use:         Initialises the Sapphire library.
+
+               EXPORT  sapphire_init
+sapphire_init  ROUT
+
+               ; --- Save arguments in high registers ---
+
+               STR     R14,sapph__space        ;Save return address
+               MOV     R8,R0                   ;Keep application name ptr
+               MOV     R9,R1                   ;Keep workspace size value
+               MOV     R10,R2                  ;Keep stack size too
+
+               ; --- Load in requested DLLs ---
+
+               ADR     R0,sapph__dllTable      ;Point to DLL table thing
+               LDMIA   R0,{R0,R1}              ;Load the base and limit
+               SWI     DLL_FindFromTable       ;Load the DLLs I want
+
+               ; --- Set up application name ---
+
+               MOV     R0,R8                   ;Point to client app name
+               SWI     DLL_NameApp             ;Register application name
+
+               ; --- Initialise the library ---
+
+               MOV     R0,R8                   ;Point to the name again
+               MOV     R1,R9                   ;Get workspace size wanted
+               MOV     R2,R10                  ;Get the stack size
+               ADR     R3,sapph__initTable     ;Point to initialisation tbl
+               BL      sapphire_doInit         ;Do the main initialisation
+
+               ; --- Now add in atexit routine ---
+
+               LDR     R14,sapph__space        ;Load the return address
+               STMFD   R13!,{R14}              ;Save it on the stack
+               SWI     DLL_SaveHandle          ;Find my application handle
+               BL      except_init             ;Initialise exception handler
+               MOV     R1,R0                   ;Pass this value in R12
+               ADR     R0,sapph__closeDown     ;Point to shutdown routine
+               BL      except_atExit           ;Register my routine
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+sapph__dllTable        DCD     |DLL$$ExternalTable$$Base|
+               DCD     |DLL$$ExternalTable$$Limit|
+
+sapph__initTable
+               DCD     |Image$$RW$$Limit|
+               DCD     |Sapphire$$LibData$$Base|
+               DCD     |Sapphire$$LibData$$Limit|
+               DCD     |Sapphire$$ClientData$$Base|
+               DCD     |Sapphire$$ClientData$$Limit|
+               DCD     -1
+               DCD     |Sapphire$$ExtTable$$Base|
+               DCD     |Sapphire$$ExtTable$$Limit|
+
+sapph__space   DCD     0
+
+               LTORG
+
+; --- sapph__closeDown ---
+;
+; On entry:    R12 == application handle
+;
+; On exit:     --
+;
+; Use:         Deregisters the application with the DLLManager module.
+
+sapph__closeDown ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R12                  ;Get application handle
+               SWI     DLL_RestoreHandle       ;Find the handle again
+               SWI     DLL_AppDying            ;Deregister this application
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               LTORG
+
+; --- sapphire_libInit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises all library sections.
+
+               EXPORT  sapphire_libInit
+sapphire_libInit
+               STMFD   R13!,{R0,R14}           ;Save a register
+               ADR     R0,sapph__initTable     ;Point to initialisation tbl
+               BL      sapphire_doLibInit      ;Actually do this job
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               LTORG
+
+; --- sapphire_disable ---
+;
+; On entry:    R0 == pointer to list of initialise routines.
+;
+; On exit:     --
+;
+; Use:         Inactivates Sapphire units.
+
+               EXPORT  sapphire_disable
+sapphire_disable
+               STMFD   R13!,{R1,R14}           ;Save a register
+               ADR     R1,sapph__initTable     ;Point to initialisation tbl
+               BL      sapphire_doDisable      ;Actually do this job
+               LDMFD   R13!,{R1,PC}^           ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/subAlloc b/StraySrc/Libraries/Sapphire/s/subAlloc
new file mode 100644 (file)
index 0000000..86f79c6
--- /dev/null
@@ -0,0 +1,217 @@
+;
+; suballoc.s
+;
+; Handling of requests for small link blocks (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:mem
+               GET     sapphire:sapphire
+
+;----- Word to the wise -----------------------------------------------------
+;
+; Various bits of Sapphire require lots of small blocks for linked lists and
+; things.  To avoid mangling the heap, we allocate very big blocks and then
+; split them up into littler ones.  These big blocks just contain lots of
+; little ones.
+;
+; The data blocks are allocated such that they are just big enough for the
+; data -- the caller must specify the actual size of the block when freeing.
+; Completely free big blocks just stay in the heap ready to be allocated
+; again by this system.  They are not returned to the heap.
+;
+; We keep a table of pointers to the big block lists for each supported
+; block size.  This is rather like the `bins' idea in the C library malloc
+; algorithms.
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- sub_alloc ---
+;
+; On entry:    R0 == size of block to allocate
+;
+; On exit:     R0 == pointer to block allocated
+;              May return an error
+;
+; Use:         Allocates a block of the size specified, typically very
+;              quickly indeed.
+;
+;              If the size is not one of those supported (currently
+;              supported sizes are 8-40 inclusive in 4 byte increments),
+;              the behaviour is undefined (but very predictable).
+
+               EXPORT  sub_alloc
+sub_alloc      ROUT
+
+               STMFD   R13!,{R1-R3,R12,R14}
+
+               ; --- Find the correct table entry ---
+
+               WSPACE  sub__wSpace             ;Find my workspace
+               ADD     R1,R12,R0               ;Find the entry in the table
+
+               ; --- Are there any free blocks? ---
+
+               LDR     R2,[R1]                 ;Get the free list offset
+               CMP     R2,#0                   ;Are there any free blocks?
+               BEQ     %20sub_alloc            ;No -- better allocate some
+
+               ; --- Mess about with the free list and return ---
+
+10sub_alloc    LDR     R0,[R2]                 ;Get next pointer from block
+               STR     R0,[R1]                 ;This is now first free block
+               MOV     R0,R2                   ;Return the old free block
+               LDMFD   R13!,{R1-R3,R12,R14}    ;Restore registers and return
+               BICS    PC,R14,#V_flag          ;Clear error as we leave
+
+               ; --- Create a big block ---
+               ;
+               ; We're now using alloc for this.  To avoid extra memory
+               ; usage, we nobble alloc's `extra' word which allows it
+               ; to find the free routine, because we'll never free it
+               ; anyway!
+
+20sub_alloc    MOV     R2,R0                   ;Keep the size safe
+               MOV     R0,R0,LSL #3            ;Find the chunk size
+               SUB     R0,R0,#4                ;This is evil.  I don't care
+               BL      alloc                   ;Allocate some memory
+               BCS     %90sub_alloc            ;If failed, report error
+               SUB     R0,R0,#4                ;Gobble alloc's overhead
+
+               ; --- Now set up the links for the free list ---
+
+               MOV     R14,#0                  ;Next free pointer start at 0
+               MOV     R3,#8                   ;We have 8 blocks to do
+00             STR     R14,[R0],R2             ;Store in next field
+               SUB     R14,R0,R2               ;Remember old block pointer
+               SUBS    R3,R3,#1                ;Point to previous block
+               BGT     %b00                    ;If more to do, continue...
+
+               ; --- The links are set up -- now take off a block ---
+
+               MOV     R2,R14                  ;Use last block allocated
+               B       %10sub_alloc            ;Then allocate as normal
+
+               ; --- Handle an error ---
+
+90             BL      alloc_error             ;Find the error message
+               LDMFD   R13!,{R1-R3,R12,R14}    ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- sub_free ---
+;
+; On entry:    R0 == pointer to block
+;              R1 == size of the block
+;
+; On exit:     --
+;
+; Use:         Frees a block allocated using sub_alloc.
+
+               EXPORT  sub_free
+sub_free       ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Preserve registers
+
+               ; --- Find the correct table entry ---
+
+               WSPACE  sub__wSpace             ;Find my workspace
+               ADD     R1,R12,R1               ;Find the entry in the table
+
+               ; --- Mess about with the list ---
+
+               LDR     R14,[R1]                ;Get current first block
+               STR     R14,[R0]                ;Store in newly freed block
+               STR     R0,[R1]                 ;And insert new block in list
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Oh, and return to caller
+
+               LTORG
+
+; --- sub_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the suballocation system for use.
+
+               EXPORT  sub_init
+sub_init       ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers
+               WSPACE  sub__wSpace             ;Find my workspace
+
+               ; --- Am I initialised? ---
+
+               LDR     R14,sub__flags          ;Get my flags word
+               TST     R14,#sub__INITED        ;Test the flag
+               LDMNEFD R13!,{R0-R2,R12,PC}^    ;Yes -- return to caller
+
+               ; --- Set up the workspace properly ---
+
+               ORR     R14,R14,#sub__INITED    ;We are now initialised
+               STR     R14,sub__flags          ;Store it in the flags
+               ADD     R0,R12,#4               ;Point to the table
+               MOV     R1,#10*4                ;Number of entries supported
+               MOV     R2,#0                   ;Zero them all
+               BL      mem_set                 ;Zero-initialise my workspace
+               BL      alloc_init              ;Make sure alloc is awake
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller
+
+               LTORG
+
+sub__wSpace    DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+sub__wStart    #       0
+
+sub__flags     #       0                       ;Various interesting flags
+
+sub__INITED    EQU     (1<<0)                  ;Am I initialised?
+
+sub__table     #       4*10                    ;The suballoc root table
+
+sub__wSize     EQU     {VAR}-sub__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     sub__wSize
+               DCD     sub__wSpace
+               DCD     0
+               DCD     sub_init
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/template b/StraySrc/Libraries/Sapphire/s/template
new file mode 100644 (file)
index 0000000..73c783e
--- /dev/null
@@ -0,0 +1,979 @@
+;
+; template.s
+;
+; Load window template resources (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:fastMove
+               GET     sapphire:except
+               GET     sapphire:mem
+               GET     sapphire:msgs
+               GET     sapphire:res
+               GET     sapphire:resources
+               GET     sapphire:resspr
+               GET     sapphire:sapphire
+               GET     sapphire:string
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- tpl__find ---
+;
+; On entry:    R0 == pointer to name to find
+;
+; On exit:     CS if template found in list, and
+;                R0 == pointer to template block (internal format)
+;              else CC if in shared resource
+;                R0 == pointer to embedded template definition
+;              May return an error
+;
+; Use:         Finds a named template in the list.
+
+tpl__find      ROUT
+
+               ORRS    R14,R14,#C_flag         ;Set C initially
+               STMFD   R13!,{R1,R2,R12,R14}    ;Stack some registers
+               WSPACE  template_wspace         ;Find my workspace
+               LDR     R2,template_list        ;Find the list head
+
+               ; --- Go through the list trying to find one ---
+
+00             CMP     R2,#0                   ;Is this the list end?
+               BEQ     %10tpl__find            ;Yes -- return the error
+               ADD     R1,R2,#tlist_name       ;Find this template's name
+               BL      str_icmp                ;Compare the names
+               LDRNE   R2,[R2,#tlist_next]     ;If no match, get next one...
+               BNE     %b00                    ;And go round again
+
+               ; --- We found a match!!! ---
+
+               MOV     R0,R2                   ;Point to the template
+               LDMFD   R13!,{R1,R2,R12,R14}    ;Unstack some registers
+               BICS    PC,R14,#V_flag          ;Return with no error
+
+               ; --- No match -- try shared resource ---
+
+10tpl__find    MOV     R1,R0                   ;Point to the template name
+               MOV     R0,#rsType_template     ;Search for template resource
+               BL      resources_find          ;Try to find the resource
+               LDMCSFD R13!,{R1,R2,R12,R14}    ;If it worked, get registers
+               BICCSS  PC,R14,#C_flag + V_flag ;And return with no error
+
+               ; --- Couldn't find it then ---
+
+20tpl__find    MOV     R2,R1                   ;Point to the template name
+               ADR     R0,tpl__notfound        ;Point to error message
+               BL      msgs_error              ;Translate the message
+               LDMFD   R13!,{R1,R2,R12,R14}    ;Unstack some registers
+               ORRS    PC,R14,#V_flag          ;Return with the error
+
+tpl__notfound  DCD     1
+               DCB     "tplTNF",0
+
+               LTORG
+
+; --- template_find ---
+;
+; On entry:    R0 == pointer to name to match
+;
+; On exit:     R0 == pointer to window definition if found
+;              May return an error
+;
+; Use:         Locates a template in the list and gives you a pointer to
+;              the corresponding window defintion.  You may update the
+;              definition to store an updated window state if you really
+;              want to.
+;
+;              Note that this call will fail if you attempt to find a
+;              template which is held in the shared resources DLL.
+
+               EXPORT  template_find
+template_find  ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save return address
+               MOV     R2,R0                   ;Remember the name
+               BL      tpl__find               ;Find the definition
+               BVS     %10template_find        ;If failed, skip onwards
+               BCC     %05template_find        ;If in resource DLL, skip
+               ADD     R0,R0,#tlist_size       ;Point to window def
+               LDMFD   R13!,{R1,R2,R14}        ;Return to caller
+               BICS    PC,R14,#V_flag
+
+               ; --- It's in the resources DLL ---
+
+05template_find        ADR     R0,tpl__notfound        ;Point to error message
+               BL      msgs_error              ;Translate the message
+
+               ; --- Couldn't find the template ---
+
+10template_find        LDMFD   R13!,{R1,R2,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- template_copy ---
+;
+; On entry:    R0 == pointer to name to match
+;
+; On exit:     R0 == pointer to copy of a window definition
+;              May return an error
+;
+; Use:         Returns a copy of a window template (for the use of the
+;              dialogue box system mainly), including all indirected data
+;              set up properly and everything.  The copy is writable.  To
+;              get rid of the copy, call template_free.
+
+               EXPORT  template_copy
+template_copy  ROUT
+
+               ; --- Find the copy first ---
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+               BL      tpl__find               ;Find the definition
+               BVS     %99template_copy        ;If it failed, tidy up
+               BCC     %50template_copy        ;In resources -- handle it
+               MOV     R5,R0                   ;Keep pointer to definition
+
+               ; --- Now allocate the memory we need ---
+
+               LDR     R0,[R5,#84+tlist_size]  ;Get the number of icons
+               MOV     R0,R0,LSL #5            ;Multiply by 32 for size
+               ADD     R0,R0,#88+tlist_size    ;Bump up by overhead
+               MOV     R2,R0                   ;Keep the size safe
+               BL      alloc                   ;Allocate the memory
+               BCS     %98template_copy        ;If that failed, skip ahead
+               MOV     R4,R0                   ;Keep that pointer safe
+
+               ; --- Copy the window defintion over ---
+
+               MOV     R1,R5                   ;Point to the definition
+               MOV     R0,R4                   ;And my new block
+               BL      fastMove                ;Copy that data across
+
+               ; --- Now see if we need do anything else
+
+               LDR     R0,[R5,#tlist_indsize]  ;Get indirected data size
+               CMP     R0,#0                   ;Is there any?
+               BEQ     %10template_copy        ;If not, skip past this bit
+
+               ; --- Allocate the indirected space ---
+
+               MOV     R2,R0                   ;Look after the size
+               BL      alloc                   ;Allocate the new block
+               BCS     %97template_copy        ;And tidy up if it failed
+
+               ; --- Copy indirected data over ---
+
+               LDR     R1,[R5,#tlist_indptr]   ;Find the old indirect block
+               BL      fastMove                ;Copy it over very quickly
+               STR     R0,[R4,#tlist_indptr]   ;Store the new block pointer
+
+               ; --- Now fix up all the references ---
+
+               SUB     R5,R0,R1                ;Get the relocation offset
+               LDR     R0,[R4,#56+tlist_size]  ;Get the title bar flags
+               ADD     R1,R4,#72+tlist_size    ;Point to the title data
+               BL      tpl__fixData            ;Fix up that data
+
+               LDR     R3,[R4,#84+tlist_size]  ;Get the number of icons
+               ADD     R2,R4,#88+tlist_size    ;Point to the first icon
+00template_copy        SUBS    R3,R3,#1                ;Decrement the icon counter
+               LDRGE   R0,[R2,#16]             ;Get the icon flags word
+               ADDGE   R1,R2,#20               ;Point to the icon data
+               BLGE    tpl__fixData            ;And fix up the icon data
+               ADDGE   R2,R2,#32               ;Move onto the next icon
+               BGE     %00template_copy        ;And move onto the next one
+
+               ; --- All done -- return the pointer ---
+
+10template_copy        ADD     R0,R4,#tlist_size       ;Point to the actual defn
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack a load of registers
+               BICS    PC,R14,#V_flag          ;Return to caller
+
+               ; --- It's in the resources DLL ---
+
+50template_copy        LDMFD   R13!,{R1-R5,R14}        ;Restore these registers
+               B       template_embedded       ;Extract embedded definition
+
+               ; --- Error -- free the template block ---
+
+97template_copy        MOV     R0,R4                   ;Point to the template block
+               BL      free                    ;Free up the block
+
+               ; --- Return the error ---
+
+98template_copy        BL      alloc_error             ;Find the correct error mesg
+
+99template_copy        LDMFD   R13!,{R1-R5,R14}        ;Restore the registers
+               ORRS    PC,R14,#V_flag          ;Return to caller
+
+               LTORG
+
+; --- tpl__fixData ---
+;
+; On entry:    R0 == icon flags
+;              R1 == pointer to icon data to fix
+;              R5 == offset to bodge data by
+;
+; On exit:     Registers preserved
+;
+; Use:         Relocates indirected data by a given amount
+
+tpl__fixData   ROUT
+
+               TST     R0,#&00000100           ;Is it indirected?
+               MOVEQS  PC,R14                  ;No -- return right now
+
+               ; --- Fix up icon data ---
+
+               STMFD   R13!,{R14}              ;Save the link register
+               LDR     R14,[R1,#0]             ;Get the data pointer
+               ADD     R14,R14,R5              ;Relocate it
+               STR     R14,[R1,#0]             ;And store it back again
+
+               ; --- Is there validation data too? ---
+
+               TST     R0,#&00000001           ;Does it contain text data?
+               LDRNE   R14,[R1,#4]             ;Yes -- get validation ptr
+               CMPNE   R14,#-1                 ;If the pointer sensible?
+               LDMEQFD R13!,{PC}^              ;No -- return
+
+               ; --- Relocate validation string pointer ---
+
+               ADD     R14,R14,R5              ;Relocate it
+               STR     R14,[R1,#4]             ;Store it back in the block
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- template_embedded ---
+;
+; On entry:    R0 == pointer to embedded template definition
+;
+; On exit:     R0 == pointer to copy (as for template_copy)
+;
+; Use:         Extracts an embedded template into a template block.
+;              Embedded templates can be generated using the templAOF
+;              program, and then linked into your application.
+
+               EXPORT  template_embedded
+template_embedded ROUT
+
+               STMFD   R13!,{R1-R7,R14}        ;Save some registers
+
+               ; --- First load the header out ---
+
+               LDMIA   R0,{R3-R5}              ;Load the three pointers out
+               ADD     R3,R3,R0                ;Relocate the window pointer
+               ADD     R4,R4,R0                ;Relocate the ind base ptr
+               ADD     R5,R5,R0                ;Relocate the ind limit ptr
+               ADD     R6,R0,#12               ;And find the relocation tbl
+
+               ; --- Allocate a block for the window definition ---
+
+               LDR     R14,[R3,#84]            ;Load the number of icons
+               MOV     R0,#88+tlist_size       ;Get the base memory req
+               ADD     R0,R0,R14,LSL #5        ;Add space for the icons
+               SUB     R2,R0,#tlist_size       ;Keep size without extras
+               BL      alloc                   ;Try to allocate the space
+               BLCS    alloc_error             ;If it failed, get error
+               BCS     %99template_embedded    ;And skip onwards
+               MOV     R7,R0                   ;Look after this pointer
+
+               ; --- Copy the window data over ---
+
+               ADD     R0,R7,#tlist_size       ;Point to window def area
+               MOV     R1,R3                   ;Point to the original def
+               BL      fastMove                ;Copy that over
+
+               ; --- Now handle the data ---
+
+               SUBS    R0,R5,R4                ;Find indirected data size
+               STR     R0,[R7,#tlist_indsize]  ;Store the size away
+               STREQ   R0,[R7,#tlist_indptr]   ;If none, store null ptr
+               BEQ     %10template_embedded    ;And skip on to relocate
+
+               BL      alloc                   ;Allocate the space
+               BLCS    alloc_error             ;If it failed, get error
+               BCS     %98template_embedded    ;And skip onwards
+               STR     R0,[R7,#tlist_indptr]   ;Store the pointer
+
+               ; --- Copy the data over ---
+
+               MOV     R1,R4                   ;Point to original data
+               SUB     R2,R5,R4                ;Find the data size
+               BL      fastMove                ;Copy it over nicely
+
+               ; --- Finally do the relocation ---
+
+10             MOV     R5,R0                   ;Look after indirected addr
+               BL      resspr_area             ;Find the sprite area
+               MOV     R4,R0                   ;Look after that too
+               ADD     R0,R7,#tlist_size       ;Find window definition
+
+00             CMP     R6,R3                   ;Finished yet?
+               BCS     %90template_embedded    ;Yes -- wrap things up
+               LDR     R14,[R6],#4             ;Load next directive
+               MOV     R2,R14,LSR #28          ;Get the directive type
+               BIC     R14,R14,#&F0000000      ;And the offset
+               ADD     PC,PC,R2,LSL #2         ;Dispatch to handler
+               DCB     "MDW!"
+               B       %15template_embedded
+               B       %20template_embedded
+               B       %b00
+
+15             LDR     R2,[R0,R14]             ;Load the word
+               ADD     R2,R2,R5                ;Relocate for indirectedness
+               STR     R2,[R0,R14]             ;Store it back again
+               B       %b00                    ;Loop
+
+20             STR     R4,[R0,R14]             ;Store the sprite area
+               B       %b00                    ;Loop
+
+               ; --- Finished -- return ---
+
+90             LDMFD   R13!,{R1-R7,R14}        ;Load lots of registers
+               BICS    PC,R14,#V_flag          ;And return errorless
+
+               ; --- Errors -- tidy up ---
+
+98             MOV     R6,R0                   ;Look after error pointer
+               MOV     R0,R7                   ;Get the template block
+               BL      free                    ;Free it
+               MOV     R0,R6                   ;Restore error pointer
+
+99             LDMFD   R13!,{R1-R7,R14}        ;Load lots of registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- template_free ---
+;
+; On entry:    R0 == pointer to block allocated with template_copy
+;
+; On exit:     --
+;
+; Use:         Frees a template copy created using template_copy.
+
+               EXPORT  template_free
+template_free  ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               SUB     R1,R0,#tlist_size       ;Find base of block
+               LDR     R0,[R1,#tlist_indptr]   ;Get indirect data pointer
+               CMP     R0,#0                   ;Is there any indirect data?
+               BLNE    free                    ;Yes -- free the memory
+               MOV     R0,R1                   ;Get the block pointer
+               BL      free                    ;Free that too
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- template_load ---
+;
+; On entry:    R0 == pointer to name of template file to load
+;
+; On exit:     May return an error
+;
+; Use:         Loads the specified template file, and adds its window
+;              definitions into the template list so they can be used when
+;              creating dialogue boxes or windows.
+;
+;              If the templates can't be loaded (e.g. there isn't enough
+;              memory) an error is generated (and can be caught using the
+;              standard Sapphire except mechanism).
+
+               EXPORT  template_load
+template_load  ROUT
+
+               ; --- We need a lot of registers! ---
+
+               STMFD   R13!,{R0-R12,R14}       ;Save the registers we want
+               WSPACE  template_wspace         ;Find my workspace
+
+               ; --- Find out how big the file is ---
+
+               MOV     R1,R0                   ;Point to the filename
+               MOV     R0,#17                  ;Info about file please
+               SWI     XOS_File                ;Try to load the file
+               BVS     %99template_load        ;If no luck, make the error
+
+               ; --- Allocate a heap block for it ---
+
+               MOV     R0,R4                   ;Get the template file size
+               BL      alloc                   ;Allocate the block
+               BLCS    alloc_error             ;If it failed, get error
+               BCS     %99template_load        ;If no luck, make the error
+               MOV     R8,R0                   ;Guard pointer with life :-)
+
+               ; --- Load template file into buffer ---
+
+               MOV     R0,#16                  ;Load a file into memory
+               LDR     R1,[R13,#0]             ;Get the filename back
+               MOV     R2,R8                   ;Point to my buffer
+               MOV     R3,#0                   ;Load into my buffer
+               SWI     XOS_File                ;Load the file now
+               BVS     %98template_load        ;Bad news -- free block first
+
+               ; --- Now we can parse the file up ---
+
+               ADD     R10,R8,#16              ;Find the first index entry
+00template_load        LDR     R0,[R10,#0]             ;Is this an empty entry?
+               CMP     R0,#0                   ;Just check quickly
+               BEQ     %05template_load        ;Yes -- we've finished
+
+               ADD     R9,R8,R0                ;Point to the actual entry
+
+               LDR     R1,[R10,#8]             ;Get the entry type number
+               SUB     R1,R1,#1                ;Convert it to zero-indexed
+               CMP     R1,#(%11-%10)/4         ;Make sure it's recognised
+               BCS     %02template_load        ;No -- don't to it then
+               STMFD   R13!,{R8,R12}           ;Save workspace and base
+               MOV     R12,R13                 ;Point to this pair
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,PC,R1,LSL #2         ;Branch table dispatch
+               B       %01template_load        ;And link in the block
+
+10template_load        B       tpl__loadWind           ;Load a window definition
+11template_load
+
+01template_load        LDMFD   R13!,{R8,R12}           ;Find workspace too
+               BVS     %98template_load        ;It failed miserably
+
+               ; --- Link the returned block into the list ---
+
+               LDR     R1,template_list        ;Find the list head
+               STR     R1,[R0,#tlist_next]     ;Make it this one's next ptr
+               STR     R0,template_list        ;And make this the list head
+
+               ; --- Move on to the next entry ---
+
+02template_load        ADD     R10,R10,#24             ;Move to the next entry
+               B       %00template_load        ;And go back again
+
+               ; --- We finished loading the file -- free buffer ---
+
+05template_load        MOV     R0,R8                   ;Point to the file buffer
+               BL      free                    ;Free the memory now
+
+               ; --- Now we can leave ---
+
+               LDMFD   R13!,{R0-R12,R14}       ;Return to caller
+               BICS    PC,R14,#V_flag
+
+               ; --- Error encountered after block allocation ---
+
+98template_load        MOV     R9,R0                   ;Keep error pointer
+               MOV     R0,R8                   ;Point to the file buffer
+               BL      free                    ;Free the memory now
+               MOV     R0,R9                   ;Restore error pointer
+
+               ; --- Error encountered before block allocation ---
+
+99template_load        ADD     R2,R0,#4                ;Point to error message
+               ADR     R0,tload__error         ;Point to error skeleton
+               BL      msgs_error              ;Create the error message
+               ADD     R13,R13,#4              ;Skip past stacked R0
+               LDMFD   R13!,{R1-R12,R14}       ;Return to caller
+               ORRS    PC,R14,#V_flag          ;With error indicator set
+
+tload__error   DCD     1
+               DCB     "tplTLE",0
+
+               LTORG
+
+template_wspace        DCD     0
+
+; --- template_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Initialises the template list and font array, and loads the
+;              `Templates' resource file.
+
+               EXPORT  template_init
+template_init  ROUT
+
+               STMFD   R13!,{R0,R1,R12,R14}    ;Store some registers
+               WSPACE  template_wspace         ;Find my workspace
+               LDR     R14,template_list       ;Get the current list
+               CMP     R14,#0                  ;Is it silly?
+               LDMNEFD R13!,{R0,R1,R12,PC}^    ;No -- we're already running
+
+               BL      alloc_init              ;Make sure we can find memory
+               BL      resspr_init             ;This will initialise res too
+               BL      except_init             ;For atexit to tidy up later
+
+               ; --- Set up the workspace nicely ---
+
+               MOV     R0,#0                   ;Store null pointers
+               STR     R0,template_list        ;No templates yet
+               STR     R0,template_fonts       ;No fonts found either
+
+               ; --- Build the name in the scratchpad ---
+
+               ADR     R0,tpl__templates       ;Point to the resource name
+               MOV     R1,R11                  ;Point to scratchpad buffer
+               ADDS    R0,R0,#0                ;Clear C and V flags
+               BL      res_find                ;Find the resource file
+
+               ; --- Load the file and return ---
+
+               BLCS    template_load           ;Load the file if it's there
+               SWIVS   OS_GenerateError        ;If it failed, make an error
+               LDMFD   R13!,{R0,R1,R12,PC}^    ;Return to the caller
+
+tpl__templates DCB     "Templates",0
+
+               LTORG
+
+; --- tpl__killFont ---
+;
+; On entry:    R12 == pointer to template workspace
+;
+; On exit:     --
+;
+; Use:         Loses loads of fonts when the application quits
+
+tpl__killFont  ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               LDR     R1,template_fonts       ;Find the font array
+               MOV     R0,#255                 ;Start at the top for this
+00tpl__killFont        LDRB    R2,[R1,R0]              ;Get the reference counter
+01tpl__killFont        SUBS    R2,R2,#1                ;Decrement the counter
+               SWIGE   Font_LoseFont           ;Lose the font
+               BGE     %01tpl__killFont        ;And go round again
+               SUBS    R0,R0,#1                ;Decrement the handle
+               BGE     %00tpl__killFont        ;And go round again
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Template loading routines --------------------------------------------
+;
+; For all routines:
+;
+; On entry:    R9 == pointer to entry in memory
+;              R10 == pointer to index entry for this object
+;              R12 == pointer to template base and workspace block
+;
+; On exit:     If successful:
+;                R0 == pointer to template entry to add into the list
+;                V flag clear
+;              If an error occurred:
+;                R0 == pointer to standard error block
+;                V flag set
+;              R1-R9 may be corrupted
+
+; --- tpl__loadWind ---
+;
+; Use:         Loads a window definition and converts it into a template
+;              list item
+
+tpl__loadWind  ROUT
+
+               STMFD   R13!,{R14}              ;Just stack the return addr
+
+               ; --- Find out how many icons there are ---
+
+               ADD     R0,R9,#84               ;Point to the right place
+               AND     R1,R0,#3                ;Get the non-word-alignedness
+               BIC     R0,R0,#3                ;And round down to word
+               LDMIA   R0,{R2,R3}              ;Get the two words we want
+               MOV     R1,R1,LSL #3            ;Turn bytes into bits
+               MOV     R8,R2,LSR R1            ;Get the bottom few bytes
+               RSB     R1,R1,#32               ;Get the shift the other way
+               ORR     R8,R8,R3,LSL R1         ;And copy in the top bytes
+
+               ; --- R8 now contains the number of icons ---
+
+               ; --- Allocate a template block ---
+
+               MOV     R3,R8,LSL #5            ;Multiply the number by 32
+               ADD     R3,R3,#88+tlist_size    ;Add on window and list block
+               MOV     R0,R3                   ;I want to allocate memory
+               BL      alloc                   ;Allocate the space
+               BLCS    alloc_error             ;If it failed, get error
+               BCS     %99tpl__loadWind        ;If it failed, return error
+               MOV     R7,R0                   ;Keep the pointer
+
+               ; --- Copy the window definition into the block ---
+
+               ADD     R0,R7,#tlist_size       ;Where to store definition
+               SUB     R2,R3,#tlist_size       ;Size of block to copy
+               MOV     R1,R9                   ;Point to the window def
+               BL      fastMove                ;And shunt the bytes over
+
+               ; --- We may as well copy the name over now too ---
+
+               ADD     R1,R10,#12              ;Point to the template name
+               ADD     R0,R7,#tlist_name       ;Point to my block section
+               LDMIA   R1,{R2-R4}              ;Get the twelve bytes
+               STMIA   R0,{R2-R4}              ;Store them in my block
+               MOV     R1,#0                   ;And zero terminate
+               STRB    R1,[R0,#12]             ;Stop the string off nicely
+
+               ; --- Widge the sprite area ---
+
+               BL      resspr_area             ;Load the sprite area ptr
+               STR     R0,[R7,#64+tlist_size]  ;Store sprite area pointer
+
+               ; --- Now count the amount of indirected data ---
+
+               MOV     R6,#0                   ;Currently no indirected size
+
+               LDR     R5,[R7,#56+tlist_size]  ;Get the title bar flags
+               ADD     R4,R7,#72+tlist_size    ;Point to the title bar data
+               BL      tpl__dataSize           ;Add in the space required
+
+               MOV     R0,R8                   ;The number of icons I have
+               ADD     R1,R7,#88+tlist_size    ;Point to the first icon
+00tpl__loadWind        SUBS    R0,R0,#1                ;Decrement the counter
+               LDRGE   R5,[R1,#16]             ;Get the flags word here
+               ADDGE   R4,R1,#20               ;Point to the icon data
+               BLGE    tpl__dataSize           ;Add in the extra data
+               ADDGE   R1,R1,#32               ;Point to the next icon defn
+               BGE     %00tpl__loadWind        ;And go back for the rest
+
+               ; --- We now have the data size in R6 ---
+
+               STR     R6,[R7,#tlist_indsize]  ;Store the buffer size away
+               CMP     R6,#0                   ;Is there any indirect space?
+               STREQ   R6,[R7,#tlist_indptr]   ;No -- store a null pointer
+               BEQ     %01tpl__loadWind        ;... and skip past allocation
+
+               ; --- Allocate the buffer properly ---
+
+               MOV     R0,R6                   ;Get the size of the block
+               BL      alloc                   ;Allocate yet more memory
+               BLCS    alloc_error             ;If failed, get error
+               BCS     %98tpl__loadWind        ;If it failed, report error
+               MOV     R6,R0                   ;Point to the new buffer
+               STR     R6,[R7,#tlist_indptr]   ;Save indirected size away
+
+               ; --- Now copy the indirected data across ---
+               ;
+               ; We also fix up the pointers at the same time, and set up
+               ; any fonts that need loading.
+
+01tpl__loadWind        LDR     R5,[R7,#56+tlist_size]  ;Get the title bar flags
+               ADD     R4,R7,#72+tlist_size    ;Point to the title bar data
+               BL      tpl__copyData           ;Process the indirect data
+               ADD     R5,R7,#56+tlist_size    ;Point to the flags now
+               BL      tpl__findFont           ;And handle any fonts
+               BVS     %97tpl__loadWind        ;Quit if something went wrong
+
+               MOV     R0,R8                   ;The number of icons I have
+               ADD     R1,R7,#88+tlist_size    ;Point to the first icon
+02tpl__loadWind        SUBS    R0,R0,#1                ;Decrement the counter
+               BLT     %03tpl__loadWind        ;If no more, skip ahead
+               LDR     R5,[R1,#16]             ;Get the flags word here
+               ADD     R4,R1,#20               ;Point to the icon data
+               BL      tpl__copyData           ;Copy over the indirect data
+               ADD     R5,R1,#16               ;Point to the flags now
+               BL      tpl__findFont           ;And handle any fonts
+               BVS     %97tpl__loadWind        ;Quit if something went wrong
+               ADD     R1,R1,#32               ;Point to the next icon defn
+               B       %02tpl__loadWind        ;Now go back for the rest
+
+               ; --- The excitement's over now, so that's it ---
+
+03tpl__loadWind        MOV     R0,R7                   ;Point at the template block
+               LDMFD   R13!,{R14}              ;Get the link register out
+               BICS    PC,R14,#V_flag          ;And return no errors
+
+               ; --- Something screwed up -- deallocate both blocks ---
+
+97tpl__loadWind        MOV     R9,R0                   ;Save error pointer
+               LDR     R0,[R7,#tlist_indptr]   ;Find the indirect block addr
+               BL      free                    ;Free indirect data block
+               MOV     R0,R9                   ;Restore error pointer
+
+               ; --- Error occurred -- free the template block ---
+
+98tpl__loadWind        MOV     R9,R0                   ;Save error pointer
+               MOV     R0,R7                   ;Point to template block
+               BL      free                    ;Free the template block
+               MOV     R0,R9                   ;Restore error pointer
+
+               ; --- Error occurred -- return with V set ---
+
+99tpl__loadWind        LDMFD   R13!,{R14}              ;Get the link register
+               ORRS    PC,R14,#V_flag          ;Set the error indicator
+
+               LTORG
+
+;----- Support functions ----------------------------------------------------
+
+; --- tpl__dataSize ---
+;
+; On entry:    R4 == pointer to icon data
+;              R5 == icon flags word
+;              R6 == counter to increment
+;              R7 == pointer to window block
+;              R8 == number of icons in the window
+;              R9 == pointer to the window definition in the template file
+;              R10 == pointer to index for current window
+;              R12 == pointer to template base and workspace block
+;
+; On exit:     R6 incremented by an appropriate amount
+;              Everything else preserved (except R14, obviously!)
+;
+; Use:         Counts the amount of indirected space required for a given
+;              icon flags/data pair and adds it into a running total
+
+tpl__dataSize  ROUT
+
+               ; --- Make sure there's something to do ---
+
+               TST     R5,#&00000100           ;Test indirected bit
+               MOVEQS  PC,R14                  ;If not indirected, go away
+
+               ; --- Locate and count the indirected data string ---
+
+               STMFD   R13!,{R14}              ;Save some registers
+               LDR     R14,[R4,#8]             ;Get the indirect buffer size
+               ADD     R6,R6,R14               ;And add this onto the count
+
+               ; --- Check if there's a validation string ---
+
+               TST     R5,#&00000001           ;Is the `Is text' bit on?
+               LDRNE   R14,[R4,#4]             ;Yes -- get validation ptr
+               CMPNE   R14,#-1                 ;Is it a sensible pointer?
+               LDMEQFD R13!,{PC}^              ;If not, we're done for now
+
+               ; --- Count length of validation string ---
+
+               STMFD   R13!,{R0}               ;Save another register
+               ADD     R0,R14,R9               ;Point to string in memory
+               BL      str_len                 ;Find its length
+               ADD     R0,R0,#1                ;Account for the terminator
+               ADD     R6,R6,R0                ;Add this to the counter
+               LDMFD   R13!,{R0,PC}^           ;And return to the caller
+
+               LTORG
+
+; --- tpl__copyData ---
+;
+; On entry:    R4 == pointer to icon data
+;              R5 == icon flags word
+;              R6 == pointer to free part of buffer
+;              R7 == pointer to window block
+;              R8 == number of icons in the window
+;              R9 == pointer to the window definition in the template file
+;              R10 == pointer to index for current window
+;              R12 == pointer to template base and workspace block
+;
+; On exit:     R6 incremented by an appropriate amount
+;              Everything else preserved (except R14, obviously!)
+;
+; Use:         Copies indirected data from an icon definition into the
+;              buffer given and fixes up pointers in the definition
+
+tpl__copyData  ROUT
+
+               ; --- Make sure there's something to do here ---
+
+               TST     R5,#&00000100           ;Check the indirected bit
+               MOVEQS  PC,R14                  ;If unset, return right now
+
+               ; --- Handle basic indirected data ---
+
+               STMFD   R13!,{R0,R1,R14}        ;Stack some registers
+               LDR     R1,[R4,#0]              ;Get the indirected pointer
+               STR     R6,[R4,#0]              ;Store the new pointer in
+               ADD     R1,R9,R1                ;Offset by window address
+               MOV     R0,R6                   ;Point to free bit of bufffer
+               BL      str_cpy                 ;Copy (and null-terminate)
+               LDR     R14,[R4,#8]             ;Get the indirect buffer size
+               ADD     R6,R6,R14               ;Move buffer pointer on by it
+
+               ; --- Check for validation string presence ---
+
+               TST     R5,#&00000001           ;Is the `Is text' bit on?
+               LDRNE   R14,[R4,#4]             ;Yes -- get validation ptr
+               CMPNE   R14,#-1                 ;Is it a sensible pointer?
+               LDMEQFD R13!,{R0,R1,PC}^        ;If not, we're done
+
+               ; --- Handle the validation string ---
+
+               STR     R6,[R4,#4]              ;Store the new pointer
+               ADD     R1,R9,R14               ;Point to the validation str
+               MOV     R0,R6                   ;Point to the bit of buffer
+               BL      str_cpy                 ;And copy the string across
+               ADD     R6,R0,#1                ;Point R6 past string term
+               LDMFD   R13!,{R0,R1,PC}^        ;That's it from us, then
+
+               LTORG
+
+; --- tpl__findFont ---
+;
+; On entry:    R5 == pointer to icon flags word
+;              R6 == pointer to free part of buffer
+;              R7 == pointer to window block
+;              R8 == number of icons in the window
+;              R9 == pointer to the window definition in the template file
+;              R10 == pointer to index for current window
+;              R12 == pointer to template base and workspace block
+;
+; On exit:     Everything preserved except R4 (and R14, obviously!)
+;
+; Use:         Fixes up an icon's anti-aliased font data.
+
+tpl__findFont  ROUT
+
+               LDR     R4,[R5]                 ;Get the icon flags word
+               TST     R4,#&00000040           ;Is it antialiased?
+               TSTNE   R4,#&00000001           ;Make sure it's text too
+               BICEQS  PC,R14,#V_flag          ;If not, return no error
+
+               ; --- Now to business -- ensure we have a font table ---
+
+               STMFD   R13!,{R0-R3,R5,R12,R14} ;Save some registers
+               LDMIA   R12,{R5,R12}            ;Load base and workspace
+               LDR     R0,template_fonts       ;Find font array pointer
+               CMP     R0,#0                   ;Is it null?
+               BEQ     %00tpl__findFont        ;Yes -- allocate it
+
+               ; --- Now locate the font table in the file ---
+
+01tpl__findFont        LDR     R3,[R5,#0]              ;Get the font table offset
+               ADD     R3,R5,R3                ;Convert it to a pointer
+
+               ; --- Find internal font handle and get table entry ---
+
+               MOV     R0,R4,LSR #24           ;Leave only the font handle
+               SUB     R0,R0,#1                ;Convert to 0-indexed
+               STMFD   R13!,{R4,R5}            ;Need some more registers!!
+               ADD     R4,R3,R0,LSL #4         ;R4 = R3 + R0 * 16
+               ADD     R4,R4,R0,LSL #5         ;Now R4 = R3 + R0 * 48
+
+               ; --- Now we must load the font width and height ---
+               ;
+               ; The problem is that they're not on word boundaries, so
+               ; we must do clever-dick things with the barrel shifter.
+
+               AND     R0,R3,#3                ;Get the bottom two bits
+               BIC     R1,R3,#3                ;Word align the base address
+               LDMIA   R1,{R2,R3,R14}          ;Get the width and height
+               MOV     R0,R0,LSL #3            ;Convert bits to bytes
+               RSB     R1,R0,#32               ;Get the other shift too
+               MOV     R2,R2,LSR R0            ;Shift the bits down here
+               ORR     R2,R2,R3,LSL R1         ;And add in the top bits
+               MOV     R3,R3,LSR R0            ;Shift down bottom bits
+               ORR     R3,R3,R14,LSL R1        ;And add in the top bits
+
+               ; --- We are now in a position to find the font ---
+
+               ADD     R1,R4,#8                ;Point to the font name
+               MOV     R4,#0                   ;Default x scaling
+               MOV     R5,#0                   ;Default y scaling
+               SWI     Font_FindFont           ;Try very hard to find it
+               LDMFD   R13!,{R4,R5}            ;Restore these registers
+               ADDVS   R13,R13,#4              ;If it failed, skip R0,
+               LDMVSFD R13!,{R1-R3,PC}         ;... and restore regs
+
+               ; --- Now bump the item in the font array ---
+
+               LDR     R1,template_fonts       ;Find the font array
+               LDRB    R2,[R1,R0]              ;Get counter for the handle
+               ADD     R2,R2,#1                ;Bump the counter a bit
+               STRB    R2,[R1,R0]              ;And store it away again
+
+               ; --- Bodge the icon flags word for the new handle ---
+
+               BIC     R4,R4,#&FF000000        ;Clear out the old handle
+               ORR     R4,R4,R0,LSL #24        ;Bring in the new...
+               STR     R4,[R5]                 ;Store the new flags word
+               LDMFD   R13!,{R0-R3,R5,R12,R14} ;Restore the registers
+               BICS    PC,R14,#V_flag          ;And return with no error
+
+               ; --- Create the font array if it's not there ---
+
+00tpl__findFont        MOV     R0,#256                 ;One byte for each font
+               BL      alloc                   ;Allocate the memory
+               BLCS    alloc_error             ;If failed, get error
+               ADDCS   R13,R13,#4              ;If it failed, bump R13
+               LDMCSFD R13!,{R1-R3,R5,R12,PC}  ;... and return with error
+               STR     R0,template_fonts       ;Store the new pointer
+
+               ; --- Clear the font array to 0s ---
+
+               MOV     R1,#256                 ;The size of the array
+               MOV     R2,#0                   ;Value to initialise with
+               BL      mem_set                 ;Clear out the array
+
+               ; --- Register our tidy-up routine ---
+
+               ADR     R0,tpl__killFont        ;Point to tidy up function
+               MOV     R1,R12                  ;Point to my workspace
+               BL      except_atExit           ;Register it properly
+               B       %01tpl__findFont        ;Return to the main proc
+
+               LTORG
+
+;----- The list structure ---------------------------------------------------
+
+               ^       0
+tlist_start    #       0
+
+tlist_next     #       4                       ;Pointer to the next one
+tlist_name     #       16                      ;Name of this template
+tlist_indptr   #       4                       ;Pointer to indirect data
+tlist_indsize  #       4                       ;Size of indirect data
+; Window definition follows
+
+tlist_size     #       0                       ;Size of that structure
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+template_wstart        #       0
+
+template_list  #       4                       ;List head for templates
+template_fonts #       4                       ;Font array if we need one
+
+template_wsize EQU     {VAR}-template_wstart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     template_wsize
+               DCD     template_wspace
+               DCD     256
+               DCD     template_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/thread b/StraySrc/Libraries/Sapphire/s/thread
new file mode 100644 (file)
index 0000000..055abc2
--- /dev/null
@@ -0,0 +1,1418 @@
+;
+; thread.s
+;
+; Preemptive multitasking of idle threads (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:suballoc
+               GET     sapphire:idle
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+thr__stkSize   EQU     1024
+thr__idleFreq  EQU     1
+
+; --- thread_create ---
+;
+; On entry:    R0 == size of stack to allocate, or 0 for a default
+;              R1 == pointer to thread routine
+;              R2 == workspace pointer to pass in R10
+;              R3 == workspace pointer to pass in R12
+;
+; On exit:     R0 == thread handle for the thread
+;              May return an error
+;
+; Use:         Creates a new thread running `in the background' (i.e. over
+;              idle events).
+;
+;              The thread is passed control with the registers R10 and R12
+;              set up from R1 and R2 passed to this routine and R13 pointing
+;              to the top of a stack chunk.  R0 on entry contains the
+;              thread's handle.  The thread is passed the scratchpad
+;              address (in R11).  The values of other registers are
+;              indeterminate and must not be relied upon.
+;
+;              The default stack size for a new thread is 1K, although this
+;              may change in future.
+;
+;              The thread may exit by calling thread_destroy or by
+;              returning in the normal way.
+
+               EXPORT  thread_create
+thread_create  ROUT
+
+               STMFD   R13!,{R1-R8,R12,R14}    ;Save some registers
+               WSPACE  thr__wSpace             ;Load my workspace pointer
+
+               ; --- Try to allocate the stack ---
+
+               CMP     R0,#0                   ;Does he want the default?
+               MOVEQ   R0,#thr__stkSize        ;Yes -- give it to him
+               CMP     R0,#256                 ;Make sure it's big enough
+               MOVLT   R0,#256                 ;If not, make it bigger
+               MOV     R5,R0                   ;Keep a copy of the size
+               BL      alloc                   ;Try to allocate it nicely
+               BLCS    alloc_error             ;It failed, so get an error
+               BVS     %99thread_create        ;And skip to the end
+               MOV     R6,R0                   ;Keep the stack block ptr
+
+               ; --- Now allocate a thread block ---
+
+               MOV     R0,#thr__size           ;The size of the block
+               BL      alloc                   ;Allocate the block for me
+               BLCS    alloc_error             ;It failed, so get an error
+               BVS     %98thread_create        ;If it failed, skip onward
+
+               ; --- Set up the initial context ---
+
+               ADD     R5,R6,R5                ;R5 is the inital R13 to give
+               MOV     R14,R1                  ;Get start address in R14
+               MOV     R1,R2                   ;Move `R10' down a register
+               MOV     R2,R11                  ;Give scratchpad in R11
+               ADR     R4,thread_destroy       ;Returning destroys thread
+               STMFD   R5!,{R1-R4,R14}         ;Save these on the stack
+               STMFD   R5!,{R0-R9}             ;Fill the rest with rubbish
+
+               ; --- Fill in the block ---
+
+               ADD     R14,R0,#thr__suspend    ;Don't fill in the links
+               STMIA   R14,{R1-R8}             ;Store information in block
+               MOV     R1,#0                   ;Thread is not suspended yet
+               MOV     R2,#0                   ;Thread not blocked on sem
+               MOV     R3,#0                   ;Start at standard priority
+               MOV     R4,#thr__idleFreq       ;Set standard timeslice
+               STMIA   R14!,{R1-R4}            ;Save these in the block
+               MOV     R4,#0                   ;Not in critical section
+               MOV     R7,#0                   ;No flags to speak of yet
+               MOV     R8,#0                   ;No error handler defined
+               STMIA   R14!,{R4-R8}            ;Fill the rest in too
+               BL      thr__insert             ;Insert it into the list
+
+               ; --- Bump the active counter ---
+
+               BL      thr__incCount           ;Bump the active counter
+               LDMFD   R13!,{R1-R8,R12,R14}    ;Restore all the registers
+               BICS    PC,R14,#V_flag          ;Return without V set
+
+               ; --- We stumbled across a mishap ---
+
+98thread_create        MOV     R4,R0                   ;Keep the error pointer
+               MOV     R0,R6                   ;Point to the stack block
+               BL      free                    ;Deallocate it -- don't want
+               MOV     R0,R4                   ;Point to the error again
+
+99thread_create        ADD     R2,R0,#4                ;Point to the error text
+               ADR     R0,thr__noCreate        ;Point to the error block
+               BL      msgs_error              ;Set up the error nicely
+               LDMFD   R13!,{R1-R8,R12,R14}    ;Restore all the registers
+               ORRS    PC,R14,#V_flag          ;Return with V set
+
+thr__noCreate  DCD     1
+               DCB     "thrNOCRT",0
+
+               LTORG
+
+; --- thread_setPriority ---
+;
+; On entry:    R0 == thread handle
+;              R1 == new priority to set
+;
+; On exit:     --
+;
+; Use:         Changes the priority of a thread.  The priority if a thread
+;              is a signed integer.  The highest priority thread is the one
+;              which runs.  If more than one thread has maximum priority,
+;              they are run in a cyclical order.
+
+               EXPORT  thread_setPriority
+thread_setPriority ROUT
+
+               STMFD   R13!,{R2,R3,R12,R14}    ;Save some registers here
+               WSPACE  thr__wSpace             ;Load my workspace pointer
+               LDR     R14,[R0,#thr__priority] ;Get the current priority
+               CMP     R1,R14                  ;Are we changing anything?
+               LDMEQFD R13!,{R2,R3,R12,PC}^    ;No -- return right now
+
+               ; --- Unlink the thread ---
+
+               LDMIA   R0,{R2,R3}              ;Get the next and previous
+               CMP     R2,#0                   ;Is there a next pointer?
+               STRNE   R3,[R2,#thr__prev]      ;Yes -- fill in its prev
+               CMP     R3,#0                   ;Is there a prev pointer?
+               STRNE   R2,[R3,#thr__next]      ;Yes -- fill in its next
+               STREQ   R2,wsp__threads         ;No -- make next first thread
+
+               ; --- Change priority and insert the thread again ---
+
+               STR     R1,[R0,#thr__priority]  ;Save the new priority
+               BL      thr__insert             ;Insert in the right place
+               LDMFD   R13!,{R2,R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- thread_setTimeSlice ---
+;
+; On entry:    R0 == thread handle
+;              R1 == new timeslice size, in centiseconds
+;
+; On exit:     --
+;
+; Use:         Changes a thread's timeslice size.  Specify 0 to indicate
+;              that thread shouldn't be pre-empted.
+
+               EXPORT  thread_setTimeSlice
+thread_setTimeSlice ROUT
+
+               STR     R1,[R0,#thr__timeSlice] ;Save the new timeslice
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+
+; --- thread_destroy ---
+;
+; On entry:    R0 == thread handle to destroy, if not executing a thread
+;
+; On exit:     --
+;
+; Use:         Destroys either the current thread or a thread with the
+;              the given handle if no thread is executing currently.  You
+;              can't destroy an arbitrary thread while running in one.
+;
+;              If a thread is waiting for a semaphore, it is removed from
+;              the waiting list.
+
+               EXPORT  thread_destroy
+thread_destroy ROUT
+
+               STMFD   R13!,{R0-R5,R12,R14}    ;Save some registers
+               WSPACE  thr__wSpace             ;Find my workspace
+               MOV     R5,R0                   ;Keep the thread pointer
+
+               ; --- Find out which thread to destroy ---
+
+               LDR     R4,wsp__current         ;Get the current thread
+               CMP     R4,#0                   ;Is there one running?
+               MOVNE   R5,R4                   ;Yes -- destroy it then
+
+               ; --- If the thread was active, decrement active count ---
+
+               LDR     R14,[R5,#thr__suspend]  ;Get the suspension counter
+               CMP     R14,#0                  ;Is it currently active?
+               BLEQ    thr__decCount           ;Yes -- decrement actives
+
+               ; --- Remove thread from semaphore waiting lists ---
+
+               LDR     R3,[R5,#thr__semaphore] ;Get the blocking semaphore
+               CMP     R3,#0                   ;Is there one?
+               BEQ     %10thread_destroy       ;No -- skip this part
+
+               MOV     R2,#0                   ;Previous item in the list
+               LDR     R0,[R3,#sem__blocked]   ;Get the blocked list
+00             CMP     R0,#0                   ;Have we reached the end?
+               BEQ     %10thread_destroy       ;Yes -- skip onwards
+               LDR     R14,[R0,#sml__thread]   ;Get the waiting thread hnd
+               CMP     R14,R5                  ;Is it this thread?
+               MOVNE   R2,R0                   ;No -- update previous ptr
+               LDRNE   R0,[R0,#sml__next]      ;Find the next link block
+               BNE     %00thread_destroy       ;And move to next block
+
+               ; --- Delete this thread waiting block ---
+
+               LDR     R14,[R0,#sml__next]     ;Find the next link block
+               CMP     R2,#0                   ;Is there a previous block?
+               STRNE   R14,[R2,#sml__next]     ;Yes -- store it as next
+               STREQ   R14,[R3,#sem__blocked]  ;No -- next is new first item
+               CMP     R14,#0                  ;Is there a next block?
+               STREQ   R2,[R3,#sem__blockEnd]  ;No -- previous one is last
+
+               BL      free                    ;Destroy the link block
+
+               ; --- Delink the thread then ---
+
+10             LDMIA   R5,{R1,R2}              ;R1 == next, R2 == prev
+               CMP     R1,#0                   ;Is there a next?
+               STRNE   R2,[R1,#thr__prev]      ;Yes -- store prev away
+               CMP     R2,#0                   ;Is there a prev?
+               STRNE   R1,[R2,#thr__next]      ;Yes -- store next pointer
+               STREQ   R1,wsp__threads         ;No -- store as list head
+
+               ; --- Destroy the thread's memory ---
+
+               LDR     R0,[R5,#thr__stack]     ;Find the thread's stack
+               BL      free                    ;Get rid of it -- it's no use
+               MOV     R0,R5                   ;Get the pointer back again
+               MOV     R1,#thr__size           ;The size of the block
+               BL      sub_free                ;Destroy the thread block
+
+               ; --- Now we must return, but where to? ---
+               ;
+               ; If the caller is not the thread itself, this is easy.
+               ; If it *was* the thread, we've just killed its stack, so
+               ; we can't return to it.  Instead, we do the same job as
+               ; thread_yield.
+
+               CMP     R4,#0                   ;Was there a current thread?
+               LDMEQFD R13!,{R0-R5,R12,PC}^    ;No -- return normally
+
+               MOV     R0,#0                   ;We're stopping current thrd
+               STR     R0,wsp__current         ;So clear current thread
+
+               BL      thr__end                ;Kill off any handlers
+               LDR     R13,wsp__stackPtr       ;Get the system stack pointer
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to thread dispatcher
+
+               LTORG
+
+; --- thr__decCount ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Decrements the active threads counter, and disables the idle
+;              claimer if there aren't any left.
+
+thr__decCount  ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save registers
+               LDR     R14,wsp__active         ;Get the active counter
+               SUBS    R14,R14,#1              ;Decrement the counter
+               STR     R14,wsp__active         ;Store it back again
+               LDMGTFD R13!,{R0-R3,PC}^        ;If some still active, return
+
+               ; --- Remove the idle claiming routine ---
+
+               MOV     R0,#thr__idleFreq       ;How often I should be called
+               ADR     R1,thr__idles           ;Point to the idle handler
+               MOV     R2,#0                   ;Don't care about R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      idle_removeHandler      ;Stop it from being called
+
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- thr__incCount ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Increments the active threads counter, and adds in the idle
+;              claimer if it was previously disabled.
+
+thr__incCount  ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save registers
+               LDR     R14,wsp__active         ;Get the active counter
+               ADD     R14,R14,#1              ;Increment the counter
+               STR     R14,wsp__active         ;Store it back again
+               CMP     R14,#1                  ;Was it previously off?
+               LDMGTFD R13!,{R0-R3,PC}^        ;No -- return right now
+
+               ; --- Add in the idle claiming routine ---
+
+               MOV     R0,#thr__idleFreq       ;How often I should be called
+               ADR     R1,thr__idles           ;Point to the idle handler
+               MOV     R2,#0                   ;Don't care about R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      idle_handler    ;Get it called nicely
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- thr__idles ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Handles idle events by passing control to each thread in
+;              turn.  This is the main scheduler for the threads.
+;
+;              We use a simple but well-respected algorithm.  We find the
+;              first active thread in the list, move it to the end of its
+;              priority group and run it.
+
+thr__idles     ROUT
+
+               ; --- Save current context away ---
+               ;
+               ; We don't actually return from this routine -- actually
+               ; we restore from thread_destroy, thread_suspend or
+               ; thread_yield, or on the CallBack from a timer interrupt.
+
+               STMFD   R13!,{R0-R12,R14}       ;Save context on the stack
+               STR     R13,wsp__stackPtr       ;Save the stack pointer
+
+               ; --- Now we need to find an unsuspended thread ---
+               ;
+               ; There must be an active thread, because we don't get called
+               ; unless the count is non-0
+
+               LDR     R10,wsp__threads        ;Find the first thread
+10thr__idles   CMP     R10,#0                  ;Is this the end?
+               LDMEQFD R13!,{R0-R12,PC}^       ;Yes -- nothing to do then
+               LDR     R0,[R10,#thr__suspend]  ;Get the thread's suspend
+               CMP     R0,#0                   ;Is this one active?
+               LDRNE   R10,[R10,#thr__next]    ;No -- get the next one out
+               BNE     %10thr__idles           ;And go round again
+
+               ; --- We have an active thread ---
+               ;
+               ; We now unlink the thread and move it to the end of its
+               ; priority group in the list, so next time the next one in
+               ; the group gets a chance.
+
+               LDR     R9,[R10,#thr__priority] ;Get the thread's priority
+               LDMIA   R10,{R0,R1}             ;Get next and prev pointers
+               CMP     R0,#0                   ;Is there a next pointer?
+               STRNE   R1,[R0,#thr__prev]      ;Yes -- fill in its prev
+               CMP     R1,#0                   ;Is there a prev pointer?
+               STRNE   R0,[R1,#thr__next]      ;Yes -- fill in its next
+               STREQ   R0,wsp__threads         ;No -- make it the new first
+
+               ; --- Now search forwards for the end of the group ---
+
+20thr__idles   CMP     R0,#0                   ;Is this the list end?
+               BEQ     %25thr__idles           ;Yes -- skip out of loop
+               LDR     R8,[R0,#thr__priority]  ;Get the next one's priority
+               CMP     R8,R9                   ;Do they match up nicely?
+               MOVGE   R1,R0                   ;This is the previous one
+               LDRGE   R0,[R0,#thr__next]      ;Get the next one out
+               BGE     %20thr__idles           ;And loop round again
+
+               ; --- Insert our thread between R1 and R0 ---
+
+25thr__idles   CMP     R1,#0                   ;Is the previous one OK?
+               STRNE   R10,[R1,#thr__next]     ;Yes -- fill in its next
+               STREQ   R10,wsp__threads        ;Otherwise make it first one
+               CMP     R0,#0                   ;Is there a next one?
+               STRNE   R10,[R0,#thr__prev]     ;Yes -- fill in its previous
+               STMIA   R10,{R0,R1}             ;Save next and prev back
+
+               ; --- Now we can run the thread at last ---
+
+               LDR     R0,[R10,#thr__timeSlice] ;Load the timeslice we want
+               BL      thr__start              ;Set up timer interrupt
+               STR     R10,wsp__current        ;Save the current thread
+               LDR     R13,[R10,#thr__stackPtr] ;Find its stack pointer
+               LDMFD   R13!,{R0-R12,R14,PC}^   ;Start it up again
+
+               LTORG
+
+; --- thr__insert ---
+;
+; On entry:    R0 == pointer to thread block
+;
+; On exit:     --
+;
+; Use:         Inserts a thread into the thread list in the right place for
+;              its priority.
+
+thr__insert    ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Save some registers
+
+               LDR     R4,[R0,#thr__priority]  ;Get the thread;s priority
+               LDR     R1,wsp__threads         ;Find the first item
+               MOV     R2,#0                   ;No previous list item yet
+10thr__insert  CMP     R1,#0                   ;Is this the end of the list?
+               BEQ     %20thr__insert          ;Yes -- skip forwards
+               LDR     R3,[R1,#thr__priority]  ;Get its priority ready
+               CMP     R3,R4                   ;How do they compare?
+               MOVGT   R2,R1                   ;Too high -- now previous
+               LDRGT   R1,[R1,#thr__next]      ;Find the next thread handle
+               BGT     %10thr__insert          ;And loop round for another
+
+               ; --- Insert the thread between R2 and R1 ---
+
+20thr__insert  CMP     R2,#0                   ;Is there a previous one?
+               STRNE   R0,[R2,#thr__next]      ;Yes -- fill in its next
+               STREQ   R0,wsp__threads         ;No -- this is the first one
+               CMP     R1,#0                   ;Is there a next one?
+               STRNE   R0,[R1,#thr__prev]      ;Yes -- fill in its prev
+               STMIA   R0,{R1,R2}              ;Store next and prev in block
+               LDMFD   R13!,{R1-R4,PC}^        ;Return to caller then
+
+               LTORG
+
+; --- thread_suspend ---
+;
+; On entry:    R0 == thread handle, or 0 for the current thread
+;
+; On exit:     --
+;
+; Use:         Suspends a thread's execution.  If a thread is currently
+;              running, that thread is suspended.  Otherwise, any thread
+;              may be suspended.
+;
+;              If the thread is currently claiming semaphores, the
+;              semaphores are not released, because we don't whether the
+;              system is in a fit state for this.
+;
+;              Thread suspensions are counted.  i.e. if you suspend a thread
+;              5 times, you have to resume it 5 times for it to become
+;              active again.
+
+               EXPORT  thread_suspend
+thread_suspend ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers away
+               WSPACE  thr__wSpace             ;Locate my workspace
+               LDR     R14,wsp__current        ;Get the current thread
+               CMP     R0,#0                   ;Is current one wanted?
+               CMPNE   R0,R14                  ;Or is it just coincidence?
+               BNE     %10thread_suspend       ;No -- deal with that case
+
+               ; --- We want to suspend the current thread ---
+               ;
+               ; To suspend, we need to save the current thread context,
+               ; and resume from the system stack.  We know the thread must
+               ; be active currently, otherwise we wouldn't be executing
+               ; it!
+
+               STMFD   R13!,{R0-R12}           ;Save entire context on stack
+               STR     R13,[R14,#thr__stackPtr] ;Save the thread's stack ptr
+               MOV     R0,#1                   ;Thread must be active
+               STR     R0,[R14,#thr__suspend]  ;So store 1 as suspend count
+               BL      thr__decCount           ;There's one less active now
+
+               ; --- Now restore context to dispatcher ---
+
+               BL      thr__end                ;Stop all the handlers
+               MOV     R0,#0                   ;There is no current thread
+               STR     R0,wsp__current         ;So clear current pointer
+               LDR     R13,wsp__stackPtr       ;Get the system stack pointer
+               LDMFD   R13!,{R0-R12,PC}^       ;Restore context again
+
+               ; --- We're just meant to suspend any old thread ---
+               ;
+               ; We just need to bump its counter -- this is easy ---
+
+10             LDR     R14,[R0,#thr__suspend]  ;Get current suspend count
+               ADD     R14,R14,#1              ;Bump it up one
+               STR     R14,[R0,#thr__suspend]  ;Store it back again
+               CMP     R14,#1                  ;Was it previously active?
+               BLEQ    thr__decCount           ;Yes -- decrement actives
+               LDMFD   R13!,{R12,PC}^          ;Return to caller happy
+
+               LTORG
+
+; --- thread_resume ---
+;
+; On entry:    R0 == thread handle
+;
+; On exit:     --
+;
+; Use:         Allows a suspended thread to continue operations.  If you
+;              resume a thread more times than it has been suspended,
+;              any excess resumes are ignored.  You can't resume a thread
+;              to stop it being blocked by a semaphore.
+
+               EXPORT  thread_resume
+thread_resume  ROUT
+
+               STMFD   R13!,{R10,R12,R14}      ;Save some registers
+               WSPACE  thr__wSpace             ;Find my workspace address
+
+               ; --- Make sure the thread isn't running now ---
+
+               LDR     R14,[R0,#thr__suspend]  ;Get the suspension counter
+               CMP     R14,#0                  ;Is it zero already?
+               LDMEQFD R13!,{R10,R12,PC}^      ;Yes -- return right now
+
+               ; --- Decrement the counter ---
+
+               LDR     R10,[R0,#thr__semaphore] ;Get the blocking semaphore
+               CMP     R10,#0                  ;Is there a blocking sem?
+               MOVEQ   R10,#0                  ;No -- minimum count is 0
+               MOVNE   R10,#1                  ;Yes -- minimum count is 1
+               SUB     R14,R14,#1              ;Decrement the counter
+               CMP     R14,R10                 ;Is it too low?
+               MOVLT   R14,R10                 ;Yes -- bring it up again
+               STR     R14,[R0,#thr__suspend]  ;Store the counter back again
+
+               ; --- Bump the active count if thread now active ---
+
+               CMP     R14,#0                  ;Is the thread active now?
+               BLEQ    thr__incCount           ;Yes -- increment the count
+               CMP     R14,#1                  ;Is the thread almost active?
+               LDMNEFD R13!,{R10,R12,PC}^      ;No -- return right now
+
+               ; --- Check if the thread can start from a semaphore ---
+
+               STMFD   R13!,{R0-R2}            ;Save some registers
+               MOV     R10,R0                  ;Look after the thread handle
+               LDR     R14,[R10,#thr__semaphore] ;Is it waiting for a sem?
+               CMP     R14,#0                  ;Is the pointer null?
+               BEQ     %20thread_resume        ;Yes -- skip to end
+
+               LDR     R0,[R14,#sem__counter]  ;Is it signalled enough?
+               CMP     R0,#0                   ;If so, it isn't 0
+               BEQ     %20thread_resume        ;If not, skip to the end
+
+               ; --- Go through the waiting list ---
+               ;
+               ; We want to find the entry in the list, but we also want
+               ; to avoid `jumping the queue' -- i.e. getting the semaphore
+               ; before an unsuspended thread.  With the algorithms used
+               ; in thread_signal, I don't think this can happen, but it's
+               ; as well to make sure.  We have to go through the list
+               ; anyway.
+
+               LDR     R0,[R14,#sem__blocked]  ;Find the blocked list
+               MOV     R2,#0                   ;No previous block found
+10             CMP     R0,#0                   ;Is it the end of the list?
+               BEQ     %20thread_resume        ;Yes -- it's all over then
+               LDR     R1,[R0,#sml__thread]    ;Get the thread's handle
+               CMP     R1,R10                  ;Do they match up?
+               BEQ     %11thread_resume        ;Yes -- skip onwards
+               LDR     R1,[R1,#thr__suspend]   ;Get the suspended count
+               CMP     R1,#0                   ;Is this thread active?
+               BEQ     %20thread_resume        ;Yes -- skip to end
+               MOV     R2,R0                   ;Set up the previous pointer
+               LDR     R0,[R0,#sml__next]      ;Get the next block
+               B       %10thread_resume        ;And go back round the loop
+
+               ; --- Remove it from the waiting list ---
+
+11thread_resume        LDR     R1,[R0,#sml__next]      ;Get the next list item
+               CMP     R2,#0                   ;Is there a previous one?
+               STRNE   R1,[R2,#sml__next]      ;Yes -- fill in its next ptr
+               STREQ   R1,[R14,#sem__blocked]  ;No -- it's the new list head
+               CMP     R1,#0                   ;Is there a next block?
+               STREQ   R2,[R14,#sem__blockEnd] ;No -- fill in the last ptr
+
+               MOV     R2,R14                  ;Keep the semaphore pointer
+               MOV     R1,#sml__size           ;Size of the link blocks
+               BL      sub_free                ;Destroy the link block
+
+               ; --- Now decrement the semaphore counter ---
+
+               LDR     R0,[R2,#sem__counter]   ;Get the current counter
+               SUB     R0,R0,#1                ;Decrement it nicely
+               STR     R0,[R2,#sem__counter]   ;Store it back again
+               MOV     R0,#0                   ;Thread not suspended at all
+               STR     R0,[R10,#thr__suspend]  ;Store 0 as suspend count
+               BL      thr__incCount           ;Increment active threads
+
+20thread_resume        LDMFD   R13!,{R0-R2,R10,R12,PC}^ ;Return to caller
+
+               LTORG
+
+; --- thread_yield ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Pauses the thread for a while.  You only need to use this
+;              call if you have stopped the current thread from being
+;              timesliced.
+
+               EXPORT  thread_yield
+thread_yield   ROUT
+
+               STMFD   R13!,{R0-R14}           ;Save the old context
+               WSPACE  thr__wSpace             ;Find my workspace pointer
+               LDR     R0,wsp__current         ;Get the current thread ptr
+               BL      thr__end                ;Kill off the handlers
+               STR     R13,[R0,#thr__stackPtr] ;Save the thread's stack ptr
+               MOV     R0,#0                   ;Current thread is stopped
+               STR     R0,wsp__current         ;So clear the pointer
+               LDR     R13,wsp__stackPtr       ;Get the system stack pointer
+               LDMFD   R13!,{R0-R12,PC}^       ;Restore main system context
+
+               LTORG
+
+; --- thread_createSem ---
+;
+; On entry:    R0 == initial value for semaphore (0 for counter, 1 for
+;                    mutex)
+;
+; On exit:     R0 == semaphore handle and V clear if all went well
+;              R0 == pointer to error and V set if something went wrong
+;
+; Use:         Creates a semaphore with the given initial counter value.
+;
+;              The semaphore can be used to provide serialised access to
+;              a resource by initialising its value to 1 and performing the
+;              following:
+;
+;              thread_wait(mySemaphore)
+;              //
+;              // Do things with the resource
+;              //
+;              thread_signal(mySemaphore)
+;
+;              Or you can inform a thread that it has items in its input
+;              queue by having the following in the thread code:
+;
+;              while true
+;                thread_wait(theSemaphore)
+;                getFromQueue(myQueue,item)
+;                process(item)
+;              endWhile
+;
+;              and when inserting queue items:
+;
+;              addToQueue(item)
+;              thread_signal(theSemaphore)
+;
+;              It is distinctly possible that input queue management will
+;              be introduced in a separate Sapphire module.
+
+               EXPORT  thread_createSem
+thread_createSem ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               MOV     R0,#sem__size           ;The size of a semaphore
+               BL      sub_alloc               ;Try to create the semaphore
+               BVS     %99thread_createSem     ;If it failed, tidy up
+
+               LDR     R1,[R13],#4             ;Get the initial sem value
+               MOV     R2,#0                   ;No threads waiting either
+               MOV     R3,#0                   ;So no last link block
+               STMIA   R0,{R1-R3}              ;Save in semaphore block
+               LDMFD   R13!,{R1-R3,PC}         ;Return to caller
+
+               ; --- Error occurred ---
+
+99             ADD     R2,R0,#4                ;Point to the error text
+               ADR     R0,thr__noSemCrt        ;Point to error block
+               BL      msgs_error              ;Translate the error message
+               ADD     R13,R13,#4              ;Don't restore R0 from stack
+               LDMFD   R13!,{R1-R3,PC}         ;Return with V set on exit
+
+thr__noSemCrt  DCD     1
+               DCB     "thrNOSEMCRT",0
+
+               LTORG
+
+; --- thread_destroySem ---
+;
+; On entry:    R0 == semaphore handle
+;
+; On exit:     --
+;
+; Use:         Destroys a semaphore when it's no use any more.  If threads
+;              are waiting for it, an error is generated.
+
+               EXPORT  thread_destroySem
+thread_destroySem ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers away
+               LDR     R14,[R0,#sem__blocked]  ;Get the waiting list head
+               CMPEQ   R14,#0                  ;Is there a waiting list?
+               BNE     %90thread_destroySem    ;If so, complain
+
+               MOV     R1,#sem__size           ;The size of a semaphore
+               BL      sub_free                ;Free up the block
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               ; --- The semaphore is still in use ---
+
+90             ADR     R0,thr__semInUse        ;Point to error message
+               BL      msgs_error              ;Translate the message
+               SWI     OS_GenerateError        ;It's a serious problem
+
+thr__semInUse  DCD     1
+               DCB     "thrSEMINUSE",0
+
+               LTORG
+
+; --- thread_threaded ---
+;
+; On entry:    --
+;
+; On exit:     CS if currently running a thread, CC otherwise
+;
+; Use:         Informs the caller whether a thread is currently executing.
+
+               EXPORT  thread_threaded
+thread_threaded        ROUT
+
+               STMFD   R13!,{R12}              ;Save a register
+               WSPACE  thr__wSpace             ;Load my workspace address
+               LDR     R12,wsp__current        ;Load current thread handle
+               CMP     R12,#0                  ;Is there a thread running?
+               LDMFD   R13!,{R12}              ;Restore the register
+               ORRNES  PC,R14,#C_flag          ;Return CS if thread running
+               BICEQS  PC,R14,#C_flag          ;Otherwise return CC
+
+               LTORG
+
+; --- thread_wait ---
+;
+; On entry:    R0 == semaphore handle
+;
+; On exit:     If successful, R0 preserved and V clear.
+;              If failed, R0 == pointer to error block and V set
+;
+; Use:         Waits on a sempahore.  The algorithm actually is as follows:
+;
+;              if semaphore.counter == 0 then
+;                addToWaitingList(semaphore,currentThread)
+;                suspend(currentThread)
+;              else
+;                semaphore.counter -= 1
+;              endIf
+;
+;              See thread_createSem for suggestions on how to make use of
+;              semaphores.
+
+               EXPORT  thread_wait
+thread_wait    ROUT
+
+               BIC     R14,R14,#V_flag         ;Assume that all is well
+               STMFD   R13!,{R10,R12-R14}      ;Save some registers
+               WSPACE  thr__wSpace             ;Locate my workspace
+               LDR     R10,wsp__current        ;Find the current thread
+               CMP     R10,#0                  ;Is it nonexistant?
+               BEQ     %99thread_wait          ;Yes -- this is an error
+
+               ; --- Do the messing about with the counter ---
+
+               LDR     R14,[R0,#sem__counter]  ;Get the semaphore counter
+               SUBS    R14,R14,#1              ;Decrement the counter
+               STRGE   R14,[R0,#sem__counter]  ;If it was nonzero, store
+               LDMEQFD R13!,{R10,R12,R14,PC}^  ;And return to caller
+
+               ; --- Add the thread to the waiting list ---
+
+               STMFD   R13!,{R0-R9}            ;Save rest of the context
+               MOV     R9,R0                   ;Keep the semaphore handle
+               MOV     R0,#sml__size           ;Size of a link block
+               BL      sub_alloc               ;Allocate a link block
+               BVS     %90thread_wait          ;If it failed, return error
+
+               MOV     R1,#0                   ;No next waiting thread
+               STMIA   R0,{R1,R10}             ;Save information in block
+               LDR     R1,[R9,#sem__blockEnd]  ;Get the last waiting block
+               CMP     R1,#0                   ;Is there one at all?
+               STRNE   R0,[R1,#sml__next]      ;Yes -- store in its next
+               STREQ   R0,[R9,#sem__blocked]   ;No -- it's the first one
+               STR     R0,[R9,#sem__blockEnd]  ;It's certainly the last one
+
+               ; --- Now suspend the thread for a while ---
+
+               MOV     R1,#1                   ;Thread is currently active
+               STR     R1,[R10,#thr__suspend]  ;Not any more it isn't
+               STR     R9,[R10,#thr__semaphore] ;Remember the blocking sem
+
+               ; --- Now switch back to main context ---
+
+               BL      thr__end                ;Remove all the handlers
+               STR     R13,[R10,#thr__stackPtr] ;Save the current stackptr
+               LDR     R13,wsp__stackPtr       ;Find the system stack ptr
+               LDMFD   R13!,{R0-R12,PC}^       ;And return to normality
+
+               ; --- An error occurred while suspending ---
+
+90thread_wait  ADD     R2,R0,#4                ;Point to the error text
+               ADR     R0,thr__noWaitSem       ;Point to the error message
+               BL      msgs_error              ;Translate the error
+               ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R12,R14}       ;Restore all the registers
+               ORRS    PC,R14,#V_flag          ;Return the error back
+
+thr__noWaitSem DCD     1
+               DCB     "thrNOWAITSEM",0
+
+               ; --- The caller isn't a thread ---
+
+99thread_wait  ADR     R0,thr__notAThrd        ;Point to the error
+               BL      msgs_error              ;Translate the message
+               SWI     OS_GenerateError        ;And generate the error
+
+thr__notAThrd  DCD     1
+               DCB     "thrNOTATHRD",0
+
+               LTORG
+
+; --- thread_signal ---
+;
+; On entry:    R0 == semaphore handle
+;
+; On exit:     --
+;
+; Use:         Increments a semaphore's counter if no threads are waiting
+;              for it, or releases a thread waiting for the semaphore.
+;
+;              The actual algorithm is shown below:
+;
+;              if semaphore.waitingList != 0 then
+;                thread = removeFromWaitingList(semaphore)
+;                unSuspend(thread)
+;              else
+;                semaphore.counter += 1;
+;              endif
+;
+;              See thread_createSem for suggestions on how to make use of
+;              semaphores.
+
+               EXPORT  thread_signal
+thread_signal  ROUT
+
+               STMFD   R13!,{R0-R3,R10,R12,R14} ;Save a load of registers
+               WSPACE  thr__wSpace             ;Locate my workspace
+
+               ; --- Find a thread to restore control to ---
+
+               MOV     R3,R0                   ;Look after the sem handle
+               MOV     R2,#0                   ;No previous block yet
+               LDR     R0,[R3,#sem__blocked]   ;Find blocked list head
+
+10thread_signal        CMP     R0,#0                   ;Is this the end?
+               BEQ     %30thread_signal        ;Yes -- increment counter
+               LDR     R10,[R0,#sml__thread]   ;Get the thread handle out
+               LDR     R14,[R10,#thr__suspend] ;Find its suspended count
+               CMP     R14,#1                  ;Is it only blocked by sem?
+               MOVGT   R2,R0                   ;No -- this is now prev
+               LDRGT   R0,[R0,#sml__next]      ;Find the next one
+               BGT     %10thread_signal        ;And check that one out
+
+               ; --- Found a suitable thread ---
+
+               LDR     R14,[R0,#sml__next]     ;Get the next pointer out
+               CMP     R2,#0                   ;Is there a previous block?
+               STRNE   R14,[R2,#sml__next]     ;Yes -- fix its next ptr
+               STREQ   R14,[R3,#sem__blocked]  ;No -- this is now first one
+               CMP     R14,#0                  ;Is there a next block?
+               STREQ   R2,[R3,#sem__blockEnd]  ;Yes -- previous is now last
+
+               MOV     R1,#sml__size           ;The size of a link block
+               BL      sub_free                ;Don't need it any more
+
+               ; --- Let the new thread go ---
+
+               MOV     R0,#0                   ;Thread is no longer blocked
+               STR     R0,[R10,#thr__suspend]  ;Unblock the thread nicely
+               STR     R0,[R10,#thr__semaphore] ;No blocking semaphore now
+               LDMFD   R13!,{R0-R3,R10,R12,PC}^ ;Return to caller happily
+
+               ; --- No threads found -- increment the counter ---
+
+30thread_signal        LDR     R14,[R3,#sem__counter]  ;Get the current counter
+               ADD     R14,R14,#1              ;Increment it a little bit
+               STR     R14,[R3,#sem__counter]  ;Store new counter back
+               LDMFD   R13!,{R0-R3,R10,R12,PC}^ ;Return to caller happily
+
+               LTORG
+
+; --- thread_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the thread system for use.
+
+               EXPORT  thread_init
+thread_init    ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+
+               ; --- Make sure we're not initialised ---
+
+               WSPACE  thr__wSpace             ;Find my workspace pointer
+               LDR     R14,wsp__flags          ;Load my flags word
+               TST     R14,#thrFlag__inited    ;Am I initialised yet?
+               LDMNEFD R13!,{R12,PC}^          ;Yes -- return right now
+               ORR     R14,R14,#thrFlag__inited ;Set the flag
+               STR     R14,wsp__flags          ;Save the flags word back
+
+               ; --- Initialise the rest of the workspace ---
+
+               STMFD   R13!,{R0-R4}            ;Save some more registers
+               MOV     R0,#0                   ;No threads registered yet
+               MOV     R1,#0                   ;No active threads, then
+               MOV     R2,#0                   ;No thread running now
+               MOV     R3,#0                   ;No system stack pointer
+               STMIB   R12,{R0-R3,R11}         ;Save them in the workspace
+
+               ; --- Start up other things we need ---
+
+               BL      alloc_init              ;We need redirectble alloc
+               BL      sub_init                ;And allocating small blocks
+
+               LDMFD   R13!,{R0-R4,R12,PC}^    ;Return to caller
+
+               LTORG
+
+thr__wSpace    DCD     0
+
+;----- Handling pre-emption of threads --------------------------------------
+
+; --- thr__start ---
+;
+; On entry:    R0 == timeslice size in centiseconds
+;
+; On exit:     --
+;
+; Use:         Sets up handlers and a timer interrupt for starting a
+;              thread.
+
+thr__start     ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers away
+               ADR     R4,wsp__handlers        ;Point to handlers save area
+
+               ; --- Set up the handlers properly ---
+
+               MOV     R0,#7                   ;Install CallBack handler
+               ADR     R1,thr__callBack        ;Point to handler routine
+               MOV     R2,R12                  ;Point to my workspace
+               ADR     R3,wsp__regBuff         ;Point to the register block
+               SWI     OS_ChangeEnvironment    ;Install the handler
+               STMIA   R4!,{R1-R3}             ;Save the old handler
+
+               MOV     R0,#10                  ;Install event handler
+               ADR     R1,thr__events          ;Point to handler routine
+               MOV     R2,R12                  ;Point to my workspace
+               SWI     OS_ChangeEnvironment    ;Install the handler
+               STMIA   R4!,{R1-R3}             ;Save the old handler
+
+               MOV     R0,#6                   ;Install error handler
+               ADR     R1,thr__errors          ;Point to handler routine
+               MOV     R2,R12                  ;Point to my workspace
+               MOV     R3,R11                  ;Use Scratchpad for error
+               SWI     OS_ChangeEnvironment    ;Install the handler
+               STMIA   R4!,{R1-R3}             ;Save the old handler
+
+               MOV     R0,#11                  ;Install exit handler
+               ADR     R1,thr__exit            ;Point to handler routine
+               MOV     R2,R12                  ;Point to my workspace
+               SWI     OS_ChangeEnvironment    ;Install the handler
+               STMIA   R4!,{R1-R3}             ;Save the old handler
+
+               ; --- Enable my event ---
+
+               MOV     R0,#14                  ;Enable an event
+               MOV     R1,#9                   ;I'll use the user event
+               SWI     OS_Byte                 ;Enable the event for me
+
+               ; --- Set up the timer for me ---
+
+               LDR     R0,[R13,#0]             ;Load the timeslice value
+               CMP     R0,#0                   ;Do we set the timer?
+               ADRNE   R1,thr__timer           ;Point to timer routine
+               MOVNE   R2,R12                  ;Point to my workspace
+               SWINE   OS_CallAfter            ;Install the handler then
+
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- thr__end ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Removes all the handlers set up when a thread starts
+
+thr__end       ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+
+               ; --- Restore handlers to their old values ---
+
+               ADR     R4,wsp__handlers        ;Point to saved handlers
+               MOV     R0,#7                   ;Restore CallBack handler
+               LDMIA   R4!,{R1-R3}             ;Restore handler registers
+               SWI     OS_ChangeEnvironment    ;Put them all back then
+               MOV     R0,#10                  ;Restore Event handler
+               LDMIA   R4!,{R1-R3}             ;Restore handler registers
+               SWI     OS_ChangeEnvironment    ;Put them all back then
+               MOV     R0,#6                   ;Restore Error handler
+               LDMIA   R4!,{R1-R3}             ;Restore handler registers
+               SWI     OS_ChangeEnvironment    ;Put them all back then
+               MOV     R0,#11                  ;Restore Exit handler
+               LDMIA   R4!,{R1-R3}             ;Restore handler registers
+               SWI     OS_ChangeEnvironment    ;Put them all back then
+
+               MOV     R0,#13                  ;Disable an event
+               MOV     R1,#9                   ;I'm using the user event
+               SWI     OS_Byte                 ;Disable it nicely
+
+               ; --- Get rid of my ticker event ---
+               ;
+               ; We try and remove it -- if it was never there anyway,
+               ; or it's happened, we don't care.
+
+               ADR     R0,thr__timer           ;Point to my timer handler
+               MOV     R1,R12                  ;Get my workspace pointer
+               SWI     XOS_RemoveTickerEvent   ;Remove the ticker event
+
+               ; --- Kill off the `In error' flag ---
+
+               LDR     R14,wsp__flags          ;Load my flags word
+               BIC     R14,R14,#thrFlag__inErr ;Clear the flag bit
+               STR     R14,wsp__flags          ;Store it back again then
+
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- thr__errors ---
+;
+; On entry:    R0 == pointer to my workspace
+;
+; On exit:     Doesn't
+;
+; Use:         Handles an error in a thread.
+
+thr__errors    ROUT
+
+               SWI     OS_IntOff               ;Disable interrupts a while
+               MOV     R12,R0                  ;Point to my workspace
+               LDR     R11,wsp__R11            ;Load scratchpad address
+               LDR     R10,wsp__current        ;Find the current thread
+               MOV     R1,#1                   ;Enter a critical section
+               STR     R1,[R10,#thr__critCount] ;Save critical counter
+               SWI     OS_IntOn                ;Safe to interrupt again
+               ADD     R9,R10,#thr__errorHnd   ;Locate the error handler
+               LDR     R5,[R9],#4              ;Get the handler address
+               CMP     R5,#0                   ;Is there one set up?
+               BEQ     %50thr__errors          ;No -- skip round next bit
+
+               ; --- Am I already doing this? ---
+
+               LDR     R14,wsp__flags          ;Load my flags word
+               TST     R14,#thrFlag__inErr     ;Am I already going?
+               BNE     %50thr__errors          ;Yes -- skip round next bit
+
+               ; --- Handle the error and find resume point ---
+
+               ORR     R14,R14,#thrFlag__inErr ;Remember I'm doing this
+               STR     R14,wsp__flags          ;Save it back again
+               ADD     R0,R11,#4               ;Point to error block
+               LDMIA   R9,{R1,R13}             ;Get registers to pass out
+               STMFD   R13!,{R12}              ;Save the old R12 away
+               MOV     R12,R1                  ;Pass its workspace pointer
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R5                   ;Call the handler
+
+               ; --- Call the resume point ---
+
+               LDMFD   R13!,{R12}              ;Restore my workspace
+               LDR     R14,wsp__flags          ;Find my flags again
+               BIC     R14,R14,#thrFlag__inErr ;We're coming out again
+               STR     R14,wsp__flags          ;Store the flags back nicely
+               BL      thread_leaveCrit        ;Leave the critical section
+               MOV     R12,R1                  ;Set up resumer's workspace
+               MOV     PC,R0                   ;Call the resumer
+
+               ; --- It all went wrong ---
+
+50thr__errors  LDR     R13,wsp__stackPtr       ;Get the system stack pointer
+               MOV     R0,#0                   ;No current thread
+               STR     R0,wsp__current         ;So clear the pointer
+               BL      thr__end                ;Remove all its handlers
+               MOV     R0,R10                  ;Point to the thread
+               BL      thread_destroy          ;Kill off the thread
+               ADD     R0,R11,#4               ;Point to error block
+               SWI     OS_GenerateError        ;Pass to main handler
+
+               LTORG
+
+; --- thr__exit ---
+;
+; On entry:    R12 == my workspace address
+;
+; On exit:     --
+;
+; Use:         Handles OS_Exit calls in a thread.  Closes down the thread
+;              and propagates the exit
+
+thr__exit      ROUT
+
+               LDR     R11,wsp__R11            ;Load scratchpad pointer
+               SWI     OS_IntOff               ;Disable interrupts off
+               LDR     R13,wsp__stackPtr       ;Get the system stack pointer
+               BL      thr__end                ;Remove all its handlers
+               SWI     OS_IntOn                ;Save to interrupt again
+               LDR     R0,wsp__current         ;Get the current thread
+               MOV     R1,#0                   ;No current thread
+               STR     R1,wsp__current         ;So clear the pointer
+               BL      thread_destroy          ;Destroy the thread
+               SWI     OS_Exit
+
+               LTORG
+
+; --- thr__callBack ---
+;
+; On entry:    R12 == pointer to my workspace
+;
+; On exit:     --
+;
+; Use:         Performs appropriate operations on receipt of a timer
+;              interrupt.  If the thread is in a critical section, it is
+;              marked `should be stopped'.  Otherwise, the context is
+;              saved on the thread's stack and control returned to the
+;              main program
+
+thr__callBack  ROUT
+
+               LDR     R10,wsp__current        ;Get the current thread
+               LDR     R14,[R10,#thr__critCount] ;Is it in a critical bit?
+               CMP     R14,#0                  ;If so, this is <>0
+               BEQ     %10thr__callBack        ;Otherwise skip forwards
+
+               ; --- Set the thread's flag and continue ---
+
+               LDR     R14,[R10,#thr__flags]   ;Get the thread's flags word
+               ORR     R14,R14,#tFlag__timeUp  ;Kill it on exit from crit
+               STR     R14,[R10,#thr__flags]   ;Store flags word back again
+               ADR     R14,wsp__regBuff        ;Point to save buffer
+               LDMIA   R14,{R0-R14}^           ;Get the user registers out
+               MOV     R0,R0                   ;Otherwise ARM complains
+               LDR     R14,[R14,#15*4]         ;Load the saved PC
+               MOVS    PC,R14                  ;Return to the thread
+
+               ; --- Save the thread's context ---
+
+10thr__callBack        ADR     R14,wsp__regBuff        ;Point to save buffer
+               LDR     R11,[R14,#13*4]         ;Find the thread's stack ptr
+               SUB     R11,R11,#15*4           ;Make way for the context
+               STR     R11,[R10,#thr__stackPtr] ;Save the thread's stack ptr
+               LDMIA   R14!,{R0-R7}
+               STMIA   R11!,{R0-R7}
+               LDMIA   R14!,{R0-R7}
+               STMIA   R11!,{R0-R4,R6,R7}      ;Don't transfer R13
+
+               ; --- Go back to the main program ---
+
+               LDR     R11,wsp__stackPtr       ;Find the system stack ptr
+               LDR     R14,[R11,#13*4]         ;Get the saved link register
+               TEQP    R14,#0                  ;Set this as the current mode
+               MOV     R0,R0                   ;Stop ARM from being odd
+               MOV     R13,R11                 ;Point to the stack properly
+               BL      thr__end                ;Stop all the handlers
+               LDMFD   R13!,{R0-R12,PC}^       ;Rejoin the main thread
+
+               LTORG
+
+; --- thr__events ---
+;
+; On entry:    R0 == event code (ideally this is 9)
+;              R1 == my magic identifier number (just this thing, y'know)
+;
+; On exit:     R12 may contain 1
+;
+; Use:         Handles events.  If it's the magic timer event, then I get
+;              myself a CallBack.
+
+thr__events    ROUT
+
+               CMP     R0,#9                   ;Is it a user event?
+               MOVNES  PC,R14                  ;No -- return right away
+               STMFD   R13!,{R14}              ;Save the link away
+               LDR     R14,thr__myMagic        ;Get my magic number
+               CMP     R1,R14                  ;Does it match up?
+               MOVEQ   R12,#1                  ;Yes -- request a CallBack
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+thr__myMagic   DCB     "MDW!"
+
+; --- thr__timer ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Generates an event that can eventually wend its way to my
+;              CallBack handler
+
+thr__timer     ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               MOV     R0,#9                   ;Make a user event
+               LDR     R1,thr__myMagic         ;My special identifier
+               SWI     OS_GenerateEvent        ;Make the event happen
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- thread_enterCrit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Declares that the current thread is about to enter a
+;              critical section and must not be interrupted.
+
+               EXPORT  thread_enterCrit
+thread_enterCrit ROUT
+
+               STMFD   R13!,{R10,R12,R14}      ;Save some registers away
+               WSPACE  thr__wSpace             ;Find my workspace
+               LDR     R10,wsp__current        ;Get the current thread
+               CMP     R10,#0                  ;Is there one?
+               LDMEQFD R13!,{R10,R12,PC}^      ;No -- this is a no-op then
+               LDR     R14,[R10,#thr__critCount] ;Get the current counter
+               ADD     R14,R14,#1              ;Bump it along one
+               STR     R14,[R10,#thr__critCount] ;Save the counter back
+               LDMFD   R13!,{R10,R12,PC}^      ;Return to caller
+
+               LTORG
+
+; --- thread_leaveCrit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Declares that the current thread has left the critical
+;              section and can be interrupted again.
+
+               EXPORT  thread_leaveCrit
+thread_leaveCrit ROUT
+
+               STMFD   R13!,{R10,R12-R14}      ;Save some registers away
+               WSPACE  thr__wSpace             ;Find my workspace
+               LDR     R10,wsp__current        ;Get the current thread
+               CMP     R10,#0                  ;Is there one?
+               LDMEQFD R13!,{R10,R12,R14,PC}^  ;No -- this is a no-op then
+               LDR     R14,[R10,#thr__critCount] ;Get the current counter
+               SUBS    R14,R14,#1              ;Chop one off it
+               MOVLT   R14,#0                  ;Stop it going negative
+               STR     R14,[R10,#thr__critCount] ;Save the counter back
+               LDMLEFD R13!,{R10,R12,R14,PC}^  ;If still critical, leave it
+
+               ; --- Check to see if it should stop now ---
+
+               LDR     R14,[R10,#thr__flags]   ;Get the thread's flags
+               TST     R14,#tFlag__timeUp      ;Has the timer happened?
+               LDMEQFD R13!,{R10,R12,R14,PC}^  ;No -- leave it to go then
+               BL      thr__end                ;Stop the handlers and things
+               STMFD   R13!,{R0-R9}            ;Save rest of the context
+               STR     R13,[R10,#thr__stackPtr] ;Save the stack pointer
+               LDR     R13,wsp__stackPtr       ;Load the system stack ptr
+               STMFD   R13!,{R0-R12,PC}^       ;Return to main thread
+
+               LTORG
+
+; --- thread_errorHandler ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R12 value to call with
+;              R2 == R13 value to call with
+;
+; On exit:     --
+;
+; Use:         Sets up the error handler for a thread.
+
+               EXPORT  thread_errorHandler
+thread_errorHandler
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  thr__wSpace             ;Locate my workspace
+               LDR     R14,wsp__current        ;Get the current thread
+               ADD     R14,R14,#thr__errorHnd  ;Point to handler block
+               STMIA   R14,{R0-R2}             ;Save the information away
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+;----- Data structures ------------------------------------------------------
+
+; --- The thread structure ---
+
+               ^       0
+thr__next      #       4                       ;Pointer to next thread
+thr__prev      #       4                       ;Pointer to previous thread
+thr__suspend   #       4                       ;Thread's suspension counter
+thr__semaphore #       4                       ;Pointer to blocking sem
+thr__priority  #       4                       ;Priority of this thread
+thr__timeSlice #       4                       ;Size of timeslice for thread
+thr__critCount #       4                       ;Critical section counter
+thr__stackPtr  #       4                       ;Thread's stack pointer
+thr__stack     #       4                       ;Pointer to thread's stack
+thr__flags     #       4                       ;Various flags for the thread
+thr__errorHnd  #       4*3                     ;The error handler for it
+thr__size      #       0                       ;Size of this block
+
+tFlag__timeUp  EQU     (1<<0)                  ;Pre-empt after critical sect
+
+; --- The semaphore link structure ---
+
+               ^       0
+sml__next      #       4                       ;Pointer to next link block
+sml__thread    #       4                       ;Pointer to suspended thread
+sml__size      #       0                       ;Size of this block
+
+; --- The main semaphore block ---
+
+               ^       0
+sem__counter   #       4                       ;Semaphore counter
+sem__blocked   #       4                       ;List of blocked threads
+sem__blockEnd  #       4                       ;Pointer to last link in list
+sem__size      #       0                       ;Size of this block
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+thr__wStart    #       0
+
+wsp__flags     #       4                       ;Various useful flags
+wsp__threads   #       4                       ;Pointer to list of threads
+wsp__active    #       4                       ;Counter of active threads
+wsp__current   #       4                       ;Pointer to current thread
+wsp__stackPtr  #       4                       ;The system stack pointer
+wsp__R11       #       4                       ;Sapphire's R11 pointer
+wsp__handlers  #       12*4                    ;Old handlers to restore
+wsp__regBuff   #       16*4                    ;Register save buffer
+
+thr__wSize     EQU     {VAR}-thr__wStart
+
+thrFlag__inited        EQU     (1<<0)                  ;Are we initialised yet?
+thrFlag__inErr EQU     (1<<1)                  ;We are handling an error
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     thr__wSize
+               DCD     thr__wSpace
+               DCD     256
+               DCD     thread_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/transWin b/StraySrc/Libraries/Sapphire/s/transWin
new file mode 100644 (file)
index 0000000..b4fb6f2
--- /dev/null
@@ -0,0 +1,343 @@
+;
+; transWin.s
+;
+; Transient window handling (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:event
+               GET     sapphire:sapphire
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- transWin_subWaiting ---
+;
+; On entry:    --
+;
+; On exit:     CS if a submenu is waiting to be opened, CC otherwise
+;
+; Use:         Informs the caller whether the menu system is waiting for
+;              a submenu to be attached.
+
+               EXPORT  transWin_subWaiting
+transWin_subWaiting ROUT
+
+               ORR     R14,R14,#C_flag         ;Assume there is one waiting
+               STMFD   R13!,{R0,R1,R12,R14}    ;Save some registers
+               WSPACE  tw__wSpace              ;Find my workspace
+
+               ; --- First, try asking TMS ---
+
+               LDR     R1,tw__twin             ;Load the global area address
+               LDR     R1,[R1,#twin_tmsHook]   ;Load the hook address
+               CMP     R1,#1                   ;Has the hook been set up?
+               MOVCS   R14,PC                  ;Yes -- set up return address
+               ADDCS   PC,R1,#tmsh__subWaiting ;And call the routine
+               LDMCSFD R13!,{R0,R1,R12,PC}^    ;Return true
+
+               ; --- Now find out about the normal WIMP ---
+
+               BL      event_last              ;Find the last event
+               CMP     R0,#17                  ;Is it some kind of message?
+               CMPNE   R0,#18                  ;Either type of message?
+               LDREQ   R0,[R1,#16]             ;Get the message code
+               MOVEQ   R14,#&40000             ;The message base number
+               ORREQ   R14,R14,#&000C0         ;We're looking for submenus
+               CMPEQ   R0,R14                  ;Do they match?
+               LDMEQFD R13!,{R0,R1,R12,PC}^    ;Return true
+               LDMFD   R13!,{R0,R1,R12,R14}    ;Unstack some registers
+               BICS    PC,R14,#C_flag          ;Return false
+
+               LTORG
+
+; --- transWin_openSub ---
+;
+; On entry:    R0 == window handle to open
+;
+; On exit:     --
+;
+; Use:         Opens the given window as a submenu.
+
+               EXPORT  transWin_openSub
+transWin_openSub ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Save some registers
+               WSPACE  tw__wSpace              ;Find my workspace
+
+               ; --- First of all, try TMS ---
+
+               LDR     R1,tw__twin             ;Load the global area address
+               LDR     R1,[R1,#twin_tmsHook]   ;Load the hook address
+               CMP     R1,#1                   ;Has the hook been set up?
+               MOVCS   R14,PC                  ;Yes -- set up return address
+               ADDCS   PC,R1,#tmsh__subWaiting ;And call the routine
+               MOVCS   R14,PC                  ;If it is waiting...
+               ADDCS   PC,R1,#tmsh__openSub    ;...get it to open the menu
+               BCS     %90transWin_openSub     ;And then return to caller
+
+               ; --- Now try the normal system ---
+
+               MOV     R2,R0                   ;Look after the window handle
+               BL      event_last              ;Find the last event
+               CMP     R0,#17                  ;Is it some kind of message?
+               CMPNE   R0,#18                  ;Either type of message?
+               LDREQ   R0,[R1,#16]             ;Get the message code
+               MOVEQ   R14,#&40000             ;The message base number
+               ORREQ   R14,R14,#&000C0         ;We're looking for submenus
+               CMPEQ   R0,R14                  ;Do they match?
+               BNE     %99transWin_openSub     ;No -- return then
+
+               ; --- Open as a normal submenu ---
+
+               ADD     R14,R1,#24              ;Point to the coordinates
+               MOV     R1,R2                   ;Get the window handle back
+               LDMIA   R14,{R2,R3}             ;Read the coordinates
+               SWI     Wimp_CreateSubMenu      ;Display the menu nicely
+               MOV     R0,R1                   ;Get window handle in R0
+
+               ; --- Register the transient menu
+
+90             BL      transWin_register       ;Register the window
+99             LDMFD   R13!,{R0-R3,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- transWin_register ---
+;
+; On entry:    R0 == window handle to register
+;
+; On exit:     --
+;
+; Use:         Registers a window as being the current transient window.
+
+               EXPORT  transWin_register
+transWin_register ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  tw__wSpace              ;Find my workspace
+               LDR     R12,tw__twin            ;Find the global area
+               STR     R0,[R12,#twin_trans]    ;Save the transient window
+               LDR     R14,[R12,#twin_flags]   ;Load the TWIN flags word
+               BIC     R14,R14,#twinFlag_recrt ;Don't recreate the menu
+               STR     R14,[R12,#twin_flags]   ;Save the flags back again
+               LDMFD   R13!,{R12,PC}^          ;And return to caller
+
+               LTORG
+
+; --- transWin_close ---
+;
+; On entry:    R0 == window handle to close
+;
+; On exit:     --
+;
+; Use:         Closes the current transient window.
+
+               EXPORT  transWin_close
+transWin_close ROUT
+
+               STMFD   R13!,{R0,R1,R10,R12,R14} ;Save some registers
+               WSPACE  tw__wSpace              ;Find my workspace
+               LDR     R14,tw__flags           ;Load my flags word
+               TST     R14,#twFlag__wimpCls    ;Did the WIMP close it?
+               MOVEQ   R1,#-1                  ;No -- kill the whole menu
+               SWIEQ   Wimp_CreateMenu         ;Using this neat trick
+               MOV     R1,R13                  ;Point at caller's handle
+               SWI     Wimp_CloseWindow        ;Close the window
+               LDR     R0,[R13,#0]             ;Load his window again
+               LDR     R12,tw__twin            ;Find the global area
+               LDR     R14,[R12,#twin_trans]   ;Load the current transient
+               SUBS    R14,R0,R14              ;Do they match nicely?
+               STREQ   R14,[R12,#twin_trans]   ;Yes -- zero the current one
+               LDMFD   R13!,{R0,R1,R10,R12,PC}^ ;And return to caller
+
+               LTORG
+
+; --- tw__faker ---
+;
+; On entry:    R0 == event code
+;              R1 == pointer to event data
+;
+; On exit:     CS and new event set up, or CC and registers preserved
+;
+; Use:         Generates dummy close events for transient windows.
+
+tw__faker      ROUT
+
+               ; --- Ignore redraw events ---
+
+               CMP     R0,#1                   ;Is it a redraw event?
+               MOVEQS  PC,R14                  ;Yes -- return right now
+
+               ; --- Start up the faking business ---
+
+               STMFD   R13!,{R9,R10,R14}       ;Save some registers
+               LDR     R14,tw__flags           ;Load my flags word
+               BIC     R14,R14,#twFlag__wimpCls ;Wimp hasn't closed it
+               STR     R14,tw__flags           ;Save the flags back again
+
+               LDR     R10,tw__twin            ;Find the global area
+               LDR     R9,[R10,#twin_trans]    ;Load the transient window
+               CMP     R9,#0                   ;Is there one defined?
+               LDMEQFD R13!,{R9,R10,PC}^       ;No -- return right now
+
+               ; --- See if the window's still open ---
+
+               CMP     R0,#9                   ;Is this a menu hit event?
+               BEQ     %10tw__faker            ;Yes -- window will close
+
+               STMFD   R13!,{R0,R1}            ;Save some more registers
+               SUB     R13,R13,#36             ;Make some stack space
+               STR     R9,[R13,#0]             ;Save window handle in there
+               MOV     R1,R13                  ;Point at the block
+               SWI     Wimp_GetWindowState     ;Read the window information
+               LDR     R14,[R13,#32]           ;Load the window flags
+               TST     R14,#&00010000          ;Is the window open still?
+               ADD     R13,R13,#36             ;Reclaim the stack space?
+               LDMNEFD R13!,{R0,R1,R9,R10,PC}^ ;Yes -- return to caller
+               LDMFD   R13!,{R0,R1}            ;Restore those registers
+
+               ; --- Fake the event ---
+
+               LDR     R14,tw__flags           ;Load my flags word
+               ORR     R14,R14,#twFlag__wimpCls ;Wimp has closed the window
+               STR     R14,tw__flags           ;Save the flags back again
+10tw__faker    STR     R9,[R1,#0]              ;Save window handle in block
+               MOV     R0,#3                   ;It's a close event
+               LDMFD   R13!,{R9,R10,R14}       ;Unstack the registers
+               ORRS    PC,R14,#C_flag          ;And return with C set
+
+               LTORG
+
+; --- transWin_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the transWin system.
+
+               EXPORT  transWin_init
+transWin_init  ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  tw__wSpace              ;Find my workspace
+
+               ; --- Make sure I'm not already running ---
+
+               LDR     R14,tw__flags           ;Load my flags word
+               TST     R14,#twFlag__inited     ;Is my initialised flag set?
+               LDMNEFD R13!,{R12,PC}^          ;Yes -- return to caller
+               MOV     R14,#twFlag__inited     ;Set the intialised flag
+               STR     R14,tw__flags           ;And save the flags back
+
+               ; --- Set up the TWIN global area ---
+
+               STMFD   R13!,{R0-R2}            ;Save some more registers
+               LDR     R0,tw__TWIN             ;Load the global name word
+               MOV     R1,#twin_size           ;And the size value
+               BL      sapphire_global         ;Find the global area
+               STR     R0,tw__twin             ;Save the address of this
+               BCS     %10transWin_init        ;If already created, skip on
+
+               MOV     R1,#0                   ;No flags set currently
+               MOV     R2,#0                   ;No transient window set up
+               MOV     R14,#0                  ;TMS hasn't registered itself
+               STMIA   R0,{R1,R2,R14}          ;Save them in the area
+
+               ; --- Now set up my fake event handler ---
+
+10transWin_init        BL      event_init              ;Make sure event is awake
+               ADR     R0,tw__faker            ;Point to the fake handler
+               MOV     R1,R12                  ;Pass it my workspace address
+               BL      event_fakeHandler       ;Register the handler
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;And return to caller
+
+tw__TWIN       DCB     "TWIN"
+
+               LTORG
+
+tw__wSpace     DCD     0
+
+;----- Workspace ------------------------------------------------------------
+
+               ; --- TWIN global area layout ---
+               ;
+               ; This global area is intended to allow communication
+               ; between transWin and menu system providers.
+               ;
+               ; The TMS hook is set by TMS to point to a pair of branch
+               ; instructions to routines tmsh_subWaiting and tmsh_openSub
+               ; respectively.
+               ;
+               ; tmsh_subWaiting should return CS if TMS is waiting to open
+               ; a submenu, and CC otherwise.  tmsh_openSub is passed a
+               ; window handle in R0, which it should open as a submenu in
+               ; whatever way it sees fit.
+               ;
+               ; If the tmsHook pointer is zero, transWin will assume that
+               ; TMS is not available.
+
+               ^       0
+twin_flags     #       4                       ;Various useful flags
+twin_trans     #       4                       ;The current transient window
+twin_tmsHook   #       4                       ;A hook to the TMS system
+twin_size      #       0                       ;The size of the global area
+
+twinFlag_recrt EQU     (1<<0)                  ;Menu will be recreated
+
+tmsh__subWaiting EQU   0
+tmsh__openSub  EQU     4
+
+               ; --- Workspace ---
+
+               ^       0,R12
+tw__wStart     #       0
+
+tw__flags      #       4                       ;Various useful flags
+tw__twin       #       4                       ;Pointer to the TWIN global
+
+tw__wSize      EQU     {VAR}-tw__wStart
+
+twFlag__inited EQU     (1<<0)                  ;We have been initialised
+twFlag__wimpCls        EQU     (1<<1)                  ;Wimp closed last dbox
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     tw__wSize
+               DCD     tw__wSpace
+               DCD     0
+               DCD     transWin_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/tspr b/StraySrc/Libraries/Sapphire/s/tspr
new file mode 100644 (file)
index 0000000..894f8cf
--- /dev/null
@@ -0,0 +1,330 @@
+;
+; tspr.s
+;
+; Toolsprite hacking for things like border sizes (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:screen
+               GET     sapphire:wimp
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- tspr_getSprAddr ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to tool sprites, or 0 if none
+;
+; Use:         Returns a pointer to the toolsprites. If the user is using
+;              RISC OS 2, or there are no toolsprites defined, then
+;              0 is returned.
+
+               EXPORT  tspr_getSprAddr
+tspr_getSprAddr        ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stack some registers
+
+               BL      wimp_version            ;Get the wimp version number
+               CMP     R0,#300                 ;Are we using RISC OS 2?
+               MOVLT   R0,#0                   ;Yes -- no sprites then
+               BLT     %90tspr_getSprAddr      ;...and return
+               SWIEQ   Wimp_BaseOfSprites      ;We want this for 3.00
+               MOVEQ   R0,R1                   ;...RAM resident part please
+               BEQ     %90tspr_getSprAddr      ;...and return
+               MOV     R1,#94                  ;We need to test with 350...
+               ADD     R1,R1,#256              ;...so create the number
+               CMP     R0,R1                   ;Is version < 3.50?
+               BLT     %10                     ;Yes -- deal with it then
+
+               ; --- We are using RISC OS 3.50 or higher ---
+
+               MOV     R0,#9                   ;Read toolsprite control blk
+               SWI     Wimp_ReadSysInfo        ;Find it then
+               B       %90tspr_getSprAddr      ;And return
+
+               ; --- We are using RISC OS 3.01 - 3.49 ---
+
+10             ADR     R1,tspr__versionList    ;Point to the version list
+20             LDR     R2,[R1],#4              ;Load the version number
+               CMP     R0,R2                   ;Is it the one we want?
+               BLT     %90tspr_getSprAddr      ;It isn't in list -- return
+               BEQ     %30tspr_getSprAddr      ;It is -- deal with it
+               CMP     R2,#-1                  ;Are we at the end?
+               MOVEQ   R0,#0                   ;Yes -- no sprite then
+               BEQ     %90tspr_getSprAddr      ;...return
+               ADD     R1,R1,#4                ;Skip past address field
+               B       %20tspr_getSprAddr      ;And keep searching
+
+               ; --- We have located the version number ---
+
+30             STMFD   R13!,{R3-R5}            ;Stack some more registers
+               LDR     R14,[R1]                ;Get the address offset
+               MOV     R0,#18                  ;Look-up module name
+               ADR     R1,tspr__moduleName     ;Point to the module name
+               SWI     OS_Module               ;Get information then
+               LDR     R0,[R4,R14]             ;Get the toolsprite address
+               SUB     R0,R0,#4                ;Correct it nicely
+               LDMFD   R13!,{R3-R5}            ;Get registers back
+
+               ; --- Return to caller ---
+
+90             LDMFD   R13!,{R1,R2,PC}^        ;Unstack registers and return
+
+tspr__moduleName
+               DCB     "WindowManager",0
+               ALIGN
+
+tspr__versionList
+               DCD     316,1676
+               DCD     322,1708
+               DCD     -1
+
+               LTORG
+
+; --- tspr_borderWidths ---
+;
+; On entry:    --
+;
+; On exit:     R0 == title bar height
+;              R1 == vertical scroll bar width
+;              R2 == horizontal scroll bar height
+;
+; Use:         Return the width of window tools by looking at the
+;              sprites associated with them, rather than creating
+;              a temporary window.
+
+               EXPORT  tspr_borderWidths
+tspr_borderWidths ROUT
+
+               STMFD   R13!,{R3-R10,R14}       ;Stack some registers
+
+               ; --- Find out about the current mode ---
+
+               BL      screen_getInfo          ;Get some screen information
+               MOV     R7,#0                   ;Flags word so far
+               LDR     R9,[R0,#screen_xEig]    ;Get the xEig Factor
+               LDR     R10,[R0,#screen_yEig]   ;and the yEig Factor
+               CMP     R9,#1                   ;Are we in a high...
+               CMPEQ   R10,#1                  ;...resolution mode?
+               ORREQ   R7,R7,#1                ;Yes -- remember this
+               LDR     R1,[R0,#screen_bpp]     ;Get the bpp
+               CMP     R1,#1                   ;Monochrome mode?
+               ORREQ   R7,R7,#2                ;Yes -- remember this too
+
+               ; --- Are we using tool sprites? ---
+
+               BL      tspr_getSprAddr         ;Find the address of sprites
+               CMP     R0,#0                   ;Are there any?
+               BEQ     %80tspr_borderWidths    ;No -- get RISC OS 2 defaults
+               MOV     R8,R0                   ;Put sprite block in R8
+
+               ; --- Use sprites to get the border widths ---
+               ;
+               ; First, find out about the title bar
+
+               ADR     R3,tspr__titleName      ;Point to title bar sprite ^
+               BL      %50tspr_borderWidths    ;Get sprite information
+               MOV     R0,R4                   ;The returned height
+               BVC     %20tspr_borderWidths    ;All OK -- now vertical
+               TST     R7,#1                   ;Are we in a high res mode?
+               MOVNE   R0,#42                  ;Yes -- use this height
+               MOVEQ   R0,#44                  ;No -- use this height
+
+               ; --- Now the vertical scroll bar ---
+
+20             ADR     R3,tspr__vertName       ;Point to vert bar sprite ^
+               BL      %50tspr_borderWidths    ;Get sprite information
+               MOVVC   R1,R3                   ;The returned height
+               MOVVS   R1,#42                  ;The default width
+
+               ; --- Finally the horizontal scroll bar height ---
+
+30             ADR     R3,tspr__horzName       ;Point to horz bar sprite ^
+               BL      %50tspr_borderWidths    ;Get sprite information
+               MOV     R2,R4                   ;The returned height
+               BVC     %90tspr_borderWidths    ;All OK -- now return
+               TST     R7,#1                   ;Are we in a high res mode?
+               MOVNE   R2,#42                  ;Yes -- use this height
+               MOVEQ   R2,#44                  ;No -- use this height
+               B       %90tspr_borderWidths    ;Return to caller
+
+               ; --- Find out about the given sprite ---
+
+50             BIC     R14,R14,#V_flag         ;No error yet
+               STMFD   R13!,{R0-R2,R14}        ;Preserve these values
+               MOV     R14,R3                  ;Remember this pointer
+               LDR     R2,[R3,R7,LSL#2]        ;Actually point to the name
+               MOV     R1,R8                   ;The sprite block
+               MOV     R0,#256+40              ;Read sprite information
+               SWI     XOS_SpriteOp            ;Read info
+               LDRVS   R2,[R14]                ;Error -- get default name
+               MOVVS   R0,#256+40              ;...read sprite information
+               SWIVS   XOS_SpriteOp            ;...try again
+               MOVVC   R3,R3,LSL R9            ;Calculate width in OS units
+               MOVVC   R4,R4,LSL R10           ;Calculate height in OS units
+               LDMFD   R13!,{R0-R2,R14}        ;Get registers back
+               ORRVSS  PC,R14,#V_flag          ;Return with error
+               BICVCS  PC,R14,#V_flag          ;Or maybe without
+
+               ; --- Use RISC OS 2 defaults ---
+
+80             MOV     R1,#42                  ;This is width in all modes
+               TST     R7,#1                   ;Are we in a high res mode?
+               MOVNE   R0,#42                  ;Yes -- use this height
+               MOVEQ   R0,#44                  ;No -- use this height
+               MOV     R2,R0                   ;This height is the same
+
+               ; --- Return to the caller ---
+
+90             LDMFD   R13!,{R3-R10,PC}^       ;Return
+
+tspr__titleName        DCD     tbarlcap
+               DCD     tbarlcap22
+               DCD     tbarlcap0
+               DCD     tbarlcap23
+
+tspr__vertName DCD     vwellbcap
+               DCD     vwellbcap22
+               DCD     vwellbcap0
+               DCD     vwellbcap23
+
+tspr__horzName DCD     hwelllcap
+               DCD     hwelllcap22
+               DCD     hwelllcap0
+               DCD     hwelllcap23
+
+tbarlcap       DCB     "tbarlcap",0
+tbarlcap22     DCB     "tbarlcap22",0
+tbarlcap0      DCB     "tbarlcap0",0
+tbarlcap23     DCB     "tbarlcap23",0
+
+vwellbcap      DCB     "vwellbcap",0
+vwellbcap22    DCB     "vwellbcap22",0
+vwellbcap0     DCB     "vwellbcap0",0
+vwellbcap23    DCB     "vwellbcap23",0
+
+hwelllcap      DCB     "hwelllcap",0
+hwelllcap22    DCB     "hwelllcap22",0
+hwelllcap0     DCB     "hwelllcap0",0
+hwelllcap23    DCB     "hwelllcap23",0
+
+               LTORG
+
+; --- tspr_adjustBox ---
+;
+; On entry:    R1 == pointer to Wimp_OpenWindow block to modify
+;
+; On exit:     Block updated in place
+;
+; Use:         Updates the open block to ensure that the window is opened
+;              on the screen.
+
+               EXPORT  tspr_adjustBox
+tspr_adjustBox ROUT
+
+               ; --- Find out which gadgets the window has ---
+
+               STMFD   R13!,{R0-R11,R14}       ;Save a job load of regs
+               SUB     R13,R13,#36             ;Space for a window state
+               LDR     R0,[R1,#0]              ;Load the caller's handle
+               STR     R0,[R13,#0]             ;Save it in my block
+               MOV     R1,R13                  ;Point to my state block
+               SWI     Wimp_GetWindowState     ;Find the window information
+               LDR     R3,[R13,#32]            ;Load the window flags out
+               ADD     R13,R13,#36             ;Reclaim the stack space
+
+               ; --- Now mangle the window block ---
+
+               BL      tspr_borderWidths       ;Get the border widths
+               LDR     R4,[R13,#4]             ;Load his pointer back again
+               LDMIB   R4,{R5-R8}              ;Load the coordinates out
+               TST     R3,#&0f000000           ;Is there a top-row gadget?
+               ADDNE   R8,R8,R0                ;Yes -- add title bar height
+               TST     R3,#&10000000           ;Is there a vert. scrollbar?
+               ADDNE   R7,R7,R1                ;Yes -- add scrollbar width
+               TST     R3,#&40000000           ;Is there a horiz. one?
+               SUBNE   R6,R6,R2                ;Yes -- sub scrollbar height
+
+               ; --- Get the screen dimensions ---
+
+               BL      screen_getInfo          ;Find the screen information
+               MOV     R11,R0                  ;Remember this block's pos
+               ADD     R0,R0,#screen_width     ;Find the screen width
+               LDMIA   R0,{R9,R10}             ;Load width and height
+
+               ; --- Now load the original coords again ---
+
+               LDMIB   R4,{R0-R3}              ;Load the coordinates out
+
+               ; --- Mangle the x coordinates first ---
+
+               SUB     R14,R7,R5               ;Get the window width
+               CMP     R14,R9                  ;Is this wider than screen?
+               SUBGT   R0,R0,R5                ;Yes -- fit it exactly then
+               SUBGT   R2,R7,R2                ;And fit right edge to screen
+               SUBGT   R2,R9,R2
+
+               SUBS    R14,R7,R9               ;Is the right edge on?
+               SUBGT   R2,R2,R14               ;No -- shift it back on then
+               SUBGT   R0,R0,R14               ;Ensure the width is constant
+
+               SUBS    R14,R5,#0               ;Is the left edge on?
+               SUBLT   R0,R0,R14               ;No -- shift it back on
+               SUBLT   R2,R2,R14               ;Ensure constant width again
+
+               ; --- Now mangle the y coordinates ---
+
+               SUBS    R14,R8,R6               ;Get the window height
+               CMP     R14,R10                 ;Is this higher than screen?
+               SUBGT   R1,R1,R6                ;Yes -- fit it exactly then
+               SUBGT   R3,R8,R3                ;And fit top edge to screen
+               SUBGT   R3,R10,R3
+
+               SUBS    R14,R8,R10              ;Is the top edge on?
+               SUBGT   R3,R3,R14               ;No -- shift it back on then
+               SUBGT   R1,R1,R14               ;Ensure height is constant
+
+               LDR     R14,[R11,#screen_dy]    ;Get screen dy value
+               SUBS    R14,R6,R14              ;Is the bottom edge on?
+               SUBLT   R1,R1,R14               ;No -- shift it back on
+               SUBLT   R3,R3,R14               ;Ensure constant height again
+
+               ; --- Store it back and return ---
+
+               STMIB   R4,{R0-R3}              ;Store coordinates back again
+               LDMFD   R13!,{R0-R11,PC}^       ;Return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/viewer b/StraySrc/Libraries/Sapphire/s/viewer
new file mode 100644 (file)
index 0000000..e97daf3
--- /dev/null
@@ -0,0 +1,2316 @@
+;
+; viewer.s
+;
+; Filer-like windows with re-arranging icons (MDW)
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:akbd
+               GET     sapphire:alloc
+               GET     sapphire:divide
+               GET     sapphire:drag
+               GET     sapphire:fastMove
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+               GET     sapphire:wimp
+               GET     sapphire:win
+               GET     sapphire:winUtils
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         MSGB    $msg,$branch
+$label         DCD     $msg
+               B       $branch
+               MEND
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+;----- Creating and deleting viewers ----------------------------------------
+
+; --- viewer_create ---
+;
+; On entry:    R0 == pointer to a viewer definition block
+;              R1 == pointer to a list
+;              R2 == sprite area for window
+;
+; On exit:     R0 == viewer handle
+;              May return an error
+;
+; Use:         Creates a viewer window.  The viewer definition block
+;              contains various interesting bits of information about the
+;              viewer which are likely to be known at assembly time:
+;
+;              (word)   address of a list manager definition block
+;              (word)   address of a shape handler function (or 0)
+;              (word)   standard width of icons
+;              (word)   standard height of icons
+;              (string) banner text message tag, or empty
+;
+;              The shape function is used to allow viewer icons to have a
+;              non-rectangular shape.  The function is called with a reason
+;              code in R0; entry and exit conditions depend on this:
+;
+;                                                      vwShape_size
+;              On entry
+;                R1 == pointer to list item
+;                R2 == standard width of icon
+;                R3 == standard height of icon
+;
+;              On exit
+;                R2 == width of this icon
+;                R3 == height of this icon
+;
+;              Use
+;                This routine is used to find the actual size of an icon.
+;                The icons are aligned on a grid according to the largest
+;                one: this routine is used to find out which one that is.
+;
+;                                                      vwShape_intersects
+;              On entry
+;                R1 == pointer to list item
+;                R2 == address of bounding box of this icon
+;                R3 == address of bounding box to compare
+;
+;              On exit
+;                CS if boxes intersect, else CC
+;
+;              Use
+;                For detecting mouse clicks etc. on an icon.  viewer has
+;                already ensured that the box in R3 intersects with the
+;                bounding box, so for rectangular icons, you can just return
+;                with C set always.  This entry is provided so that you
+;                can check against the sprite and text of a text+sprite
+;                icon separately.
+;
+;              More reason codes may be added later; it will always be
+;              sensible to return immediately preserving all registers and
+;              flags.
+
+               EXPORT  viewer_create
+viewer_create  ROUT
+
+               STMFD   R13!,{R1-R5,R10,R14}    ;Save some registers
+
+               ; --- Move arguments into other registers ---
+
+               MOV     R5,R0                   ;Look after block def
+               MOV     R4,R2                   ;And the sprite area
+
+               ; --- Allocate a viewer block ---
+
+               MOV     R0,#vw__size            ;Get the block size
+               BL      alloc                   ;Allocate the memory
+               BLCS    alloc_error             ;If it failed, get error
+               BCS     %99viewer_create        ;And return to caller
+               MOV     R10,R0                  ;Look after the pointer
+
+               ; --- Fill in bits of the block ---
+
+               STR     R1,[R10,#vw__list]      ;Store the list address
+               LDMIA   R5!,{R0-R3}             ;Load regs from def block
+               STR     R0,[R10,#vw__listDef]   ;Store list definition addr
+               CMP     R1,#0                   ;Is the shape function 0?
+               ADREQ   R1,vw__dummyShape       ;Yes -- use default one
+               STR     R1,[R10,#vw__shape]     ;Store that away nicely
+               ADD     R14,R10,#vw__stdDimens  ;Point to standard icon sz
+               STMIA   R14,{R2,R3}             ;Store them away nicely
+               LDRB    R0,[R5,#0]              ;Load first byte of banner
+               CMP     R0,#0                   ;Is it actually defined?
+               MOVNE   R0,R5                   ;Yes -- point to it then
+               BLNE    msgs_lookup             ;And translate the tag
+               STR     R0,[R10,#vw__banner]    ;Store that away nicely
+
+               ; --- Now create a window ---
+
+               MOV     R0,R11                  ;Copy definition to scratch
+               ADR     R1,vw__windDef          ;Point to my definition
+               MOV     R2,#88                  ;Size of window definition
+               BL      fastMove                ;Copy the data over
+
+               STR     R4,[R11,#64]            ;Store caller's sprite area
+               ADD     R14,R10,#vw__title      ;Point to title buffer
+               STR     R14,[R11,#72]           ;Save this in window block
+               MOV     R1,R11                  ;Point to window definition
+               SWI     XWimp_CreateWindow      ;Try to do that then
+               BVS     %98viewer_create        ;If it failed, tidy up
+               STR     R0,[R10,#vw__window]    ;Save the window handle
+
+               ; --- Set up the event handler ---
+
+               ADR     R1,vw__events           ;Point to event handler
+               MOV     R2,R10                  ;Use viewer handle as R10
+               MOV     R3,R12                  ;Pass workspace in R12 (*)
+               BL      win_eventHandler        ;Set up the event handler
+               BVS     %97viewer_create        ;If it failed, tidy up
+
+               ; --- Fix up rest of viewer block ---
+
+               MOV     R14,#0                  ;No handler defined yet
+               STR     R14,[R10,#vw__handler]  ;Save that in my block
+               STR     R14,[R10,#vw__flags]    ;Clear the flags too
+               STR     R14,[R10,#vw__tempSel]  ;No temporary selection
+
+               ; --- Now return to caller ---
+
+               MOV     R0,R10                  ;Get the viewer handle
+               LDMFD   R13!,{R1-R5,R10,R14}    ;Restore registers
+               BICS    PC,R14,#V_flag          ;And return to caller
+
+               ; --- Handle minor mishaps ---
+
+97viewer_create        MOV     R5,R0                   ;Look after error pointer
+               ADD     R1,R10,#vw__window      ;Point to window handle
+               SWI     Wimp_DeleteWindow       ;Destroy the window
+               MOV     R0,R5                   ;And get the error back
+
+98viewer_create        MOV     R5,R0                   ;Look after error pointer
+               MOV     R0,R10                  ;Point to viewer block
+               BL      free                    ;Free the block up
+               MOV     R0,R5                   ;And get the error back
+
+99viewer_create        ADD     R2,R0,#4                ;Point to error text
+               ADR     R0,vw__createErr        ;Point to error skeleton
+               BL      msgs_error              ;Translate and substitute
+               LDMFD   R13!,{R1-R5,R10,R14}    ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+vw__dummyShape ORRS    PC,R14,#C_flag          ;Dummy shape function
+
+vw__createErr  DCD     1
+               DCB     "vwCRTE",0
+
+vw__windDef    DCD     0,0,0,0
+               DCD     0,0
+               DCD     0
+               DCD     &BF000002
+               DCB     7,2,7,1,3,1,12,0
+               DCD     0,0,0,0
+               DCD     &1700013D
+               DCD     &0000A000
+               DCD     1
+               DCW     1,0
+               DCD     0,-1,256
+               DCD     0
+
+               LTORG
+
+; --- viewer_destroy ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Destroys a viewer, removing it from the screen etc.
+
+               EXPORT  viewer_destroy
+viewer_destroy ROUT
+
+               STMFD   R13!,{R0,R1,R10,R14}    ;Save some registers
+               MOV     R10,R0                  ;Look after the handle
+               LDR     R0,[R10,#vw__window]    ;Load the window handle
+               BL      win_windowDeleted       ;Say it's been deleted
+               ADD     R1,R10,#vw__window      ;Find the window handle
+               SWI     Wimp_DeleteWindow       ;Destroy the window
+               MOV     R0,R10                  ;Point to the viewer block
+               BL      free                    ;Release the memory
+               LDMFD   R13!,{R0,R1,R10,PC}^    ;And return to caller
+
+               LTORG
+
+;----- Opening and closing --------------------------------------------------
+
+; --- viewer_open ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == opening style
+;              R2,R3 == extra arguments
+;
+; On exit:     --
+;
+; Use:         Opens a viewer window on the screen.
+
+               EXPORT  viewer_open
+viewer_open    ROUT
+
+               STMFD   R13!,{R0,R1,R4,R10,R14} ;Save some registers
+               MOV     R10,R0                  ;Get the viewer handle
+               MOV     R4,R1                   ;Look after opening style
+
+               SUB     R13,R13,#36             ;Make a window state block
+               LDR     R14,[R10,#vw__window]   ;Load the window handle
+               STR     R14,[R13,#0]            ;Save it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;And read the window state
+
+               ; --- If window is open, skip on ---
+
+               BL      vw__open                ;Is the window open?
+               BCS     %10viewer_open          ;Yes -- skip onwards then
+
+               ; --- Open the window onto the screen ---
+
+               LDR     R1,[R10,#vw__listDef]   ;Find the list definition
+               LDR     R0,[R10,#vw__list]      ;And the list base
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R1,#vw__items        ;Find how many items
+               STR     R1,[R10,#vw__icons]     ;Store this away
+
+               MOV     R1,R13                  ;Point at window state blk
+               BL      vw__tWidth              ;Work out title width
+               BL      vw__rescanSize          ;Rescan the item size
+               BL      vw__extend              ;Yes -- make it big then
+               BL      vw__resize              ;Work out new arrangement
+               BL      vw__setExtent           ;Set the window's extent
+
+               ; --- Finally work out where to open it ---
+
+10viewer_open  MOV     R0,R4                   ;Get the opening style
+               BL      winUtils_setPosition    ;Set the window position
+               BL      vw__openWindow          ;Open the window there
+               ADD     R13,R13,#36             ;Reclaim the stack space
+               LDR     R14,[R10,#vw__flags]    ;Load the flags word
+               ORR     R14,R14,#vwFlag__opened ;We've now opened it
+               STR     R14,[R10,#vw__flags]    ;Store the flags back
+               LDMFD   R13!,{R0,R1,R4,R10,PC}^ ;And return to caller
+
+               LTORG
+
+; --- viewer_close ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Closes a viewer window.
+
+               EXPORT  viewer_close
+viewer_close   ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               ADD     R1,R0,#vw__window       ;Find the window handle
+               SWI     Wimp_CloseWindow        ;Close the window
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Event handling -------------------------------------------------------
+
+; --- viewer_eventHandler ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == pointer to event handler
+;              R2 == value to pass in R10
+;              R3 == value to pass in R12
+;
+; On exit:     R1-R3 == old values
+;
+; Use:         Sets up the event handle for the viewer.
+
+               EXPORT  viewer_eventHandler
+viewer_eventHandler ROUT
+
+               STMFD   R13!,{R4-R6,R14}        ;Save some registers
+               ADD     R14,R0,#vw__handler     ;Point to handler block
+               LDMIA   R14,{R4-R6}             ;Load the old handler
+               STMIA   R14,{R1-R3}             ;Save the new one
+               MOV     R1,R4                   ;Transfer information over
+               MOV     R2,R5                   ;All of it, don't let it
+               MOV     R3,R6                   ;Get away!
+               LDMFD   R13!,{R4-R6,PC}^        ;And return to caller
+
+               LTORG
+
+; --- vw__events ---
+;
+; On entry:    R0 == event code
+;              R1 == pointer to event block
+;
+; On exit:     CS if handled, else CC
+;
+; Use:         Handles events for a viewer window.
+
+vw__events     ROUT
+
+               CMP     R0,#17                  ;Is this a message?
+               CMPNE   R0,#18                  ;Check *both* types
+               BEQ     %10vw__events           ;Yes -- handle them
+               CMP     R0,#9                   ;Is the event interesting?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch it then
+               MOVS    PC,R14                  ;Otherwise ignore it
+
+               ; --- Branch table ---
+
+               MOVS    PC,R14
+               B       vw__evRedraw
+               B       vw__evOpen
+               B       vw__evClose
+               MOVS    PC,R14
+               MOVS    PC,R14
+               B       vw__evMouse
+               MOVS    PC,R14
+               B       vw__evKey
+
+               ; --- Handle messages ---
+               ;
+               ; This is a little odd, in the interests of expandability.
+
+10vw__events   STMFD   R13!,{R2-R4,R14}        ;Save some registers
+               LDR     R2,[R1,#16]             ;Load the message code
+               ADR     R3,vw__msgTable         ;Point to the message table
+00             LDR     R4,[R3],#8              ;Load the message code
+               CMP     R4,R2                   ;Do I recognise this event?
+               SUBEQ   R3,R3,#4                ;Yes -- point to branch instr
+               STREQ   R3,[R13,#12]            ;Store as return address
+               CMPNE   R4,#-1                  ;Is it the end of the list?
+               BNE     %b00                    ;No -- keep looping then
+               LDMFD   R13!,{R2-R4,PC}^        ;Call the routine
+
+               ; --- Message table ---
+
+vw__msgTable   MSGB    &1,vw__mDataSave
+               MSGB    &3,vw__mDataLoad
+               MSGB    &502,vw__mHelpRq
+               MSGB    &400CF,vw__mFontChnge
+               DCD     -1,-1
+
+               LTORG
+
+; --- vw__dispatch ---
+;
+; On entry:    R0 == event code
+;              R1-R5 set up for event
+;
+; On exit:     CS or CC according to event handler
+;
+; Use:         Dispatches an event to the user's handler.
+
+               EXPORT  vw__dispatch
+vw__dispatch   ROUT
+
+               STMFD   R13!,{R8-R10,R12,R14}   ;Save some registers
+               ADD     R14,R10,#vw__handler    ;Find the handler routine
+               MOV     R9,R10                  ;Pass viewer handle in R9
+               LDMIA   R14,{R8,R10,R12}        ;Load the things out
+               ADDS    R0,R0,#0                ;Clear the carry flag
+               TEQ     R8,#0                   ;Is there a routine?
+               MOVNE   R14,PC                  ;Yes -- set up return addr
+               MOVNE   PC,R8                   ;And call the routine
+               LDMFD   R13!,{R8-R10,R12,R14}   ;Restore registers
+               ORRCSS  PC,R14,#C_flag          ;If it set C, we do too
+               BICCCS  PC,R14,#C_flag          ;Otherwise we clear it
+
+               LTORG
+
+; --- vw_evRedraw ---
+;
+; On entry:    R1 == pointer to window handle in block
+;
+; On exit:     CS
+;
+; Use:         Redraws a viewer window.
+
+vw__evRedraw   ROUT
+
+               STMFD   R13!,{R0-R7,R14}        ;Save some registers
+               SWI     Wimp_RedrawWindow       ;Start the redraw job
+               CMP     R0,#0                   ;Is this the end yet?
+               BEQ     %90vw__evRedraw         ;Yes -- do nothing then
+
+               ; --- Find the window origin ---
+
+               MOV     R7,R1                   ;Remember the block pointer
+               LDR     R2,[R7,#4]              ;Load the left hand side
+               ADD     R14,R7,#16              ;Point to top and scroll pos
+               LDMIA   R14,{R3-R5}             ;Load those positions out
+               SUB     R6,R3,R5                ;Find the top position
+               SUB     R5,R2,R4                ;And the left side
+               SUB     R13,R13,#32             ;Space for rectangle block
+
+               ; --- The main redraw loop ---
+               ;
+               ; First of all, handle the banner.
+
+10vw__evRedraw LDR     R14,[R10,#vw__banner]   ;Load the banner address
+               CMP     R14,#0                  ;Is there one defined?
+               BEQ     %f00                    ;No -- skip ahead then
+
+               ; --- See if we need to do this ---
+
+               LDR     R14,[R7,#28+16]         ;Load the top coordinate
+               CMP     R14,R6                  ;Is this above the line?
+               BLT     %f00                    ;No -- don't bother then
+
+               ; --- Render the banner's background ---
+
+               MOV     R0,#3                   ;Get the banner colour
+               SWI     Wimp_SetColour          ;Set this as the colour
+
+               MOV     R0,#4                   ;Move the graphics cursor
+               LDR     R1,[R7,#28+0]           ;Find left side of window
+               MOV     R2,R6                   ;Baseline on window origin
+               SWI     OS_Plot                 ;Do the cursor move
+               MOV     R0,#101                 ;Rectangle fill absolute
+               LDR     R1,[R7,#28+8]           ;Load right side of window
+               ADD     R2,R6,#vw__banHeight    ;Get the banner height
+               SWI     OS_Plot                 ;Do that too
+
+               ; --- Now plot the banner text ---
+
+               MOV     R14,R13                 ;Point at the stack block
+
+               MOV     R0,#28                  ;We have an odd left side
+               MOV     R1,#0                   ;Baseline is along origin
+               LDR     R2,[R10,#vw__fixedWidth] ;Load width of the banner
+               MOV     R3,#vw__banHeight       ;Get the banner's height
+               STMIA   R14!,{R0-R3}            ;Save the coordinates
+
+               LDR     R0,=&37000131           ;Get the icon flags word
+               LDR     R1,[R10,#vw__banner]    ;Load the banner pointer
+               MOV     R2,#-1                  ;No validation string
+               MOV     R3,#1                   ;Bogus string length
+               STMIA   R14!,{R0-R3}            ;Save the other bits
+
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the text as an icon
+
+               ; --- Now alter the graphics rectangle ---
+
+00             ADD     R14,R7,#28              ;Find the clipping rectangle
+               LDMIA   R14,{R0-R3}             ;Load the rectangle out
+               SUB     R0,R0,R5                ;Convert to window coords
+               SUB     R1,R1,R6                ;This isn't terribly hard
+               SUB     R2,R2,R5                ;Just subtract origin posn
+               SUB     R3,R3,R6                ;For all the coordinates
+               STMIA   R14,{R0-R3}             ;Store those in the block
+
+               ; --- Plot each interesting icon ---
+
+               MOV     R0,#vwEvent_redraw      ;Say this is a redraw event
+               MOV     R1,#0                   ;Start at the beginning
+               MOV     R2,R13                  ;Use my stack buffer
+               ADD     R3,R7,#28               ;Point to the clip block
+00             BL      vw__enum                ;Get next icon ready
+               BCC     %f00                    ;If no more, skip onwards
+               BL      vw__intSimple           ;Do quick clipping check
+               BLCS    vw__dispatch            ;Yes -- package off the event
+               B       %b00                    ;Loop round for the rest
+
+               ; --- Finish off the redraw loop ---
+
+00             MOV     R1,R7                   ;Point at the event block
+               BL      drag_redraw             ;Draw the drag box if reqd
+               SWI     Wimp_GetRectangle       ;Get another rectangle
+               CMP     R0,#0                   ;Is there more to do?
+               BNE     %10vw__evRedraw         ;Yes -- loop back to do it
+
+               ADD     R13,R13,#32             ;Restore the stack pointer
+
+90vw__evRedraw LDMFD   R13!,{R0-R7,R14}        ;Unstack the registers
+               ORRS    PC,R14,#C_flag          ;And *claim the event*
+
+               LTORG
+
+; --- vw__evOpen ---
+;
+; On entry:    R1 == pointer to an open-window block
+;
+; On exit:     CS
+;
+; Use:         Opens a viewer window.
+
+vw__evOpen     ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R14,#0                  ;Force horizontal scroll
+               STR     R14,[R1,#20]            ;To stop it looking odd
+               BL      screen_justChangedMode  ;Just had a mode change?
+               BCS     %50vw__evOpen           ;Yes -- handle that
+
+               ; --- Just rescan the size like nice people ---
+
+               BL      vw__resize              ;Modify the arrangement
+               BLCS    vw__setExtent           ;Maybe modify the extent too
+               BLCS    vw__refresh             ;If so, force a redraw
+               BL      vw__openWindow          ;Whatever, open the window
+               LDMFD   R13!,{R0,R14}           ;Restore the registers
+               ORRS    PC,R14,#C_flag          ;And claim the event
+
+               ; --- Just changed mode -- anything could have happened ---
+
+50vw__evOpen   BL      vw__tWidth              ;Rescan the title width
+               BL      vw__rescanSize          ;Rescan the icon sizes
+               BL      vw__resize              ;Rearrange the icons
+               BL      vw__setExtent           ;Rework the extent
+               BL      vw__refresh             ;Redraw the work area
+               BL      vw__openWindow          ;And reopen the window
+               LDMFD   R13!,{R0,R14}           ;Restore the registers
+               ORRS    PC,R14,#C_flag          ;And claim the event
+
+               LTORG
+
+; --- vw__evClose ---
+;
+; On entry:    R1 == pointer to block
+;
+; On exit:     CC or CS
+;
+; Use:         Handles a close request for a viewer,
+
+vw__evClose    ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,#vwEvent_close       ;Get the event code
+               BL      vw__dispatch            ;Send it to the user
+               LDMFD   R13!,{R0,PC}            ;And return this state
+
+               LTORG
+
+; --- vw__evMouse ---
+;
+; On entry:    R1 == pointer to pointer info block
+;
+; On exit:     CS
+;
+; Use:         Handles a mouse click on the viewer.
+
+vw__evMouse    ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R4,R1                   ;Look after this pointer
+               LDMIA   R4,{R2,R3}              ;Load the coordinates out
+               BL      vw__whichIcon           ;Which icon is that?
+
+               LDR     R2,[R4,#8]              ;Load the button state
+               TST     R2,#&002                ;Is this a menu click?
+               MOVNE   R0,#vwEvent_menu        ;Yes -- pass that event
+               TST     R2,#&005                ;Another normal click?
+               MOVNE   R0,#vwEvent_double      ;Yes -- that's a double
+               TST     R2,#&050                ;Is it a drag?
+               MOVNE   R0,#vwEvent_drag        ;Yes -- use that event then
+               TST     R2,#&500                ;Or a normal click?
+               MOVNE   R0,#vwEvent_click       ;Yes -- that's a real one
+               BL      vw__dispatch            ;Sent the event on
+               LDMFD   R13!,{R0-R4,R14}        ;Save some registers
+               ORRS    PC,R14,#C_flag          ;We dealt with it
+
+               LTORG
+
+; --- vw__evKey ---
+;
+; On entry:    R1 == pointer to caret info block
+;
+; On exit:     CC if unclaimed, else CS
+;
+; Use:         Handles a keypress while the viewer has the input focus.
+
+vw__evKey      ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R0,[R1,#24]             ;Load the character code
+               BL      akbd_translate          ;Try translating the key
+               MOV     R1,R0                   ;Put this back in R1
+               MOV     R0,#vwEvent_key         ;Get the event code
+               BL      vw__dispatch            ;Dispatch the event
+               LDMFD   R13!,{R0,R1,R14}        ;Restore registers
+               ORRCSS  PC,R14,#C_flag          ;Claim if he claimed it
+               BICCCS  PC,R14,#C_flag          ;Don't claim if he didn't
+
+               LTORG
+
+; --- vw__mDataSave ---
+;
+; On entry:    R0 == message code
+;              R1 == pointer to message block
+;
+; On exit:     --
+;
+; Use:         Handles a file dropped on the viewer.
+
+vw__mDataSave  ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R4,#vwDrop_save         ;Say it's a save event
+               ADD     R3,R1,#44               ;Point to the filename
+               LDR     R2,[R1,#36]             ;Load the estimated size
+               LDR     R1,[R1,#40]             ;And the filetype
+               MOV     R0,#vwEvent_drop        ;Get the event code
+               BL      vw__dispatch            ;And send it to the client
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+; --- vw__mDataLoad ---
+;
+; On entry:    R0 == message code
+;              R1 == pointer to message block
+;
+; On exit:     --
+;
+; Use:         Handles a file dropped on the viewer.
+
+vw__mDataLoad  ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R4,#vwDrop_load         ;Say it's a load event
+               ADD     R3,R1,#44               ;Point to the filename
+               LDR     R2,[R1,#36]             ;Load the estimated size
+               LDR     R1,[R1,#40]             ;And the filetype
+               MOV     R0,#vwEvent_drop        ;Get the event code
+               BL      vw__dispatch            ;And send it to the client
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+; --- vw__mHelpRq ---
+;
+; On entry:    R0 == message code
+;              R1 == pointer to message block
+;
+; On exit:     --
+;
+; Use:         Handles a help request for the viewer.
+
+vw__mHelpRq    ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               ADD     R14,R1,#20              ;Find the mouse position
+               LDMIA   R14,{R2,R3}             ;Load the coordinates
+               BL      vw__whichIcon           ;Find the icon pointed at
+               MOV     R0,#vwEvent_help        ;It's a help request
+               BL      vw__dispatch            ;Send it to the client
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+; --- vw__mFontChnge ---
+;
+; On entry:    R0 == message code
+;              R1 == pointer to message block
+;
+; On exit:     --
+;
+; Use:         Handles font changed events for the viewer.
+
+vw__mFontChnge ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               SUB     R13,R13,#36             ;Make a window state block
+               LDR     R14,[R10,#vw__window]   ;Load viewer's window handle
+               STR     R14,[R13,#0]            ;Store it in the block
+               MOV     R1,R13                  ;Point to this block
+               SWI     Wimp_GetWindowState     ;Read the window information
+               BL      vw__tWidth              ;Rescan the title width
+               BL      vw__rescanSize          ;Rescan the icon sizes
+               BL      vw__resize              ;Rearrange the icons
+               BL      vw__setExtent           ;Rework the extent
+               BL      vw__refresh             ;Redraw the work area
+               BL      vw__openWindow          ;And reopen the window
+               ADD     R13,R13,#36             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+;----- Icon position handling -----------------------------------------------
+
+; --- vw__callShape ---
+;
+; On entry:    R0 == reason code
+;              R1-R? == other arguments
+;              R10 == pointer to viewer block
+;
+; On exit:     R0-R? and C returned from shape function
+;
+; Use:         Calls a shape function and returns the result.
+
+               EXPORT  vw__callShape
+vw__callShape  ROUT
+
+               STMFD   R13!,{R8-R10,R12,R14}   ;Save some registers
+               LDR     R8,[R10,#vw__shape]     ;Load the shape function addr
+               MOV     R9,R10                  ;Point to the viewer block
+               ADD     R14,R10,#vw__handler+4  ;Find owner's R10 and R12
+               LDMIA   R14,{R10,R12}           ;Load them out nicely too
+               CMP     R0,R0                   ;Set the C flag on entry
+               MOV     R14,PC                  ;Set up the return address
+               MOV     PC,R8                   ;Call the shape function
+               LDMFD   R13!,{R8-R10,R12,R14}   ;Restore registers
+               ORRCSS  PC,R14,#C_flag          ;If it set C, return C set
+               BICCCS  PC,R14,#C_flag          ;Otherwise return C clear
+
+               LTORG
+
+; --- vw__whichIcon ---
+;
+; On entry:    R2,R3 == mouse coordinates (screen relative)
+;              R10 == pointer to viewer block
+;
+; On exit:     R1 == icon beneath the mouse pointer
+;
+; Use:         Works out which icon the user is pointing at, should this be
+;              interesting.
+
+vw__whichIcon  ROUT
+
+               STMFD   R13!,{R0,R2-R6,R14}     ;Save lots of registers
+
+               ; --- Find the window's state ---
+
+               SUB     R13,R13,#36             ;Drop the stack to make a blk
+               LDR     R14,[R10,#vw__window]   ;Get the window handle
+               STR     R14,[R13,#0]            ;Store that in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Read the window state
+
+               LDR     R0,[R13,#4]             ;Load the left hand side
+               ADD     R14,R13,#16             ;Point to the top edge
+               LDMIA   R14,{R4-R6}             ;Load those values out
+               SUB     R5,R0,R5                ;Work out x origin position
+               SUB     R6,R4,R6                ;And the y origin position
+
+               ; --- Find the click position ---
+
+               SUB     R2,R2,R5                ;Translate click coordinates
+               SUB     R3,R3,R6                ;Do that nicely
+               MOV     R14,R13                 ;Point to my nice block
+               STMIA   R14!,{R2,R3}            ;Save coordinates away
+               STMIA   R14!,{R2,R3}            ;And do it again
+
+               ; --- Now do the enumeration ---
+
+               MOV     R1,#0                   ;Start at the beginning
+               ADD     R2,R13,#16              ;Point to spare bit of block
+               MOV     R3,R13                  ;Point to my coordinates
+               BL      vw__withinBox           ;Try to find a match
+               MOVCC   R1,#0                   ;No match -- no icon
+               ADD     R13,R13,#36             ;Recover stack space
+               LDMFD   R13!,{R0,R2-R6,PC}^     ;And return to caller
+
+               LTORG
+
+; --- vw__rescanSize ---
+;
+; On entry:    R10 == pointer to viewer block
+;
+; On exit:     --
+;
+; Use:         Recalculates the sizes of icons in the viewer.
+
+vw__rescanSize ROUT
+
+               STMFD   R13!,{R0-R7,R14}        ;Save some registers
+
+               ; --- Set up for the loop ---
+
+               LDR     R6,[R10,#vw__listDef]   ;Find the list block
+               MOV     R1,#0                   ;No item found yet
+               ADD     R7,R10,#vw__stdDimens   ;Find standard dimensions
+               LDMIA   R7,{R4,R5}              ;These are minimum sizes
+
+               ; --- Now read all the items ---
+
+00             LDR     R0,[R10,#vw__list]      ;Find the list head
+               MOV     R2,#0                   ;Match any flags
+               MOV     R3,#0                   ;Still match any flags
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R6,#vw__enumerate    ;Read the next list item
+               BCC     %10vw__rescanSize       ;If no more, skip on
+               LDMIA   R7,{R2,R3}              ;Load standard sizes
+               MOV     R0,#vwShape_size        ;Get the reason code
+               BL      vw__callShape           ;And call the shape function
+               CMP     R4,R2                   ;Now update the sizes
+               MOVCC   R4,R2                   ;Use the biggest on both
+               CMP     R5,R3                   ;Check the height too
+               MOVCC   R5,R3                   ;Use the biggest again
+               B       %b00                    ;Now loop round for more
+
+               ; --- Finished -- store result away ---
+
+10             ADD     R14,R10,#vw__iconWidth  ;Find current sizes
+               STMIA   R14,{R4,R5}             ;Store these new sizes
+               LDMFD   R13!,{R0-R7,PC}^        ;And return to caller
+
+               LTORG
+
+; --- vw__intSimple ---
+;
+; On entry:    R2 == pointer to a box
+;              R3 == pointer to another box
+;
+; On exit:     CS if boxes intersect, else CC
+;
+; Use:         Informs you whether boxes intersect.  Saves lots of
+;              registers.  This is typically used before calling the
+;              caller's shape routine to see if it's really worth it.
+
+               EXPORT  vw__intSimple
+vw__intSimple  ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Save some registers
+               LDMIA   R3,{R4-R6,R14}          ;Load second box out
+               LDMIA   R2,{R0-R3}              ;Load first box out
+               CMP     R2,R4                   ;Now do the compare
+               CMPGE   R3,R5
+               CMPGE   R6,R0
+               CMPGE   R14,R1
+               LDMFD   R13!,{R0-R6,R14}        ;Restore registers
+               ORRGES  PC,R14,#C_flag          ;Return C set if OK
+               BICLTS  PC,R14,#C_flag          ;Otherwise return CC
+
+               LTORG
+
+; --- vw__enum ---
+;
+; On entry:    R1 == 0 for first call, or item pointer
+;              R2 == pointer to 16-byte coordinate buffer
+;              R4 == continuation value from old call
+;              R10 == pointer to viewer block
+;
+; On exit:     CS if more icons, and
+;                R1 == item handle
+;                R4 == new continuation value
+;              else CC and
+;                R1,R4 corrupted
+;
+; Use:         Scans through icons, returning their coordinates in the
+;              block.
+;
+;              This routine is exported, although it isn't for user
+;              consumption.  People using it in application code will be
+;              shot.
+
+               EXPORT  vw__enum
+vw__enum       ROUT
+
+               STMFD   R13!,{R0,R2,R3,R5-R8,R14} ;Save some registers
+
+               ; --- Set up for first go round ---
+
+               CMP     R1,#0                   ;Is this the first go?
+               BNE     %05vw__enum             ;No -- skip onwards then
+
+               MOV     R4,#0                   ;Yes -- start at top left
+
+               ADD     R14,R10,#vw__iconWidth  ;Find the icon dimensions
+               LDMIA   R14,{R7,R14}            ;Load them out of the block
+               MOV     R5,#vw__iconGap         ;Set up the gap nicely
+               ADD     R7,R5,R7                ;Work out right hand side
+               MOV     R8,#-vw__iconGap        ;Work out top edge
+               SUB     R6,R8,R14               ;And set up the bottom
+               STMIA   R2,{R5-R8}              ;Save all of those away
+               B       %10vw__enum             ;Now skip on to next bit
+
+               ; --- Sort out a subsequent round ---
+
+05vw__enum     LDMIA   R2,{R5,R6}              ;Load bottom left of icon
+               ADD     R14,R10,#vw__iconWidth  ;Find the icon dimensions
+               LDMIA   R14,{R7,R8}             ;Load them out of the block
+               ADD     R4,R4,#1                ;Bump horizontal position
+               LDR     R14,[R10,#vw__across]   ;How many icons going across?
+               CMP     R4,R14                  ;Reached the edge yet?
+               ADDCC   R5,R5,R7                ;No -- move along then
+               ADDCC   R5,R5,#vw__iconGap      ;Add on our extra spacing
+               MOVCS   R5,#vw__iconGap         ;Otherwise go back to left
+               MOVCS   R4,#0                   ;Return left side position
+               SUBCS   R6,R6,R8                ;Drop down one row
+               SUBCS   R6,R6,#vw__iconGap      ;And add on the spacing
+               ADD     R7,R5,R7                ;Work out other box position
+               ADD     R8,R6,R8                ;To make the box right
+               STMIA   R2,{R5-R8}              ;Store all that away
+
+               ; --- Now advance the icon pointer ---
+
+10vw__enum     LDR     R0,[R10,#vw__list]      ;Load the list base
+               MOV     R2,#0                   ;Give me all the icons
+               MOV     R3,#0                   ;I really mean that
+               LDR     R5,[R10,#vw__listDef]   ;Find the list block
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R5,#vw__enumerate    ;Get the next item
+               LDMFD   R13!,{R0,R2,R3,R5-R8,R14} ;Unstack registers
+               ORRCSS  PC,R14,#C_flag          ;If more to come, OK
+               BICCCS  PC,R14,#C_flag          ;Otherwise return the end
+
+               LTORG
+
+; --- vw__withinBox ---
+;
+; On entry:    R1 == 0 for first call, or pointer from previous
+;              R2 == pointer to 16-byte buffer
+;              R3 == pointer to coordinate box (window relative)
+;              R4 == value from previous call
+;              R10 == pointer to viewer block
+;
+; On exit:     CS if match found, and
+;                R1 == item handle of match
+;                R4 == continuation value
+;              else CC and
+;                R1,R4 corrupted
+;
+; Use:         Enumerates icons which intersect a given rectangle.  The
+;              coordinates of a matching icon are left in the block; these
+;              must be set up correctly for the next call.
+
+vw__withinBox  ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,#vwShape_intersects  ;Get shape fn reason code
+00             BL      vw__enum                ;Get another icon
+               BCC     %10vw__withinBox        ;If no more, return now
+               BL      vw__intSimple           ;Check simple intersection
+               BLCS    vw__callShape           ;And then the complex one
+               BCC     %b00                    ;If no match, skip back
+               LDMFD   R13!,{R0,R14}           ;Restore registers
+               ORRS    PC,R14,#C_flag          ;And return match
+
+10vw__withinBox        LDMFD   R13!,{R0,R14}           ;Restore registers
+               BICS    PC,R14,#C_flag          ;Return no match
+
+               LTORG
+
+; --- vw__iconBox ---
+;
+; On entry:    R1 == item pointer
+;              R2 == pointer to a block to fill in
+;              R10 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Works out the bounding box of an icon (within the window).
+
+vw__iconBox    ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+
+               ; --- First, get the icon index ---
+
+               LDR     R0,[R10,#vw__list]      ;Load the list head pointer
+               LDR     R5,[R10,#vw__listDef]   ;Find the definition too
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R5,#vw__itemToIndex  ;Find the item's index
+
+               ; --- Now work out its across and down position ---
+
+               MOV     R0,R1                   ;Get the item index
+               LDR     R1,[R10,#vw__across]    ;Find icons going across
+               BL      divide                  ;Do the division
+
+               ; --- Finally find the actual position ---
+
+               ADD     R14,R10,#vw__iconWidth  ;Point to icon dimens
+               LDMIA   R14,{R4,R5}             ;Load the width and height
+               ADD     R3,R4,#vw__iconGap      ;Add on the gap here
+               ADD     R14,R5,#vw__iconGap     ;And again, please
+               MUL     R14,R0,R14              ;Work out vertical placing
+               MUL     R0,R1,R3                ;And the horizontal placing
+               RSB     R14,R14,#0              ;Make vertical position -ve
+               ADD     R0,R0,#vw__iconGap      ;Push the icon in a little
+               SUB     R14,R14,#vw__iconGap    ;And push it down a little
+               ADD     R3,R0,R4                ;Work out the right side
+               SUB     R1,R14,R5               ;And the bottom edge
+               STMIA   R2,{R0,R1,R3,R14}       ;Save them in my block
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Default selection model ----------------------------------------------
+
+; --- viewer_select ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == icon handle
+;              R2 == 0 to unselect, 1 to select or 2 to toggle
+;
+; On exit:     --
+;
+; Use:         Selects an icon, or maybe unselects it.  Whatever, it doesn't
+;              flicker if it doesn't need to.
+
+               EXPORT  viewer_select
+viewer_select  ROUT
+
+               CMP     R1,#0                   ;Is there an icon?
+               MOVEQS  PC,R14                  ;No -- do nothing then
+
+               STMFD   R13!,{R0-R5,R10,R14}    ;Save some registers
+               MOV     R10,R0                  ;Get the viewer block pointer
+
+               ; --- Read the current flags ---
+
+               LDR     R4,[R10,#vw__listDef]   ;Get the list definition
+               MOV     R5,R2                   ;And get the argument
+               MOV     R3,#0                   ;Don't toggle flags
+               MOV     R2,#0                   ;Don't clear any flags
+               LDR     R0,[R10,#vw__list]      ;Load the list base address
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R4,#vw__setFlags     ;Read the current flags
+
+               ; --- Work out the new ones ---
+
+               AND     R2,R2,#1                ;Leave only selected flag
+               CMP     R5,#1                   ;What is the operation?
+               MOVLT   R3,#0                   ;Clear -- clear the flag
+               MOVEQ   R3,#1                   ;Set -- set the flag
+               EORGT   R3,R2,#1                ;Toggle -- toggle the flag
+               CMP     R3,R2                   ;Have we made a difference?
+               LDMEQFD R13!,{R0-R5,R10,PC}^    ;No -- return now then
+
+               ; --- Set the new flags now ---
+
+               MOV     R2,#1                   ;Clear the selected bit
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R4,#vw__setFlags     ;Set the new flags
+               MOV     R0,R10                  ;Get handle in R0
+               BL      viewer_update           ;Update the icon
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;Return to caller
+
+               LTORG
+
+; --- viewer_isSelected ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == icon handle
+;
+; On exit:     CS if icon is selected, else CC
+;
+; Use:         Informs you whether an icon is selected.
+
+               EXPORT  viewer_isSelected
+viewer_isSelected ROUT
+
+               CMP     R1,#0                   ;Is there an icon?
+               BICEQS  PC,R14,#C_flag          ;No -- not selected then
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R2,#0                   ;Don't clear any flags
+               MOV     R3,#0                   ;Don't toggle any either
+               LDR     R4,[R0,#vw__listDef]    ;Find the list block
+               LDR     R0,[R0,#vw__list]       ;Find the list base
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R4,#vw__setFlags     ;Read the current flags
+               TST     R2,#1                   ;Is it selected then?
+               LDMFD   R13!,{R0-R4,R14}        ;Restore caller's registers
+               ORRNES  PC,R14,#C_flag          ;If selected, return C set
+               BICEQS  PC,R14,#C_flag          ;Otherwise clear C on exit
+
+               LTORG
+
+; --- viewer_selectAll ---
+;
+; On entry:    R0 == viewer handle
+;              R2 == 0 to deselect, or 1 to select
+;
+; On exit:     --
+;
+; Use:         Selects or deselects all the icons in a viewer.
+
+               EXPORT  viewer_selectAll
+viewer_selectAll ROUT
+
+               STMFD   R13!,{R0-R5,R10,R14}    ;Save some registers
+               MOV     R10,R0                  ;Look after the handle
+               MOV     R1,#0                   ;Start at the beginning
+               MOV     R4,R2                   ;Look after selection state
+               LDR     R5,[R10,#vw__listDef]   ;Find the list block
+
+00             LDR     R0,[R10,#vw__list]      ;Find the list head
+               MOV     R2,#1                   ;Check the selected bit
+               EOR     R3,R4,#1                ;Find interesting icons
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R5,#vw__enumerate    ;Find next icon
+               BCC     %f00                    ;If all done, skip on
+               MOV     R0,R10                  ;Get viewer handle
+               MOV     R2,R4                   ;Get selection state
+               BL      viewer_select           ;Do the selection
+               B       %b00                    ;And skip back for the rest
+
+00             MOV     R14,#0                  ;Clear temporary selection
+               STR     R14,[R10,#vw__tempSel]  ;Store that in the block
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;Return to caller when done
+
+               LTORG
+
+; --- viewer_click ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == icon handle (or 0)
+;              R2 == mouse button state
+;
+; On exit:     --
+;
+; Use:         Handles a click, drag etc. according to the standard
+;              selection model.
+
+               EXPORT  viewer_click
+viewer_click   ROUT
+
+               TST     R2,#&002                ;Is this a menu click?
+               BNE     %20viewer_click         ;Yes -- handle it then
+               TST     R2,#&400                ;Is this a SELECT click?
+               BNE     %10viewer_click         ;Yes -- handle that
+               TST     R2,#&050                ;Is this a drag?
+               BNE     %50viewer_click         ;Yes -- start a drag box
+               TST     R2,#&100                ;Is this an ADJUST click?
+               MOVEQS  PC,R14                  ;No -- do nothing then
+
+               ; --- Handle an ADJUST click ---
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               BL      viewer_clearTemp        ;Clear temporary selection
+               MOV     R2,#2                   ;Now select interesting icon
+               BL      viewer_select           ;Do the selection op
+               LDMFD   R13!,{R2,PC}^           ;And return to caller
+
+               ; --- Handle a SELECT click ---
+
+10viewer_click STMFD   R13!,{R2,R14}           ;Save some registers
+               BL      viewer_clearTemp        ;Clear temporary selection
+               BL      viewer_isSelected       ;Is the icon selected?
+               LDMCSFD R13!,{R2,PC}^           ;Yes -- do nothing then
+               MOV     R2,#0                   ;Clear entire selection
+               BL      viewer_selectAll        ;Do that then
+               MOV     R2,#1                   ;Now select my icon
+               BL      viewer_select           ;Go do that then
+               LDMFD   R13!,{R2,PC}^           ;And return to caller
+
+               ; --- Handle a MENU click ---
+
+20viewer_click STMFD   R13!,{R0-R5,R10,R14}    ;Save some registers
+               MOV     R10,R0                  ;Look after the handle
+               BL      viewer_clearTemp        ;Clear temporary selection
+               MOV     R4,R1                   ;Look after icon handle
+               LDR     R5,[R10,#vw__listDef]   ;Find the list definition
+               LDR     R0,[R10,#vw__list]      ;Find the list base
+               MOV     R1,#0                   ;Start at the beginning
+               MOV     R2,#1                   ;Check selected bit
+               MOV     R3,#1                   ;Any with it set?
+               MOV     R14,PC                  ;Set return address
+               ADD     PC,R5,#vw__enumerate    ;Find first selected icon
+               LDMCSFD R13!,{R0-R5,R10,PC}^    ;Robust selection -- quit now
+               MOV     R0,R10                  ;Get the handle back
+               MOV     R1,R4                   ;Get clicked icon
+               MOV     R2,#1                   ;Select the icon
+               BL      viewer_select           ;Go select it then
+               STR     R1,[R10,#vw__tempSel]   ;This is temporary selection
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;Return to caller
+
+               ; --- Handle a drag ---
+
+50viewer_click CMP     R1,#0                   ;Is there actually an icon?
+               BNE     %60viewer_click         ;Yes -- handle that
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R4,R0                   ;Pass viewer handle in R10
+               MOV     R5,#0                   ;I have no workspace
+               LDR     R0,[R4,#vw__window]     ;Load the window handle
+               MOV     R1,#0                   ;No flags to set
+               ADR     R2,vw__dragSel          ;Point to drag handler
+               MOV     R3,#0                   ;No magic number in R9
+               BL      drag_start              ;Start the drag operation
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               ; --- Handle drag on an icon -- select it ---
+
+60viewer_click STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,#1                   ;Select the icon
+               BL      viewer_select           ;Do that then
+               LDMFD   R13!,{R2,PC}^           ;And return to caller
+
+               LTORG
+
+; --- vw__dragSel ---
+;
+; On entry:    R0 == drag op event code
+;              Other registers depend on this
+;
+; On exit:     --
+;
+; Use:         Handles events during a marquee-select drag operation.
+
+vw__dragSel    ROUT
+
+               CMP     R0,#7                   ;Is this a kosher event?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- then dispatch it
+               MOVS    PC,R14                  ;Otherwise ignore it
+
+               B       vw__dragRender          ;Draw the drag box
+               B       vw__dragRender          ;Undraw the drag box
+               B       vw__dragRender          ;Rotate the drag box
+               MOVS    PC,R14                  ;Do no coordinate conversion
+               B       vw__dragScroll          ;Auto-scroll the viewer
+               B       vw__dragDone            ;Completed the drag OK
+               MOVS    PC,R14                  ;Drag operation cancelled
+
+               ; --- Draw the drag box ---
+
+vw__dragRender STMFD   R13!,{R0-R5,R14}        ;Save some registers
+
+               ; --- Set the colour up ---
+
+               MOV     R0,#1                   ;Background colour is 1
+               MOV     R1,#7                   ;Make lines black, please
+               BL      drag_eorColour          ;Set the colour up
+
+               ; --- Now render the drag box ---
+
+               SUB     R4,R4,R2                ;Get the box width
+               SUB     R5,R5,R3                ;And the box height
+
+               MOV     R0,#4                   ;Move cursor absolute
+               ADD     R1,R6,R2                ;Find the start position
+               ADD     R2,R7,R3                ;Set up the y position too
+               SWI     OS_Plot                 ;Move the graphics cursor
+
+               MOV     R0,#17                  ;Relative dotted plot
+               MOV     R1,R4                   ;Plot bottom line
+               MOV     R2,#0                   ;Keep y constant
+               SWI     OS_Plot
+               MOV     R0,#49                  ;Relative dotted plot
+               MOV     R1,#0                   ;Keep x constant
+               MOV     R2,R5                   ;Plot right hand side
+               SWI     OS_Plot
+               MOV     R0,#49                  ;Relative dotted plot
+               RSB     R1,R4,#0                ;Plot top line
+               MOV     R2,#0                   ;Keep y constant
+               SWI     OS_Plot
+               MOV     R0,#57                  ;Relative dotted plot
+               MOV     R1,#0                   ;Keep x constant
+               RSB     R2,R5,#0                ;Plot left hand side
+               SWI     OS_Plot                 ;Plot that too
+
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               ; --- Scroll the window during the drag ---
+
+vw__dragScroll STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               BL      drag_scroll             ;Get the scroll position
+               STR     R3,[R1,#24]             ;Save vertical scroll posn
+               BL      vw__openWindow          ;Reopen the window
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               ; --- Handle the end of the drag ---
+
+vw__dragDone   STMFD   R13!,{R0-R5,R14}        ;Save some registers
+
+               ; --- Fiddle the coordinates ---
+
+               CMP     R2,R4                   ;Are these the right way?
+               EORGT   R2,R2,R4                ;No -- swap them round then
+               EORGT   R4,R2,R4
+               EORGT   R2,R2,R4
+
+               CMP     R3,R5                   ;Are these the right way?
+               EORGT   R3,R3,R5                ;No -- swap them round then
+               EORGT   R5,R3,R5
+               EORGT   R3,R3,R5
+
+               ; --- Now enumerate matching boxes ---
+
+               STMFD   R13!,{R2-R5}            ;Stuff the drag box on stack
+               SUB     R13,R13,#16             ;And make another block
+
+               MOV     R0,R10                  ;Get the viewer handle
+               MOV     R1,#0                   ;Start at the beginning
+               ADD     R3,R13,#16              ;Point at the drag box
+
+00             MOV     R2,R13                  ;Point to my spare block
+               BL      vw__withinBox           ;Get next matching icon
+               MOVCS   R2,#1                   ;Select this icon please
+               BLCS    viewer_select           ;Please do that
+               BCS     %b00                    ;And loop back
+
+               ; --- Finished -- return ---
+
+               ADD     R13,R13,#32             ;Restore the stack block
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               LTORG
+
+; --- viewer_clearTemp ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Clears the temporary selection (use when you receive a
+;              menu closed event).
+
+viewer_clearTemp ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               LDR     R1,[R0,#vw__tempSel]    ;Find temporary selection
+               CMP     R1,#0                   ;Is that defined?
+               LDMEQFD R13!,{R1,R2,PC}^        ;No -- return now
+               MOV     R2,#0                   ;Yes -- deselect the icon
+               BL      viewer_select           ;Go do that then
+               MOV     R14,#0                  ;And also clear temp select
+               STR     R14,[R0,#vw__tempSel]   ;Store that in the block
+               LDMFD   R13!,{R1,R2,PC}^        ;Return to caller when done
+
+               LTORG
+
+; --- viewer_dragSelection ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Starts a drag of the icons within the viewer.  When the drag
+;              is finished, you get sent a vwEvent_dragged event.
+
+               EXPORT  viewer_dragSelection
+viewer_dragSelection ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Save lots of registers
+               MOV     R10,R0                  ;Look after the viewer handle
+               LDR     R9,[R10,#vw__listDef]   ;Find the list definition
+
+               ; --- First, see if we need DragASprite ---
+
+               MOV     R0,#161                 ;Read CMOS locations
+               MOV     R1,#28                  ;Various strange status flags
+               SWI     OS_Byte                 ;Do the read op
+               TST     R2,#2                   ;Is the bit set?
+               BEQ     %50viewer_dragSelection ;No -- use normal Wimp box
+
+               ; --- Work out what sprite to use ---
+               ;
+               ; We need to ask the client here.
+
+               LDR     R0,[R10,#vw__list]      ;Load the list base pointer
+               MOV     R1,#0                   ;Start at the beginning
+               MOV     R2,#1                   ;Check the selected bit
+               MOV     R3,#1                   ;Make sure it's on
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R9,#vw__enumerate    ;Read first matching item
+               BCC     %90viewer_dragSelection ;No selection -- no drag
+               MOVCS   R4,R1                   ;Match -- get icon handle
+               MOVCS   R14,PC                  ;And set up again
+               ADDCS   PC,R9,#vw__enumerate    ;Read next matching iten
+               MOVCS   R4,#-1                  ;If more than one, say `many'
+
+               MOV     R1,R4                   ;Give this to the client
+               MOV     R0,#vwEvent_sprite      ;Pretend it's an event
+               BL      vw__dispatch            ;And send it off nicely
+               BCC     %50viewer_dragSelection ;Told to use Wimp box
+
+               ; --- Now use DragASprite nicely ---
+
+               MOV     R2,R1                   ;Look after the name
+               MOV     R3,R0                   ;And the sprite area
+               SUB     R13,R13,#20             ;Make a small block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetPointerInfo     ;Read the pointer position
+               MOV     R14,R13                 ;Point to the block
+               LDMIA   R14,{R0,R1}             ;Load the coordinates out
+               SUB     R0,R0,#64               ;Turn into a little box
+               SUB     R1,R1,#64               ;Chop off a little bit
+               STMIA   R14!,{R0,R1}            ;Store them back
+               ADD     R0,R0,#128              ;Work out the other side
+               ADD     R1,R1,#128              ;Add on quite a lot actually
+               STMIA   R14!,{R0,R1}            ;Store them back
+
+               MOV     R0,#&C5                 ;DragASprite flags
+               MOV     R1,R3                   ;Get the sprite area
+               MOV     R3,R13                  ;Point to my rectangle block
+               SWI     XDragASprite_Start      ;Start the drag operation
+               ADD     R13,R13,#20             ;Reclaim the stack pointer
+               BVC     %70viewer_dragSelection ;If it worked, set up handler
+
+               ; --- Try and do a dotted outline ---
+
+50             SUB     R13,R13,#40             ;Make a small block
+               LDR     R0,[R10,#vw__list]      ;Find the list definition
+               MOV     R1,#0                   ;Start at the beginning
+               MOV     R2,#1                   ;Check selected bits
+               MOV     R3,#1                   ;Make sure they're on
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R9,#vw__enumerate    ;Do the enumeration
+               ADDCC   R13,R13,#40             ;Restore stack pointer
+               BCC     %90viewer_dragSelection ;No selection -- no drag
+
+               MOV     R2,R13                  ;Point to a block
+               BL      vw__iconBox             ;Find the icon's bounding box
+               LDMIA   R2,{R4-R7}              ;Load the bounding box
+
+               ; --- Now work out the bounding box of selected icons ---
+
+00             MOV     R2,#1                   ;Check selected bits
+               MOV     R3,#1                   ;Make sure they're on
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R9,#vw__enumerate    ;Do the enumeration
+               BCC     %f00                    ;No more -- skip onwards
+               MOV     R2,R13                  ;Point to a block
+               BL      vw__iconBox             ;Find the bounding box
+               LDMIA   R2,{R2,R3,R8,R14}       ;Load these coordinates
+
+               CMP     R4,R2
+               MOVGT   R4,R2
+               CMP     R5,R3
+               MOVGT   R5,R3
+               CMP     R6,R8
+               MOVLT   R6,R8
+               CMP     R7,R14
+               MOVLT   R7,R14
+
+               B       %b00                    ;Loop back for the rest now
+
+               ; --- Translate coordinates to screen relative ---
+
+00             MOV     R1,R13                  ;Point to my block
+               SWI     Wimp_GetPointerInfo     ;Read the pointer position
+               LDMIA   R13,{R8,R9}             ;Load the position out
+
+               LDR     R14,[R10,#vw__window]   ;Load the window handle
+               STR     R14,[R13,#0]            ;Store it in the block
+               SWI     Wimp_GetWindowState     ;Read the window position
+               LDR     R0,[R13,#4]             ;Load the left hand side
+               ADD     R14,R13,#16             ;Point to top edge/scroll
+               LDMIA   R14,{R1-R3}             ;Load those out nicely
+               SUB     R2,R0,R2                ;Work out x origin pos
+               SUB     R3,R1,R3                ;And the y origin pos
+
+               ADD     R4,R4,R2
+               ADD     R5,R5,R3
+               ADD     R6,R6,R2
+               ADD     R7,R7,R3
+
+               SUB     R4,R4,#vw__iconGap /2
+               SUB     R5,R5,#vw__iconGap /2
+               ADD     R6,R6,#vw__iconGap /2
+               ADD     R7,R7,#vw__iconGap /2
+
+               ADD     R14,R13,#8              ;Point to bit of block
+               STMIA   R14,{R4-R7}             ;Save the drag box position
+
+               ; --- Work out the parent box position ---
+
+               SUB     R4,R4,R8                ;Work out min x position
+               SUB     R5,R5,R9                ;And the min y position
+               SUB     R6,R6,R8                ;Fiddle with max x
+               SUB     R7,R7,R9                ;And max y
+               BL      screen_getInfo          ;Read the screen information
+               ADD     R14,R0,#screen_width    ;Find the screen dimensions
+               LDMIA   R14,{R8,R9}             ;Load them out nicely
+               ADD     R6,R6,R8                ;Work out max x position
+               ADD     R7,R7,R9                ;And the max y position
+               ADD     R14,R0,#screen_dx       ;Get the pixel sizes
+               LDMIA   R14,{R8,R9}             ;Load those out too
+               SUB     R6,R6,R8                ;Subtract a pixel off
+               SUB     R7,R7,R9                ;To make things nice
+               ADD     R14,R13,#24             ;Point to parent box area
+               STMIA   R14,{R4-R7}             ;Save that lot away
+
+               ; --- Start the drag (phew...) ---
+
+               MOV     R14,#5                  ;Drag fixed sized box
+               STR     R14,[R13,#4]            ;Store it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_DragBox            ;And start the drag op
+               ADD     R13,R13,#40             ;Reclaim my drag box block
+
+               ; --- Set up my handler at the end of it ---
+
+70             ADR     R0,vw__dragIcn          ;Point to my handler
+               MOV     R2,R10                  ;Pass viewer handle in R10
+               MOV     R3,R12                  ;And workspace (?) in R12
+               BL      win_unknownHandler      ;Register that routine please
+90             LDMFD   R13!,{R0-R10,PC}^       ;And return to caller
+
+               LTORG
+
+; --- vw__dragIcn ---
+;
+; On entry:    R0 == event code
+;              R1 == pointer to event block
+;
+; On exit:     --
+;
+; Use:         Handles events during a selection drag.
+
+vw__dragIcn    ROUT
+
+               CMP     R0,#7                   ;Is it a drag end event?
+               MOVNES  PC,R14                  ;Nope -- nothing to do
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               SWI     XDragASprite_Stop       ;Turn off any sprite drags
+               SUB     R13,R13,#20             ;Make a little block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetPointerInfo     ;Read the pointer position
+               ADD     R14,R1,#12              ;Point to window handle
+               LDMIA   R14,{R1,R2}             ;Load window and icon
+               ADD     R13,R13,#20             ;Restore stack block
+               MOV     R0,#vwEvent_dragged     ;Get the event code
+               BL      vw__dispatch            ;Send it the event
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Miscellaneous --------------------------------------------------------
+
+; --- viewer_window ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     R0 == window handle
+;
+; Use:         Returns the window handle of the viewer.
+
+               EXPORT  viewer_window
+viewer_window  ROUT
+
+               LDR     R0,[R0,#vw__window]     ;Load the window handle
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- viewer_update ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == icon handle
+;
+; On exit:     --
+;
+; Use:         Updates (redraws) a given icon.
+
+               EXPORT  viewer_update
+viewer_update  ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,#vwEvent_redraw      ;Normal is redraw event
+               BL      vw__doUpdate            ;Go and do the update
+               LDMFD   R13!,{R2,PC}^           ;And return to caller
+
+               LTORG
+
+; --- vw__doUpdate ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == icon handle
+;              R2 == event code to send
+;
+; On exit:     --
+;
+; Use:         Updates an item, passing a given event to the client.  This
+;              is purely for the use of gallery ;-)
+
+               EXPORT  vw__doUpdate
+vw__doUpdate   ROUT
+
+               STMFD   R13!,{R0-R7,R10,R14}    ;Save some registers
+               MOV     R10,R0                  ;Get the viewer handle in R10
+               MOV     R7,R2                   ;Find the event code
+
+               ; --- Start the update job ---
+
+               SUB     R13,R13,#32+44          ;Make a rectangle block
+               MOV     R2,R13                  ;Point to space for box
+               BL      vw__iconBox             ;Find the icon's box
+
+               LDMIA   R2,{R2-R5}              ;Load the box coordinates
+               ADD     R14,R13,#32+4           ;Find the update block
+               STMIA   R14,{R2-R5}             ;Store the rectangle there
+               LDR     R14,[R10,#vw__window]   ;Load the window handle
+               STR     R14,[R13,#32+0]         ;Store in my nice block
+               MOV     R4,R1                   ;Look after icon handle
+               ADD     R1,R13,#32              ;Point to update block
+               SWI     Wimp_UpdateWindow       ;Start the update job
+               CMP     R0,#0                   ;Anything to do?
+               BEQ     %90vw__doUpdate         ;No -- skip to end then
+
+               ; --- Read the window origin ---
+
+               LDR     R2,[R13,#32+4]          ;Load the left hand side
+               ADD     R14,R13,#32+16          ;Find top and scroll offsets
+               LDMIA   R14,{R3,R5,R6}          ;Load those out too
+               SUB     R6,R3,R6                ;Find the y origin position
+               SUB     R5,R2,R5                ;And the x origin position
+
+               ; --- Now embark on the main loop ---
+
+00             ADD     R14,R13,#32+28          ;Point to graphics rectangle
+               LDMIA   R14,{R0-R3}             ;Load that out
+               SUB     R0,R0,R5                ;Adjust the block by origin
+               SUB     R1,R1,R6                ;This is just to keep the
+               SUB     R2,R2,R5                ;User's event handler happy
+               SUB     R3,R3,R6                ;I know what needs to be done
+               STMIA   R14,{R0-R3}             ;Store that lot back
+
+               MOV     R0,R7                   ;Get the redraw event ready
+               MOV     R1,R4                   ;Point to the item
+               MOV     R2,R13                  ;Point to his icon block
+               ADD     R3,R13,#32+28           ;Point to clipping block
+               BL      vw__dispatch            ;Send to the handler
+
+               ; --- Do any other bits of drawing ---
+
+               ADD     R1,R13,#32              ;Point to update block
+               CMP     R7,#vwEvent_draw        ;Gallery redraw event? (yuk)
+               BLEQ    drag_redraw             ;Yes -- update drag rectangle
+               SWI     Wimp_GetRectangle       ;Do that rectangle
+               CMP     R0,#0                   ;Any more to do?
+               BNE     %b00                    ;Yes -- do it then
+
+               ; --- Wrap up and return ---
+
+90             ADD     R13,R13,#32+44          ;Restore the stack
+               LDMFD   R13!,{R0-R7,R10,PC}^    ;And return to caller
+
+               LTORG
+
+; --- viewer_setTitle ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == title string
+;
+; On exit:     --
+;
+; Use:         Sets the viewer window's title.
+
+               EXPORT  viewer_setTitle
+viewer_setTitle        ROUT
+
+               STMFD   R13!,{R0-R2,R10,R14}    ;Save some registers
+               MOV     R10,R0                  ;Get the viewer handle
+               LDR     R2,[R10,#vw__window]    ;Load the window handle
+               MOV     R0,R1                   ;Get the string to set
+               ADD     R1,R10,#vw__title       ;Point to title bar buffer
+               BL      winUtils_setTitle       ;Do the title setting
+               BL      vw__open                ;Is the window open?
+               LDMCCFD R13!,{R0-R2,R10,PC}^    ;No -- do nothing then
+
+               SUB     R13,R13,#36             ;Make a window state block
+               LDR     R14,[R10,#vw__window]   ;Load the window handle
+               STR     R14,[R13,#0]            ;Store it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Read the current position
+
+               BL      vw__tWidth              ;Yes -- reset the width
+               BL      vw__setExtent           ;And reset the extent
+               BL      vw__openWindow          ;Open the window, in case
+               ADD     R13,R13,#36             ;And reset the stack pointer
+               LDMFD   R13!,{R0-R2,R10,PC}^    ;And return to caller
+
+               LTORG
+
+; --- vw__open ---
+;
+; On entry:    R10 == pointer to viewer block
+;
+; On exit:     CS if window is open, else CC
+;
+; Use:         Sees if a viewer window is currently open.
+
+vw__open       ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               SUB     R13,R13,#36             ;Make some space
+               LDR     R14,[R10,#vw__window]   ;Load the window handle
+               STR     R14,[R13,#0]            ;Save it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Read the information
+               LDR     R14,[R13,#32]           ;Load the flags word
+               TST     R14,#1<<16              ;Is the window open?
+               ADD     R13,R13,#36             ;Reclaim the stack space
+               LDMFD   R13!,{R0,R1,R14}        ;Restore registers
+               ORRNES  PC,R14,#C_flag          ;Return with C set if so
+               BICEQS  PC,R14,#C_flag          ;Otherwise clear C
+
+               LTORG
+
+; --- vw__openWindow ---
+;
+; On entry:    R1 == pointer to window state block
+;              R10 == pointer to viewer block
+;
+; On exit:     R0 corrupted (just like Wimp_OpenWindow)
+;
+; Use:         Opens a viewer window, and informs the user through the
+;              vwEvent_open event.
+
+vw__openWindow ROUT
+
+               SWI     Wimp_OpenWindow         ;Reopen the window as ordered
+               MOV     R0,#vwEvent_open        ;Send the event along nicely
+               B       vw__dispatch            ;And report, and return
+
+               LTORG
+
+; --- vw__tWidth ---
+;
+; On entry:    R10 == pointer to viewer block
+;
+; On exit:     --
+;
+; Use:         Updates the window's fixed width parameter.
+
+vw__tWidth     ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               ADD     R0,R10,#vw__title       ;Point to title buffer
+               BL      wimp_strWidth           ;Get the string width
+               ADD     R1,R0,#vw__titleAdd     ;Add on a fudge factor
+               LDR     R0,[R10,#vw__banner]    ;Load the banner address
+               CMP     R0,#0                   ;Is the banner there?
+               BLNE    wimp_strWidth           ;Yes -- get its width
+               ADDNE   R0,R0,#vw__banAdd       ;And add on its fudge
+               CMP     R1,R0                   ;Which is bigger?
+               MOVCC   R1,R0                   ;Use the biggest one
+               STR     R1,[R10,#vw__fixedWidth] ;Store the new width
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+; --- viewer_rescan ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Rescans all the icons in the viewer and forces a redraw,
+;              in case icons have been added or deleted (or renamed).  Note
+;              that the redraw is done *anyway* -- it's your responsibility
+;              to avoid calling this routine when you don't need to.
+
+               EXPORT  viewer_rescan
+viewer_rescan  ROUT
+
+               STMFD   R13!,{R0,R1,R10,R14}    ;Save some registers
+               MOV     R10,R0                  ;Get the viewer handle
+               BL      vw__open                ;Is the window open at all?
+               LDMCCFD R13!,{R0,R1,R10,PC}^    ;No -- handle on open then
+
+               SUB     R13,R13,#36             ;Make a window state block
+               LDR     R14,[R10,#vw__window]   ;Load the window handle
+               STR     R14,[R13,#0]            ;Save it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;And read the window state
+
+               ; --- Open the window onto the screen ---
+
+               LDR     R1,[R10,#vw__listDef]   ;Find the list definition
+               LDR     R0,[R10,#vw__list]      ;And the list base
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R1,#vw__items        ;Find how many items
+               STR     R1,[R10,#vw__icons]     ;Store this away
+
+               MOV     R1,R13                  ;Point at window state blk
+               BL      vw__rescanSize          ;Rescan the item size
+               BL      vw__extend              ;Yes -- make it big then
+               BL      vw__resize              ;Work out new arrangement
+               BL      vw__setExtent           ;Set the window's extent
+               BL      vw__refresh             ;Force update of display
+               BL      vw__openWindow          ;And open the window
+               ADD     R13,R13,#36             ;Reclaim my stack space
+               LDMFD   R13!,{R0,R1,R10,PC}^    ;And return to caller
+
+               LTORG
+
+;----- Icon rearrangement routines ------------------------------------------
+
+; --- vw__resize ---
+;
+; On entry:    R1 == pointer to window state block
+;              R10 == pointer to viewer block
+;
+; On exit:     CS if the size has changed, else CC
+;
+; Use:         Updates the icon arrangement within a window, returning
+;              whether the arrangement is different now.  Note that this
+;              doesn't redraw the window; it just recaches the extent.
+;              If the size has changed, you'll probably need to call
+;              vw__setExtent and vw__refresh to get everything looking nice.
+
+vw__resize     ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Now work out how many icons we should have ---
+
+               LDMIB   R1,{R1-R3}              ;Load the x coords from win
+               SUB     R0,R3,R1                ;Work out the window width
+               SUB     R0,R0,#vw__iconGap      ;Subtract off extra border
+               LDR     R2,[R10,#vw__iconWidth] ;Load the icon width out
+               ADD     R1,R2,#vw__iconGap      ;Add on the gap
+               BL      divide                  ;Divide one by the other
+               MOV     R3,R0                   ;Icons which fit across win
+
+               BL      screen_getInfo          ;Find the screen information
+               LDR     R0,[R0,#screen_width]   ;Load the screen width
+               SUB     R0,R0,#40+vw__iconGap   ;Fudge for scroll bar
+               ADD     R1,R2,#vw__iconGap      ;Get icon width+gap again
+               BL      divide                  ;Divide one by the other
+               MOV     R2,R0                   ;Icons which fit across scrn
+
+               ; --- Fiddle these numbers appropriately ---
+
+               LDR     R0,[R10,#vw__icons]     ;Load number of icons
+               CMP     R3,R0                   ;Too many across window?
+               MOVCS   R3,R0                   ;Yes -- use number we have
+               CMP     R2,R0                   ;Too many across screen?
+               MOVCS   R2,R0                   ;Yes -- use number we have
+               CMP     R2,R3                   ;More than fit across screen?
+               MOVCS   R2,R3                   ;Use -- use that then (erk)
+               CMP     R2,#0                   ;No icons at all?
+               MOVEQ   R2,#1                   ;Then have at least one
+
+               ; --- Work out how many go down ---
+
+               MOV     R1,R2                   ;Get number going across
+               BL      divide                  ;Do the division
+               CMP     R1,#0                   ;Any extra ones on bottom?
+               ADDNE   R0,R0,#1                ;Yes -- add an extra row
+               MOVS    R3,R0                   ;Look after this value
+               MOVEQ   R3,#0                   ;If it's zero, use one
+
+               ; --- Now see if anything's changed ---
+
+               ADD     R14,R10,#vw__across     ;Find old across counter
+               LDMIA   R14,{R0,R1}             ;Load across and down values
+               CMP     R0,R2                   ;Compare with old ones
+               CMPEQ   R1,R3                   ;Are they the same?
+               STMNEIA R14,{R2,R3}             ;If not, store new ones
+               LDMFD   R13!,{R0-R3,R14}        ;Restore caller's registers
+               ORRNES  PC,R14,#C_flag          ;If changed, return C set
+               BICEQS  PC,R14,#C_flag          ;Otherwise return C clear
+
+               LTORG
+
+; --- vw__setExtent ---
+;
+; On entry:    R10 == pointer to viewer block
+;
+; On exit:     --
+;
+; Use:         Resets the extent of a viewer window, in case the
+;              arrangement of icons or banner/title text has changed.
+;              If the window is currently open, you should follow this
+;              call with a Wimp_OpenWindow SWI.
+
+vw__setExtent  ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Work out correct horizontal extent ---
+
+               BL      screen_getInfo          ;Find the screen information
+               LDR     R0,[R0,#screen_width]   ;Load the screen width
+               SUB     R0,R0,#40+vw__iconGap   ;Fudge for scroll bar
+               MOV     R2,R0                   ;Look after this value
+               LDR     R3,[R10,#vw__iconWidth] ;Load the icon width
+               ADD     R3,R3,#vw__iconGap      ;Add on the inter-icon gap
+               MOV     R1,R3                   ;Divide by this
+               BL      divide                  ;Divide one by the other
+               LDR     R14,[R10,#vw__icons]    ;Load the number of icons
+               CMP     R0,R14                  ;Is this bigger?
+               MOVCS   R0,R14                  ;Yes -- then use that
+               CMP     R0,#0                   ;Unless there's none
+               MOVEQ   R0,#1                   ;In which case use one
+               MUL     R2,R3,R0                ;Work out the correct width
+               ADD     R2,R2,#vw__iconGap      ;Add on extra border around
+               LDR     R14,[R10,#vw__fixedWidth] ;Load width of title/banner
+               CMP     R2,R14                  ;Do we have enough here?
+               MOVCC   R2,R14                  ;No -- then use more
+
+               ; --- And now the vertical extent ---
+
+               LDR     R1,[R10,#vw__iconHeight] ;Load the icon height
+               ADD     R1,R1,#vw__iconGap      ;Add on the gap
+               LDR     R14,[R10,#vw__down]     ;Load vertical number of icns
+               MUL     R1,R14,R1               ;Work out the size
+               ADD     R1,R1,#vw__iconGap      ;Add on extra border
+
+               ; --- Work out the other two ---
+
+               RSB     R1,R1,#0                ;And vertical extent -ve
+               LDR     R3,[R10,#vw__banner]    ;Load banner pointer
+               CMP     R3,#0                   ;Do we have a banner?
+               MOVNE   R3,#vw__banHeight       ;Yes -- then add above origin
+               MOV     R0,#0                   ;Start at the left side
+
+               ; --- Make sure the extent is big enough ---
+
+               SUBS    R14,R2,#vw__minWidth    ;Get the minimum width
+               SUBCC   R2,R2,R14               ;Make bigger if needs be
+               SUB     R14,R3,R1               ;Work out extent height
+               SUBS    R14,R14,#vw__minHeight  ;Get the minimum height
+               ADDCC   R1,R1,R14               ;Make bigger if needs be
+
+               ; --- Finally set up the extent ---
+
+               ADD     R14,R10,#vw__extent     ;Set the window extent
+               STMIA   R14,{R0-R3}             ;Save the values in there
+               LDR     R0,[R10,#vw__window]    ;Load the window handle
+               ADD     R1,R10,#vw__extent      ;Point to the extent block
+               SWI     Wimp_SetExtent          ;Set the window's extent
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+; --- vw__refresh ---
+;
+; On entry:    R10 == pointer to a viewer block
+;
+; On exit:     --
+;
+; Use:         Forces a redraw of the contents of a viewer.  Use in
+;              conjunction with vw__resize.
+
+vw__refresh    ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               LDR     R0,[R10,#vw__window]    ;Load the window handle
+               MOV     R1,#-&FFFFFFF           ;Force a redraw of the world
+               MOV     R2,#-&FFFFFFF           ;This hack prevents problems
+               MOV     R3,#&FFFFFFF            ;with the extent being bodged
+               MOV     R4,#&FFFFFFF            ;by the Wimp.
+               SWI     Wimp_ForceRedraw        ;Redraw the whole lot
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+; --- vw__extend ---
+;
+; On entry:    R1 == pointer to window open block
+;              R10 == pointer to a viewer block
+;
+; On exit:     --
+;
+; Use:         Extends the viewer window if necessary to accomodate new
+;              items.  The new coordinates to open are written back to the
+;              window open block.  Correct procedure for adding items is
+;              as follows:
+;
+;              1. Get window state
+;              2. Call vw__extend
+;              3. Call vw__resize
+;              4. Call vw__setExtent
+;              5. Call vw__refresh
+
+vw__extend     ROUT
+
+               STMFD   R13!,{R0-R8,R14}        ;Save some registers
+
+               ; --- Load current and maximum width and height ---
+
+               MOV     R8,R1                   ;Look after this address
+               LDMIB   R8,{R4-R7}              ;Load the window dimensions
+               SUB     R6,R6,R4                ;Find the window width
+               SUB     R7,R7,R5                ;And its height
+
+               ADD     R14,R10,#vw__extent     ;Find the current extent
+               LDMIA   R14,{R0-R3}             ;Load the dimensions out
+               SUB     R4,R2,R0                ;Find the maximum width
+               SUB     R5,R3,R1                ;And the maximum height
+               LDR     R14,[R10,#vw__flags]    ;Load the flags word
+               TST     R14,#vwFlag__opened     ;Has viewer ever been opened?
+               BNE     %f00                    ;Yes -- skip onwards
+
+               ; --- Set up special values for first time ---
+
+               MOV     R4,#0                   ;No -- force width to max
+               MOV     R5,#0                   ;And height forced to max
+               LDR     R6,[R10,#vw__fixedWidth] ;Set a default width though
+               CMP     R6,#vw__minWidth        ;Get the minimum width
+               MOVCC   R6,#vw__minWidth        ;If too small, use this
+               MOV     R7,#vw__minHeight       ;Use the minimum height too
+
+               ; --- Find out if we have anything to do horizontally ---
+               ;
+               ; We only try to extend if the window is currently as wide
+               ; as it will go.
+
+00             CMP     R6,R4                   ;Does the width shape up?
+               BCC     %50vw__extend           ;No -- skip to vertical
+
+               ; --- Extend the width ---
+               ;
+               ; We ensure that the width of the window is the smaller
+               ; of the maximum width we allow and the width of the number
+               ; of icons in the window.
+
+               MOV     R0,#vw__maxWidth        ;Get the maximum width
+               LDR     R3,[R10,#vw__iconWidth] ;Find the icon width
+               ADD     R3,R3,#vw__iconGap      ;And add on the gap as usual
+               MOV     R1,R3                   ;Divide by this
+               BL      divide                  ;Divide one by the other
+               LDR     R1,[R10,#vw__icons]     ;Load total number of icns
+               CMP     R0,R1                   ;Which one is bigger?
+               MOVCS   R0,R1                   ;Use the smaller
+               CMP     R0,#0                   ;Are there no icons at all?
+               MOVEQ   R0,#1                   ;None -- make space for one
+               MUL     R0,R3,R0                ;Work out new improved width
+               ADD     R0,R0,#vw__iconGap      ;Add on the extra border
+               CMP     R6,R0                   ;Which is bigger?
+               MOVCC   R6,R0                   ;Use the bigger of the two
+
+               ; --- Now do things vertically ---
+               ;
+               ; This is basically the same.  We only extend if the window
+               ; is as tall at it will go.
+
+50vw__extend   CMP     R7,R5                   ;Does the height shape up?
+               BCC     %90vw__extend           ;No -- skip on then
+
+               ; --- Extend the height ---
+               ;
+               ; This is trickier, because we have to work out how many
+               ; icons there will be vertically.
+
+               LDR     R3,[R10,#vw__iconHeight] ;Load the icon height
+               ADD     R3,R3,#vw__iconGap      ;Add on the inter-icon gap
+               SUB     R0,R6,#vw__iconGap      ;Get the current width
+               LDR     R1,[R10,#vw__iconWidth] ;Find the icon width
+               ADD     R1,R1,#vw__iconGap      ;And add on the gap as usual
+               BL      divide                  ;Find how many will fit
+
+               MOV     R1,R0                   ;We will divide by this
+               LDR     R0,[R10,#vw__icons]     ;Load the number of icons
+               BL      divide                  ;Work out number down
+               CMP     R1,#0                   ;Is there a remainder?
+               ADDNE   R0,R0,#1                ;Yes -- extra one then
+               CMP     R0,#0                   ;Are there no icons?
+               MOVEQ   R0,#1                   ;None -- make space for one
+               MOV     R2,R0                   ;Look after this value
+
+               MOV     R0,#vw__maxHeight       ;Get the maximum height
+               MOV     R1,R3                   ;And the icon height
+               BL      divide                  ;Do the division again
+               CMP     R0,R2                   ;Which one is bigger?
+               MOVCS   R0,R2                   ;Use the smaller
+               MUL     R0,R3,R0                ;Work out new improved height
+               ADD     R0,R0,#vw__iconGap      ;Add on the extra border
+               LDR     R14,[R10,#vw__banner]   ;Do we have a banner string?
+               CMP     R14,#0                  ;Quick check for that...
+               ADDNE   R0,R0,#vw__banHeight    ;Yes -- add that on too
+               CMP     R7,R0                   ;Which is bigger?
+               MOVCC   R7,R0                   ;Use the bigger
+
+               ; --- Now update the window block ---
+
+90vw__extend   LDMIB   R8,{R0-R3}              ;Load the current values
+               ADD     R2,R0,R6                ;Work out new right side
+               SUBS    R1,R3,R7                ;And the new bottom
+               SUBLT   R3,R3,R1                ;Move the top if hit bottom
+               SUBLT   R1,R1,R1                ;And move the bottom too
+               STMIB   R8,{R0-R3}              ;Save that lot back again
+               LDMFD   R13!,{R0-R8,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Viewer block structure -----------------------------------------------
+;
+; This is shadowed by gallery.s -- keep them in step.
+
+               ^       0
+
+               ; --- Information about the window ---
+
+vw__window     #       4                       ;Window handle
+vw__extent     #       16                      ;Current window extent
+vw__flags      #       4                       ;Any flags of interest
+vw__list       #       4                       ;Pointer to list head
+vw__listDef    #       4                       ;Pointer to list handler
+vw__handler    #       12                      ;Viewer's event handler
+gl__handler    #       4                       ;Gallery's event handler
+vw__shape      #       4                       ;Shape handler function
+vw__banner     #       4                       ;Pointer to banner string
+vw__fixedWidth #       4                       ;Width of banner/title
+
+               ; --- Icon sizing information ---
+
+vw__icons      #       4                       ;Cache number of icons
+vw__stdDimens  #       8                       ;`Standard' width and height
+vw__iconWidth  #       4                       ;Width of icons currently
+vw__iconHeight #       4                       ;Height of icons currently
+vw__across     #       4                       ;Number of icons across
+vw__down       #       4                       ;Number of icons down
+
+               ; --- Data for default selection model ---
+
+vw__tempSel    #       4                       ;Temporary selected icon
+
+               ; --- Big buffers at the end ---
+
+vw__title      #       256                     ;Title bar buffer
+
+vw__size       #       0                       ;Size of a viewer block
+
+               ; --- Flags bits ---
+               ;
+               ; Gallery `borrows' top-end flags bits here
+
+vwFlag__opened EQU     (1<<0)                  ;Has the window been opened?
+
+;----- Constants ------------------------------------------------------------
+
+vw__iconGap    EQU     16                      ;Gap between icons
+vw__banHeight  EQU     48                      ;Height of viewer banner
+
+vw__minWidth   EQU     380                     ;Minimum width for a viewer
+vw__minHeight  EQU     160                     ;Minimum height
+
+vw__titleAdd   EQU     164                     ;Fudge factor to add to title
+vw__banAdd     EQU     64                      ;Fudge factor for the banner
+
+vw__maxWidth   EQU     900-vw__iconGap         ;Maximum width of a viewer
+vw__maxHeight  EQU     700-vw__iconGap         ;Maximum height of a viewer
+
+;----- List definition format -----------------------------------------------
+
+               ^       0
+vw__itemToIndex        #       4                       ;Item to index routine
+                                               ;Entry: R0 == pointer to list
+                                               ;       R1 == pointer to item
+                                               ;Exit:  R1 == index, or -1
+
+vw__indexToItem        #       4                       ;Index to item routine
+                                               ;Entry: R0 == pointer to list
+                                               ;       R1 == index of item
+                                               ;Exit:  R1 == item ptr, or 0
+
+vw__enumerate  #       4                       ;Enumeration function
+                                               ;Entry: R0 == list pointer
+                                               ;       R1 == item, or 0
+                                               ;       R2 == BIC mask
+                                               ;       R3 == test mask
+                                               ;Exit:  CS if match, and
+                                               ;       R1 == item ptr
+
+vw__items      #       4                       ;Function to return items
+                                               ;Entry: R0 == list pointer
+                                               ;Exit:  R1 == number of items
+
+vw__setFlags   #       4                       ;Function to set/read flags
+                                               ;Entry: R1 == pointer to item
+                                               ;       R2 == BIC mask
+                                               ;       R3 == EOR mask
+                                               ;Exit:  R2 == new flags
+
+;----- Shape function reason codes ------------------------------------------
+
+               ^       0
+vwShape_size   #       1                       ;Read an icon's size
+                                               ;Entry: R1 == list item
+                                               ;       R2,R3 == std size
+                                               ;Exit:  R2,R3 == actual size
+
+vwShape_intersects #   1                       ;Does icon intersect box?
+                                               ;Entry: R1 == list item
+                                               ;       R2 == ptr to icon box
+                                               ;       R3 == ptr to box
+                                               ;Exit:  CS if intersect
+
+vwShape_slowBit        #       1                       ;Does slow bit need redraw?
+                                               ;Entry: R1 == list item
+                                               ;       R2 == ptr to icon box
+                                               ;       R3 == ptr to box
+                                               ;Exit:  CS if intersect
+
+;----- Viewer event codes ---------------------------------------------------
+
+               ^       0
+vwEvent_close  #       1                       ;User has closed the window
+
+vwEvent_click  #       1                       ;User has clicked an icon
+                                               ;R1 == icon handle (or 0)
+                                               ;R2 == mouse status
+
+vwEvent_double #       1                       ;User has double-clicked
+                                               ;R1 == icon handle (or 0)
+                                               ;R2 == mouse status
+
+vwEvent_drag   #       1                       ;User has dragged the mouse
+                                               ;R1 == icon handle (or 0)
+                                               ;R2 == mouse status
+
+vwEvent_menu   #       1                       ;User has clicked menu
+                                               ;R1 == icon handle (or 0)
+                                               ;R2 == mouse status
+
+vwEvent_redraw #       1                       ;Redraw a viewer icon
+                                               ;R1 == icon handle
+                                               ;R2 == pointer to coords blk
+                                               ;R3 == pointer to clip blk
+                                               ;R5,R6 == window origin
+
+vwEvent_drop   #       1                       ;File dropped on the viewer
+                                               ;R1 == filetype of data
+                                               ;R2 == estimated size
+                                               ;R3 == address of filename
+                                               ;R4 == drop type
+
+vwEvent_help   #       1                       ;Help request for the viewer
+                                               ;R1 == icon handle, or 0
+
+vwEvent_key    #       1                       ;Key pressed
+                                               ;R1 == key code (translated)
+                                               ;Return CS if used, else CC
+
+vwEvent_dragged        #       1                       ;Icons dropped on a window
+                                               ;R1 == destination window
+                                               ;R2 == destination icon
+
+vwEvent_sprite #       1                       ;Return sprite name to use
+                                               ;Entry: R1 == icon handle
+                                               ;         (-1 for many)
+                                               ;Exit:  CS if sprite found,
+                                               ;       R0 == ptr to spr area
+                                               ;       R1 == pointer to name
+                                               ;       else CC
+
+vwEvent_open   #       1                       ;The viewer has been moved
+                                               ;R1 == ptr to open/state blk
+
+vwEvent_draw   #       1                       ;Slowly redraw icon
+                                               ;R1 == icon handle
+                                               ;R2 == pointer to coords blk
+                                               ;R3 == pointer to clip blk
+                                               ;R5,R6 == window origin
+                                               ;(Event only used by gallery)
+
+vwEvent_unDraw #       1                       ;Undraw temporary part
+                                               ;R1 == icon handle
+                                               ;R2 == pointer to coords blk
+                                               ;R3 == pointer to clip blk
+                                               ;R5,R6 == window origin
+                                               ;(Event only used by gallery)
+
+               ; --- Drop event subreason codes ---
+
+               ^       0
+vwDrop_save    #       1                       ;File from another app
+vwDrop_load    #       1                       ;File from filing system
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/warning b/StraySrc/Libraries/Sapphire/s/warning
new file mode 100644 (file)
index 0000000..0e6c9dc
--- /dev/null
@@ -0,0 +1,244 @@
+;
+; warning.s
+;
+; Displays warning boxes (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:buttons
+               GET     sapphire:dbox
+               GET     sapphire:errorBox
+               GET     sapphire:msgs
+               GET     sapphire:nopoll
+               GET     sapphire:sapphire
+               GET     sapphire:string
+               GET     sapphire:template
+               GET     sapphire:wimp
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- warning ---
+;
+; On entry:    R0 == pointer to warning text to display
+;              R1 == pointer to buttons block
+;
+; On exit:     R0 == button that was clicked
+;              CS if this was default, CC otherwise
+;
+; Use:         Displays a warning to the user.  The warning box can have up
+;              to five buttons (because it's too small for any more than
+;              that).  These are placed in a column on the right hand side
+;              of the dialogue.  The buttons are numbered from 0 up to 4
+;              from the bottom upwards, 0 being the default.  You can
+;              choose one button to be `Cancel', in which case pressing
+;              escape will activate it.
+;
+;              Note that a call to this routine cannot fail, since the
+;              dialogue is created at initialisation time.
+
+               EXPORT  warning
+warning                ROUT
+
+               STMFD   R13!,{R1-R4,R12,R14}    ;Save some registers
+               WSPACE  warn__wSpace            ;Find my workspace address
+               MOV     R4,R0                   ;Look after the warning text
+
+               ; --- Set up the buttons ---
+
+               LDR     R0,warn__dbox           ;Load the dbox handle
+               MOV     R2,#wIcon__buttons      ;Find the buttons base
+               MOV     R3,#warn__buttons       ;Find the button count
+               BL      buttons_setup           ;Set all that lot up
+               STR     R2,warn__butFlags       ;Save the defined buttons
+               STR     R3,warn__cancel         ;Save the cancel button too
+               MOV     R1,#wIcon__text         ;Get the text icon handle
+               MOV     R2,R4                   ;Get the text string too
+               BL      dbox_setField           ;Write that into the icon
+
+               ; --- Display the window in its glory ---
+
+               BL      errorBox_beep           ;Make a nice noise
+               MOV     R1,#dbOpen_persist+dbOpen_centre+dbOpen_nonSub
+               BL      dbox_open               ;Open the dialogue
+
+               BL      dbox_window             ;Get its window handle
+               BL      nopoll_open             ;Let nopoll take over a bit
+               BL      nopoll_process          ;Get a reply from the dbox
+               LDMFD   R13!,{R1-R4,R12,R14}    ;Reload some registers
+               SUBS    R0,R0,#wIcon__buttons   ;Was it the default button?
+               ORREQS  PC,R14,#C_flag          ;Yes -- set C flag on exit
+               BICNES  PC,R14,#C_flag          ;No -- clear the C flag
+
+               LTORG
+
+; --- warn__dbHandler ---
+;
+; On entry:    R0 == dialogue box event code
+;              R1-R7 depend on the event
+;
+; On exit:     --
+;
+; Use:         Handles events for a warning box.
+
+warn__dbHandler        ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               CMP     R0,#dbEvent_OK          ;Is it a return press?
+               MOVEQ   R0,#wIcon__buttons      ;Yes -- set to be default
+               CMP     R0,#dbEvent_cancel      ;Was it a cancel?
+               LDREQ   R0,warn__cancel         ;Yes -- load cancel button
+               CMPEQ   R0,#-1                  ;Was it defined by user?
+               MOVEQ   R0,#wIcon__buttons      ;No -- make it do OK then
+
+               SUB     R14,R0,#wIcon__buttons  ;Subtract the buttons base
+               CMP     R14,#warn__buttons      ;Is it in range?
+               LDMCSFD R13!,{PC}^              ;Yes -- then return
+
+               STMFD   R13!,{R0,R1}            ;Save another register
+               LDR     R1,warn__butFlags       ;Which buttons are created?
+               MOV     R14,#1                  ;Use a bit to test
+               TST     R1,R14,LSL R0           ;Test the correct bit
+               LDMEQFD R13!,{R0,R1,PC}^        ;Not created -- return then
+
+               MOV     R1,R0                   ;Put icon into R1
+               LDR     R0,warn__dbox           ;Get dialogue in R0
+               BL      dbox_slab               ;Slab the icon nicely
+               BL      dbox_close              ;Close the window
+               BL      dbox_unslab             ;Unslab the icon again
+               MOV     R0,R1                   ;Put icon back in R0
+               BL      nopoll_close            ;Return this to main code
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+; --- warn_init ---
+;
+; On entry:    R0 == program name
+;
+; On exit:     --
+;
+; Use:         Sets up the Warning dialogue box for use.
+
+               EXPORT  warn_init
+warn_init      ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  warn__wSpace            ;Load my workspace address
+               LDR     R14,warn__dbox          ;Load the dialogue handle
+               CMP     R14,#0                  ;Is it defined yet?
+               LDMNEFD R13!,{R12,PC}^          ;Yes -- then return to caller
+
+               ; --- Ensure other bits are initialised ---
+
+               BL      wimp_init               ;We need to create windows
+               BL      template_init           ;Make sure we can get these
+               BL      dbox_init               ;We want to create dialogues
+               BL      nopoll_init             ;We may need this
+
+               ; --- Create a dialogue box ---
+
+               STMFD   R13!,{R0-R3}            ;Save some more registers
+               MOV     R2,R0                   ;Keep the application name
+               ADR     R0,warn__dbName         ;Point at my dialogue name
+               BL      dbox_create             ;Try to create it
+               SWIVS   OS_GenerateError        ;Don't take errors lying down
+               STR     R0,warn__dbox           ;Save my dialogue handle
+
+               ADR     R0,warn__titleSkel      ;Point to skeleton title
+               BL      msgs_lookup             ;Translate it nicely
+               MOV     R1,R11                  ;Build in scratchpad
+               BL      str_subst               ;Do the stuff required
+               MOV     R2,R0                   ;Make it ready for dbox
+               LDR     R0,warn__dbox           ;Get the dialogue back again
+               MOV     R1,#-1                  ;Put it in the title bar
+               BL      dbox_setField           ;Fill in the title bar
+
+               MOV     R1,#wIcon__title        ;Set up the title icon
+               BL      dbox_setEmbeddedTitle   ;Write title in group box
+
+               ; --- Set up the event handler ---
+
+               ADR     R1,warn__dbHandler      ;Point to handler routine
+               MOV     R2,R10                  ;Pass (bogus) R10
+               MOV     R3,R12                  ;Pass it my workspace
+               BL      dbox_eventHandler       ;Set that up nicely
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;Return to caller
+
+warn__dbName   DCB     "warning",0
+warn__titleSkel        DCB     "warnFROM",0
+
+               LTORG
+
+warn__wSpace   DCD     0
+
+;----- Icon handles ---------------------------------------------------------
+
+wIcon__text    EQU     2                       ;The actual text icon
+wIcon__title   EQU     1                       ;Embedded title icon
+wIcon__buttons EQU     3                       ;Buttons from here on up
+
+warn__buttons  EQU     5                       ;Number of buttons allowed
+
+;----- Warning button table layout ------------------------------------------
+
+wFlag_cancel   EQU     (1<<0)                  ;This is the cancel button
+                                               ;+0
+
+wFlag_text     EQU     (1<<1)                  ;This button contains text
+                                               ;+0 == message tag
+                                               ;+n
+
+wFlag_last     EQU     (1<<31)                 ;This is the last item
+                                               ;+0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+warn__wStart   #       0
+
+warn__dbox     #       4                       ;The warning dialogue handle
+warn__cancel   #       4                       ;The cancel icon, or -1
+warn__butFlags #       4                       ;Which buttons are available
+
+warn__wSize    EQU     {VAR}-warn__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     warn__wSize
+               DCD     warn__wSpace
+               DCD     0
+               DCD     warn_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/wimp b/StraySrc/Libraries/Sapphire/s/wimp
new file mode 100644 (file)
index 0000000..d66c7a1
--- /dev/null
@@ -0,0 +1,281 @@
+;
+; wimp.s
+;
+; Starting and ending of Wimp tasks (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:except
+               GET     sapphire:libOpts
+               GET     sapphire:roVersion
+               GET     sapphire:sapphire
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- wimp_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Initialises the WindowManager, and stores away useful
+;              snippets of information, like the task handle we've been
+;              given.  It also registers an exit handler so that the Wimp
+;              gets closed down.
+
+               EXPORT  wimp_init
+wimp_init      ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Stash some registers
+               WSPACE  wimp__wSpace            ;Find my workspace
+
+               ; --- Make sure I'm not already running ---
+
+               LDR     R0,wimp__taskh          ;What's my task handle?
+               CMP     R0,#0                   ;0 is a silly task handle
+               LDMNEFD R13!,{R0-R3,R12,PC}^    ;If not silly, quit now
+
+               ; --- Find what WIMP version we're set for ---
+
+               LDR     R0,wimp__optName        ;Find the option name
+               BL      libOpts_find            ;Try to find the option block
+               LDRCS   R3,[R0,#0]              ;If found, load version
+               MOVCC   R3,#0                   ;Otherwise use a default
+
+               ; --- Suss out the Wimp version from the OS version ---
+
+               BL      rov_init                ;Initialise RISC OS version
+               BL      rov_version             ;Work out the RISC OS version
+               LDR     R14,=310                ;Get the number 310
+               CMP     R0,R14                  ;Is it version 3.10 yet?
+               MOVLT   R0,#200                 ;No -- use RISC OS 2
+               MOVGE   R0,R14                  ;Otherwise use RISC OS 3.10
+
+               ; --- Now use whichever is bigger ---
+               ;
+               ; Woe betides a foolish person who sets wimp_minVersion to
+               ; be 350 :-)
+
+               CMP     R0,R3                   ;Which is the biggest?
+               MOVLT   R0,R3                   ;If the user's, use that
+
+               ; --- Initialise the Wimp ---
+
+               LDR     R1,=&4B534154           ;The traditional magic no.
+               LDR     R2,[R13,#0]             ;Get the app name pointer
+               MOV     R3,#-1                  ;Give me *all* messages
+               SWI     Wimp_Initialise         ;Crank up the WindowMangler
+
+               ; --- Store useful stuff away ---
+
+               STR     R0,wimp__version        ;Store WIMP's real version
+               STR     R1,wimp__taskh          ;Store my task handle too
+
+               ; --- Set me up to close down at the end ---
+
+               BL      except_init             ;Make sure except is going
+               ADR     R0,wimp__die            ;Point to my exit handler
+               MOV     R1,R12                  ;Get my workspace pointer
+               BL      except_atExit           ;Set it up nicely then
+
+               ; --- Return with the knowledge of a job well done ---
+
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;Return to caller
+
+wimp__optName  DCB     "WIMP"
+
+               LTORG
+
+wimp__wSpace   DCD     0
+
+; --- wimp__die ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Closes down the WindowManager nicely, just so that it
+;              doesn't have to do it itself.
+
+wimp__die      ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Stash my registers
+               LDR     R0,wimp__taskh          ;Get my task handle
+               LDR     R1,=&4B534154           ;The magic number again
+               SWI     XWimp_CloseDown         ;Close down the WIMP then
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- wimp_taskHandle ---
+;
+; On entry:    --
+;
+; On exit:     R0 == the application's task handle
+;
+; Use:         Returns the application's task handle.
+
+               EXPORT  wimp_taskHandle
+wimp_taskHandle        ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R0,wimp__wSpace         ;Find my workspace offset
+               LDR     R14,sapph_workspace     ;Load workspace block base
+               LDR     R0,[R0,R14]             ;Load WIMP version number
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- wimp_version ---
+;
+; On entry:    --
+;
+; On exit:     R0 == the WIMP's version number (may not be the one the
+;                    client asked for)
+;
+; Use:         Returns the WindowManager's version number.
+
+               EXPORT  wimp_version
+wimp_version   ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               WSPACE  wimp__wSpace,R0         ;Find workspace
+               LDR     R0,[R0,#:INDEX: wimp__version]
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- wimp_strWidth ---
+;
+; On entry:    R0 == pointer to a string
+;
+; On exit:     R0 == width of the string in OS units
+;
+; Use:         Returns the width of a string, as it would be displayed in
+;              an icon (i.e. taking into account things like the current
+;              desktop font etc.)  The width is exact, so if you want to
+;              e.g. draw a box round it, you'll have to add on a little
+;              clearance at each end.  8 OS units seems to be a good size
+;              for the clearance (so the total width you'd use is given by
+;              wimp_strWidth(string)+16, because it has two ends).
+
+               EXPORT  wimp_strWidth
+wimp_strWidth  ROUT
+
+               ; --- We need to find the string length anyway ---
+               ;
+               ; This length calculation is done inline to avoid a
+               ; dependency on string.  It's not very long, anyway, and
+               ; it *does* save a MOV R5,R0 :-)
+
+               STMFD   R13!,{R1-R7,R14}        ;Save a bunch of registers
+               MOV     R5,#0                   ;Length counter starts at 0
+               MOV     R7,#0                   ;Width so far
+               MOV     R6,R0                   ;Keep string pointer
+00wimp_strWidth        LDRB    R14,[R0,R5]             ;Get a byte from the string
+               CMP     R14,#' '                ;Is it a control char?
+               ADDCS   R5,R5,#1                ;Bump on *anyway* (see above)
+               BCS     %00wimp_strWidth        ;If more to go, loop back
+
+               ; --- Now try to find the current font handle ---
+
+               MOV     R0,#8                   ;Read Wimp font handle
+               SWI     XWimp_ReadSysInfo       ;Find out from WindowMangler
+               BVS     %01wimp_strWidth        ;If Wimp too old/buggy, skip
+               CMP     R0,#0                   ;Is there there a real font?
+               BEQ     %01wimp_strWidth        ;No -- skip ahead too
+
+               ; --- Now suss out the width of the string ---
+               ;
+               ; There maybe a shift character on the beginning, so
+               ; treat that seperately ;-)
+
+               LDRB    R14,[R6,#0]             ;Load the first character
+               CMP     R14,#&8B                ;Is it a shift character
+               BNE     %10wimp_strWidth        ;No -- jump on a bit
+               ADD     R6,R6,#1                ;Yes -- point past this char
+               MOV     R5,R0                   ;Look after font handle
+               BL      wimp_version            ;Get the wimp version
+               CMP     R0,#340                 ;RISC OS 3.5 or higher?
+               CMPGE   R1,#1                   ;Is there a symbol font?
+               MOVGE   R0,R1                   ;Yes -- use this
+               MOVGE   R1,R14                  ;And the shift character
+               MOVLT   R0,R5                   ;Otherwise use current hnd
+               MOVLT   R1,#'M'                 ;...and be generous
+               MOV     R2,#(1<<4)              ;Return OS coords
+               SWI     Font_CharBBox           ;Get bounding box
+               MOV     R0,R5                   ;Put normal handle back in R0
+               SUB     R7,R3,R1                ;Put width in R7
+
+10wimp_strWidth        SWI     Font_SetFont            ;Set up the desktop font
+               MOV     R1,#1000                ;A nice big round number
+               MOV     R2,R1                   ;And another nice big number
+               SWI     Font_Converttopoints    ;Font_StringWidth is weird
+               MOV     R3,R2                   ;Move coords to right regs
+               MOV     R2,R1                   ;That means both of them
+               MOV     R1,R6                   ;Retreive string pointer
+               MOV     R4,#-1                  ;Don't split the string
+               ADD     R5,R5,#1                ;Move this counter on one
+               SWI     Font_StringWidth        ;Find the width of the string
+               MOV     R1,R2                   ;Move coordinates back again
+               MOV     R2,R3                   ;Again, that means both
+               SWI     Font_ConverttoOS        ;Convert to OS units now
+               MOV     R0,R1                   ;Put the width in R0
+               ADD     R0,R0,R7                ;Add on previous width
+               LDMFD   R13!,{R1-R7,PC}^        ;Return to caller, then
+
+               ; --- Just normal system font ---
+
+01wimp_strWidth        MOV     R0,R5,LSL #4            ;Multiply by character width
+               LDMFD   R13!,{R1-R7,PC}^        ;Return to caller
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+wimp__wStart   #       0
+
+wimp__taskh    #       4                       ;Wimp task handle
+wimp__version  #       4                       ;Wimp version number
+
+wimp__wSize    EQU     {VAR}-wimp__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     wimp__wSize
+               DCD     wimp__wSpace
+               DCD     0
+               DCD     wimp_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/win b/StraySrc/Libraries/Sapphire/s/win
new file mode 100644 (file)
index 0000000..7f5cf69
--- /dev/null
@@ -0,0 +1,526 @@
+;
+; win.s
+;
+; Window event dispatching (TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:sapphire
+               GET     sapphire:suballoc
+               GET     sapphire:event
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- win__addToList ---
+;
+; On entry:    R0 == window handle
+;              R1 == pointer to routine to call
+;              R2 == R10 value to call routine
+;              R3 == R12 value to call routine with
+;              R4 == pointer to list head to use
+;
+; On exit:     R0-R4 preserved
+;
+; Use:         Adds a rountine to the given list. Later added
+;              routines are called first
+
+win__addToList ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+
+               ; --- Allocate a block ---
+
+               MOV     R0,#list__size          ;Size to allocate
+               BL      sub_alloc               ;Allocate the block
+               BVS     %01                     ;Branch ahead if error
+
+               ; --- Fill the block in ---
+
+               LDR     R1,[R4]                 ;Get the list head
+               STR     R1,[R0,#list__next]     ;Store in next field
+               STR     R0,[R4]                 ;Store new block at head
+
+               LDMIA   R13,{R1-R4}             ;Get parameters
+               STMIB   R0,{R1-R4}              ;Store them in the block
+
+               ; --- And return to user ---
+
+               LDMFD   R13!,{R0-R4,R14}        ;Load back link
+               BICS    PC,R14,#V_flag          ;Return without error
+
+               ; --- Barf if an error occured ---
+
+01             ADD     R13,R13,#4              ;Skip over R0
+               LDMFD   R13!,{R1-R4,R14}        ;Branch if error
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+; --- win__removeFromList ---
+;
+; On entry:    R0 == window handle
+;              R1 == pointer to routine to called
+;              R2 == R10 value routine is called with
+;              R3 == R12 value routine is called with
+;              R4 == pointer to list head to use
+;
+; On exit:     All registers/flags preserved
+;
+; Use:         Removes a routine from the given list. All values are
+;              compared.
+
+win__removeFromList
+               ROUT
+
+               STMFD   R13!,{R0-R10,R12,R14}
+
+               ; --- Find the block ---
+
+               MOV     R5,#0                   ;The previous pointer
+               MOV     R12,R4                  ;Remember where the head is
+               LDR     R4,[R4]                 ;Get the head of the list
+01             TEQ     R4,#0                   ;Are we at the end?
+               LDMEQFD R13!,{R0-R10,R12,PC}^   ;Yes -- return
+               LDR     R9,[R4],#4              ;Get the next pointer
+               LDMIA   R4,{R6-R8,R10}          ;Load data from the block
+               CMP     R6,R0                   ;Are handles/R4 the same?
+               CMPEQ   R7,R1                   ;Yes -- and routines to call?
+               CMPEQ   R8,R2                   ;Yes -- R10 value?
+               CMPEQ   R10,R3                  ;Yes -- R12 value?
+               SUBNE   R5,R4,#4                ;If no, remember previous
+               MOVNE   R4,R9                   ;...get list pointer
+               BNE     %01                     ;...and keep looking
+
+               ; --- So now the block has been found ---
+
+               SUB     R0,R4,#4                ;Put the block in R0
+               MOV     R1,#list__size          ;Get the size
+               BL      sub_free                ;Free the block
+               CMP     R5,#0                   ;Was there a previous block
+               STREQ   R9,[R12,#0]             ;No -- store next blk in head
+               STRNE   R9,[R5,#0]              ;Yes -- store in prev next ^
+
+               ; --- And return to the user ---
+
+               LDMFD   R13!,{R0-R10,R12,PC}^
+
+               LTORG
+
+; --- win_eventHandler ---
+;
+; On entry:    R0 == window handle
+;              R1 == pointer to routine to call
+;              R2 == R10 value to call routine with
+;              R3 == R12 value to call routine with
+;
+; On exit:     May return an error
+;
+; Use:         Adds a routine to the event handler list. Later added
+;              routines are called first. The event handing routine
+;              must preserve all the registers, but may alter the carry
+;              flag. If it returns with carry set, then no more event
+;              handlers, OR post-filters, will be called.
+
+               EXPORT  win_eventHandler
+win_eventHandler
+               ROUT
+
+
+               STMFD   R13!,{R4,R9,R14}        ;Save some registers
+
+               ; --- Be careful not to alter flags ---
+
+               WSPACE  win__wSpace,R9          ;Get my workspace pointer
+               ADR     R4,win__eHandlers       ;Get the event handlers
+               BL      win__addToList          ;Add the routine to the list
+               LDMFD   R13!,{R4,R9,PC}         ;Return cunningly
+
+; --- win_removeEventHandler ---
+;
+; On entry:    R0 == window handle
+;              R1 == pointer to routine called
+;              R2 == R10 value routine is called with
+;              R3 == R12 value routine is called with
+;
+; On exit:     --
+;
+; Use:         Removes a routine to the event handler list.
+
+               EXPORT  win_removeEventHandler
+win_removeEventHandler
+               ROUT
+
+               STMFD   R13!,{R4,R9,R14}        ;Stack some registers
+               WSPACE  win__wSpace,R9          ;Get my workspace pointer
+               ADR     R4,win__eHandlers       ;Get the event handlers
+               BL      win__removeFromList     ;Remove routine from the list
+               LDMFD   R13!,{R4,R9,PC}^        ;Load registers
+
+               LTORG
+
+; --- win_swapWindow ---
+;
+; On entry:    R0 == old window handle
+;              R1 == new window handle
+;
+; On exit:     --
+;
+; Use:         Searches for all the event handlers for window R0, and
+;              changes the window handle for R1.  This is designed for
+;              situations in wihich a window has been deleted and
+;              recreated.
+
+               EXPORT  win_swapWindow
+win_swapWindow ROUT
+
+               STMFD   R13!,{R0-R3,R9,R14}     ;Stack some registers
+               WSPACE  win__wSpace,R9          ;Get my workspace pointer
+               LDR     R2,win__eHandlers       ;Get my event handlers list
+10             TEQ     R2,#0                   ;Are we at the end
+               BEQ     %20win_swapWindow       ;Yes -- jump ahead
+               LDMIA   R2,{R3,R14}             ;Load some information
+               TEQ     R14,R0                  ;Are window handles the same
+               STREQ   R1,[R2,#list__wHandle]  ;Yes -- store new window hnd
+               MOV     R2,R3                   ;Put next handler in R2
+               B       %10win_swapWindow       ;Try another handler
+20             LDMFD   R13!,{R0-R3,R9,PC}^     ;Return to caller
+
+               LTORG
+
+; --- win_windowDeleted ---
+;
+; On entry:    R0 == window handle
+;
+; On exit:     --
+;
+; Use:         Removes all the event handlers associated with the given
+;              window handle.  It is intended to be used when a window
+;              has been deleted.
+
+               EXPORT  win_windowDeleted
+win_windowDeleted ROUT
+
+               STMFD   R13!,{R0-R5,R9,R14}     ;Stack some registers
+               WSPACE  win__wSpace,R9          ;Get my workspace pointer
+
+               ; --- Find the block ---
+
+               MOV     R5,#0                   ;The previous pointer
+               LDR     R2,win__eHandlers       ;Get the event handlers
+01             TEQ     R2,#0                   ;Are we at the end?
+               LDMEQFD R13!,{R0-R5,R9,PC}^     ;Yes -- return
+               LDMIA   R2,{R3,R4}              ;Get next/handle
+               CMP     R4,R0                   ;Are handles the same?
+               MOVNE   R5,R2                   ;If no, remember previous
+               MOVNE   R2,R3                   ;...get list pointer
+               BNE     %01win_windowDeleted    ;...and keep looking
+
+               ; --- So now the block has been found ---
+
+               MOV     R0,R2                   ;Put the block in R0
+               MOV     R1,#list__size          ;Get the size
+               BL      sub_free                ;Free the block
+               CMP     R5,#0                   ;Was there a previous block
+               ADREQ   R14,win__eHandlers      ;No -- point to list head
+               STREQ   R3,[R14,#0]             ;No -- store next blk in head
+               STRNE   R3,[R5,#0]              ;Yes -- store in prev next ^
+
+               ; --- Now search for the next one ---
+
+               MOV     R2,R3                   ;Put the next block in R2
+               B       %01win_windowDeleted    ;And keep on searching
+
+               LTORG
+
+; --- win_unknownHandler ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R4 value to call routine with
+;              R2 == R10 value to call routine with
+;              R3 == R12 value to call routine with
+;
+; On exit:     May return an error
+;
+; Use:         Adds a rountine to the event handler list. Later added
+;              routines are called first. The event handing routine
+;              must preserve all the registers, but may alter the carry
+;              flag. If it returns with carry set, then no more event
+;              handlers, OR post-filters, will be called.
+
+               EXPORT  win_unknownHandler
+win_unknownHandler
+               ROUT
+
+
+               STMFD   R13!,{R4,R9,R14}        ;Save some registers
+
+               ; --- Be careful not to alter flags ---
+
+               WSPACE  win__wSpace,R9          ;Get my workspace pointer
+               ADR     R4,win__uHandlers       ;Get the unknowns list
+               BL      win__addToList          ;Add the routine to the list
+               LDMFD   R13!,{R4,R9,PC}         ;Return cunningly
+
+; --- win_removeUnknownHandler ---
+;
+; On entry:    R0 == pointer to routine called
+;              R1 == R4 value routine is called with
+;              R2 == R10 value routine is called with
+;              R3 == R12 value routine is called with
+;
+; On exit:     --
+;
+; Use:         Removes a routine to the unknown handler list.
+
+               EXPORT  win_removeUnknownHandler
+win_removeUnknownHandler
+               ROUT
+
+               STMFD   R13!,{R4,R9,R14}        ;Stack some registers
+               WSPACE  win__wSpace,R9          ;Get my workspace pointer
+               ADR     R4,win__uHandlers       ;Get the event handlers
+               BL      win__removeFromList     ;Remove routine from the list
+               LDMFD   R13!,{R4,R9,PC}^        ;Load registers
+
+               LTORG
+
+; --- win__dispatchUnknown ---
+;
+; On entry:    R0  == reason code returned from Wimp_Poll
+;              R1  == pointer to block
+;              R12 == pointer to workspace
+;
+; On exit:     R0-R1 preserved
+;              C Clear if the event is not claimed, Set otherwise
+
+win__dispatchUnknown
+               ROUT
+
+               ; --- Note ---
+               ;
+               ; At this point, we've already got R2-R5, R9, R10, R12
+               ; and R14 on the stack.
+
+               ; --- Go through the handlers list ---
+
+02             ADDS    R0,R0,#0                ;Clear carry flag
+               LDR     R2,win__uHandlers       ;Get my event handlers list
+10             TEQ     R2,#0                   ;Are we at the end
+               BEQ     %20                     ;Yes -- jump ahead
+               LDMIA   R2,{R2-R4,R10,R12}      ;Load parameters to pass
+               MOV     R14,PC                  ;Set return address
+               MOV     PC,R3                   ;Branch to handler
+               BCC     %10                     ;Try next handler
+20             LDMFD   R13!,{R2-R5,R9,R10,R14} ;Load registers
+               ORRCSS  PC,R14,#C_flag          ;... and return
+               BICCCS  PC,R14,#C_flag
+
+               LTORG
+
+win__dispatchEvents
+               ROUT
+
+               STMFD   R13!,{R2-R5,R9,R10,R14} ;Stack some registers
+               MOV     R9,R12                  ;Put my workspace in R9
+
+               ; --- Messages need special attention ---
+
+               CMP     R0,#17                  ;Is this User_Message?
+               CMPNE   R0,#18                  ;Or User_Message_Recorded?
+               BEQ     %30                     ;Yes -- off we go then
+
+               ; --- If it's some weird kind of message ---
+
+               CMP     R0,#13                  ;Highest event I know
+               BGT     win__dispatchUnknown    ;Too high -- unknown then
+
+               ; --- Find the table and get window handle offset ---
+
+               ADR     R14,win__eventTbl       ;Point to the table
+               LDRB    R5,[R14,R0]             ;Get offset for this event
+               CMP     R5,#255                 ;Is this event `unknown'?
+               BEQ     win__dispatchUnknown    ;Yes -- call unknown list
+               CMP     R5,#254                 ;Is it broadcastable?
+               LDRNE   R5,[R1,R5]              ;Get the window handle
+               MOVEQ   R5,#&40000000           ;Or set up for broadcast
+
+               ; --- Go through the handlers list ---
+
+05             ADDS    R0,R0,#0                ;Clear carry flag
+               LDR     R2,win__eHandlers       ;Get my event handlers list
+10             TEQ     R2,#0                   ;Are we at the end
+               BEQ     %20                     ;Yes -- jump ahead
+               LDMIA   R2,{R2,R3,R4,R10,R12}   ;Load parameters to pass
+               TEQ     R5,R3                   ;Are window handles the same
+               TEQNE   R5,#&40000000           ;Or is this a broadcast?
+               BNE     %10                     ;No -- try another handler
+               MOV     R14,PC                  ;Set return address
+               MOV     PC,R4                   ;Branch to handler
+               BCC     %10                     ;Try next handler
+20             LDMFD   R13!,{R2-R5,R9,R10,R14} ;Load the registers
+               BICCCS  PC,R14,#C_flag          ;Return with carry clear
+               ORRCSS  PC,R14,#C_flag          ;... or with carry set
+
+               ; --- Now try unknowns if I'm not claiming the message ---
+
+30             LDR     R2,[R1,#16]             ;Get message code
+               ADR     R14,win__msgTbl         ;Point to message table
+00             LDMIA   R14!,{R3,R4}            ;Load code and offset
+               CMP     R2,R3                   ;Does the code match?
+               LDREQ   R5,[R1,R4]              ;Yes -- load window handle
+               BEQ     %05                     ;And continue going
+               CMP     R3,#-1                  ;Is this the end yet?
+               BNE     %b00                    ;No -- keep going then
+
+               ; --- See if it's broadcastable ---
+
+               ADR     R14,win__broadTbl       ;Point to the table
+00             LDR     R3,[R14],#4             ;Load the message code
+               CMP     R2,R3                   ;Do we have a match?
+               MOVEQ   R5,#&40000000           ;Yes -- signal broadcast
+               BEQ     %05                     ;And dispatch appropriately
+               CMP     R3,#-1                  ;Is this the end yet?
+               BNE     %b00                    ;No -- keep on going
+
+               B       win__dispatchUnknown    ;Unknown event -- dispatch it
+
+               DCB     0                       ;Hint_Received
+win__eventTbl  DCB     255                     ;Null
+               DCB     0                       ;Redraw
+               DCB     0                       ;Open
+               DCB     0                       ;Close
+               DCB     0                       ;Leave window
+               DCB     0                       ;Enter window
+               DCB     12                      ;Mouse click
+               DCB     255                     ;Drag event
+               DCB     0                       ;Key press
+               DCB     255                     ;Menu choice
+               DCB     0                       ;Scroll request
+               DCB     0                       ;Lose caret
+               DCB     0                       ;Gain caret
+               DCB     255                     ;Poll word nonzero
+               ALIGN
+
+win__msgTbl    DCD     &1,     20              ;DataSave
+               DCD     &3,     20              ;DataLoad
+               DCD     &502,   32              ;HelpRequest
+               DCD     &11,    20              ;Dragging (drag'n'drop)
+               DCD     -1,     -1
+
+win__broadTbl  DCD     &9                      ;PaletteChange
+               DCD     &400C1                  ;ModeChange
+               DCD     &400CF                  ;FontChange
+               DCD     -1
+
+               LTORG
+
+; --- win_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the win system.
+
+               EXPORT  win_init
+win_init       ROUT
+
+               STMFD   R13!,{R0,R1,R9,R14}     ;Stack some registers
+               WSPACE  win__wSpace,R9          ;Get my workspace
+
+               ; --- Are we already initialised? ---
+
+               LDR     R0,win__flags           ;Get my flags
+               TST     R0,#win__INITED         ;Are we initialised?
+               LDMNEFD R13!,{R0,R1,R9,PC}^     ;Yes -- return
+
+               ORR     R0,R0,#win__INITED      ;Set initialised flag
+               STR     R0,win__flags           ;And store them back
+
+               ; --- Clear rest of workspace ---
+
+               MOV     R0,#0                   ;Zero some registers
+               STR     R0,win__eHandlers       ;Clear event handlers list
+               STR     R0,win__uHandlers       ;Clear unknown list
+
+               ; --- Initialise event system ---
+
+               BL      event_init              ;Initialise event system
+
+               ; --- Set up a post filter for the win system ---
+
+               ADR     R0,win__dispatchEvents  ;Call this routine
+               MOV     R1,R9                   ;Put my workspace in R12
+               BL      event_postFilter        ;Add it to post-filter list
+
+               ; --- That's it now ---
+
+               LDMFD   R13!,{R0,R1,R9,PC}^     ;Return
+
+               LTORG
+
+win__wSpace    DCD     0                       ;My workspace pointer
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R9
+win__wStart    #       0
+
+win__flags     #       4                       ;Flags
+
+win__INITED    EQU     (1<<0)                  ;I've been initialised
+
+win__eHandlers #       4                       ;Event handler list
+win__uHandlers #       4                       ;Unknown event handlers
+
+win__wSize     EQU     {VAR}-win__wStart
+
+; --- list structure ---
+
+               ^       0
+list__next     #       4                       ;The next block
+list__wHandle  #       4                       ;The window handle
+list__proc     #       4                       ;Handler code
+list__r10      #       4                       ;R12 to call with
+list__r12      #       4                       ;R12 to call with
+
+list__size     #       0
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     win__wSize              ;Workspace size
+               DCD     win__wSpace             ;Workspace pointer
+               DCD     0                       ;Scratchpad size
+               DCD     win_init                ;Initialisation code
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/winUtils b/StraySrc/Libraries/Sapphire/s/winUtils
new file mode 100644 (file)
index 0000000..0eb0ff3
--- /dev/null
@@ -0,0 +1,292 @@
+;
+; winUtils.s
+;
+; Various window utility functions (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:screen
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- winUtils_setTitle ---
+;
+; On entry:    R0 == pointer to string to set in title
+;              R1 == pointer to title bar buffer
+;              R2 == window handle to write to
+;
+; On exit:     --
+;
+; Use:         Sets a window's title string.  If the string is different,
+;              the title is redrawn.  The contortion to do this is
+;              unpleasant, and is not to be performed in public.
+
+               EXPORT  winUtils_setTitle
+winUtils_setTitle ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Save some registers
+
+               ; --- Copy the string over nicely ---
+
+               MOV     R3,#0                   ;Not changed anything yet
+00             LDRB    R4,[R0],#1              ;Get a byte from new string
+               LDRB    R5,[R1],#1              ;Get a byte from old string
+
+               CMP     R4,#' '                 ;Convert control chars...
+               MOVLT   R4,#0                   ;... to null bytes
+               CMP     R5,#' '                 ;And again for the other char
+               MOVLT   R5,#0
+
+               CMP     R4,R5                   ;Are they different?
+               MOVNE   R3,#1                   ;Yes -- set the flag
+               STRNEB  R4,[R1,#-1]             ;And store in the buffer
+
+               CMP     R4,#0                   ;Is this the end of it all?
+               BNE     %00winUtils_setTitle    ;No -- go round for another
+               STRB    R4,[R1,#-1]             ;Terminate string with NULL
+
+               ; --- Return if it was the same ---
+
+               CMP     R3,#0                   ;Did we do anything?
+               LDMEQFD R13!,{R0-R6,PC}^        ;No -- return right now
+
+               ; --- Read the window coordinates (yuk) ---
+
+               SUB     R13,R13,#36             ;Make way for a window block
+               STR     R2,[R13,#0]             ;Store the handle in there
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window information
+
+               LDR     R14,[R13,#32]           ;Get the window flags
+               TST     R14,#&00010000          ;Check that it's open
+               ADDEQ   R13,R13,#36             ;No -- reclaim stack space
+               LDMEQFD R13!,{R0-R6,PC}^        ;No -- return right now
+
+               LDMIB   R13,{R2-R5}             ;Load the coordinates out
+               SWI     Wimp_GetWindowOutline   ;Now find the real position
+               LDR     R6,[R13,#16]            ;Load the top coordinate
+
+               MOV     R0,#-1                  ;Redraw everything (yuk)
+               MOV     R1,R2                   ;The left hand side to do
+               MOV     R2,R5                   ;The bottom part to do
+               MOV     R3,R4                   ;The right hand side to do
+               MOV     R4,R6                   ;And the top part to do
+               SWI     Wimp_ForceRedraw        ;Force the screen update
+
+               ADD     R13,R13,#36             ;Restore the stack again
+               LDMFD   R13!,{R0-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- winUtils_setPosition ---
+;
+; On entry:    R0 == window opening style
+;              R1 == pointer to window state block
+;              R2,R3 == extra arguments for displaying the window
+;
+; On exit:     R2,R3 contain position for opening with Wimp_CreateMenu
+;
+; Use:         Modifies the window state block pointed to by R0 so that the
+;              window appears as required in the given opening style.  The
+;              window is always moved to the top.
+
+               EXPORT  winUtils_setPosition
+winUtils_setPosition ROUT
+
+               STMFD   R13!,{R0,R1,R4-R8,R14}  ;Save some registers
+
+               ; --- Set up values in registers ---
+
+               LDMIB   R1,{R4-R7}              ;Load the window position
+               SUB     R6,R6,R4                ;Get window width in R6
+               SUB     R7,R7,R5                ;And window height in R7
+
+               ; --- Dispatch to display style handler ---
+
+               CMP     R0,#(%10-%00)/4         ;Is the opening style known?
+               MOV     R8,PC                   ;Set up return address
+               ADDCC   PC,PC,R0,LSL #2         ;Call positioning routine
+               B       %50winUtils_setPosition ;And write values back
+
+               ; --- Branch table for window positioning ---
+
+00             MOVS    PC,R8                   ;Do nothing -- leave as is
+               B       %15winUtils_setPosition ;Centre window on the screen
+               B       %20winUtils_setPosition ;Centre window over pointer
+               B       %25winUtils_setPosition ;Set y position as given
+               B       %30winUtils_setPosition ;Set top left as given
+10
+               ; --- Centre a window on the screen ---
+
+15             BL      screen_getInfo          ;Find the screen information
+               ADD     R14,R0,#screen_width    ;Point to width/height info
+               LDMIA   R14,{R2,R3}             ;Load the values out
+               SUB     R4,R2,R6                ;Centre the window...
+               MOV     R4,R4,LSR #1            ;... horizontally
+               SUB     R5,R3,R7                ;Also centre it...
+               MOV     R5,R5,LSR #1            ;... vertically
+               MOVS    PC,R8                   ;And return to set the state
+
+               ; --- Centre a window over the pointer ---
+
+20             SWI     OS_Mouse                ;Find immediate pointer pos
+               SUB     R4,R0,R6,LSR #1         ;Centre the x position
+               SUB     R5,R1,R7,LSR #1         ;And the y position
+               LDR     R1,[R13,#4]             ;Reload the block pointer
+               MOVS    PC,R8                   ;And return to caller
+
+               ; --- Open window at given y position ---
+
+25             SUB     R5,R2,R7                ;Sort out the y positioning
+               MOVS    PC,R8                   ;And return to caller
+
+               ; --- Open window at given position ---
+
+30             MOV     R4,R2                   ;Set up the left hand side
+               SUB     R5,R3,R7                ;And set up the *top*
+               MOVS    PC,R8                   ;Return to main program
+
+               ; --- Now sort out all the return values ---
+
+50             ADD     R6,R4,R6                ;Work out window right pos
+               ADD     R7,R5,R7                ;And the window top position
+               STMIB   R1,{R4-R7}              ;Save all the values in there
+               MOV     R14,#-1                 ;Ensure window opens on top
+               STR     R14,[R1,#28]            ;Save in `behind' field
+               MOV     R2,R4                   ;Return left side in R2
+               MOV     R3,R7                   ;And top edge in R3
+               LDMFD   R13!,{R0,R1,R4-R8,PC}^  ;And return to caller
+
+               LTORG
+
+; --- winUtils_findValid ---
+;
+; On entry:    R0 == pointer to icon block
+;              R1 == character to find in block (not case-sensitive)
+;              R2 == old pointer to search from, or 0
+;
+; On exit:     R1 == character forced to lower case
+;              CS if found, and
+;                R2 points to command string
+;              else CC and
+;                R2 corrupted
+;
+; Use:         Tries to find a validation string command in the given
+;              icon block.
+
+               EXPORT  winUtils_findValid
+winUtils_findValid ROUT
+
+               BIC     R14,R14,#C_flag         ;Assume we won't find it
+               STMFD   R13!,{R3,R14}           ;Preserve for later use
+
+               ; --- Ensure the icon is text and indirected ---
+
+               LDR     R3,[R0,#16]             ;Get flags word
+               TST     R3,#1<<23               ;Is it deleted?
+               MOVEQ   R14,#&100               ;Can't put 101 in one instr
+               ORREQ   R14,R14,#&01            ;Check indirect and text
+               ANDEQ   R3,R3,R14               ;Mask the bits off
+               CMPEQ   R3,R14                  ;Were they both set?
+               LDMNEFD R13!,{R3,PC}^           ;No -- return huffily
+
+               ; --- Find the validation string ---
+
+               LDR     R3,[R0,#24]             ;Get pointer to valid string
+               CMP     R3,#-1                  ;Is it empty?
+               LDMEQFD R13!,{R3,PC}^           ;No -- return huffily
+
+               ; --- Start from the right index ---
+
+               ORR     R1,R1,#&20              ;Make valid char lower case
+               CMP     R2,#0                   ;Is it the start?
+               ADDNE   R2,R2,#1                ;No -- miss out one char
+               BNE     %02winUtils_findValid   ;And skip this command
+               MOV     R2,R3                   ;Start at the beginning
+
+               ; --- Check the first char of a validation string ---
+
+00             LDRB    R14,[R2],#1             ;Get a byte from string
+               ORR     R3,R14,#&20             ;Make lower case
+               CMP     R3,R1                   ;Is it a match?
+               SUBEQ   R2,R2,#1                ;Point back to character
+               LDMEQFD R13!,{R3,R14}           ;And return
+               ORREQS  PC,R14,#C_flag          ;Set C on exit for this
+               MOV     R3,#0                   ;Not an excaped character
+
+               ; --- Skip ahead to the next validation string ---
+
+01             CMP     R14,#' '                ;Is it a control char?
+               LDMLTFD R13!,{R3,PC}^           ;Yes -- return
+               CMP     R3,#1                   ;Are we escaping?
+               MOVEQ   R3,#0                   ;Yes -- done that now
+               BEQ     %02winUtils_findValid   ;So skip this bit
+               CMP     R14,#';'                ;Is it a semicolon?
+               BEQ     %00winUtils_findValid   ;Yes -- try a new command
+               CMP     R14,#'\'                ;Is it a backslash?
+               MOVEQ   R3,#1                   ;Yes -- escape next char
+02             LDRB    R14,[R2],#1             ;Get another character
+               B       %01winUtils_findValid   ;And try again
+
+               LTORG
+
+; --- winUtils_shaded ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;
+; On exit:     CS if icon is shaded, CC otherwise
+;
+; Use:         Informs caller whether an icon is shaded in the Sapphire
+;              sense (ESG 31 or shaded bit set).
+
+               EXPORT  winUtils_shaded
+winUtils_shaded        ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               SUB     R13,R13,#40             ;Make an icon block
+               STMIA   R13,{R0,R1}             ;Save icons in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetIconState       ;Read the icon information
+               LDR     R14,[R13,#24]           ;Load the icon flags
+               EOR     R14,R14,#&005F0000      ;Toggle shaded and ESG bits
+               TST     R14,#&00400000          ;Was the shaded bit set?
+               TSTNE   R14,#&001F0000          ;No -- test the ESG bits
+               ADD     R13,R13,#40             ;Restore the stack pointer
+               LDMFD   R13!,{R0,R1,R14}        ;Unstack loads of registers
+               ORREQS  PC,R14,#C_flag          ;Set C if icon is shaded
+               BICNES  PC,R14,#C_flag          ;Clear C if not shaded
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/s/writable b/StraySrc/Libraries/Sapphire/s/writable
new file mode 100644 (file)
index 0000000..d9dee6a
--- /dev/null
@@ -0,0 +1,398 @@
+;
+; writable.s
+;
+; Writable dialogue boxes (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:fastMove
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:string
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- writable ---
+;
+; On entry:    R0 == pointer to writable dialogue block
+;              R1 == pointer to default string to display, or 0 for null
+;              R2 == pointer to routine to call when string set
+;              R3 == value to pass to routine in R10
+;              R4 == value to pass to routine in R12
+;
+; On exit:     R0 == dialogue handle of created dialogue box
+;              May return an error
+;
+; Use:         Displays a writable dialogue box, i.e. one with a writable
+;              icon and OK button, used instead of writable menu items,
+;              for reasons to do with caret blinking and pointer changing.
+;
+;              The writable dialogue block consists of:
+;
+;              Size    Meaning
+;              ~~~~    ~~~~~~~
+;              4       Flags (see below)
+;              n       Validation string to use, may be null
+;              m       Title string (message tag) to display
+;
+;              The flags are:
+;
+;              Bit     Meaning
+;              ~~~     ~~~~~~~
+;              0-7     Maximum string length
+;              8       Right align text in writable icon
+;              9-31    Reserved; must be 0
+;
+;              The routine returns a dialogue handle because you may want
+;              to attach a numWrite control to the writable icon, which
+;              is icon number 0.
+;
+;              The handler routine is passed:
+;
+;              R0 == pointer to string typed in
+;              R1 == dialogue box handle (for numWrite again)
+;              R10, R12 as set up here
+;
+;              It must preserve all registers.  If the carry flag is set
+;              on exit, the dialogue box will not be closed.  If it is
+;              clear, the dialogue may be closed depending on the button
+;              status.
+;
+;              Note that this routine does *not* require a template --
+;              a suitable window is generated at run-time.
+
+               EXPORT  writable
+writable       ROUT
+
+               STMFD   R13!,{R1-R3,R12,R14}    ;Save some registers away
+               WSPACE  wrt__wSpace             ;Find my workspace pointer
+
+               ; --- Save the handler information ---
+
+               ADR     R14,wrt__proc           ;Point to the handler stuff
+               STMIA   R14,{R2-R4}             ;Save the handler info away
+               MOV     R3,R0                   ;Keep the description block
+
+               ; --- Save the default string away ---
+
+               ADR     R0,wrt__buffer          ;Point to writable buffer
+               CMP     R1,#0                   ;Is there a default string?
+               STREQB  R1,[R0,#0]              ;No -- save a null string
+               BLNE    str_cpy                 ;Otherwise copy the string
+
+               ; --- Set up the dialogue box sizes ---
+
+               LDR     R1,[R3,#0]              ;Load the string length/flags
+               AND     R0,R1,#&FF              ;Just get the bottom byte
+               ADD     R0,R0,#1                ;Allow for the terminator
+               STR     R0,wrt__dbDef+wOff__writeData+8
+               CMP     R0,#41                  ;Is the string really big?
+               MOVGT   R0,#41                  ;Yes -- make it sane at least
+               MOV     R0,R0,LSL #4            ;Multiply up to pixels
+               ADD     R0,R0,#106              ;Get the left of the icon
+               RSB     R0,R0,#0                ;And make it negative
+               STR     R0,wrt__dbDef+wOff__writeBox
+               SUB     R0,R0,#24               ;Get left side of the window
+               STR     R0,wrt__dbDef+wOff__open
+               STR     R0,wrt__dbDef+wOff__extent
+
+               ; --- Fix up string alignment ---
+
+               LDR     R14,wrt__dbDef+wOff__writeFlag
+               TST     R1,#wrtFlag_rAlign      ;Do we right align text?
+               ORRNE   R14,R14,#&200           ;Yes -- set the bit then
+               BICEQ   R14,R14,#&200           ;No -- clear it instead
+               STR     R14,wrt__dbDef+wOff__writeFlag
+
+               ; --- Fill in the validation string ---
+
+               ADR     R0,wrt__valid           ;Point to validation buffer
+               ADR     R1,wrt__x7              ;Point to base validation
+               BL      str_cpy                 ;Copy it onto the end
+               ADD     R1,R3,#4                ;Point to validation string
+               LDRB    R14,[R1],#1             ;Load the first byte
+               CMP     R14,#32                 ;Is this an empty string?
+               BLO     %20writable             ;Yes -- miss this bit out
+
+               MOV     R2,#';'                 ;Put a delimiter string in
+               STRB    R2,[R0],#1              ;Save in validation buffer
+10writable     STRB    R14,[R0],#1             ;Save the valid character
+               LDRB    R14,[R1],#1             ;Load another byte
+               CMP     R14,#32                 ;Is this the string end?
+               BHS     %10writable             ;No -- go round again
+               MOV     R14,#0                  ;Null terminate nicely
+               STRB    R14,[R0],#1             ;Save it in the buffer
+
+               ; --- Finally, fill in the title string ---
+
+20writable     MOV     R0,R1                   ;Point to title message tag
+               BL      msgs_lookup             ;Find the message string
+               MOV     R1,R0                   ;Point to the message
+               ADR     R0,wrt__title           ;Point to the title buffer
+               BL      str_cpy                 ;And copy that over nicely
+
+               ; --- Build the dialogue box ---
+
+               ADR     R0,wrt__dbDef           ;Point to the dialogue defn
+               BL      dbox_fromDefn           ;Create a dialogue box
+               BVS     %90writable             ;Return if it failed
+
+               ADR     R1,wrt__handler         ;Point to the handler
+               MOV     R2,R0                   ;Pass dialogue handle in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      dbox_eventHandler       ;Set up the event handler
+
+               MOV     R1,#dbOpen_pointer+dbOpen_trans
+               BL      dbox_open               ;Display the dialogue box
+               LDMFD   R13!,{R1-R3,R12,R14}    ;Restore all the registers
+               BICS    PC,R14,#V_flag          ;Return without an error
+
+               ; --- Couldn't create the dialogue box ---
+
+90writable     LDMFD   R13!,{R1-R3,R12,R14}    ;Restore all the registers
+               ORRS    PC,R14,#V_flag          ;Return the error pointer
+
+wrt__x7                DCB     "x7",0                  ;Tim's neat writable border
+
+               LTORG
+
+; --- wrt__handler ---
+;
+; On entry:    R0 == dialogue box event code
+;              R1-R7 == depend on the event type
+;              R10 == dialogue box handle
+;              R12 == pointer to my workspace
+;
+; On exit:     --
+;
+; Use:         Handles events for the writable dialogue box.
+
+wrt__handler   ROUT
+
+               CMP     R0,#dbEvent_close       ;Someone closed my dialogue?
+               BEQ     %10wrt__handler         ;Yes -- destroy it then
+               CMP     R0,#dbEvent_OK          ;Is it an OK click?
+               CMPNE   R0,#wrtIcon__ok         ;Or a click on the OK button?
+               MOVNES  PC,R14                  ;No -- then return to caller
+
+               ; --- Handle an OK click ---
+
+               STMFD   R13!,{R0-R3,R10,R12,R14} ;Save loads of registers
+               MOV     R2,R1                   ;Look after the button state
+               MOV     R0,R10                  ;Get the dialogue handle
+               MOV     R1,#wrtIcon__ok         ;And the OK button handle
+               BL      dbox_slab               ;Slab the button in
+
+               ; --- Call the user's handler ---
+
+               ADR     R0,wrt__buffer          ;Point to the string
+               MOV     R1,R10                  ;Get the dialogue box handle
+               ADR     R14,wrt__proc           ;Find his event handler
+               LDMIA   R14,{R3,R10,R12}        ;Load all the handler stuff
+               ADDS    R0,R0,#0                ;Clear C flag cunningly
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R3                   ;And call the handler
+
+               ; --- Find out what to do next ---
+
+               TSTCS   R2,#0                   ;Set Z flag if carry set
+               TSTCC   R2,#1                   ;Otherwise, test Adjustness
+               MOV     R0,R1                   ;Get the dialogue handle
+               BLEQ    dbox_close              ;If Select then close dbox
+               BL      dbox_unslab             ;Unslab the OK button
+               BLEQ    dbox_destroy            ;If Select then trash dbox
+               LDMFD   R13!,{R0-R3,R10,R12,PC}^ ;And return to caller
+
+               ; --- The dialogue box closed ---
+
+10wrt__handler STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R10                  ;Get the dialogue handle
+               BL      dbox_destroy            ;Kill the dialogue box
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+; --- wrt_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the writable dialogue box for use.
+
+               EXPORT  wrt_init
+wrt_init       ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  wrt__wSpace             ;Load my workspace pointer
+               LDR     R14,wrt__flags          ;Load the flags word nicely
+               TST     R14,#wFlag__inited      ;Have we done this already?
+               LDMNEFD R13!,{R12,PC}^          ;Yes -- return to caller
+
+               ; --- Set up the flags nicely ---
+
+               STMFD   R13!,{R0-R2}            ;Save some more registers
+               ORR     R14,R14,#wFlag__inited  ;Set the initialised flag
+               STR     R14,wrt__flags          ;Save the flags back again
+               BL      dbox_init               ;Make sure dboxes are going
+
+               ; --- Now copy the window definition over ---
+
+               ADR     R0,wrt__dbDef           ;Point to the workspace block
+               ADR     R1,wrt__window          ;Point to the window def
+               MOV     R2,#wrt__windSize       ;Get the size of the block
+               BL      fastMove                ;Copy the block over nicely
+
+               ; --- Fill in bits of the window definition ---
+
+               ADR     R14,wrt__title          ;Point to the title buffer
+               STR     R14,[R0,#wOff__titleData]
+               ADR     R14,wrt__buffer
+               STR     R14,[R0,#wOff__writeData]
+               ADR     R14,wrt__valid
+               STR     R14,[R0,#wOff__writeData+4]
+
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller
+
+               LTORG
+
+wrt__wSpace    DCD     0
+
+;----- Constants ------------------------------------------------------------
+
+               ; --- Icon numbers ---
+
+wrtIcon__write EQU     0                       ;The writable icon
+wrtIcon__ok    EQU     1                       ;The OK button
+
+               ; --- Flags ---
+
+wrtFlag_rAlign EQU     (1<<8)                  ;Align text to right side
+
+;----- Window definition ----------------------------------------------------
+
+; --- Note ---
+;
+; The main window definition here gets copied into workspace so that I can
+; modify it nicely at runtime, to change the width of the window etc.
+
+; --- Macro: WOFF ---
+;
+; Arguments:   label == symbol to assign with current offset into window def
+;
+; Use:         Sets a symbol to an offset in the window definition
+
+               MACRO
+$label         WOFF
+$label         EQU     {PC}-wrt__window
+               MEND
+
+               ; --- The main window block ---
+
+wrt__window
+
+wOff__open     WOFF
+               DCD     -324,-96,0,0            ;Width dynamically adjusted
+               DCD     0,0                     ;Window doesn't scroll (hope)
+               DCD     -1                      ;Always open on the top
+               DCD     &84170002               ;Window flags word (various)
+               DCB     7,2,7,1,3,1,2,0         ;Window colours words
+
+wOff__extent   WOFF
+               DCD     -324,-96,0,0            ;Dynamically adjust width
+               DCD     &00000109               ;Window title bar flags
+               DCD     &00000000               ;Work area button type
+               DCD     1                       ;Wimp sprite area, I think
+               DCD     0                       ;Default minimum sizes
+
+wOff__titleData        WOFF
+               DCD     0,-1,24                 ;Title bar icon data
+               DCD     2                       ;2 icons following
+
+               ; --- The writable area icon ---
+
+wOff__writeBox WOFF
+               DCD     -300,-68,-110,-28       ;24 in from the left
+
+wOff__writeFlag        WOFF
+               DCD     &0700F131               ;Icon flags word
+
+wOff__writeData        WOFF
+               DCD     0,0,0                   ;Fill in all the data later
+
+               ; --- The OK button ---
+
+               DCD     -72,-72,-24,-24         ;Icon bounding box
+               DCD     &17003139               ;Icon flags word
+               DCD     wrt__ok,wrt__x2,3       ;Icon data strings
+
+wrt__windSize  WOFF
+
+               ; --- Indirected text for OK button ---
+
+wrt__ok                DCB     "OK",0                  ;Button text string
+wrt__x2                DCB     "x2",0                  ;Button border command
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+wrt__wStart    #       0
+
+wrt__flags     #       4                       ;Various flags
+
+               ; --- The user's handler routine ---
+
+wrt__proc      #       4                       ;The routine to call
+wrt__R10       #       4                       ;Value to pass in R10
+wrt__R12       #       4                       ;Value to pass in R12
+
+               ; --- The copy of the window definition ---
+
+wrt__dbDef     #       wrt__windSize           ;The window definition copy
+wrt__valid     #       24                      ;Icon validation string
+wrt__title     #       24                      ;Window title text string
+wrt__buffer    #       256                     ;The actual data string
+
+wrt__wSize     EQU     {VAR}-wrt__wStart
+
+wFlag__inited  EQU     (1<<0)                  ;Have we initialised yet?
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     wrt__wSize
+               DCD     wrt__wSpace
+               DCD     0
+               DCD     wrt_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/Changes b/StraySrc/Libraries/Sapphire/sail/Changes
new file mode 100644 (file)
index 0000000..fa7cc4c
--- /dev/null
@@ -0,0 +1,14 @@
+Files dealt with
+~~~~~~~~~~~~~~~~
+
+anchor.sh      (suddenly it's got nicer)
+
+interp.s       (no real changes here)
+sail.s                 (formerly termScript)
+stracc.s       (could be dodgy!)
+tokenise.s      (no changes needed)
+
+Don't forget
+~~~~~~~~~~~~
+
+DIM's still use RMA stuff
\ No newline at end of file
diff --git a/StraySrc/Libraries/Sapphire/sail/Makefile,fe1 b/StraySrc/Libraries/Sapphire/sail/Makefile,fe1
new file mode 100644 (file)
index 0000000..4614096
--- /dev/null
@@ -0,0 +1,243 @@
+#
+# TermScript makefile
+#
+# © 1994 Straylight
+#
+
+#----- Flag definitions -----------------------------------------------------
+#
+# This section only contains common flags -- others (e.g. debugging flags
+# and predefined macros) are defined in the howto lines.
+
+linkFlags=      -d -o $@ -aif $(linkx)
+flinkFlags=     -bin -base 0 -o $@ $(linkx)
+objFlags=      -g -stamp -throwback -depend !Depend -quit $(objx)
+
+#----- Member list ----------------------------------------------------------
+#
+# Because this list is used in a few of the targets below, it is defined as
+# a macro here for changability.
+
+members=       @.o.var \
+               @.o.tree \
+               @.o.tokenise \
+               @.o.termite \
+               @.o.termScript \
+               @.o.strBucket \
+               @.o.stracc \
+               @.o.interp \
+               @.o.getToken \
+               @.o.express \
+               @.o.error \
+               @.o.divide \
+               @.o.ctrl \
+
+testMembers=   $(members) \
+               @.o.mem \
+               @.o.driver
+
+realMembers=   $(members) \
+               @.o.mem_real
+
+libs=          libs:o.rdump
+
+#----- Making the library ---------------------------------------------------
+#
+# For brevity's sake, this is done using implicit dependencies.
+
+.SUFFIXES:     .o .s
+.s.o:;         objasm $(objFlags) -from $< -to $@
+
+all:           @.termScript
+
+sh.tokens:     tableGen
+               here:tableGen
+
+sh.errTable:   errGen
+               here:errGen
+
+@.termScript:  $(testMembers) $(libs)
+               setdate o.version \
+                 version="1.00 (%zdy %mo %ce%yr)" \
+                 cright="Straylight"
+               /link $(linkFlags) $(testMembers) $(libs) @.o.version
+
+@.tScript:     $(realMembers) $(libs)
+               setdate o.version \
+                 version="1.00 (%zdy %mo %ce%yr)" \
+                 cright="Straylight"
+               /link -base 0 -bin -o $@ $(realMembers) $(libs) @.o.version
+               settype $@ ffd
+#              codescr -util $@
+
+#----- Other targets --------------------------------------------------------
+#
+# The targets available are:
+#
+#      Target  Meaning
+#
+#      relink  Force a relink of the executable.
+#      remake  Force a complete remake of the entire project.
+
+recreate:;     remove @.!RunImage
+               @amu all ccx=$(ccx) linkx=$(linkx) objx=$(objx)
+
+remake:;       create @.o.dummy
+               wipe @.o.* ~c~v~r~f
+               @amu all ccx=$(ccx) linkx=$(linkx) objx=$(objx)
+
+#----- Dynamic dependencies -------------------------------------------------
+#
+# The following are set up by compilers/assemblers and added to the Makefile
+# autoamtically.  For this to work, amu requires that the following active
+# comment is inserted in the makefile:
+#
+# Dynamic dependencies:
+o.mem: s.mem
+o.mem: libs:header
+o.mem: libs:swis
+o.mem: libs:stream
+o.mem: sh.errNum
+o.mem: sh.error
+o.mem_real: s.mem_real
+o.mem_real: libs:header
+o.mem_real: libs:swis
+o.mem_real: libs:stream
+o.mem_real: sh.errNum
+o.mem_real: sh.error
+o.divide: s.divide
+o.divide: libs:header
+o.divide: libs:swis
+o.var: s.var
+o.var: libs:header
+o.var: libs:swis
+o.var: libs:stream
+o.var: sh.anchor
+o.var: sh.errNum
+o.var: sh.error
+o.var: sh.tree
+o.tree: s.tree
+o.tree: libs:header
+o.tree: libs:swis
+o.tree: libs:stream
+o.tree: sh.anchor
+o.tree: sh.mem
+o.termScript: s.termScript
+o.termScript: libs:header
+o.termScript: libs:swis
+o.termScript: libs:stream
+o.termScript: sh.anchor
+o.termScript: sh.ctrl
+o.termScript: sh.interp
+o.termScript: sh.mem
+o.termScript: sh.strBucket
+o.termScript: sh.termite
+o.termScript: sh.tree
+o.termScript: sh.tokenise
+o.termScript: sh.var
+o.strBucket: s.strBucket
+o.strBucket: libs:header
+o.strBucket: libs:swis
+o.strBucket: libs:stream
+o.strBucket: sh.anchor
+o.strBucket: sh.mem
+o.error: s.error
+o.error: libs:header
+o.error: libs:swis
+o.error: libs:stream
+o.error: sh.anchor
+o.error: sh.termScript
+o.error: sh.errTable
+o.error: sh.errTable
+o.tokenise: s.tokenise
+o.tokenise: libs:header
+o.tokenise: libs:swis
+o.tokenise: libs:stream
+o.tokenise: sh.anchor
+o.tokenise: sh.tokens
+o.tokenise: sh.var
+o.tokenise: sh.tokTable
+o.interp: s.interp
+o.interp: libs:header
+o.interp: libs:swis
+o.interp: libs:stream
+o.interp: sh.anchor
+o.interp: sh.ctrl
+o.interp: sh.errNum
+o.interp: sh.error
+o.interp: sh.express
+o.interp: sh.getToken
+o.interp: sh.termite
+o.interp: sh.termScript
+o.interp: sh.tokens
+o.interp: sh.upcalls
+o.getToken: s.getToken
+o.getToken: libs:header
+o.getToken: libs:swis
+o.getToken: libs:stream
+o.getToken: sh.anchor
+o.getToken: sh.tokClasses
+o.express: s.express
+o.express: libs:header
+o.express: libs:swis
+o.express: libs:stream
+o.express: sh.anchor
+o.express: sh.ctrl
+o.express: sh.divide
+o.express: sh.errNum
+o.express: sh.error
+o.express: sh.getToken
+o.express: sh.stracc
+o.express: sh.termite
+o.express: sh.termScript
+o.express: sh.tokenise
+o.express: sh.tokens
+o.express: sh.upcalls
+o.express: sh.mem
+o.express: sh.var
+o.driver: s.driver
+o.driver: libs:header
+o.driver: libs:swis
+o.driver: libs:stream
+o.stracc: s.stracc
+o.stracc: libs:header
+o.stracc: libs:swis
+o.stracc: libs:stream
+o.stracc: sh.anchor
+o.stracc: sh.mem
+o.termite: s.termite
+o.termite: libs:header
+o.termite: libs:swis
+o.termite: libs:stream
+o.termite: sh.anchor
+o.termite: sh.ctrl
+o.termite: sh.errNum
+o.termite: sh.error
+o.termite: sh.express
+o.termite: sh.getToken
+o.termite: sh.interp
+o.termite: sh.stracc
+o.termite: sh.strBucket
+o.termite: sh.termscript
+o.termite: sh.tokens
+o.termite: sh.upcalls
+o.termite: sh.var
+o.ctrl: s.ctrl
+o.ctrl: libs:header
+o.ctrl: libs:swis
+o.ctrl: libs:stream
+o.ctrl: sh.anchor
+o.ctrl: sh.divide
+o.ctrl: sh.errNum
+o.ctrl: sh.error
+o.ctrl: sh.express
+o.ctrl: sh.getToken
+o.ctrl: sh.interp
+o.ctrl: sh.mem
+o.ctrl: sh.stracc
+o.ctrl: sh.strBucket
+o.ctrl: sh.termite
+o.ctrl: sh.termscript
+o.ctrl: sh.tokens
+o.ctrl: sh.tree
+o.ctrl: sh.var
diff --git a/StraySrc/Libraries/Sapphire/sail/SAILInfo b/StraySrc/Libraries/Sapphire/sail/SAILInfo
new file mode 100644 (file)
index 0000000..0d82187
--- /dev/null
@@ -0,0 +1,261 @@
+
+                               The SAIL System
+                               ~~~~~~~~~~~~~~~
+
+The name
+~~~~~~~~
+
+       SAIL stands for Straylight Application Interface Language.  It's
+       Another Straylight Contrived Acronym (ASCA).
+
+The Concept
+~~~~~~~~~~~
+
+       To allow a nice script language in major Sapphire application.  In
+       particualr is allows access to most of sapphire, making extensible
+       applications easy and powerful.
+
+SAIL API
+~~~~~~~~
+
+Requirements
+
+       Intialisation routine, done through normal Sapphire architecture
+
+Environments
+
+       A SAIL environment contains the following sorts of information:
+
+         * A parent environment, from which this one inherits.  There is a
+           default environment provided by SAIL which interfaces to
+           important bits of Sapphire.
+
+         * The names and code for any CALLs which the environment supports.
+           We must ensure that we allow extension DLLs to add their own
+           CALLs into this structure somehow.
+
+       sail_createEnvironment
+
+       On entry:       R0 == parent environment handle, or 0
+                       R1 == address of CALL table
+
+       On exit:        R0 == environment handle
+                       May return an error
+
+       Use:            Creates an environment
+
+       CALL table format
+
+       string          name of this CALL
+       align
+       word            address to call
+       ...
+       word            0
+
+       sail_addCalls
+
+       On entry:       R0 == environment handle
+                       R1 == address of new call table
+
+       On exit:        May return an error (but probably not)
+
+       Use:            Adds an extra CALL table to an environment.  Useful
+                       for extension DLLs.
+
+Initialising a script
+
+       Initialisation of a script requires the following information:
+
+         * An environment to attach the script to.
+
+         * A global variable pool which it can play with.
+
+         * How often to pre-empt the script while it's running.
+
+         * A flex block/filename containing the text.
+
+       After all the excitement of building data structures and tokenising
+       the script, you end up with a script handle.
+
+
+       sail_initScript
+
+       On entry:       R0 == flex block handle of file
+                       R1 == environment handle to attach script to
+                       R2 == flex anchor of global variable pool
+                       R3 == how often to pre-empt the script (-1 == don't)
+
+       On exit:        R0 == script handle
+
+       Use:            Tokenises the script, set up global labels etc.
+
+
+       sail_killScript
+
+       On entry:       R0 == handle of the script
+
+       On exit:        --
+
+       Use:            Removes all the information associates with a given
+                       script.
+
+Running a script
+
+       Given a script handle, we can start executing by:
+
+         * running a particular procedure
+
+         * starting from a line number
+
+         * evaluating an expression in the script's context
+
+         * where it is at the moment (if it was pre-empted)
+
+
+       sail_goto
+
+       On entry:       R0 == handle of the script
+                       R1 == name of label (may contain really strange
+                         chars), or 0 for start
+
+       On exit:        R1 == 0 if finished, else more to go
+
+       Use:            Starts executing the script from the given label.
+
+       sail_contine
+
+       On entry:       R0 == handle of the script
+
+       On exit:        R1 == 0 if finished, else more to go
+
+       Use:            Executes the script from its current position.  This
+                       is used for scripts which can be pre-empted.
+
+       sail_eval
+
+       On entry:       R0 == handle of the script
+                       R1 == pointer to string to evaluate
+
+       On exit:        R1 == 0 if finished, else more to go
+
+       Use:            Evaluates the given string.
+
+       sail_proc
+
+       On entry:       R0 == handle of the script
+                       R1 == pointer to parameter block
+
+       On exit:        R1 == 0 if finished, else more to go
+
+       Use:            Calls the given procedure by binding to arguments
+                       in the block to the formal arguments of the
+                       procedure definition.
+
+       The block looks like this:
+
+       Word            Variable type
+       Data            Variable data
+       ...
+       -1
+
+
+Variable handling
+~~~~~~~~~~~~~~~~~
+
+Global variables
+
+       Access to the global variable pool is done via the `@' symbol.  All
+       label, procedure, function and variable names may be preficed by an
+       @, in which case the varible is looked up in the global pool.
+
+
+Useful routines
+
+
+       sail_createPool
+
+       On entry:       --
+
+       On exit:        R0 == handle of an empty variable pool
+                       May return an error
+
+       Use:            Creates a variable pool, so you can attach it as a
+                       global variable pool to a script.
+
+       sail_findVar
+
+       On entry:       R0 == script handle
+                       R1 == name of variable
+                       R2 == type of variable to find
+
+       On exit:        CS if variable found, and
+                         R1,R2 == lvalue of the variable
+                       else CC
+
+       sail_createVar
+
+       On entry:       R0 == script handle
+                       R1 == name of variable
+                       R2 == type of variable to create
+
+       On exit:        R1,R2 == lvalue of variable
+
+
+       sail_load
+
+       On entry:       R0 == script handle
+                       R1,R2 == lvalue of variable
+
+       On exit:        R3,R4 == rvalue of variable
+
+
+       sail_store
+
+       On entry:       R0 == script handle
+                       R1,R2 == lvalue of variable
+                       R3,R4 == new rvalue to write
+
+       On exit:        --
+
+       Note that we use appropriate floating point registers (i.e. F1
+       instead of R1 etc.) if the variables have floating point values.
+
+Important CALLs to have available
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+       Sail_Expand
+       Sail_CallAddress
+
+
+Example button code
+~~~~~~~~~~~~~~~~~~~
+
+       CALL "Dbox_Create","myTemplate" TO myDbox%
+       CALL "Dbox_EventHandler",myDbox%,"myDboxHandler"
+       CALL "Dbox_Open",myDbox%
+       END
+
+       DEF PROCmyDboxHandler(reason%,args%)
+       CASE reason% OF
+         WHEN 4
+           CALL "Sail_Expand",args% TO ,buttons%
+           CALL "Dbox_Slab",4
+           ...
+           CALL "Dbox_Unslab"
+         ...
+       ENDCASE
+       ENDPROC
+
+
+The transmogrification of TermScript (nah!) into SAIL (whuppeeee!)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+       Use flex memory management
+       Allow for floatinng point variables
+       Add SAIL API
+       Do new global variable handling
+       No more RAM grabbing (use alloc)
+       Removal of Termite specific commands
+       New CALL syntax (slightly)
+       Enviroment handing
+       Error handling
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/ctrl b/StraySrc/Libraries/Sapphire/sail/_s/ctrl
new file mode 100644 (file)
index 0000000..b67869d
--- /dev/null
@@ -0,0 +1,3222 @@
+;
+; ctrl.s
+;
+; Control flow handling
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.divide
+               GET     sh.errNum
+               GET     sh.error
+               GET     sh.express
+               GET     sh.getToken
+               GET     sh.interp
+               GET     sh.mem
+               GET     sh.stracc
+               GET     sh.strBucket
+               GET     sh.termite
+               GET     sh.termscript
+               GET     sh.tokens
+               GET     sh.tree
+               GET     sh.var
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+;----- Execution stack handling ---------------------------------------------
+
+; --- ctrl__pushFrame ---
+;
+; On entry:    R0 == type of frame to create
+;
+; On exit:     R0 == address of frame data to fill in
+;
+; Use:         Creates a new frame of the given type on the execution stack.
+
+ctrl__pushFrame        ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+               MOV     R3,R0                   ;Look after thing to push
+               ADR     R14,ctrl__frSize        ;Point to frame size table
+               LDRB    R4,[R14,R3]             ;Load the frame size
+               ADR     R1,tsc_execStack        ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               ADD     R5,R1,R4                ;New used size
+               ADD     R1,R5,#255              ;Align to next size thing
+               BIC     R1,R1,#255              ;Finish the align
+               CMP     R1,R2                   ;Has it got too big?
+               BLGT    mem_realloc             ;Yes -- get more space then
+               STRGT   R1,tsc_execStkSize      ;Store new size maybe
+               STR     R5,tsc_execStkPtr       ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R0,R0,R5                ;Address to put next thing on
+               STR     R3,[R0,#-4]             ;Store the new frame type
+               SUB     R0,R0,R4                ;And return frame base addr
+               LDMFD   R13!,{R1-R5,PC}^        ;And return to caller
+
+               LTORG
+
+; --- ctrl__peekFrame ---
+;
+; On entry:    --
+;
+; On exit:     R0 == type of topmost frame
+;              R1 == base address of frame
+;
+; Use:         Returns the type of the topmost frame, so a routine can
+;              work out if it needs to be removed.
+
+ctrl__peekFrame        ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               ADR     R0,tsc_execStack        ;Point to stack info block
+               LDMIA   R0,{R0,R1}              ;Load anchor addr and sp
+               LDR     R0,[R0]                 ;WimpExt_Heap's oddness again
+               ADD     R14,R0,R1               ;Find top of the stack
+               LDR     R0,[R14,#-4]            ;Load the frame type
+               ADR     R1,ctrl__frSize         ;Find the frame size table
+               LDRB    R1,[R1,R0]              ;Load the size of this entry
+               SUB     R1,R14,R1               ;Find base of this frame
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- ctrl__popFrame ---
+;
+; On entry:    --
+;
+; On exit:     R0 == frame type
+;              R1 == base address of frame
+;
+; Use:         Pops the top stack frame off the execution stack.  A pointer
+;              to the frame's data is returned; this data is *still on
+;              the stack*, so be careful about pushing more on.
+
+ctrl__popFrame ROUT
+
+               STMFD   R13!,{R2-R5,R14}        ;Save some registers
+               ADR     R1,tsc_execStack        ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+               LDR     R14,[R0]                ;Load the actual base address
+               ADD     R14,R14,R1              ;Find the top of the stack
+               LDR     R3,[R14,#-4]            ;Load type of top frame
+               ADR     R14,ctrl__frSize        ;Point to frame size table
+               LDRB    R5,[R14,R3]             ;And get the frame size
+
+               SUB     R4,R1,R5                ;The new size
+               ADD     R1,R4,#255              ;Align up again
+               BIC     R1,R1,#255              ;Aligned down
+               ADD     R1,R1,#256              ;At more than we need
+               CMP     R1,R2                   ;Has this size changed?
+               BLLT    mem_realloc             ;Yes -- reduce memory reqs.
+               STRLT   R1,tsc_execStkSize      ;Store new size maybe
+               STR     R4,tsc_execStkPtr       ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R1,R0,R4                ;Find the frame base address
+               MOV     R0,R3                   ;And get the frame type
+               LDMFD   R13!,{R2-R5,PC}^        ;And return to caller
+
+               LTORG
+
+ctrl__frSize   DCB     cFor__size+4
+               DCB     cWhile__size+4
+               DCB     cRepeat__size+4
+
+               DCB     cGosub__size+4
+               DCB     cLocal__size+4
+               DCB     cReturn__size+4
+               DCB     cProc__size+4
+               DCB     cFn__size+4
+               DCB     cDead__size+4
+
+;----- Command handlers -----------------------------------------------------
+
+; --- ctrl_let ---
+
+               EXPORT  ctrl_let
+ctrl_let       ROUT
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Leave that on the stack
+               CMP     R9,#'='                 ;Is this an assignment op?
+               BNE     %10ctrl_let             ;No -- maybe more complex
+               BL      getToken                ;Get another token
+               MOV     R0,#0                   ;Read a general expression
+               BL      express_read            ;Read that nicely
+
+               BL      express_popTwo          ;Pop two values off the stack
+               BL      ctrl_store              ;Stuff one into the other
+               B       interp_next             ;Move on to next instruction
+
+               ; --- Try other assignment ops then ---
+
+10             CMP     R7,#tClass_assign       ;Is it an assign op?
+               MOVNE   R0,#err_mistake         ;No -- that's a mistake
+               BNE     error_report            ;So complain at someone
+
+               ; --- Read the rvalue ---
+
+               MOV     R6,R8                   ;Look after the index
+               BL      getToken                ;Get another token
+               BL      express_pop             ;Pop off the lvalue
+               BL      ctrl_load               ;Load it's value
+               STMFD   R13!,{R0,R1}            ;Look after the lvalue
+               MOV     R0,#0                   ;Read a general expression
+               BL      express_read            ;Read that nicely
+               BL      express_pop             ;Pop the rvalue
+               MOV     R4,R0                   ;Look after rvalue
+               MOV     R5,R1
+               LDMFD   R13!,{R0,R1}            ;Load the lvalue back
+
+               ADD     PC,PC,R6,LSL #2         ;Jump to the right routine
+               DCB     "TMA!"
+
+               B       %20ctrl_let             ;+=
+               B       %30ctrl_let             ;-=
+               B       %40ctrl_let             ;*=
+               B       %50ctrl_let             ;/=
+
+               ; --- The operations ---
+               ;
+               ; Addition.
+
+20             CMP     R3,#vType_string
+               BEQ     %25ctrl_let
+               CMP     R3,#vType_integer
+               MOVNE   R0,#err_arrayBad
+               BNE     error_report
+               CMP     R5,#vType_integer
+               MOVNE   R0,#err_numNeeded
+               BNE     error_report
+               ADD     R2,R2,R4
+               BL      ctrl_store
+               B       interp_next
+
+25             CMP     R5,#vType_string        ;This is a string I hope
+               MOVNE   R0,#err_strNeeded       ;No -- get error number
+               BNE     error_report            ;...and report the error
+
+               MOV     R14,R4,LSL #24          ;Get the second string len
+               CMN     R14,R2,LSL #24          ;Is the string short enough?
+               ADDCC   R2,R2,R14,LSR #24       ;Add on second length
+               BLCC    ctrl_store
+               BCC     interp_next
+
+               MOV     R0,#err_strTooLong      ;String is too long
+               B       error_report
+
+               ; --- Subtraction ---
+
+30             CMP     R3,#vType_integer
+               CMPEQ   R5,#vType_integer
+               MOVNE   R0,#err_numNeeded
+               BNE     error_report
+               SUB     R2,R2,R4
+               BL      ctrl_store
+               B       interp_next
+
+               ; --- Multiplication ---
+
+40             CMP     R3,#vType_integer
+               CMPEQ   R5,#vType_integer
+               MOVNE   R0,#err_numNeeded
+               BNE     error_report
+               MUL     R2,R4,R2
+               BL      ctrl_store
+               B       interp_next
+
+               ; --- Division ---
+
+50             CMP     R3,#vType_integer
+               CMPEQ   R5,#vType_integer
+               MOVNE   R0,#err_numNeeded
+               BNE     error_report
+               STMFD   R13!,{R0,R1}
+               MOV     R0,R2
+               MOV     R1,R4
+               BL      divide
+               MOV     R2,R0
+               LDMFD   R13!,{R0,R1}
+               BL      ctrl_store
+               B       interp_next
+
+               LTORG
+
+; --- ctrl_timeEq ---
+
+               EXPORT  ctrl_timeEq
+ctrl_timeEq    ROUT
+
+               CMP     R9,#'='                 ;Next char must be `='
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the equals sign
+               MOV     R0,#0                   ;Read the expression
+               BL      express_read
+               BL      express_pop             ;Pop the result
+               CMP     R1,#vType_integer       ;It must be an integer
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+               MOV     R1,R0                   ;Look after this result
+               SWI     OS_ReadMonotonicTime    ;Find the current real time
+               SUB     R0,R0,R1                ;Work out the correct offset
+               STR     R0,tsc_timeOff          ;Store it away nicely
+               B       interp_next             ;And read another instruction
+
+               LTORG
+
+; --- ctrl_for ---
+
+               EXPORT  ctrl_for
+ctrl_for       ROUT
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Leave that on the stack
+               CMP     R9,#'='                 ;We now need an equals
+               MOVNE   R0,#err_eqInFor         ;If we don't have it, moan
+               BNE     error_report
+               BL      getToken                ;Skip over the equals sign
+               MOV     R0,#0                   ;Read the base value
+               BL      express_read
+               CMP     R9,#tok_to              ;Make sure we have a TO
+               MOVNE   R0,#err_expTo           ;If we don't have it, moan
+               BNE     error_report
+               BL      getToken                ;Skip over the TO token
+               MOV     R0,#0                   ;Read the end value
+               BL      express_read
+               CMP     R9,#tok_step            ;Is there a STEP?
+               BLEQ    getToken                ;Yes -- get another token
+               MOVEQ   R0,#0                   ;...read another rvalue
+               BLEQ    express_read
+               BLEQ    express_pop             ;...and get this value
+               MOVNE   R0,#1                   ;Otherwise use sensible value
+               MOVNE   R1,#vType_integer
+
+               ; --- Create the stack frame ---
+
+               STMFD   R13!,{R0,R1}            ;Save step again for a bit
+               MOV     R0,#cFrame__for         ;Create a FOR loop frame
+               BL      ctrl__pushFrame         ;Stick that on the stack
+               MOV     R4,R0                   ;Look after the frame pointer
+               LDMFD   R13!,{R0,R1}            ;Load the step value again
+               CMP     R1,#vType_integer       ;Check it's an integer
+               BNE     ctrl__notAnInt          ;If not, complain
+               STR     R0,[R4,#cFor__step]     ;Save the step away
+
+               BL      express_pop             ;Find the end marker
+               CMP     R1,#vType_integer       ;Check it's an integer
+               BNE     ctrl__notAnInt          ;If not, complain
+               STR     R0,[R4,#cFor__end]      ;Stuff that in the end pos
+
+               BL      express_popTwo          ;Get ctrl var and start pos
+               CMP     R1,#vType_lvInt         ;Ensure lvalue is integral
+               CMPNE   R1,#vType_lvWord
+               CMPNE   R1,#vType_lvByte
+               MOVNE   R0,#err_badForVar       ;If not, find suitable error
+               BNE     error_report            ;And tell the user
+               BL      ctrl_store              ;Initialise it nicely
+               ADD     R14,R4,#cFor__lval      ;Find the lvalue position
+               STMIA   R14,{R0,R1}             ;Save that away too
+
+               ADD     R14,R4,#cFor__resume    ;Point to resume buffer
+               LDR     R1,tsc_tokAnchor        ;Find anchor of script buff
+               LDR     R1,[R1]                 ;SODDING WIMPEXTENSION!!!
+               SUB     R1,R10,R1               ;Work out current offset
+               LDR     R0,tsc_line             ;Get the current line number
+               STMIA   R14,{R0,R1}             ;Save these in the frame
+
+               B       interp_next             ;Move on to next instruction
+
+               LTORG
+
+; --- ctrl_next ---
+
+               EXPORT  ctrl_next
+ctrl_next      ROUT
+
+               ; --- First check for identifier ---
+               ;
+               ; If there is one, we need to search for a specific FOR
+               ; frame.  Otherwise any old one will do.
+
+               SUBS    R14,R9,#'_'             ;Is this an identifier?
+               SUBNE   R14,R9,#'A'             ;No -- check for uppercase
+               CMP     R14,#26
+               SUBCS   R14,R9,#'a'             ;No -- check for lowercase
+               CMPCS   R14,#26
+
+               ; --- Read the lvalue given ---
+
+               MOVCC   R0,#1                   ;Read an lvalue
+               BLCC    express_read            ;And put it on the stack
+               BLCC    express_pop             ;Get it in registers
+               MOVCS   R1,#-1                  ;Otherwise get bogus value
+               MOV     R2,R0                   ;Look after the lvalue
+               MOV     R3,R1                   ;And the type
+10             MOV     R0,#cFrame__for         ;Look for a FOR frame
+               BL      ctrl__findFrame         ;Try to find the frame
+               MOVCC   R0,#err_noFor           ;Complain if we hit routine
+               BCC     error_report
+               ADD     R14,R1,#cFor__lval      ;Find the lvalue
+               LDMIA   R1,{R4,R5}              ;Load them out nicely
+               CMP     R2,R4                   ;Now check for a match
+               CMPEQ   R3,R5                   ;Check the type too
+               CMPNE   R3,#-1                  ;Or maybe we don't care
+               BLNE    ctrl__popFrame          ;No match -- discard frame
+               BNE     %10ctrl_next            ;And loop back round
+
+               ; --- Now step the variable ---
+
+               MOV     R6,R1                   ;Look after frame base
+               MOV     R0,R4                   ;Get the original lvalue back
+               MOV     R1,R5                   ;And its type
+               BL      ctrl_load               ;Load the current value
+               LDR     R4,[R6,#cFor__step]     ;Load the step size
+               ADD     R2,R2,R4                ;Bump the loop counter
+               BL      ctrl_store              ;Save the modified counter
+               LDR     R14,[R6,#cFor__end]     ;Find the end limit
+               CMP     R4,#0                   ;Are we going backwards?
+               SUBGT   R14,R2,R14              ;Yes -- subtract this way
+               SUBLT   R14,R14,R2              ;Otherwise the other way
+               CMP     R14,#0                  ;Now which way do we go?
+               BGT     %50ctrl_next            ;Finished the loop -- stop
+
+               ; --- Now resume from the FOR loop ---
+
+               ADD     R14,R6,#cFor__resume    ;Find the resume point
+               LDMIA   R14,{R0,R1}             ;Load the line and offset
+               STR     R0,tsc_line             ;Save the line counter
+               LDR     R14,tsc_tokAnchor       ;Find the anchor of the file
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R1              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrack to read prev token
+               MOV     R9,#0                   ;Give bogus current token
+               BL      getToken                ;Read this token
+               B       interp_next             ;And continue merrily
+
+               ; --- Now see if there's more loops to close ---
+
+50ctrl_next    BL      ctrl__popFrame          ;Remove defunct FOR frame
+               CMP     R9,#','                 ;Do we have more loops?
+               BLEQ    getToken                ;Yes -- skip the comma
+               BEQ     ctrl_next               ;And close them too
+
+               B       interp_next             ;Finished this instruction
+
+               LTORG
+
+; --- ctrl_repeat ---
+
+               EXPORT  ctrl_repeat
+ctrl_repeat    ROUT
+
+               MOV     R0,#cFrame__repeat      ;Create a REPEAT frame
+               BL      ctrl__pushFrame         ;Stick that on the stack
+               LDR     R2,tsc_tokAnchor        ;Find anchor of script buff
+               LDR     R2,[R2]                 ;SODDING WIMPEXTENSION!!!
+               SUB     R2,R10,R2               ;Work out current offset
+               LDR     R1,tsc_line             ;Get the current line number
+               STMIA   R0,{R1,R2}              ;Save these in the frame
+               B       interp_exec             ;Get the next instruction
+
+               LTORG
+
+; --- ctrl_until ---
+
+               EXPORT  ctrl_until
+ctrl_until     ROUT
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read an expression
+               BL      express_pop             ;Read it then
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- complain then
+               MOV     R2,R0                   ;Look after the result
+
+               ; --- Find the REPEAT frame ---
+
+               MOV     R0,#cFrame__repeat      ;Look for a REPEAT frame
+               BL      ctrl__findFrame         ;Try to find the frame
+               MOVCC   R0,#err_noRepeat        ;Complain if we hit routine
+               BCC     error_report
+
+               CMP     R2,#0                   ;Should we REPEAT?
+               BLNE    ctrl__popFrame          ;No -- pop the repeat frame
+               BNE     interp_next             ;No -- just continue then
+
+               ; --- Go back to the REPEAT ---
+
+               LDMIA   R1,{R0,R1}              ;Load the line and offset
+               STR     R0,tsc_line             ;Save the line counter
+               LDR     R14,tsc_tokAnchor       ;Find the anchor of the file
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R1              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrack to read prev token
+               MOV     R9,#-1                  ;Give bogus current token
+               BL      getToken                ;Read this token
+               B       interp_exec             ;And continue merrily
+
+               LTORG
+
+; --- ctrl_while ---
+
+               EXPORT  ctrl_while
+ctrl_while     ROUT
+
+               ; --- Push a while frame on the stack ---
+
+               MOV     R0,#cFrame__while       ;Create a REPEAT frame
+               BL      ctrl__pushFrame         ;Stick that on the stack
+               LDR     R2,tsc_tokAnchor        ;Find anchor of script buff
+               LDR     R2,[R2]                 ;SODDING WIMPEXTENSION!!!
+               SUB     R2,R10,R2               ;Work out current offset
+               LDR     R1,tsc_line             ;Get the current line number
+               STMIA   R0,{R1,R2}              ;Save these in the frame
+
+               ; --- Read the expression ---
+
+               MOV     R0,#0                   ;Read an expression
+               BL      express_read            ;Read it ithen
+               BL      express_pop             ;Pop the resut
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- that's bad then
+               CMP     R0,#0                   ;Is is FALSE?
+               BNE     interp_exec             ;No -- continue then
+
+               ; --- Scan for the first ENDWHILE then ---
+
+               MOV     R2,#0                   ;Keep a nesting count
+               LDR     R4,tsc_line             ;Get current line number
+10ctrl_while   BL      getToken                ;Get another token
+               CMP     R9,#&FF                 ;Reached the end yet?
+               BEQ     %90ctrl_while           ;If so, moan about ENDWHILE
+               CMP     R9,#tok_while           ;Is it a WHILE token?
+               ADDEQ   R2,R2,#1                ;Yes -- bump nesting count
+
+               CMP     R9,#tok_endwhile        ;Yes -- check for ENDWHILE
+               SUBEQ   R2,R2,#1                ;Yes -- decrement nesting
+               CMP     R2,#0                   ;Have we dropped out?
+               BGE     %10ctrl_while           ;No -- loop
+
+               ; --- We found the ENDWHILE ---
+
+               BL      getToken                ;Get the next token
+               BL      ctrl__popFrame          ;Get rid of my WHILE frame
+               B       interp_next             ;And execute from here
+
+               ; --- We fell off the end -- oops ---
+
+90ctrl_while   STR     R4,tsc_line             ;Save bogus line back
+               MOV     R0,#err_expEndwhile     ;Hmm... should have had an...
+               B       error_report            ;ENDWHILE somewhere
+
+               LTORG
+
+; --- ctrl_endwhile ---
+
+               EXPORT  ctrl_endwhile
+ctrl_endwhile  ROUT
+
+               ; --- Find the ENDWHILE frame ---
+
+               MOV     R0,#cFrame__while       ;Look for a REPEAT frame
+               BL      ctrl__findFrame         ;Try to find the frame
+               MOVCC   R0,#err_noWhile         ;Complain if we hit routine
+               BCC     error_report
+
+               ; --- Remember where we are ---
+
+               LDR     R2,tsc_line             ;Get the line number
+               MOV     R3,R10                  ;And our position
+
+               ; --- Go back to the WHILE ---
+
+               LDMIA   R1,{R0,R1}              ;Load the line and offset
+               STR     R0,tsc_line             ;Save the line counter
+               LDR     R14,tsc_tokAnchor       ;Find the anchor of the file
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R1              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrack to read prev token
+               MOV     R9,#-1                  ;Give bogus current token
+               BL      getToken                ;Read this token
+
+               ; --- Now read the expression ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the value
+               CMP     R0,#0                   ;Should we go from here?
+               BNE     interp_exec             ;Yes -- execute then
+
+               ; --- Execute from the ENDWHILE ---
+
+               BL      ctrl__popFrame          ;Pop the WHILE frame
+               SUB     R10,R3,#1               ;Set R10 up
+               STR     R2,tsc_line             ;Store the line number
+               MOV     R9,#-1                  ;Make getToken happy
+               BL      getToken                ;Get a token then
+               B       interp_next             ;And execute happily
+
+               LTORG
+
+; --- ctrl__readLabel ---
+;
+; On entry:    --
+;
+; On exit:     CS if there was a label and,
+;                R0 == pointer to the label node
+;                R1, R2 corrupted
+;              CC otherwise
+;
+; Use:         Reads a label fromthe current position, and looks it
+;              up inthe symbol table.
+
+ctrl__readLabel        ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link
+
+               ADR     R2,tsc_misc             ;Point to a nice buffer
+               SUBS    R14,R9,#'_'             ;Is it a valid characer?
+               SUBNE   R14,R9,#'A'
+               CMP     R14,#26
+               SUBCS   R14,R9,#'a'
+               CMPCS   R14,#26
+               SUBCS   R14,R9,#'0'
+               CMPCS   R14,#10
+               BCS     %90ctrl__readLabel      ;No -- bark then
+               STRB    R9,[R2],#1              ;And store in the buffer
+
+10             BL      getToken                ;Get the next character
+               SUBS    R14,R9,#'_'             ;Is it a valid characer?
+               SUBNE   R14,R9,#'A'
+               CMP     R14,#26
+               SUBCS   R14,R9,#'a'
+               CMPCS   R14,#26
+               SUBCS   R14,R9,#'0'
+               CMPCS   R14,#10
+               STRCCB  R9,[R2],#1              ;Yes -- store in the buffer
+               BCC     %10ctrl__readLabel      ;...and keep on looping
+
+               MOV     R14,#0
+               STRB    R14,[R2],#1
+
+               ; --- Now find the node ---
+
+               MOV     R0,#vType_label         ;This is a label
+               ADR     R1,tsc_misc             ;Point at the name
+               BL      tree_find               ;Try to find it
+               MOVCC   R0,#err_noLabel         ;Not there -- complain
+               BCC     error_report
+
+               LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#C_flag          ;Return 'label here'
+
+               ; --- The label was bad --
+
+90             LDMFD   R13!,{R14}              ;Load the link back
+               BICS    PC,R14,#C_flag          ;Return 'no label'
+
+               LTORG
+
+; --- ctrl_gosub ---
+
+               EXPORT  ctrl_gosub
+ctrl_gosub     ROUT
+
+               ; --- Read the label ---
+
+               BL      ctrl__readLabel         ;Read a label
+               BCC     %90ctrl_gosub           ;No there -- barf
+               MOV     R3,R0                   ;Look after node address
+
+               ; --- Push a GOSUB frame ---
+
+               MOV     R0,#cFrame__gosub       ;Create a REPEAT frame
+               BL      ctrl__pushFrame         ;Stick that on the stack
+               LDR     R2,tsc_tokAnchor        ;Find anchor of script buff
+               LDR     R2,[R2]                 ;SODDING WIMPEXTENSION!!!
+               SUB     R2,R10,R2               ;Work out current offset
+               LDR     R1,tsc_line             ;Get the current line number
+               STMIA   R0,{R1,R2}              ;Save these in the frame
+
+               ; --- Branch off somewhere ---
+
+               LDMIB   R3,{R0,R1}              ;Load out address/line
+               STR     R1,tsc_line             ;Store the line number
+               LDR     R1,tsc_tokAnchor        ;Load anchor address
+               LDR     R1,[R1,#0]              ;WimpExtension is bollocks
+               MOV     R9,#-1                  ;Don't confuse getToken
+               ADD     R10,R0,R1               ;This is where we are
+               BL      getToken                ;Prime the lookahead token
+               LDR     R14,tsc_flags           ;Load the flags word
+               BIC     R14,R14,#tscFlag_nl     ;Clear the newline flag
+               STR     R14,tsc_flags           ;Store the flasg back
+               B       interp_exec             ;Execute from here!
+
+90ctrl_gosub   MOV     R0,#err_expLabel        ;Get the error number
+               B       error_report            ;Report the error
+
+               LTORG
+
+; --- ctrl_return ---
+
+               EXPORT  ctrl_return
+ctrl_return    ROUT
+
+               MOV     R0,#cFrame__gosub       ;Look for a GOSUB frame
+               BL      ctrl__findFrame         ;Try to find the frame
+               MOVCC   R0,#err_notInSub        ;Complain if not a GOSUB
+               BCC     error_report
+               BL      ctrl__popFrame          ;Pop off the frame
+               LDMIA   R1,{R0,R1}              ;Load the line and offset
+               STR     R0,tsc_line             ;Save the line counter
+               LDR     R14,tsc_tokAnchor       ;Find the anchor of the file
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R1              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrac a little
+               MOV     R9,#-1                  ;Give bogus current token
+               BL      getToken                ;Read this token
+               B       interp_next             ;And continue merrily
+
+; --- ctrl_if ---
+
+               EXPORT  ctrl_if
+ctrl_if                ROUT
+
+               LDR     R14,tsc_flags           ;Load the flags word
+               BIC     R14,R14,#tscFlag_nl     ;Clear the newline flag
+               STR     R14,tsc_flags           ;Store the flasg back
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read
+               BL      express_pop             ;Get that value
+               CMP     R1,#vType_integer       ;It must be an integer
+               MOVNE   R0,#err_numNeeded       ;Isn't -- get error
+               BNE     error_report            ;And report the error
+               CMP     R0,#0                   ;Should we execute this?
+               BEQ     %10ctrl_if              ;No -- look for the else
+
+               CMP     R9,#tok_then            ;Is there a THEN here?
+               BLEQ    getToken                ;Yes -- skip over it then
+               B       interp_exec             ;And just execute from here
+
+               ; --- Look for an ELSE statement ---
+
+10ctrl_if      CMP     R9,#tok_then            ;Do we have a THEN then?
+               BNE     %30ctrl_if              ;No -- search line for else
+
+               BL      getToken                ;Get another token
+               CMP     R9,#&0a                 ;Is this a return?
+               BNE     %30ctrl_if              ;No -- search line then
+
+               ; --- Now look for ELSE ... ENDIF structure ---
+
+               MOV     R3,#0                   ;My counter thing
+               LDR     R4,tsc_line             ;Get the current line
+
+20ctrl_if      MOV     R2,R9                   ;Remmber the previous char
+               BL      getToken                ;Skip over the return
+               CMP     R9,#&FF                 ;Is this the end of file?
+               BEQ     %50ctrl_if              ;Yes -- jump ahead
+               CMP     R2,#&0a                 ;Was prev a newline?
+               CMPNE   R9,#&0a                 ;Or even this one?
+               BNE     %20ctrl_if              ;Neither -- keep looping
+
+               CMP     R2,#tok_then            ;Did we just read a then
+               ADDEQ   R3,R3,#1                ;Yes -- increment the count
+               BEQ     %20ctrl_if              ;And keep on looping
+
+               CMP     R9,#tok_else            ;Or an else?
+               CMPEQ   R3,#0                   ;Yes -- at bottom level?
+               CMPNE   R9,#tok_endif           ;Is this an endif?
+               SUBEQ   R3,R3,#1                ;Yes -- decrement the count
+               CMP     R3,#0                   ;Are we ready to execute?
+               BGE     %20ctrl_if              ;No -- loop then
+
+               BL      getToken                ;Get the next token
+               B       interp_next             ;Execute from here!
+
+               ; --- Search on the same line ---
+
+30ctrl_if      MOV     R0,R9                   ;Look after this char
+               CMP     R9,#&FF                 ;At end of file?
+               BLNE    getToken                ;No -- read next token
+               CMPNE   R0,#tok_else            ;Stop at ELSE tokens
+               CMPNE   R0,#&0a                 ;And at line end
+               BNE     %30ctrl_if              ;If not, loop back again
+               B       interp_exec             ;And carry on going
+
+               ; -- Missing ENDIF ---
+
+50ctrl_if      STR     R4,tsc_line             ;Store original line number
+               MOV     R0,#err_expEndif        ;Get the error number
+               B       error_report            ;And report the error
+
+               LTORG
+
+; --- ctrl_else ---
+
+               EXPORT  ctrl_else
+ctrl_else      ROUT
+
+               LDR     R0,tsc_flags            ;Load the flags word
+               TST     R0,#tscFlag_nl          ;Have we just had a newline?
+               BNE     %20ctrl_else            ;Yes -- look for an ENDIF
+
+               ; --- Search for the line end ---
+
+10ctrl_else    MOV     R0,R9                   ;Look after old token
+               CMP     R9,#&FF                 ;Is this the EOF
+               BLNE    getToken                ;No - get a token
+               CMP     R0,#&0a                 ;Was it the line end?
+               BNE     %10ctrl_else            ;No -- keep on looking
+               B       interp_next             ;Execute from here
+
+               ; --- Look for an ENDIF ---
+
+20ctrl_else    MOV     R3,#0                   ;My counter thing
+               LDR     R4,tsc_line             ;Get the current line
+               MOV     R2,#0                   ;Dummy previous char
+               B       %45ctrl_else
+
+40ctrl_else    MOV     R2,R9                   ;Remember the previous token
+               BL      getToken                ;Get a new one
+45ctrl_else    CMP     R9,#&FF                 ;Is this the end of file?
+               BEQ     %50ctrl_else            ;Yes -- jump ahead
+               CMP     R2,#&0a                 ;Was prev a newline?
+               CMPNE   R9,#&0a                 ;Or even this one?
+               BNE     %40ctrl_else            ;Neither -- keep looping
+
+               CMP     R2,#tok_then            ;Did we just read a then
+               ADDEQ   R3,R3,#1                ;Yes -- increment the count
+               BEQ     %40ctrl_else            ;And keep on looping
+
+               CMP     R9,#tok_endif           ;Is this an endif?
+               SUBEQ   R3,R3,#1                ;Yes -- decrement the count
+               CMP     R3,#0                   ;Are we ready to execute?
+               BGE     %40ctrl_else            ;No -- loop then
+
+               BL      getToken                ;Get the next token
+               B       interp_next             ;Execute from here!
+
+               ; -- Missing ENDIF ---
+
+50ctrl_else    STR     R4,tsc_line             ;Store original line number
+               MOV     R0,#err_expEndif        ;Get the error number
+               B       error_report            ;And report the error
+
+               LTORG
+
+; --- ctrl_goto ---
+
+               EXPORT  ctrl_goto
+ctrl_goto      ROUT
+
+               BL      ctrl__readLabel         ;Read the label
+               BCC     %90ctrl_goto            ;Not there -- barf
+
+               LDMIB   R0,{R0,R1}              ;Load out address/line
+               STR     R1,tsc_line             ;Store the line number
+               LDR     R1,tsc_tokAnchor        ;Load anchor address
+               LDR     R1,[R1,#0]              ;WimpExtension is bollocks
+               MOV     R9,#-1                  ;Don't confuse getToken
+               ADD     R10,R0,R1               ;This is where we are
+               BL      getToken                ;Prime the lookahead token
+               LDR     R14,tsc_flags           ;Load the flags word
+               BIC     R14,R14,#tscFlag_nl     ;Clear the newline flag
+               STR     R14,tsc_flags           ;Store the flasg back
+               B       interp_exec             ;Execute from here!
+
+90ctrl_goto    MOV     R0,#err_expLabel        ;Get the error number
+               B       error_report            ;Report the error
+
+               LTORG
+
+; --- ctrl_case ---
+
+               EXPORT  ctrl_case
+ctrl_case      ROUT
+
+               MOV     R0,#0                   ;Read the comparand
+               BL      express_read
+               BL      express_pop             ;Read the value of that
+               CMP     R1,#vType_integer       ;Is it an integer?
+               CMPNE   R1,#vType_string        ;Or a string?
+               MOVNE   R0,#err_arrayBad        ;No -- then point to error
+               BNE     error_report            ;And report the error
+               MOV     R2,R0                   ;Look after compare value
+               MOV     R3,R1                   ;And the type too, please
+
+               CMP     R9,#tok_of              ;We pointlessly expect `OF'
+               MOVNE   R0,#err_expOf           ;If not there, complain
+               BNE     error_report
+               BL      getToken                ;Get the next token
+               CMP     R9,#&0A                 ;This must be the line end
+               MOVNE   R0,#err_afterCase       ;If not, complain annoyingly
+               BNE     error_report
+
+               ; --- Now keep an eye out for WHENs and OTHERWISEs ---
+
+               MOV     R5,#0                   ;Keep a nesting count
+               LDR     R6,tsc_line             ;Get current line number
+10ctrl_case    MOV     R4,R9                   ;Look after previous char
+               BL      getToken                ;Get another token
+               CMP     R9,#&FF                 ;Reached the end yet?
+               BEQ     %90ctrl_case            ;If so, moan about ENDCASE
+               CMP     R9,#tok_case            ;Is it a CASE token?
+               ADDEQ   R5,R5,#1                ;Yes -- bump nesting count
+               CMP     R4,#&0A                 ;Was previous newline?
+               BNE     %10ctrl_case            ;No -- nothing doing here
+
+               CMP     R5,#0                   ;At bottom nesting level?
+               CMPEQ   R9,#tok_otherwise       ;Yes -- check for OTHERWISE
+               CMPNE   R9,#tok_endcase         ;Or maybe an ENDCASE?
+               SUBEQ   R5,R5,#1                ;Yes -- decrement nesting
+               CMP     R5,#0                   ;Have we dropped out?
+               BLLT    getToken                ;Yes -- get the next token
+               BLT     %80ctrl_case            ;Yes -- start executing
+               CMPEQ   R9,#tok_when            ;Now check for a W
+               BNE     %10ctrl_case            ;No -- loop
+               BL      getToken                ;Get another token
+
+               ; --- Found a WHEN -- check for a match ---
+
+11ctrl_case    MOV     R0,#0                   ;Read an rvalue
+               BL      express_read
+               BL      express_pop             ;Get result from the stack
+               BL      ctrl_compare            ;Compare the values
+               BEQ     %15ctrl_case            ;Match -- skip other exprs
+               CMP     R1,#vType_string        ;Did we load a string?
+               BLEQ    stracc_free             ;Yes -- reomve the string
+               CMP     R9,#','                 ;Comma next?
+               BLEQ    getToken                ;Yes -- skip it
+               BEQ     %11ctrl_case            ;And try next expression
+               B       %10ctrl_case            ;Otherwise hope we get lucky
+
+               ; --- Skip other expressions ---
+               ;
+               ; BASIC allows extreme bogosity here, and so shall we.
+
+15ctrl_case    CMP     R1,#vType_string        ;Did we load a string?
+               BLEQ    stracc_free             ;Yes -- reomve the string
+00             CMP     R5,#0                   ;Are we quoted?
+               CMPEQ   R9,#':'                 ;No -- check for colon
+               CMPNE   R9,#&0A                 ;Newline?
+               BEQ     %80ctrl_case            ;Yes -- let it rip
+               CMP     R9,#'"'                 ;Is this a quote?
+               EOREQ   R5,R5,#1                ;Yes -- toggle quoted bit
+               BL      getToken                ;Get another token
+               B       %b00                    ;And keep going
+
+               ; --- Return to interp_next, removing str from stracc ---
+
+80ctrl_case    CMP     R3,#vType_string        ;Were we dealing with a str?
+               MOVEQ   R0,R2                   ;Yes -- put it in R0
+               BLEQ    stracc_free             ;...and remove it from stracc
+               B       interp_next             ;Keep on interpreting
+
+               ; --- We fell off the end -- oops ---
+
+90ctrl_case    STR     R6,tsc_line             ;Save bogus line back
+               MOV     R0,#err_expEndcase      ;Hmm... should have had an...
+               B       error_report            ;ENDCASE somewhere
+
+               LTORG
+
+; --- ctrl_when ---
+
+               EXPORT  ctrl_when
+
+; --- ctrl_otherwise ---
+
+               EXPORT  ctrl_otherwise
+
+ctrl_when      ROUT
+ctrl_otherwise
+
+               MOV     R3,#0                   ;My counter thing
+               LDR     R4,tsc_line             ;Get the current line
+               MOV     R2,#0                   ;Dummy previous char
+               B       %45ctrl_when
+
+40ctrl_when    MOV     R2,R9                   ;Remember the previous token
+               BL      getToken                ;Get a new one
+45ctrl_when    CMP     R9,#&FF                 ;Is this the end of file?
+               BEQ     %50ctrl_when            ;Yes -- jump ahead
+               CMP     R9,#tok_case            ;Did we just read a CASE
+               ADDEQ   R3,R3,#1                ;Yes -- increment the count
+               BEQ     %40ctrl_when            ;And keep on looping
+               CMP     R2,#&0a                 ;Was prev a newline?
+               CMPEQ   R9,#tok_endcase         ;Is this an endcase?
+               SUBEQ   R3,R3,#1                ;Yes -- decrement the count
+               CMP     R3,#0                   ;Are we ready to execute?
+               BGE     %40ctrl_when            ;No -- loop then
+
+               BL      getToken                ;Get the next token
+               B       interp_next             ;Execute from here!
+
+               ; -- Missing ENDCASE ---
+
+50ctrl_when    STR     R4,tsc_line             ;Store original line number
+               MOV     R0,#err_expEndcase      ;Get the error number
+               B       error_report            ;And report the error
+
+               LTORG
+
+; --- ctrl_end ---
+
+               EXPORT  ctrl_end
+ctrl_end       ROUT
+
+               MOV     R0,#0
+               B       tsc_end
+
+               LTORG
+
+; --- ctrl_swap ---
+
+               EXPORT  ctrl_swap
+ctrl_swap      ROUT
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read
+               CMP     R9,#','                 ;Do we have a comma?
+               MOVNE   R0,#err_expComma        ;No -- get the error number
+               BNE     error_report            ;And report the error
+               BL      getToken                ;Skip over the comma
+               MOV     R0,#1                   ;Read another lvalue
+               BL      express_read
+               BL      express_popTwo          ;Pop off the two lvalues
+
+               ; --- Swap the contents of the lvalues ---
+
+10ctrl_swap    MOV     R4,R2                   ;Look after parm 2
+               MOV     R5,R3
+               BL      ctrl_load               ;Load the parameter
+               STMFD   R13!,{R2,R3}            ;Store rvalue
+               STMFD   R13!,{R0,R1}            ;And lvalue
+               MOV     R0,R4                   ;Get the second one
+               MOV     R1,R5
+               BL      ctrl_load               ;Load it's value too
+               LDMFD   R13!,{R0,R1}            ;Get back lvalue
+               BL      ctrl_store              ;Store rvalue in lvalue
+               MOV     R0,R4                   ;Get the second one
+               MOV     R1,R5
+               LDMFD   R13!,{R2,R3}            ;Load rvalue
+               BL      ctrl_store              ;Complete the swap
+               B       interp_next             ;All over and happy
+
+               LTORG
+
+; --- ctrl_ptr ---
+
+               EXPORT  ctrl_ptr
+ctrl_ptr       ROUT
+
+               MOV     R0,#2                   ;Read an rvalue ident
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_integer       ;Is this a string?
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+               MOV     R3,R0                   ;Remember file handle
+
+               CMP     R9,#'='                 ;Next char must be `='
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the equals sign
+               MOV     R0,#0                   ;Read the expression
+               BL      express_read
+               BL      express_pop             ;Pop the result
+               CMP     R1,#vType_integer       ;It must be an integer
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+
+               MOV     R2,R0                   ;Put pointer in R2
+               MOV     R1,R3                   ;And handle in R1
+               MOV     R0,#1                   ;Write pointer
+               SWI     XOS_Args                ;Write the pointer
+               BVS     tsc_error               ;Report possible error
+
+               B       interp_next             ;And read another instruction
+
+               LTORG
+
+; --- ctrl_ext ---
+
+               EXPORT  ctrl_ext
+ctrl_ext       ROUT
+
+               MOV     R0,#2                   ;Read an rvalue ident
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_integer       ;Is this a string?
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+               MOV     R3,R0                   ;Remember file handle
+
+               CMP     R9,#'='                 ;Next char must be `='
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the equals sign
+               MOV     R0,#0                   ;Read the expression
+               BL      express_read
+               BL      express_pop             ;Pop the result
+               CMP     R1,#vType_integer       ;It must be an integer
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+
+               MOV     R2,R0                   ;Put extent in R2
+               MOV     R1,R3                   ;And handle in R1
+               MOV     R0,#3                   ;Write pointer
+               SWI     XOS_Args                ;Write the extent
+               BVS     tsc_error               ;Report possible error
+
+               B       interp_next             ;And read another instruction
+
+               LTORG
+
+; --- ctrl_close ---
+
+               EXPORT  ctrl_close
+ctrl_close     ROUT
+
+               MOV     R0,#2                   ;Read an rvalue ident
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_integer       ;Is this a string?
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+               MOV     R1,R0                   ;Remember file handle
+               MOV     R0,#0                   ;Close file
+               SWI     XOS_Find                ;Close it then
+               BVS     interp_next             ;And read another instr
+
+               AND     R0,R0,#&FF              ;Make sure this is a byte
+               ADR     R1,tsc_files            ;Find file bit-array
+               MOV     R14,R0,LSR #5           ;Get word index
+               LDR     R14,[R1,R14,LSL #2]!    ;Load the word I want
+               MOV     R2,#(1<<31)             ;Set the top bit here
+               BIC     R14,R14,R2,ROR R0       ;Clear the correct bit
+               STR     R14,[R1,#0]             ;Save the word back again
+               B       interp_next             ;And read another instr
+
+               LTORG
+
+; --- ctrl_bput ---
+
+               EXPORT  ctrl_bput
+ctrl_bput      ROUT
+
+               ; --- First, make sure we have a hash ---
+
+               CMP     R9,#'#'                 ;We must have a hash
+               MOVNE   R0,#err_expHash         ;No -- complain then
+               BNE     error_report            ;And report an error
+               BL      getToken                ;Get the next token
+
+               ; --- Now read the channel number ---
+
+               MOV     R0,#2                   ;Read an rvalue ident
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_integer       ;Is this a string?
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+               MOV     R3,R0                   ;Remember file handle
+
+               ; --- Skip over the comma ---
+
+               CMP     R9,#','                 ;Next char must be `,'
+               MOVNE   R0,#err_expComma        ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Now we read an expression ---
+
+               MOV     R0,#0                   ;Read the expression
+               BL      express_read
+               BL      express_pop             ;Pop the result
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BEQ     %10ctrl_bput            ;Yes -- jump ahead
+               CMP     R1,#vType_string        ;Make sure it is a string
+               MOVNE   R0,#err_arrayBad        ;Nope -- get error message
+               BNE     error_report            ;So if it isn't, complain
+
+               ; --- Write a string to the file ---
+
+               MOV     R5,R0                   ;Look after the value
+               LDR     R1,tsc_stracc           ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R4,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R1,R3                   ;Get the file handle
+               CMP     R2,#0                   ;Is this a short string?
+00             LDRGTB  R0,[R4],#1              ;Load a character
+               SWIGT   XOS_BPut                ;Put the byte
+               BVS     error_reportReal        ;Report possible error
+               SUBS    R2,R2,#1                ;Reduce the count
+               BGT     %b00                    ;And keep on goin'
+
+               MOV     R0,R5                   ;Put the string in R0
+               BL      stracc_free             ;Free it from stracc
+
+               CMP     R9,#';'                 ;Is there a semicolon now?
+               BLEQ    getToken                ;Yes -- get a token
+               MOVNE   R0,#10                  ;Get a terminator
+               SWINE   XOS_BPut                ;Put the byte
+               B       interp_next             ;And read another instruction
+
+               ; --- Just write a character ---
+
+10             MOV     R1,R3                   ;Get the file handle
+               SWI     XOS_BPut                ;Put the byte
+               BVS     error_reportReal        ;Report possible error
+               B       interp_next             ;And read another instruction
+
+               LTORG
+
+;----- Odds and sods --------------------------------------------------------
+
+; --- ctrl_error ---
+
+               EXPORT  ctrl_error
+ctrl_error     ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,tsc_stracc           ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,tsc_misc             ;Point to the misc buffer
+               MOV     R14,#1                  ;A sillu error number
+               STR     R14,[R0],#4             ;Store that
+               BL      ctrl_copyString         ;Copy the string over
+               ADR     R0,tsc_misc             ;Point to the misc buffer
+               B       tsc_error               ;Return the error
+
+               LTORG
+
+; --- ctrl_oscli ---
+
+               EXPORT  ctrl_oscli
+ctrl_oscli     ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,tsc_stracc           ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,tsc_misc             ;Point to the misc buffer
+               BL      ctrl_copyString         ;Copy the string over
+               SWI     OS_CLI                  ;Do the command
+               MOV     R0,R5                   ;Get the rvalue back
+               BL      stracc_free             ;Free the string from stracc
+               B       interp_next             ;Continue happily
+
+               LTORG
+
+
+
+;----- DATA and the like ----------------------------------------------------
+
+; --- ctrl__findDATA ---
+;
+; On entry:    All the normal things
+;
+; On exit:     R0 == *address* in file of next DATA
+;
+; Use:         Sets the internal data pointer to the first DATA statement
+;              fromthe current position.
+
+               EXPORT  ctrl_findDATA
+ctrl_findDATA  ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               LDR     R0,tsc_dataPtr          ;Load the current position
+               LDR     R1,tsc_tokAnchor        ;Load the anchor
+               LDR     R1,[R1]
+               ADD     R0,R1,R0                ;Point into the file
+               LDR     R2,tsc_dataLine         ;Line number of DATA
+
+               ; --- Search the file for DATA, or EOF ---
+
+00             LDRB    R14,[R0],#1             ;Load a byte
+               CMP     R14,#10                 ;Are we at a return?
+               ADDEQ   R2,R2,#1                ;Yes -- inc line number
+               CMP     R14,#&FF                ;Is this the EOF?
+               SUBEQ   R0,R0,#1                ;Yes -- point to it
+               CMPNE   R14,#tok_data           ;Did we read a DATA?
+               BNE     %b00                    ;No -- keep on looking
+
+90             SUB     R1,R0,R1                ;Get it as an offset
+               STR     R1,tsc_dataPtr          ;Save this away then
+               STR     R2,tsc_dataLine         ;And the line number
+               LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- ctrl_read ---
+
+               EXPORT  ctrl_read
+ctrl_read      ROUT
+
+               ; --- Point at the current position ---
+
+               LDR     R4,tsc_dataPtr          ;Load the current position
+               LDR     R5,tsc_tokAnchor        ;Load the anchor
+               LDR     R5,[R5]
+               ADD     R4,R5,R4                ;Point into the file
+
+00ctrl_read    LDRB    R14,[R4,#0]             ;Load the byte there
+               CMP     R14,#&FF                ;Is it the EOF?
+               MOVEQ   R0,#err_outOfDATA       ;Yes -- get error num
+               BEQ     error_report            ;And report the error
+               CMP     R14,#10                 ;Are we at the line end?
+               BLEQ    ctrl_findDATA           ;Yes -- find next data
+               MOVEQ   R4,R0                   ;...put ptr in R0
+               BEQ     %00ctrl_read            ;...and start again
+               CMP     R14,#','                ;Is it a comma?
+               ADDEQ   R4,R4,#1                ;Yes -- skip over it
+
+               ; --- Read an rvalue from this position ---
+
+               LDR     R6,tsc_line             ;Load the line number
+               STMFD   R13!,{R6-R10}           ;Stack position details
+               MOV     R10,R4                  ;Point just before data
+               LDR     R14,tsc_dataLine        ;Get the line number
+               STR     R14,tsc_line            ;Store as actual line
+               MOV     R9,#-1                  ;Make getToken happy
+               BL      getToken                ;Get a token
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get it off the stack
+               LDR     R14,tsc_line            ;Get line number
+               STR     R14,tsc_dataLine        ;Store as DATA line number
+               SUB     R4,R10,#1               ;Restore data pointer
+               LDMFD   R13!,{R6-R10}           ;Load back position
+               STR     R6,tsc_line             ;Restore line number
+               MOV     R2,R0                   ;Put rvalue in R2,R3
+               MOV     R3,R1
+
+               ; --- We are hopefully pointing at some data ---
+
+               MOV     R0,#1                   ;Prepare to read an lvalue
+               BL      express_read            ;Read one then
+               BL      express_pop             ;Get it off the stack
+               BL      ctrl_store              ;Store the rvalue
+
+               SUB     R14,R4,R5               ;Get data pointer as offset
+               STR     R14,tsc_dataPtr         ;Store this away
+               CMP     R9,#','                 ;Should we read more?
+               BLEQ    getToken                ;Yes -- skip over the comma
+               BEQ     %00ctrl_read            ;..and loop back again
+
+               B       interp_next             ;Do next instruction
+
+               LTORG
+
+; --- ctrl_restore ---
+
+               EXPORT  ctrl_restore
+ctrl_restore   ROUT
+
+               BL      ctrl__readLabel         ;Read the label
+               MOVCC   R0,#0                   ;Not there -- offset is 0
+               MOVCC   R1,#1                   ;Line is 1
+               LDMCSIB R0,{R0,R1}              ;Load out address/line
+
+               STR     R0,tsc_dataPtr          ;Save the data pointer
+               STR     R1,tsc_dataLine         ;And the line number
+               BL      ctrl_findDATA           ;Find the DATA
+               B       interp_next             ;And do the next instruction
+
+               LTORG
+
+;----- SYS and friends ------------------------------------------------------
+
+; --- ctrl_call ---
+
+               EXPORT  ctrl_call
+ctrl_call      ROUT
+
+               BL      ctrl_setUpRegs          ;Set up the regs then
+
+               CMP     R10,#vType_integer      ;Is this an integer?
+               MOVNE   R0,#err_numNeeded       ;No -- get error number
+               BNE     error_report            ;...and report the error
+
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R9                   ;Execute the code
+
+               ADRL    R9,ctrl__returned       ;Point to some space
+               STMIA   R9!,{R0-R8}             ;Store returned registers
+               MOV     R14,PC,LSR #28          ;Get the flags
+               STMIA   R9,{R14}                ;Strore the flags too
+               LDMFD   R13!,{R7-R12}           ;Load back position info
+               LDMFD   R13!,{R0}               ;Load stracc offset
+               BL      stracc_free             ;Free any strings I had
+
+               ; --- We have now done the SWI instr ---
+
+               ADRL    R0,ctrl__returned       ;Point to the returned regs
+               BL      ctrl_resolveRegs        ;Do the other half now
+               B       interp_next             ;If flags -- return
+
+               LTORG
+
+; --- ctrl_sys ---
+
+               EXPORT  ctrl_sys
+ctrl_sys       ROUT
+
+               BL      ctrl_setUpRegs          ;Set up the registers
+               STMFD   R13!,{R0-R8}            ;Stack these registers
+
+               CMP     R10,#vType_integer      ;Did user use an integer?
+               MOVEQ   R0,R9                   ;Yes -- use that then
+               BEQ     %10ctrl_sys             ;And jump ahead
+
+               ; --- Convert the name to a number ---
+
+               LDR     R1,tsc_stracc           ;Load the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R9,LSR #8         ;Point to the name
+               SWI     XOS_SWINumberFromString ;Convert it then
+               BVS     error_reportReal        ;Report possible error
+
+               ; --- We have the SWI number in R0 ---
+               ;
+               ; We build the following instructions on the stack:
+               ;
+               ;       SWI     <R0>
+               ;       MOV     PC,R14
+
+10             ORR     R9,R0,#&EF000000        ;Build the SWI instruction
+               LDR     R10,=&E1A0F00E          ;Get the MOV instr too
+               LDMFD   R13!,{R0-R8}            ;Load the registers
+               SUB     R13,R13,#8              ;Make some room
+               STMIA   R13,{R9,R10}            ;Stack code
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R13                  ;Call my code
+
+               ADD     R13,R13,#8              ;Get rid of my code
+               ADR     R9,ctrl__returned       ;Point to some space
+               STMIA   R9!,{R0-R8}             ;Store returned registers
+               MOV     R14,PC,LSR #28          ;Get the flags
+               STMIA   R9,{R14}                ;Strore the flags too
+               LDMFD   R13!,{R7-R12}           ;Load back position info
+               LDMFD   R13!,{R0}               ;Load stracc offset
+               BL      stracc_free             ;Free any strings I had
+
+               ; --- We have now done the SWI instr ---
+
+               ADR     R0,ctrl__returned       ;Point to the returned regs
+               BL      ctrl_resolveRegs        ;Do the other half now
+               B       interp_next             ;Do the next instruction
+
+ctrl__returned DCD     0,0,0,0,0,0,0,0,0,0,0
+
+               LTORG
+
+; --- ctrl_setUpRegs ---
+;
+; On entry:    R7-R10 == position info
+;
+; On exit:     R0-R8 set up for sys call
+;              R9,R10 == rvalue of first parameter
+;              On the stack:
+;                new position info, R7-R12
+;                place to stracc free
+;
+; Use:         Sets up all the registers as required by a SYS or SYSCALL
+;              command.
+
+               EXPORT  ctrl_setUpRegs
+ctrl_setUpRegs ROUT
+
+               MOV     R3,R14                  ;Look after the link
+               BL      stracc_ensure           ;Get current stracc offset
+               STMFD   R13!,{R1}               ;Put it on the stack
+               MOV     R5,#0                   ;Might be useful
+
+               ; --- Read the complusory argument ---
+
+               MOV     R0,#0                   ;It's an rvalue
+               BL      express_read            ;Read the expression
+               BL      express_pop             ;Pop it
+               BL      express_push            ;Push it again
+
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BEQ     %f00                    ;Yes -- go round again then
+               CMP     R1,#vType_string        ;Was it a string?
+               MOVNE   R0,#err_arrayBad        ;No -- get error number
+               BNE     error_report            ;And report the error
+               BL      stracc_ensure           ;If it was -- ensure room
+               STRB    R5,[R0,#0]              ;...store a terminator
+               AND     R0,R0,#3                ;Get the alignment
+               RSB     R0,R0,#4
+               ORR     R0,R1,R0                ;...set up the rvalue
+               BL      stracc_added            ;Tell stracc about this
+
+               ; --- Now read all other parameters ---
+
+00             MOV     R2,#0                   ;Mask of regs read
+               MOV     R4,#0                   ;Number we have read
+00             CMP     R9,#','                 ;Do we have a comma?
+               BNE     %10ctrl_setUpRegs       ;No -- we have finshed then
+05             ADD     R4,R4,#1                ;Increment the counter
+               CMP     R4,#8                   ;Have we read 8?
+               MOVEQ   R0,#err_sysTooManyI     ;Yes -- get error number
+               BEQ     error_report            ;And report the error
+               BL      getToken                ;Skip over the comma
+               CMP     R9,#','                 ;Another comma?
+               MOVEQ   R2,R2,LSL #1            ;Yes -- shift R2 along
+               BEQ     %b05                    ;And go back for more
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               MOV     R2,R2,LSL #1            ;Shift R2 along
+               ORR     R2,R2,#1                ;And set the bit
+               BL      express_pop             ;Get it off the stack
+               BL      express_push            ;Oh -- better not!
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BEQ     %b00                    ;Yes -- go round again then
+               CMP     R1,#vType_string        ;Was it a string?
+               MOVNE   R0,#err_arrayBad        ;No -- get error number
+               BNE     error_report            ;And report the error
+               BL      stracc_ensure           ;If it was -- ensure room
+               STRB    R5,[R0]                 ;...store a terminator
+               AND     R0,R0,#3                ;Get the alignment
+               RSB     R0,R0,#4
+               ORR     R0,R1,R0                ;...set up the rvalue
+               BL      stracc_added            ;Tell stracc about this
+               B       %b00                    ;And go round for more
+
+               ; --- We have read the input parameters ---
+               ;
+               ; We must put the position infor on the stack before
+               ; the link here, so that it remains on the stack at return
+               ; time.
+
+10             STMFD   R13!,{R7-R12}           ;Stack position info
+               STMFD   R13!,{R3}               ;And then stack the link!
+               LDR     R9,tsc_stracc           ;Load the stracc anchor
+               LDR     R9,[R9]                 ;Get it's address
+               MOV     R10,R2                  ;Put the mask in R10
+
+               ; --- Now transfer the info to R0-R8 ---
+               ;
+               ; Each routine is padded to eight bytes, for niceness (?)
+               ; To start, we set everything to
+
+               MOV     R14,R4                  ;Look after number of regs
+               MOV     R0,#0
+               MOV     R1,#0
+               MOV     R2,#0
+               MOV     R3,#0
+               MOV     R4,#0
+               MOV     R5,#0
+               MOV     R6,#0
+               MOV     R7,#0
+               MOV     R8,#0
+
+               CMP     R14,#0                  ;Read no registers?
+               BEQ     %30ctrl_setUpRegs       ;Indeed -- jump ahead then
+               RSB     R14,R14,#9              ;Make R4 right
+               ADD     R14,R14,R14,LSL #1      ;Multiply by 3
+               ADDS    PC,PC,R14,LSL #3        ;Jump to the routine (*24)
+               DCB     "TMA!"                  ;Pad pad pad pad...
+
+28             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %27ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R8,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R8,R0                   ;No -- it's an integer then
+
+27             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %26ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R7,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R7,R0                   ;No -- it's an integer then
+
+26             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %25ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R6,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R6,R0                   ;No -- it's an integer then
+
+25             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %24ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R5,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R5,R0                   ;No -- it's an integer then
+
+24             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %23ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R4,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R4,R0                   ;No -- it's an integer then
+
+23             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %22ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R3,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R3,R0                   ;No -- it's an integer then
+
+22             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %21ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R2,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R2,R0                   ;No -- it's an integer then
+
+21             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %20ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R1,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R1,R0                   ;No -- it's an integer then
+
+20             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %30ctrl_setUpRegs       ;No go -- jump ahead then
+               STMFD   R13!,{R1}               ;Stack R1
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R0,R9,R0,LSR #8         ;Yes -- point to string
+               LDMFD   R13!,{R1}               ;Restore R1
+
+               ; --- All the registers are now set up, phew! ---
+
+30             STMFD   R13!,{R0,R1}            ;Stack some registers
+               BL      express_pop             ;Get off first arg!
+               MOV     R9,R0                   ;Put rvalue in R9,R10
+               MOV     R10,R1
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- ctrl_resolveRegs ---
+;
+; On entry:    R0 == pointer to register block
+;
+; On exit:     CS if flags were required, CC otherwise
+;
+; Use:         Resolves the registers returned from a SYS or SYSCALL
+;              into the appropriate variables.  The code assumes that
+;              we have possibly just read a TO command, and goes on
+;              from there.
+
+               EXPORT  ctrl_resolveRegs
+ctrl_resolveRegs ROUT
+
+               ; --- See if we require register return ---
+
+               CMP     R9,#tok_to              ;Do we have a TO?
+               MOVNES  PC,R14                  ;No -- return PDQ then
+
+               STMFD   R13!,{R0-R6,R14}        ;Stack registers
+               BL      getToken                ;Skip over the TO
+               MOV     R4,R0                   ;Put the block in R4
+               MOV     R5,#0                   ;Number read so far
+               ADD     R6,R4,#9*4              ;Point tothe flags
+
+00             CMP     R9,#':'                 ;Is this the end?
+               CMPNE   R9,#10
+               CMPNE   R9,#&FF
+               CMPNE   R9,#tok_else
+               BEQ     %90ctrl_resolveRegs     ;Yes -- return then
+               CMP     R9,#','                 ;Do we skip this one?
+               ADDEQ   R4,R4,#4                ;Yes -- go onto next reg
+               ADDEQ   R5,R5,#1                ;We have done this many
+               CMP     R5,#9                   ;Is this reg 9?
+               MOVEQ   R0,#err_sysTooManyO     ;Yes -- get error number
+               BEQ     error_report            ;And report then error
+               CMP     R9,#','                 ;Compare again with comma
+               BLEQ    getToken                ;Yes -- skip the comma
+               BEQ     %b00                    ;Keep on going
+
+               ; --- We must read one then ---
+               ;
+               ; Actually, we may be reading the flags too.
+
+               CMP     R9,#';'                 ;Do we have a semicolon?
+               BEQ     %30ctrl_resolveRegs     ;Yes -- deal with it then
+
+               MOV     R0,#1                   ;We are reading an lvalue
+               BL      express_read            ;Read it
+               BL      express_pop             ;Pop it off the stack
+               BL      ctrl_load               ;Load the value
+               CMP     R3,#vType_integer       ;Is it an integer?
+               BEQ     %20ctrl_resolveRegs     ;Yes -- jump ahead
+
+               CMP     R3,#vType_string        ;Is it a string then?
+               MOVNE   R0,#err_arrayBad        ;No -- get error number
+               BNE     error_report            ;And report the error
+
+               ; --- We have to return a string ---
+
+               STMFD   R13!,{R0,R1}            ;Look after the lvalue
+               MOV     R0,R2                   ;Put the rvalue in R0
+               BL      stracc_free             ;Free the string from stracc
+
+               LDR     R2,[R4,#0]              ;Load the string address
+               BL      stracc_ensure           ;Make sure we have room
+               MOV     R3,#0                   ;Length so far
+
+10             LDRB    R14,[R2],#1             ;Load a byte
+               CMP     R14,#0                  ;Is it 0?
+               STRNEB  R14,[R0],#1             ;No -- store it then
+               ADDNE   R3,R3,#1                ;...increment the length
+               BNE     %b10                    ;And go round for more
+
+               ORR     R0,R1,R3                ;Create the rvalue
+               BL      stracc_added            ;Tell stracc about this
+               MOV     R2,R0                   ;Put rvalue in R2 too
+               MOV     R3,#vType_string        ;This is a string
+               LDMFD   R13!,{R0,R1}            ;Load the lvalue back
+               BL      ctrl_store              ;Store the new value
+               B       %b00                    ;Go round again
+
+               ; --- It's just an integer then ---
+
+20             LDR     R2,[R4,#0]              ;Load the integer
+               BL      ctrl_store              ;Store this result
+               B       %b00                    ;Go round again
+
+               ; --- We must read the flags ---
+
+30             BL      getToken                ;Skip over the ';'
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get it off the stack
+               BL      ctrl_load               ;Load the current value
+               CMP     R3,#vType_integer       ;Is it an integer?
+               MOVNE   R0,#err_numNeeded       ;No -- get error number
+               BNE     error_report            ;And report the error
+               LDR     R2,[R6,#0]              ;Load the flags word
+               BL      ctrl_store              ;Store the new value
+               LDMFD   R13!,{R0-R6,R14}        ;Load back registers
+               ORRS    PC,R14,#C_flag          ;Return with C set
+
+90             LDMFD   R13!,{R0-R6,R14}        ;Load back registers
+               BICS    PC,R14,#C_flag          ;Return with C clear
+
+               LTORG
+
+;----- Function/Procedure call ----------------------------------------------
+
+; --- FN ---
+;
+; OK, maybe it shouldn't be here.  I don't really care.
+;
+; Hack warning:        This is a hack.  We unwind express_read's stack and stuff
+;              them away somewhere completely different.
+
+               EXPORT  ctrl_fn
+ctrl_fn                ROUT
+
+               ; --- First we need to make a FN frame ---
+               ;
+               ; This involves taking a copy of express_read's stack and
+               ; stuffing it into the frame so we can restore it afterwards.
+               ; This basically means that we can recurse mightily without
+               ; using any R13 stack space.  Huzzah!
+
+               MOV     R0,#cFrame__fn          ;Get the frame type
+               BL      ctrl__pushFrame         ;Push the frame
+               LDR     R14,tsc_oldAnchor       ;Load the old anchor address
+               STR     R14,[R0,#cFn__anchor]   ;Save it in the frame
+               STR     R6,[R0,#cFn__flags]     ;Save express_read's flags
+               STMFD   R13!,{R0}               ;Save some register
+               BL      stracc_ensure           ;Get current strac position
+               LDMFD   R13!,{R0}               ;Load registers back again
+               STR     R1,[R0,#cFn__stracc]    ;Save this away
+               LDR     R14,tsc_currAnchor      ;Load the current anchor
+               STR     R14,tsc_oldAnchor       ;Save this as the old one
+               LDR     R14,tsc_tokAnchor       ;Now we work from the file
+               STR     R14,tsc_currAnchor      ;So set this as current one
+
+               ADD     R14,R0,#cFn__stack+32   ;Find the stack copy bit
+               LDMFD   R13!,{R1-R4}            ;Load some registers
+               STMFD   R14!,{R1-R4}            ;Save them into the frame
+               LDMFD   R13!,{R1-R4}            ;Load some registers again
+               STMFD   R14!,{R1-R4}            ;Save them into the frame
+
+               ; --- Now get on with the business of calling ---
+
+               LDR     R1,tsc_execStack        ;Load the stack anchor
+               LDR     R1,[R1,#0]              ;Tycho bops WimpExtension
+               SUB     R6,R0,R1                ;Turn into an offset
+
+               ; --- Substitute the arguments ---
+
+               MOV     R0,#vType_fn            ;This is a FN
+               BL      ctrl__subArgs           ;Substitute the args
+
+               LDR     R0,tsc_execStack        ;Load the stack anchor
+               LDR     R0,[R0,#0]              ;Tycho bops WimpExtension
+               ADD     R0,R0,R6                ;Point to my frame
+               STMIA   R0,{R3,R4}              ;Save the return point away
+
+               B       interp_exec             ;Execute next instruction
+
+               LTORG
+
+; --- = ---
+
+               EXPORT  ctrl_equals
+ctrl_equals    ROUT
+
+               ; --- First, evaluate the argument ---
+
+               MOV     R0,#0                   ;Get an rvalue for it
+               BL      express_read            ;Read the expression
+               CMP     R9,#&0A                 ;Now at end of line?
+               CMPNE   R9,#':'                 ;Or end of statement (weird)
+               CMPNE   R9,#&FF                 ;Or end of file?
+               CMPNE   R9,#tok_else            ;Or an ElSE?
+               MOVNE   R0,#err_syntax          ;No -- that's a cock-up
+               BNE     error_report            ;So be righteous about it
+
+               ; --- If the result is a string, copy it ---
+
+               BL      express_pop             ;Pop off the result
+               MOV     R4,R0                   ;Put the rvalue in R4
+               MOV     R5,R1                   ;And the type in R5
+               CMP     R5,#vType_string        ;Is it a string?
+               BNE     %10ctrl_equals          ;No -- jump ahead
+
+               ; --- Copy the string elsewhere ---
+               ;
+               ; We do this since there may be local strings that are
+               ; removed from stracc, underneath the result.
+
+               LDR     R1,tsc_stracc           ;Load stracc's anchor
+               LDR     R1,[R1]                 ;Load the address
+               ADD     R1,R1,R4,LSR #8         ;Point to the string
+
+               ADR     R0,tsc_misc             ;Point to a misc buffer
+               ANDS    R2,R4,#&FF              ;Get the length
+               BEQ     %10ctrl_equals          ;Nothin' doin', jump
+
+00             LDRB    R14,[R1],#1             ;Load a byte
+               STRB    R14,[R0],#1             ;Store a byte
+               SUBS    R2,R2,#1                ;Reduce counter
+               BNE     %b00                    ;Do this lots
+               MOV     R0,R4                   ;Put the rvalue in R0
+               BL      stracc_free             ;Free the string
+
+               ; --- Find the frame thing ---
+
+10ctrl_equals  MOV     R0,#cFrame__fn          ;Search for a FN frame
+               BL      ctrl__unwind            ;Look for one of these then
+               MOVCC   R0,#err_notInFn         ;Get possible error num
+               BCC     error_report            ;And report the error
+               MOV     R6,R1                   ;Look after frame address
+
+               ; --- Put stracc in the right place ---
+
+               LDR     R0,[R6,#cFn__stracc]    ;Load the offset
+               BL      stracc_free             ;Okaydokey
+
+               ; --- Reset other things ---
+
+               LDMIA   R1,{R0,R1}              ;Load the line and offset
+               STR     R1,tsc_line             ;Save the line counter
+               LDR     R14,tsc_oldAnchor       ;Find the anchor of the file
+               STR     R14,tsc_currAnchor      ;This is the current one
+               LDR     R1,[R6,#cFn__anchor]    ;Load the saved anchor
+               STR     R1,tsc_oldAnchor        ;This is the old one
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R0              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrack a little
+               MOV     R9,#-1                  ;Give bogus current token
+               BL      getToken                ;Read this token
+
+               ; --- Put a string result back on stracc ---
+
+               MOV     R0,R4                   ;Get the rvalue
+               MOV     R1,R5                   ;And the type
+               CMP     R1,#vType_string        ;Was it a string?
+               BNE     %20ctrl_equals          ;No -- jump ahead
+
+               ; --- Copy the result back into stracc ---
+
+               BL      stracc_ensure           ;Make sure we have room
+               ADR     R2,tsc_misc             ;Point to our string
+               ANDS    R3,R4,#&FF              ;Get the length
+               BEQ     %15ctrl_equals          ;Very short -- jump
+00             LDRB    R14,[R2],#1             ;Load a byte
+               STRB    R14,[R0],#1             ;Store a byte
+               SUBS    R3,R3,#1                ;Reduce a counter
+               BNE     %b00                    ;Lots more please
+
+15             ANDS    R3,R4,#&FF              ;Get the length again
+               ORR     R0,R1,R3                ;Put the rvalue in R0
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+20             BL      express_push            ;Push this result
+
+               ; --- Now we need to return to express_read ---
+               ;
+               ; Hack warning: This is a hack.
+
+               ADD     R14,R6,#cFn__stack      ;Find stack contents
+               LDMFD   R14!,{R0-R3}            ;Load contents out
+               STMFD   R13!,{R0-R3}            ;Stuff them back on the stack
+               LDMFD   R14!,{R0-R3}
+               STMFD   R13!,{R0-R3}
+               LDR     R6,[R6,#cFn__flags]     ;Restore express_read's flags
+               B       express_fnCont          ;And resume horridly
+
+               LTORG
+
+; --- PROC ---
+
+               EXPORT  ctrl_proc
+ctrl_proc      ROUT
+
+               ; --- First, we push a PROC frame onto the stack ---
+
+               MOV     R0,#cFrame__proc        ;Push on this type
+               BL      ctrl__pushFrame         ;Push on the frame
+               LDR     R14,tsc_oldAnchor       ;Get the old anchor
+               STR     R14,[R0,#cProc__anchor] ;Save it in the frame
+               LDR     R14,tsc_tokAnchor       ;Args must be in the file
+               STR     R14,tsc_oldAnchor       ;So read them from there
+               STMFD   R13!,{R0}               ;Save some register
+               BL      stracc_ensure           ;Get current strac position
+               LDMFD   R13!,{R0}               ;Load registers back again
+               STR     R1,[R0,#cProc__stracc]  ;Save this away
+               LDR     R1,tsc_execStack        ;Load the stack anchor
+               LDR     R1,[R1,#0]              ;Tycho bops WimpExtension
+               SUB     R6,R0,R1                ;Turn into an offset
+
+               ; --- Substitute the arguments ---
+
+               MOV     R0,#vType_proc          ;This is a PROC
+               BL      ctrl__subArgs           ;Substitute the args
+
+               LDR     R0,tsc_execStack        ;Load the stack anchor
+               LDR     R0,[R0,#0]              ;Tycho bops WimpExtension
+               ADD     R0,R0,R6                ;Point to my frame
+               STMIA   R0,{R3,R4}              ;Save the return point away
+               LDR     R14,[R0,#cProc__anchor] ;Load anchor we saved above
+               STR     R14,tsc_oldAnchor       ;Re-instate this again
+
+               B       interp_exec             ;Execute next instruction
+
+               LTORG
+
+; --- ENDPROC ---
+
+               EXPORT  ctrl_endproc
+ctrl_endproc   ROUT
+
+               MOV     R0,#cFrame__proc        ;Search for a PROC frame
+               BL      ctrl__unwind            ;Look for one of these then
+               MOVCC   R0,#err_notInProc       ;Get possible error num
+               BCC     error_report            ;And report the error
+
+               LDR     R0,[R1,#cProc__stracc]  ;Load the offset
+               BL      stracc_free             ;Okaydokey
+
+               LDMIA   R1,{R0,R1}              ;Load the line and offset
+               STR     R1,tsc_line             ;Save the line counter
+               LDR     R14,tsc_tokAnchor       ;Find the anchor of the file
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R0              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrac a little
+               MOV     R9,#-1                  ;Give bogus current token
+               BL      getToken                ;Read this token
+               B       interp_next             ;And continue merrily
+
+               LTORG
+
+; --- DATA ---
+
+               EXPORT  ctrl_data
+ctrl_data
+
+; --- DEF  ---
+
+               EXPORT  ctrl_def
+
+ctrl_def       ROUT
+
+               ; --- Simply search for a newline! ---
+
+00             CMP     R9,#10                  ;Is this a newline?
+               CMPNE   R9,#&FF                 ;Or the EOF?
+               BNE     getToken                ;No -- get another token
+               BNE     %b00                    ;...get another one then
+               B       interp_next             ;And carry on as before
+
+               LTORG
+
+; --- LOCAL ---
+
+               EXPORT  ctrl_local
+ctrl_local     ROUT
+
+               ; --- We read lots of lvalues, and create local frames ---
+
+00             MOV     R0,#cFrame__local       ;We want a local frame
+               BL      ctrl__pushFrame         ;Create the frame then
+               MOV     R5,R0                   ;Look after the address
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Go to it then
+               BL      express_pop             ;Pop it off
+               BL      ctrl_load               ;Load its value out
+               STMIA   R5,{R0-R3}              ;Store this in the frame
+
+               CMP     R9,#','                 ;Do we have a comma now?
+               BLEQ    getToken                ;Yes -- gobble it up
+               BEQ     %b00                    ;...and do another one
+
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+; --- ctrl__subArgs ---
+;
+; On entry:    R0 == type of routine to find
+;
+; On exit:     R3 == offset of return point
+;              R4 == line number of return point
+;              R0-R2, R5 corrupted
+;
+; Use:         Performs argument substitution.  The next token to read
+;              should be the name of the routine to execute.  On exit,
+;              the interpreter will begin execution of the routine.
+
+ctrl__subArgs  ROUT
+
+               ; --- A nasty macro ---
+               ;
+               ; Swap between the two states
+
+               MACRO
+               READARG
+               LDR     R0,tsc_oldAnchor
+               LDR     R0,[R0]
+               MOV     R14,R10
+               SUB     R10,R3,#1
+               ADD     R10,R10,R0
+               LDR     R0,tsc_currAnchor
+               LDR     R0,[R0]
+               SUB     R3,R14,R0
+               LDR     R14,tsc_line
+               STR     R4,tsc_line
+               MOV     R4,R14
+               MOV     R9,#-1
+               BL      getToken
+               MEND
+
+               MACRO
+               READDEF
+               LDR     R0,tsc_currAnchor
+               LDR     R0,[R0]
+               MOV     R14,R10
+               SUB     R10,R3,#1
+               ADD     R10,R10,R0
+               LDR     R0,tsc_oldAnchor
+               LDR     R0,[R0]
+               SUB     R3,R14,R0
+               LDR     R14,tsc_line
+               STR     R4,tsc_line
+               MOV     R4,R14
+               MOV     R9,#-1
+               BL      getToken
+               MEND
+
+               ; --- Now get on with it ---
+               ;
+               ; We're calling express_read during the first part of this,
+               ; so we don't have the luxury of a stack...
+
+               MOV     R5,R14                  ;Remember the return address
+
+               ; --- First, get the PROC/FN name ---
+
+               ADR     R2,tsc_misc             ;Point to a nice buffer
+               SUBS    R14,R9,#'_'             ;Is it a valid characer?
+               SUBNE   R14,R9,#'A'
+               CMP     R14,#26
+               SUBCS   R14,R9,#'a'
+               CMPCS   R14,#26
+               SUBCS   R14,R9,#'0'
+               CMPCS   R14,#10
+               MOVCS   R0,#err_badCall         ;No -- get error then
+               BCS     error_report            ;And report it
+               STRB    R9,[R2],#1              ;And store in the buffer
+
+00             BL      getToken                ;Get the next character
+               SUBS    R14,R9,#'_'             ;Is it a valid characer?
+               SUBNE   R14,R9,#'A'
+               CMP     R14,#26
+               SUBCS   R14,R9,#'a'
+               CMPCS   R14,#26
+               SUBCS   R14,R9,#'0'
+               CMPCS   R14,#10
+               STRCCB  R9,[R2],#1              ;Yes -- store in the buffer
+               BCC     %b00                    ;...and keep on looping
+
+               MOV     R14,#0
+               STRB    R14,[R2],#1
+
+               ; --- Now find the PROC/FN ---
+
+               ADR     R1,tsc_misc             ;Point to the name
+               BL      tree_find               ;Try to find the thing
+               MOVCC   R0,#err_noProc          ;Not there -- complain
+               BCC     error_report
+               LDMIB   R0,{R3,R4}              ;Load out address/line
+               ADD     R3,R3,#1                ;Skip past the proc
+
+               ; --- First, see if we have an open banana ---
+
+               SUBS    R1,R9,#'('              ;Do we have actual arguments?
+               BLEQ    getToken                ;Yes -- gobble the bracket
+               MOVNE   R1,#1                   ;No -- remember this then
+               READDEF                         ;Swap to the def
+               SUBS    R2,R9,#'('              ;Do we have formal args?
+               BLEQ    getToken                ;Yes -- gobble the bracket
+               MOVNE   R2,#1                   ;No -- remember this then
+               CMP     R1,R2                   ;Are both the same?
+               MOVNE   R0,#err_badArgs         ;No -- get an error
+               BNE     error_report            ;So report it then
+               CMP     R1,#0                   ;Any arguments?
+               BNE     %90ctrl__subArgs        ;No -- just tidy up then
+
+               MOV     R2,#0                   ;No arguments read yet
+
+               ; --- Stage 1: Read actual and formal arguments ---
+               ;
+               ; Here we will build 3 records on the val stack for each
+               ; argument:
+               ;
+               ;   If argument is RETURN, lvalue of actual arg, else 0
+               ;   rvalue of actual arg (read to avoid aliassing problems)
+               ;   lvalue of formal arg
+
+10ctrl__subArgs        CMP     R9,#tok_return          ;Is this a RETURN token?
+               BLEQ    getToken                ;If so, gobble it
+               READARG                         ;Swap back to the call
+               BNE     %f00                    ;No -- skip to read rvalue
+
+               ; --- Read lvalue for actual arg ---
+
+               MOV     R0,#1                   ;Read the lvalue here
+               BL      express_read            ;Read that please
+               STMFD   R13!,{R2,R3}            ;Save some registers
+               BL      express_pop             ;Pop the lvalue
+               BL      ctrl_load               ;Load the rvalue out
+               BL      express_push            ;Push the lvalue back
+               MOV     R0,R2                   ;Get the rvalue now
+               MOV     R1,R3                   ;And its type, please
+               BL      express_push            ;Push that too
+               LDMFD   R13!,{R2,R3}            ;Restore my registers
+               B       %f01                    ;Now skip to handling formal
+
+               ; --- Read rvalue for actual arg ---
+
+00             MOV     R1,#-1                  ;Mark a strange lvalue type
+               BL      express_push            ;Push that on
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Do that then
+
+               ; --- Now swap and read the formal argument ---
+
+01             ADD     R2,R2,#1                ;Bump argument counter
+               CMP     R9,#')'                 ;Is this a close bracket?
+               CMPNE   R9,#','                 ;Or maybe a comma?
+               MOVNE   R0,#err_badCall         ;No -- that's an error
+               BNE     error_report            ;So complain about it
+               MOV     R1,R9                   ;Look after this token
+               BL      getToken                ;Gobble the token
+
+               READDEF                         ;Swap back to the DEF
+               MOV     R0,#1                   ;Read an lvalue now
+               BL      express_read            ;Read the expression
+
+               CMP     R9,#')'                 ;Is this a close bracket?
+               CMPNE   R9,#','                 ;Or maybe a comma?
+               MOVNE   R0,#err_expBracket      ;No -- error (odd BASIC one)
+               BNE     error_report            ;So complain about it
+
+               CMP     R1,R9                   ;Do these match?
+               MOVNE   R0,#err_badArgs         ;No -- someone can't count
+               BNE     error_report            ;So report that
+               CMP     R9,#','                 ;Is there more to come?
+               BL      getToken                ;Get the next token
+               BEQ     %10ctrl__subArgs        ;Yes -- read the rest then
+
+               ; --- Stage 2: Bind arguments, and queue value/returns ---
+               ;
+               ; Here, we build the LOCAL frames for the arguments, and
+               ; store the actual arguments into the formal ones.  We also
+               ; remember which ones are value/return so we can sort them
+               ; out later.  Fortunately we've now done all the messing
+               ; about with express_read that we need to, so we can stack
+               ; registers and seriously get down to business...
+
+               STMFD   R13!,{R0-R10}           ;Save loads of registers
+               MOV     R10,R2                  ;Look after argument count
+               MOV     R9,#0                   ;Counter of valret args
+
+               ; --- First, build the LOCAL frame for formal arg ---
+
+00             MOV     R0,#cFrame__local       ;Create a local frame
+               BL      ctrl__pushFrame         ;Push that on the stack
+               MOV     R4,R0                   ;Look after the address
+               BL      express_pop             ;Pop a formal arg lvalue
+               BL      ctrl_load               ;Load the current value
+               STMIA   R4,{R0-R3}              ;Save all that lot away
+
+               ; --- Now read the rvalue and lvalue of actual arg ---
+
+               MOV     R4,R0                   ;Look after this lvalue
+               MOV     R5,R1                   ;Copy it away somewhere
+               BL      express_popTwo          ;Pop the lvalue and rvalue
+               CMP     R1,#-1                  ;Do we have an actual lvalue?
+               STMNEFD R13!,{R0,R1,R4,R5}      ;Yes -- stack that lot away
+               ADDNE   R9,R9,#1                ;And increment the counter
+               MOV     R0,R4                   ;Put formal lvalue in R0,R1
+               ORR     R1,R5,#(1<<31)          ;Don't remove strs from strc
+               BL      ctrl_store              ;And bind the argument
+
+               SUBS    R10,R10,#1              ;Decrement arg counter
+               BGT     %b00                    ;And loop till all done
+
+               ; --- Stage 3: Finally deal with value/return args ---
+               ;
+               ; We have to create the value/return frames now.  This is
+               ; complicated by the need to prevent LOCAL from over-
+               ; zealously restoring values.  We transform any LOCAL frames
+               ; which might do this into deadlocal ones, which won't.
+
+               CMP     R9,#0                   ;Do I need to do any of this?
+               BEQ     %85ctrl__subArgs        ;No -- go away then
+               LDR     R8,tsc_execStkPtr       ;Find ctrl stack pointer
+               LDR     R7,tsc_execStack        ;And find the anchor
+
+               ; --- Check for matching LOCAL frame ---
+
+05             LDR     R0,[R13,#0]             ;Load the lvalue to match
+               LDR     R14,[R7,#0]             ;Load the stack anchor
+               ADD     R14,R14,R8              ;And find the stack top
+00             LDR     R1,[R14,#-4]            ;Load the frame type
+               CMP     R1,#cFrame__local       ;Is this a local frame?
+               CMPNE   R1,#cFrame__dead        ;Or one we nobbled earlier?
+               BNE     %f00                    ;No -- not there then
+
+               LDR     R1,[R14,#-20]!          ;Load the lvalue from here
+               CMP     R1,R0                   ;Do these match?
+               BNE     %b00                    ;No -- keep looking then
+               MOV     R0,#cFrame__dead        ;Nobble this frame
+               STR     R0,[R14,#16]            ;Change the type to a dummy
+
+               ; --- Now create a value/return frame ---
+
+00             MOV     R0,#cFrame__return      ;Get the frame type
+               BL      ctrl__pushFrame         ;Push this frame
+               LDMFD   R13!,{R1-R4}            ;Load the lvalues out
+               STMIA   R0,{R1-R4}              ;Save that information away
+               SUBS    R9,R9,#1                ;One less of them to do
+               BGT     %b05                    ;If any more to do, do them
+
+               ; --- We're done here -- return to caller ---
+
+85             LDMFD   R13!,{R0-R10}           ;Restore registers
+90             MOVS    PC,R5                   ;And return (slurrrp)
+
+               LTORG
+
+; --- ctrl__unwind ---
+;
+; On entry:    R0 == type of frame to find (PROC or FN)
+;
+; On exit:     CS and R1 == address of frame found, else
+;              CC and R1 corrupted
+;              R0 corrupted
+;
+; Use:         Pops frames off the stack, until it finds a frame which
+;              matches the type specified. Looping constructs are ignored,
+;              and locals, deadlocals and return locals are all dealt with.
+;              It will stop at any other routine frame, and return CC.
+
+ctrl__unwind   ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack registers
+               MOV     R4,R0                   ;Look after the routine type
+               MOV     R5,#0                   ;Number of return-frames now
+00             BL      ctrl__popFrame          ;Pop the frame off the stack
+               CMP     R0,#cFrame__routine     ;Is it a routine frame?
+               BLT     %b00                    ;Nope -- keep on looking then
+
+               ; --- Now pop off routine frames ---
+
+               CMP     R0,R4                   ;Have we found it?
+               BEQ     %90ctrl__unwind         ;Yes -- return success
+
+               CMP     R0,#cFrame__local       ;Is this a local frame?
+               BNE     %10ctrl__unwind         ;No -- jump ahead
+
+               ; --- Deal with local frames ---
+
+               LDMIA   R1,{R0-R3}              ;Load lvalue/rvalue
+               ORR     R1,R1,#(1<<31)          ;Don't remove strings
+               BL      ctrl_store              ;Put it back to how it was
+               B       %b00                    ;And go round for more
+
+               ; --- Check for dead frame ---
+
+10             CMP     R0,#cFrame__dead        ;Is this frame dead?
+               BEQ     %b00                    ;Yes -- ignore it then
+
+15             CMP     R0,#cFrame__return      ;A return frame?
+               BNE     %95ctrl__unwind         ;Nope -- return CC then
+
+               ; --- We have a return frame ---
+
+               MOV     R6,R1                   ;Look after frame address
+               ADD     R1,R1,#8                ;Point to formal lvalue
+               LDMIA   R1,{R0,R1}              ;Load that out
+               BL      ctrl_load               ;Get its value
+               LDMIA   R6,{R0,R1}              ;Load destination lvalue
+               STMFD   R13!,{R0-R3}            ;Store on the R13 stack
+               ADD     R5,R5,#1                ;Increment number so far
+               B       %b00                    ;Yes -- ignore it then
+
+               ; --- We found what we were looking for ---
+               ;
+               ; Resolve all the value return types ---
+
+90             MOV     R6,R1                   ;Look after frame address
+               CMP     R5,#0                   ;And value returns on stack?
+00             LDMNEFD R13!,{R0-R3}            ;Load lvalue/rvalue
+               BLNE    ctrl_store              ;Store the value away
+               SUBNES  R5,R5,#1                ;Decrement the counter
+               BNE     %b00                    ;And do this for all
+
+               MOV     R1,R6                   ;Put address in R1
+               LDMFD   R13!,{R2-R6,R14}        ;Load registers
+               ORRS    PC,R14,#C_flag          ;Return success then
+
+               ; --- We didn't find it :-( ---
+
+95             LDMFD   R13!,{R2-R6,R14}        ;Load registers
+               BICS    PC,R14,#C_flag          ;Return failure
+
+               LTORG
+
+;----- String manipulation --------------------------------------------------
+
+; --- ctrl__alterStr ---
+;
+; On entry:    R2 == rvalue of string to change
+;              R3 == index to copy into
+;              R4 == number of chars to copy
+;              R5 = rvalue of string to copy from
+;
+; On exit:     --
+
+ctrl__alterStr         ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R0,R5                   ;Remeber rvalue of string 2
+               LDR     R14,tsc_stracc          ;Get the stracc address
+               LDR     R14,[R14]
+               ADD     R2,R14,R2,LSR #8        ;Point to the string
+               ADD     R2,R2,R3                ;Point into the string
+               ADD     R5,R14,R5,LSR #8        ;Point to second string
+
+               CMP     R4,#0                   ;Anything to copy?
+00             LDRGTB  R14,[R5],#1             ;Load a byte
+               STRGTB  R14,[R2],#1             ;Store it again
+               SUBS    R4,R4,#1                ;Reduce the counter
+               BGT     %b00                    ;And keep on going
+
+               MOV     R1,#vType_string        ;R0 is a string
+               BL      stracc_free             ;We don't need it now
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+; --- ctrl_leftS ---
+
+               EXPORT  ctrl_leftS
+ctrl_leftS     ROUT
+
+               ; --- First, read the string variable ---
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the lvalue
+               BL      ctrl_load               ;Load the string into stracc
+               CMP     R3,#vType_string        ;Make sure we have a string
+               BNE     ctrl__notAString        ;And report the error
+               AND     R6,R2,#&FF              ;Get the length too
+               STMFD   R13!,{R0,R1}            ;Remember the lvalue
+
+               ; --- We need a comma now ---
+
+               CMP     R9,#','                 ;We need a comma now
+               MOVNE   R0,#err_expComma        ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Read the number of characters ---
+
+               MOV     R1,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- barf then
+               CMP     R0,R6                   ;Reading too many?
+               MOVLE   R4,R0                   ;Put the number in R4
+               MOVGT   R4,R6                   ;Put it in range
+               MOV     R3,#0                   ;The index is 0
+
+               ; --- Look for ')=' now ---
+
+               CMP     R9,#')'                 ;We need a ')' now
+               MOVNE   R0,#err_expBracket      ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+               CMP     R9,#'='                 ;We need a '=' now
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Now we need a replacement string ---
+
+               MOV     R0,#0                   ;Read another rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_string        ;Is it a string?
+               BNE     ctrl__notAString        ;And report the error
+               MOV     R5,R0                   ;Put the rvalue in R5
+               AND     R6,R0,#&FF              ;Get the length of that one
+               CMP     R4,R6                   ;Only copy enough
+               MOVGT   R4,R6                   ;To save embarrassment
+
+               BL      ctrl__alterStr          ;Do the string transform
+               MOV     R3,#vType_string        ;It is a string
+               LDMFD   R13!,{R0,R1}            ;Get the lvalue back
+               BL      ctrl_store              ;Store back the new string
+
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+; --- ctrl_midS ---
+
+               EXPORT  ctrl_midS
+ctrl_midS      ROUT
+
+               ; --- First, read the string variable ---
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the lvalue
+               BL      ctrl_load               ;Load the string into stracc
+               CMP     R3,#vType_string        ;Make sure we have a string
+               BNE     ctrl__notAString        ;And report the error
+               AND     R6,R2,#&FF              ;Get the length too
+               STMFD   R13!,{R0,R1}            ;Remember the lvalue
+
+               ; --- We need a comma now ---
+
+               CMP     R9,#','                 ;We need a comma now
+               MOVNE   R0,#err_expComma        ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Read the index ---
+
+               MOV     R1,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- barf then
+               SUBS    R3,R0,#1                ;Put it in R4
+               MOVLE   R3,#0                   ;Put it in range
+               CMP     R3,R6                   ;Is the index too high?
+               MOVGT   R3,R6                   ;Put it in range
+               SUB     R4,R6,R3                ;Get max to read
+
+               ; --- We may have a comma now ---
+
+               CMP     R9,#','                 ;We need a comma now
+               BNE     %10ctrl_midS            ;And jump ahead
+
+               ; --- Read the number of characters ---
+
+               BL      getToken                ;Skip past the comma
+               MOV     R1,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- barf then
+               CMP     R0,R4                   ;Is the index too high?
+               MOVLE   R4,R0                   ;Put the number in R4
+               CMP     R4,#0                   ;Not below 0 either
+               MOVLT   R4,#0
+
+               ; --- Look for ')=' now ---
+
+10ctrl_midS    CMP     R9,#')'                 ;We need a ')' now
+               MOVNE   R0,#err_expBracket      ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+               CMP     R9,#'='                 ;We need a '=' now
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Now we need a replacement string ---
+
+               MOV     R0,#0                   ;Read another rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_string        ;Is it a string?
+               BNE     ctrl__notAString        ;And report the error
+               MOV     R5,R0                   ;Put the rvalue in R5
+               AND     R6,R0,#&FF              ;Get the length of that one
+               CMP     R4,R6                   ;Only copy enough
+               MOVGT   R4,R6                   ;To save embarrassment
+
+               BL      ctrl__alterStr          ;Do the string transform
+               MOV     R3,#vType_string        ;It is a string
+               LDMFD   R13!,{R0,R1}            ;Get the lvalue back
+               BL      ctrl_store              ;Store back the new string
+
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+; --- ctrl_rightS ---
+
+               EXPORT  ctrl_rightS
+ctrl_rightS    ROUT
+
+               ; --- First, read the string variable ---
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the lvalue
+               BL      ctrl_load               ;Load the string into stracc
+               CMP     R3,#vType_string        ;Make sure we have a string
+               BNE     ctrl__notAString        ;And report the error
+               AND     R6,R2,#&FF              ;Get the length too
+               STMFD   R13!,{R0,R1}            ;Remember the lvalue
+
+               ; --- We need a comma now ---
+
+               CMP     R9,#','                 ;We need a comma now
+               MOVNE   R0,#err_expComma        ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Read the number of characters ---
+
+               MOV     R1,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- barf then
+               CMP     R0,R6                   ;Reading too many?
+               MOVLE   R4,R0                   ;Put the number in R4
+               MOVGT   R4,R6                   ;Put it in range
+               SUBS    R3,R6,R4                ;Work out the index
+
+               ; --- Look for ')=' now ---
+
+               CMP     R9,#')'                 ;We need a ')' now
+               MOVNE   R0,#err_expBracket      ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+               CMP     R9,#'='                 ;We need a '=' now
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Now we need a replacement string ---
+
+               MOV     R0,#0                   ;Read another rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_string        ;Is it a string?
+               BNE     ctrl__notAString        ;And report the error
+               MOV     R5,R0                   ;Put the rvalue in R5
+               AND     R0,R0,#&FF              ;Get the length of that one
+               CMP     R4,R0                   ;Only copy enough
+               MOVGT   R4,R0                   ;To save embarrassment
+               SUBGT   R3,R6,R4
+
+               BL      ctrl__alterStr          ;Do the string transform
+               MOV     R3,#vType_string        ;It is a string
+               LDMFD   R13!,{R0,R1}            ;Get the lvalue back
+               BL      ctrl_store              ;Store back the new string
+
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+;----- Arrays ---------------------------------------------------------------
+
+; --- ctrl_dim ---
+
+               EXPORT  ctrl_dim
+ctrl_dim       ROUT
+
+               ; --- Stash current position ---
+
+               LDR     R6,tsc_line             ;Find the current line
+               STMFD   R13!,{R6-R10}           ;Save current position info
+
+               ; --- Now try reading an identifier ---
+
+               ADR     R1,tsc_misc             ;Point to a buffer
+               MOV     R2,#vType_dimInt        ;Currently it's an int array
+
+               SUBS    R14,R9,#'_'             ;Allow strange ident chars
+               SUBNE   R14,R9,#'A'             ;Check for uppercase letters
+               CMP     R14,#26                 ;In range?
+               SUBCS   R14,R9,#'a'             ;Check for lowercase letters
+               CMPCS   R14,#26                 ;In range?
+               MOVCS   R0,#err_badDim          ;No -- get an error
+               BCS     error_report            ;And kill the program
+
+00             STRB    R9,[R1],#1              ;Store the character away
+               BL      getToken                ;Get another token
+               SUBS    R14,R9,#'_'             ;Allow strange ident chars
+               SUBNE   R14,R9,#'A'             ;Check for uppercase letters
+               CMP     R14,#26                 ;In range?
+               SUBCS   R14,R9,#'a'             ;Check for lowercase letters
+               CMPCS   R14,#26                 ;In range?
+               SUBCS   R14,R9,#'0'             ;Check for digits too now
+               CMPCS   R14,#10                 ;In range?
+               BCC     %b00                    ;We're OK here -- loop
+
+               ; --- Found something which stopped us ---
+
+               CMP     R9,#'$'                 ;Is it a dollar sign?
+               MOVEQ   R2,#vType_dimStr        ;It's a string array now
+               CMPNE   R9,#'%'                 ;Or a percentage?
+               STREQB  R9,[R1],#1              ;Yes -- store it then
+               CMPNE   R9,#' '                 ;Just check for a space
+               BLEQ    getToken                ;Valid terminator -- get tok
+
+               ; --- Now see if this is an array ---
+
+               CMP     R9,#'('                 ;Defining an array here?
+               BNE     %50ctrl_dim             ;No -- allocate a block then
+               ADD     R13,R13,#20             ;Lose positioning info
+               MOV     R14,#0                  ;Terminate the identifier
+               STRB    R14,[R1],#1             ;Store zero on the end
+               BL      getToken                ;Get the next token
+
+               ; --- Ensure that the name isn't already used ---
+
+               MOV     R0,R2                   ;Get the array type
+               ADR     R1,tsc_misc             ;Point to the name
+               BL      tree_find               ;Is it there already?
+               MOVCS   R0,#err_reDim           ;Yes -- moan then
+               BCS     error_report            ;And kill things off
+
+               ; --- Stuff the string on stracc ---
+
+               BL      stracc_ensure           ;Make enough space for it
+               ADR     R3,tsc_misc             ;Point to the misc buffer
+00             LDRB    R14,[R3],#1             ;Load the byte out
+               STRB    R14,[R0],#1             ;Store in the buffer
+               ADD     R1,R1,#1                ;And increment the length
+               CMP     R14,#0                  ;Finished yet?
+               BNE     %b00                    ;No -- then loop round
+               MOV     R0,R1                   ;Get the rvalue I made
+               BL      stracc_added            ;I've added this string
+               MOV     R5,R1                   ;Look after this value
+
+               ; --- Now read the subscripts ---
+               ;
+               ; We use the stack to keep track of them all.  This is
+               ; fairly crufty, but I don't care.
+
+               MOV     R3,#0                   ;No subscripts so far
+               MOV     R4,#1                   ;Number of items we need
+00             MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Evaluate an expression
+               BL      express_pop             ;Pop the rvalue
+               CMP     R1,#vType_integer       ;Ensure it's an integer
+               MOVNE   R0,#err_numNeeded       ;No -- moan then
+               BNE     error_report            ;And stop the program
+               ADD     R0,R0,#1                ;BASIC subscripts are odd
+               STMFD   R13!,{R0}               ;Stash the subscript
+               ADD     R3,R3,#1                ;Increment the counter
+               MUL     R4,R0,R4                ;Update the size we nee
+               CMP     R9,#','                 ;Is this a comma?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     %b00                    ;And read another subscript
+               CMP     R9,#')'                 ;Well, this must be next
+               MOVNE   R0,#err_dimKet          ;No -- well, get an error
+               BNE     error_report            ;And die horridly
+               BL      getToken                ;Get another token
+
+               ; --- We now have the subscripts on the stack ---
+
+               LDR     R14,tsc_stracc          ;Find the stracc anchor
+               LDR     R14,[R14]               ;Bop WimpExtension for fun
+               ADD     R1,R14,R5,LSR #8        ;Find the name base
+               MOV     R0,R2                   ;Get the variable type
+               MOV     R2,R13                  ;Point to subscripts
+               BL      var_create              ;Create the array
+               MOV     R0,R5                   ;Get the rvalue again
+               BL      stracc_free             ;And release the memory
+               ADD     R13,R13,R3,LSL #2       ;Restore the stack pointer
+               B       %80ctrl_dim             ;And possibly go round again
+
+               ; --- Allocate a block of memory ---
+
+50ctrl_dim     LDMFD   R13!,{R6-R10}           ;Restore positioning info
+               STR     R6,tsc_line             ;Restore the line number
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read that then
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;And read that too
+               BL      express_pop             ;Get the block size
+               CMP     R1,#vType_integer       ;Ensure it's an integer
+               MOVNE   R0,#err_numNeeded       ;No -- get the error then
+               BNE     error_report            ;And moan at the user
+               ADD     R3,R0,#8                ;Add a link word, 1 byte and
+               BIC     R3,R3,#3                ;...word align too
+               MOV     R0,#6                   ;Claim some memory
+               SWI     XOS_Module              ;From the RMA (bletch)
+               MOVVS   R0,#err_noMem           ;If it failed assume no mem
+               BVS     error_report            ;So deal appropriately
+               LDR     R14,tsc_rmaList         ;Load RMA list head
+               STR     R2,tsc_rmaList          ;Store this block in there
+               STR     R14,[R2],#4             ;Stuff the old link away
+               BL      express_pop             ;Pop the lvalue
+               MOV     R3,#vType_integer       ;Pointer is an integer
+               BL      ctrl_store              ;Store it away
+
+               ; --- Do more DIMs if wee need to ---
+
+80ctrl_dim     CMP     R9,#','                 ;Is there a comma now?
+               BLEQ    getToken                ;Yes -- get the next token
+               BEQ     ctrl_dim                ;Yes -- do another dim then
+
+               B       interp_next             ;Do another instruction
+
+               LTORG
+
+;----- Other useful routines ------------------------------------------------
+
+; --- ctrl_copyString ---
+;
+; On entry:    R0 == buffer to copy string to
+;              R1 == point to the string
+;              R2 == length of string to copy
+;
+; On exit:     --
+;
+; Use:         Copies the string into the buffer.
+
+               EXPORT  ctrl_copyString
+ctrl_copyString ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack registers
+               CMP     R2,#0                   ;Is this a short string?
+00             LDRGTB  R14,[R1],#1             ;Load a character
+               STRGTB  R14,[R0],#1             ;And then store it
+               SUBS    R2,R2,#1                ;Reduce the count
+               BGT     %b00                    ;And keep on goin'
+               MOV     R14,#0                  ;Get a terminator
+               STRB    R14,[R0],#1             ;Store the byte and return
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- ctrl__notAnInt ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Moans because something isn't an integer.
+
+ctrl__notAnInt ROUT
+
+               MOV     R0,#err_numNeeded
+               B       error_report
+
+               LTORG
+
+; --- ctrl__notAString ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Moans because something isn't a string.
+
+ctrl__notAString ROUT
+
+               MOV     R0,#err_strNeeded
+               B       error_report
+
+               LTORG
+
+; --- ctrl__findFrame ---
+;
+; On entry:    R0 == frame type
+;
+; On exit:     R0 == frame type we stopped at
+;              R1 == pointer to base of frame
+;              CS if frame type matched, else CC
+;
+; Use:         Finds a frame with the given type.  It pops frames from the
+;              exec stack until it finds either a frame which matches the
+;              type in R0 or a routine frame.  The frame which stopped the
+;              loop is *not* popped.
+
+ctrl__findFrame        ROUT
+
+               ORR     R14,R14,#C_flag         ;Assume a match -- be happy
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,R0                   ;Look after the frame type
+10             BL      ctrl__peekFrame         ;Look at the top frame
+               CMP     R0,R2                   ;Is this a match?
+               LDMEQFD R13!,{R2,PC}^           ;Yes -- unstack and return
+               CMP     R0,#cFrame__routine     ;Is this a routine frame?
+               BLCC    ctrl__popFrame          ;No -- remove it then
+               BCC     %10ctrl__findFrame      ;And keep on going
+               LDMFD   R13!,{R2,R14}           ;Unstack registers
+               BICS    PC,R14,#C_flag          ;And return with C clear
+
+               LTORG
+
+; --- ctrl_store ---
+;
+; On entry:    R0,R1 == lvalue to store in
+;              R2,R3 == rvalue to write
+;
+;              If bit 31 of R1 is set, then for strings only, the old
+;              string is NOT removed from the stracc. This is
+;              so that variables can be restored after a procedure.
+;
+; On exit:     --
+;
+; Use:         Stores an rvalue into an lvalue.
+
+               EXPORT  ctrl_store
+ctrl_store     ROUT
+
+               ; --- First, see what we're storing in ---
+
+               STMFD   R13!,{R14}              ;Save a register
+               BIC     R14,R1,#(1<<31)         ;Clear the weird bit
+               SUB     R14,R14,#vType_lvInt    ;Get the lvalue index thing
+               CMP     R14,#vType_lvStrArr-vType_lvInt+1
+               ADDCC   PC,PC,R14,LSL #2        ;It's OK, dispatch then
+               B       %00ctrl_store           ;Righty ho, on we go
+
+               B       ctrl__strInt            ;Store in an integer var
+               B       ctrl__strStr            ;Store in a string var
+               B       ctrl__strWord           ;Store in a memory word
+               B       ctrl__strByte           ;Store in a memory byte
+               B       ctrl__strBytes          ;Store in a memory string
+               B       ctrl__strIntArr         ;Store in a whole int array
+               B       ctrl__strStrArr         ;Store in a whole str array
+
+00ctrl_store   MOV     R0,#err_erk             ;This should never happen...
+               B       error_report            ;Since we always get lvalues
+
+               ; --- Store in an integer variable ---
+
+ctrl__strInt   CMP     R3,#vType_integer       ;Make sure we're storing int
+               LDREQ   R14,tsc_varTree         ;Find the tree base
+               LDREQ   R14,[R14]               ;Why is WimpExt so odd?
+               STREQ   R2,[R14,R0]             ;Store the value in node
+               LDMEQFD R13!,{PC}^              ;And return to caller
+               B       ctrl__notAnInt
+
+               ; --- Store in a memory word somewhere ---
+
+ctrl__strWord  CMP     R3,#vType_integer       ;Make sure we're storing int
+               STREQ   R2,[R0,#0]              ;Save the word away
+               LDMEQFD R13!,{PC}^              ;And return to caller
+               B       ctrl__notAnInt
+
+               ; --- Store in a byte somewhere ---
+
+ctrl__strByte  CMP     R3,#vType_integer       ;Make sure we're storing int
+               STREQB  R2,[R0,#0]              ;Save the byte away
+               LDMEQFD R13!,{PC}^              ;And return to caller
+               B       ctrl__notAnInt
+
+               ; --- Store in a string variable ---
+
+ctrl__strStr   CMP     R3,#vType_string        ;Make sure we've got a string
+               BNE     ctrl__notAString        ;No -- complain then
+
+               ; --- Now do some messing about ---
+
+               STMFD   R13!,{R0-R5}            ;Store some registers
+               MOV     R5,R1                   ;Look after our flag bit
+
+               LDR     R4,tsc_varTree          ;Find the tree base
+               LDR     R4,[R4]                 ;Who designed this heap?
+               ADD     R4,R4,R0                ;Work out the node address
+               LDR     R0,[R4,#0]              ;Load the old string offset
+               BL      strBucket_free          ;Don't want it any more
+
+               AND     R0,R2,#&FF              ;Get the string's length
+               BL      strBucket_alloc         ;Get a new string entry
+               STR     R1,[R4,#0]              ;Tuck that away nicely
+
+               LDR     R4,tsc_stracc           ;Find string accumulator
+               LDR     R4,[R4]                 ;It must be one of those days
+               ADD     R4,R4,R2,LSR #8         ;Work out string address
+               ANDS    R3,R2,#&FF              ;Get the length
+00             LDRNEB  R14,[R4],#1             ;Load a string byte
+               STRNEB  R14,[R0],#1             ;Save it in the bucket
+               SUBNES  R3,R3,#1                ;Decrement the length count
+               BNE     %b00                    ;And loop back again
+
+               TST     R5,#(1<<31)             ;Do we remove from bucket?
+               MOV     R0,R2                   ;Get the offset
+               BLEQ    stracc_free             ;Free it nicely
+
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               LTORG
+
+               ; --- Store a string in memory ---
+
+ctrl__strBytes CMP     R3,#vType_string        ;Make sure we've got a string
+               BNE     ctrl__notAString        ;No -- complain then
+
+               STMFD   R13!,{R0-R4}            ;Store some registers
+               LDR     R4,tsc_stracc           ;Find string accumulator
+               LDR     R4,[R4]                 ;It must be one of those days
+               ADD     R4,R4,R2,LSR #8         ;Work out string address
+               ANDS    R3,R2,#&FF              ;Get the length
+00             LDRNEB  R14,[R4],#1             ;Load a string byte
+               STRNEB  R14,[R0],#1             ;Save it in the bucket
+               SUBNES  R3,R3,#1                ;Decrement the length count
+               BNE     %b00                    ;And loop back again
+               MOV     R14,#13                 ;Get the terminator
+               STRB    R14,[R0],#1             ;And store that too
+
+               TST     R1,#(1<<31)             ;Do we remove from bucket?
+               MOV     R0,R2                   ;Put offset in R1
+               BLEQ    stracc_free             ;Free it nicely
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+ctrl__strIntArr
+ctrl__strStrArr
+
+               MOV     R0,#err_arrayBad        ;Point to the error message
+               B       error_report            ;And report the message
+
+; --- ctrl_load ---
+;
+; On entry:    R0,R1 == lvalue to read
+;
+; On exit:     R2,R3 == rvalue read from lvalue
+;
+; Use:         Loads the current value of the given lvalue.
+
+               EXPORT  ctrl_load
+ctrl_load      ROUT
+
+               ; --- First, see what we're storing in ---
+
+               SUB     R2,R1,#vType_lvInt      ;Get the lvalue index thing
+               CMP     R2,#vType_lvStrArr-vType_lvInt+1
+               ADDCC   PC,PC,R2,LSL #2         ;It's OK, dispatch then
+               B       %00ctrl_load            ;Righty ho, on we go
+
+               B       ctrl__ldInt             ;Store in an integer var
+               B       ctrl__ldStr             ;Store in a string var
+               B       ctrl__ldWord            ;Store in a memory word
+               B       ctrl__ldByte            ;Store in a memory byte
+               B       ctrl__ldBytes           ;Store in a memory string
+               B       ctrl__ldIntArr          ;Store in a whole int array
+               B       ctrl__ldStrArr          ;Store in a whole str array
+
+00ctrl_load    MOV     R0,#err_erk             ;This should never happen...
+               B       error_report            ;Since we always get lvalues
+
+               ; --- Load an integer variable ---
+
+ctrl__ldInt    MOV     R3,#vType_integer       ;We're loading an integer
+               LDR     R2,tsc_varTree          ;Find the tree base
+               LDR     R2,[R2]                 ;Why is WimpExt so odd?
+               LDR     R2,[R2,R0]              ;Load the value out
+               MOVS    PC,R14                  ;Return to caller
+
+               ; --- Load from a memory word somewhere ---
+
+ctrl__ldWord   MOV     R3,#vType_integer       ;We're loading an integer
+               LDR     R2,[R0,#0]              ;Load the word
+               MOVS    PC,R14                  ;And return to caller
+
+               ; --- Load from a byte somewhere ---
+
+ctrl__ldByte   MOV     R3,#vType_integer       ;We're loading an integer
+               LDRB    R2,[R0,#0]              ;Load the byte
+               MOVS    PC,R14                  ;And return to caller
+
+               ; --- Load a string into stracc ---
+
+ctrl__ldStr    STMFD   R13!,{R0,R1,R4,R14}     ;Save some registers
+
+               LDR     R14,tsc_varTree         ;Find the variable tree
+               LDR     R14,[R14]               ;Irate?  Me?
+               ADD     R3,R14,R0               ;Find the actual node
+               BL      stracc_ensure           ;Make sure there's enough
+
+               LDR     R3,[R3,#0]              ;Find the bucket entry
+               CMP     R3,#0                   ;Is there a string here
+               MOVEQ   R2,R1                   ;Yes -- return 0 length
+               BEQ     %f10                    ;...and branch ahead
+               LDR     R14,tsc_bucket          ;Find the bucket anchor
+               LDR     R14,[R14]               ;I hate this!  I hate it!
+               ADD     R3,R14,R3               ;Find the actual string
+
+               LDRB    R4,[R3,#-1]             ;Load the string length
+               ORR     R2,R4,R1                ;Build the rvalue ready
+
+00             LDRB    R14,[R3],#1             ;Load a byte from string
+               STRB    R14,[R0],#1             ;And store byte in stracc
+               SUBS    R4,R4,#1                ;Decrement the length
+               BNE     %b00
+
+10             MOV     R3,#vType_string        ;This is a string
+               MOV     R0,R2                   ;Damn -- we need it in R0,R1
+               BL      stracc_added            ;Tell stracc about string
+               LDMFD   R13!,{R0,R1,R4,PC}^     ;And return to caller
+
+               ; --- Load a string from memory ---
+
+ctrl__ldBytes  STMFD   R13!,{R0,R1,R4,R14}     ;Save some registers
+
+               MOV     R3,R0                   ;Remember string pointer
+               BL      stracc_ensure           ;Make sure there's enough
+
+               MOV     R4,#0                   ;Make the length 0
+00             LDRB    R14,[R3],#1             ;Load a byte from string
+               CMP     R14,#13                 ;Is it the terminator
+               BEQ     %f10                    ;Yes -- jump ahead
+               STRB    R14,[R0],#1             ;And store byte in stracc
+               ADD     R4,R4,#1                ;Decrement the length
+               CMP     R4,#255                 ;Are we at the limit
+               BLT     %b00                    ;No -- go round for more
+
+10             MOV     R3,#vType_string        ;This is a string
+               ORR     R2,R1,R4                ;Get the rvalue
+               MOV     R0,R2                   ;Damn -- we need it in R0,R1
+               BL      stracc_added            ;Tell stracc about string
+               LDMFD   R13!,{R0,R1,R4,PC}^     ;And return to caller
+
+               LTORG
+
+ctrl__ldIntArr
+ctrl__ldStrArr
+               MOV     R0,#err_arrayBad        ;Get the error number
+               B       error_report            ;And report the error
+
+; --- ctrl_compare ---
+;
+; On entry:    R0,R1 == thing to compare
+;              R2,R3 == thing to compare the other thing with
+;
+; On exit:     The flags indicate the result of the comparison
+;
+; Use:         Compares two things.  Note that R3 contains the dominant
+;              type. If it is comparing strings, the string in R0,R1
+;              will be removed from stracc.
+
+               EXPORT  ctrl_compare
+ctrl_compare   ROUT
+
+               CMP     R3,#vType_integer       ;Is it an integer?
+               BNE     %10ctrl_compare         ;No -- jump ahead
+
+               ; --- We are comparing integers ---
+
+               CMP     R1,#vType_integer       ;Make sure we have an int
+               BNE     ctrl__notAnInt          ;No -- barf then
+               CMP     R0,R2                   ;Do the comparison
+               MOV     PC,R14                  ;And return to caller
+
+               ; --- Try to compare strings ---
+
+10ctrl_compare CMP     R3,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_arrayBad        ;No -- get the error number
+               BNE     error_report            ;...and report the error
+               CMP     R1,#vType_string        ;Make sure other is string
+               MOVNE   R0,#err_strNeeded       ;Nope -- complain
+               BNE     error_report
+
+               STMFD   R13!,{R0-R5,R14}        ;Stack some registers
+               AND     R1,R0,#&FF              ;Get length of first string
+               AND     R3,R2,#&FF              ;And of the second one
+               CMP     R3,R1                   ;Find the lowest
+               EORLT   R1,R1,R3                ;And put lowest in R1
+               EORLT   R3,R1,R3
+               EORLT   R1,R3,R1
+               MOVS    R5,R1                   ;How long is it?
+               BEQ     %50ctrl_compare         ;0 length -- jump ahead
+
+               LDR     R4,tsc_stracc           ;Find string accumulator
+               LDR     R4,[R4]                 ;It must be one of those days
+               ADD     R2,R4,R2,LSR #8         ;of both strings
+               ADD     R0,R4,R0,LSR #8         ;Work out string address
+00             LDRB    R14,[R0],#1             ;Load a string byte
+               LDRB    R4,[R2],#1              ;from both strings
+               CMP     R14,R4                  ;Are they the same?
+               BNE     %19ctrl_compare         ;Nope -- return failure
+               SUBS    R5,R5,#1                ;Decrement the length count
+               BNE     %b00                    ;And loop back again
+               CMP     R1,R3                   ;Compare lengths then
+
+19ctrl_compare LDR     R0,[R13,#0]             ;Load an rvalue
+               BL      stracc_free             ;Free it then
+               LDMFD   R13!,{R0-R5,PC}         ;Load back registers
+
+50ctrl_compare CMP     R1,R3                   ;Make another comaprison
+               B       %19ctrl_compare         ;And return
+
+               LTORG
+
+;----- Stack frames ---------------------------------------------------------
+
+; --- Frame types ---
+
+               ^       0
+
+cFrame__loop   #       0
+
+cFrame__for    #       1
+cFrame__while  #       1
+cFrame__repeat #       1
+
+cFrame__routine        #       0
+
+cFrame__gosub  #       1
+cFrame__local  #       1
+cFrame__return #       1
+cFrame__proc   #       1
+cFrame__fn     #       1
+cFrame__dead   #       1
+
+; --- Frame formats ---
+
+               ; --- FOR ---
+
+               ^       0
+cFor__lval     #       8
+cFor__end      #       4
+cFor__step     #       4
+cFor__resume   #       8
+cFor__size     #       0
+
+               ; --- PROC ---
+
+               ^       0
+cProc__resume  #       8
+cProc__anchor  #       4
+cProc__stracc  #       4
+cProc__size    #       0
+
+               ; --- FN ---
+
+               ^       0
+cFn__resume    #       8
+cFn__flags     #       4
+cFn__anchor    #       4
+cFn__stracc    #       4
+cFn__stack     #       32
+cFn__size      #       0
+
+               ; --- REPEAT ---
+
+               ^       0
+cRepeat__resume        #       8
+cRepeat__size  #       0
+
+               ; --- WHILE ---
+
+               ^       0
+cWhile__resume #       8
+cWhile__size   #       0
+
+               ; --- GOSUB ---
+
+               ^       0
+cGosub__resume #       8
+cGosub__size   #       0
+
+               ; --- LOCAL ---
+
+               ^       0
+cLocal__lval   #       8
+cLocal__rval   #       8
+cLocal__size   #       0
+
+               ; --- RETURN ---
+
+               ^       0
+cReturn__lvalA #       8
+cReturn__lvalF #       8
+cReturn__size  #       0
+
+               ; --- DEAD ---
+
+               ^       0
+cDead__lval    #       8
+cDead__rval    #       8
+cDead__size    #       0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/driver b/StraySrc/Libraries/Sapphire/sail/_s/driver
new file mode 100644 (file)
index 0000000..de07e05
--- /dev/null
@@ -0,0 +1,262 @@
+;
+; driver.s
+;
+; Test driver for Termite script language
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  |Image$$RW$$Limit|
+               IMPORT  |!!!TermScript$$Header$$Base|
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Driver$$Code|,CODE,READONLY
+               ENTRY
+
+main           ROUT
+
+               SWI     OS_GetEnv
+               MOV     R13,R1
+
+               SUB     R3,R1,#2048
+               LDR     R12,=|Image$$RW$$Limit|
+               ADD     R1,R12,#512
+               SUB     R3,R3,R1
+               MOV     R0,#0
+               SWI     OS_Heap
+               STR     R1,[R12,#0]
+
+               ; --- load the file ---
+
+               SWI     OS_GetEnv
+thingy         LDRB    R14,[R0],#1
+               CMP     R14,#32
+               BNE     thingy
+               BL      loadFile
+               STR     R0,[R12,#4]
+
+               ADR     R11,upcalls
+               LDR     R10,=|!!!TermScript$$Header$$Base|
+
+               ; --- Initialise ---
+
+               ADD     R2,R12,#4
+               MOV     R3,R1
+               MOV     R14,PC
+               ADD     PC,R10,#8
+               MOV     R9,R0
+
+               ; --- The main loop ---
+
+testloop       MOV     R0,R9
+               CMN     R0,#0
+               MOV     R14,PC
+               ADD     PC,R10,#12
+               BVS     error
+               CMP     R0,#0
+               BEQ     testloop
+
+               CMP     R0,#2
+               ADRLT   R0,end
+               ADREQ   R0,chain
+               ADRGT   R0,finish
+               SWI     OS_Write0
+
+done           MOV     R0,R9
+               MOV     R14,PC
+               ADD     PC,R10,#24
+
+               SWI     OS_WriteS
+               DCB     "+++ Finished!!!",10,13,0
+               SWI     OS_Exit
+
+error          SWI     OS_WriteS
+               DCB     "+++ Error: `",0
+               ADD     R0,R0,#4
+               SWI     OS_Write0
+               SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               B       done
+
+end            DCB     "+++ End",13,10,0
+chain          DCB     "+++ Chain",13,10,0
+finish         DCB     "+++ Finnish",13,10,0
+
+               LTORG
+
+loadFile       ROUT
+
+               STMFD   R13!,{R0-R5,R14}
+               MOV     R1,R0
+               MOV     R0,#17
+               SWI     OS_File
+               MOV     R3,R4
+               STR     R4,[R13,#4]
+               LDR     R1,[R12,#0]
+               MOV     R0,#2
+               SWI     OS_Heap
+               MOV     R3,#0
+               LDR     R1,[R13,#0]
+               STR     R2,[R13,#0]
+               MOV     R0,#16
+               SWI     OS_File
+               LDMFD   R13!,{R0-R5,PC}^
+
+upcalls                B       makeBeep
+               B       sendRemote
+               B       reportMessage
+               B       printMessage
+               B       sendLocal
+               B       logFileAdd
+               B       clearScreen
+               B       download
+               B       upload
+               B       checkCarrier
+               MOVS    PC,R14
+               B       readRemote
+               B       readLocal
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+
+makeBeep       SWI     OS_WriteS
+               DCB     "+++ Beep!!!",7,10,13,0
+               MOVS    PC,R14
+
+sendRemote     STMFD   R13!,{R0-R3}
+               SWI     OS_WriteS
+               DCB     "+++ Sending out `",0
+dosod          CMP     R3,#0
+               BEQ     sodret
+sodloop                LDRB    R0,[R2],#1
+               CMP     R0,#127
+               CMPNE   R0,#31
+               SWIGT   OS_WriteC
+               BGT     sodendl
+               SWI     OS_WriteI+'['
+               AND     R1,R0,#15
+               MOV     R0,R0,LSR #4
+               CMP     R0,#10
+               ADDCC   R0,R0,#'0'
+               ADDCS   R0,R0,#'A'-10
+               SWI     OS_WriteC
+               CMP     R1,#10
+               ADDCC   R0,R1,#'0'
+               ADDCS   R0,R1,#'A'-10
+               SWI     OS_WriteC
+               SWI     OS_WriteI+']'
+sodendl                SUBS    R3,R3,#1
+               BGT     sodloop
+sodret         SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               LDMFD   R13!,{R0-R3}
+               MOVS    PC,R14
+
+reportMessage  STMFD   R13!,{R0,R14}
+               SWI     OS_WriteS
+               DCB     "+++ Reporting: `",0
+               SWI     OS_Write0
+               SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               LDMFD   R13!,{R0,PC}^
+
+printMessage   STMFD   R13!,{R0,R14}
+               SWI     OS_WriteS
+               DCB     "+++ Printing: `",0
+               SWI     OS_Write0
+               SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               LDMFD   R13!,{R0,PC}^
+
+sendLocal      STMFD   R13!,{R0-R3}
+               SWI     OS_WriteS
+               DCB     "+++ Sending in: `",0
+               B       dosod
+
+logFileAdd     STMFD   R13!,{R0,R14}
+               SWI     OS_WriteS
+               DCB     "+++ Adding to log: `",0
+               SWI     OS_Write0
+               SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               LDMFD   R13!,{R0,PC}^
+
+clearScreen    SWI     OS_WriteS
+               DCB     "+++ Clear screen",13,10,0
+               MOVS    PC,R14
+
+download       STMFD   R13!,{R0}
+               SWI     OS_WriteS
+               DCB     "+++ Download, protocol == `",0
+               MOV     R0,R2
+               SWI     OS_Write0
+               SWI     OS_WriteS
+               DCB     "', filename == `",0
+               CMP     R3,#0
+               ADREQ   R0,defname
+               MOVNE   R0,R3
+               SWI     OS_Write0
+               SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               LDMFD   R13!,{R0}
+               MOVS    PC,R14
+
+defname                DCB     "<default>",0
+
+upload         STMFD   R13!,{R0,R3,R14}
+               SWI     OS_WriteS
+               DCB     "+++ Upload, protocol == `",0
+               MOV     R0,R2
+               SWI     OS_Write0
+               SWI     OS_WriteS
+               DCB     "', files:",13,10,0
+uploop         LDRB    R0,[R3],#1
+               CMP     R0,#0
+               LDMEQFD R13!,{R0,R3,PC}^
+               SWI     OS_WriteS
+               DCB     "+++   ",0
+upotherloop    SWI     OS_WriteC
+               LDRB    R0,[R3],#1
+               CMP     R0,#0
+               BNE     upotherloop
+               SWI     OS_NewLine
+               B       uploop
+
+checkCarrier   SWI     OS_WriteS
+               DCB     "+++ Carrier detect? [yn] ",0
+               SWI     OS_ReadC
+               ORR     R0,R0,#&20
+               CMP     R0,#'n'
+               MOVNE   R0,#'y'
+               SWI     OS_WriteC
+               SWI     OS_NewLine
+               SUBS    R0,R0,#'n'
+               MOVNE   R0,#1
+               MOVS    PC,R14
+
+readLocal      SWI     OS_ReadC
+               MOVS    PC,R14
+
+readRemote     SWI     OS_ReadC
+               MOVS    PC,R14
+
+;----- Workspace ------------------------------------------------------------
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/error b/StraySrc/Libraries/Sapphire/sail/_s/error
new file mode 100644 (file)
index 0000000..0a90cd9
--- /dev/null
@@ -0,0 +1,127 @@
+;
+; error.s
+;
+; Generation and handling of errors
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.termScript
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- error_report ---
+;
+; On entry:    R0 == error number
+;
+; On exit:     doesn't -- reports error to Termite
+;
+; Use:         Reports an error, attaching the error number etc. and
+;              terminating the script.
+
+               EXPORT  error_report
+error_report   ROUT
+
+               ADR     R1,tsc_misc             ;Point to the misc buffer
+               STR     R0,[R1],#4              ;Save the error number away
+
+               ; --- Find the error string ---
+
+               ADR     R14,errTable            ;Point to error table
+               LDR     R0,[R14,R0,LSL #2]      ;Find the error offset
+               ADD     R0,R14,R0               ;And convert that to address
+
+               ; --- Now build the actual string ---
+
+10error_report LDRB    R14,[R0],#1             ;Load byte from error text
+               CMP     R14,#0                  ;Is this the end yet?
+               STRNEB  R14,[R1],#1             ;No -- store the byte
+               BNE     %10error_report         ;And keep looping until done
+
+               ; -- Stick `at line' on the end ---
+
+               ADR     R0,error__atLine        ;Point to literal string
+20error_report LDRB    R14,[R0],#1             ;Load byte from text
+               CMP     R14,#0                  ;Is this the end yet?
+               STRNEB  R14,[R1],#1             ;No -- store the byte
+               BNE     %20error_report         ;And keep looping until done
+
+               ; --- Now attach the line number ---
+
+               LDR     R0,tsc_line             ;Get the line number
+               MOV     R2,#256                 ;Assume a big buffer
+               SWI     OS_ConvertInteger4      ;Attach that to the end
+
+               ; --- Finally throw the error at Termite ---
+
+               ADR     R0,tsc_misc             ;Point to error base
+               B       tsc_error               ;And return the error
+
+error__atLine  DCB     " at line ",0
+               ALIGN
+
+               GET     sh.errTable
+
+               LTORG
+
+; --- error_reportReal ---
+;
+; On entry:    R0 == error block
+;
+; On exit:     doesn't -- reports error to Termite
+;
+; Use:         Reports an error, attaching the error number etc. and
+;              terminating the script.
+
+               EXPORT  error_reportReal
+error_reportReal ROUT
+
+               ADR     R1,tsc_misc             ;Point to the misc buffer
+               LDR     R14,[R0],#4             ;Load the error number
+               STR     R14,[R1],#4             ;Save the error number away
+
+               ; --- Now build the actual string ---
+
+10             LDRB    R14,[R0],#1             ;Load byte from error text
+               CMP     R14,#0                  ;Is this the end yet?
+               STRNEB  R14,[R1],#1             ;No -- store the byte
+               BNE     %10error_reportReal     ;And keep looping until done
+
+               ; -- Stick `at line' on the end ---
+
+               ADRL    R0,error__atLine        ;Point to literal string
+20             LDRB    R14,[R0],#1             ;Load byte from text
+               CMP     R14,#0                  ;Is this the end yet?
+               STRNEB  R14,[R1],#1             ;No -- store the byte
+               BNE     %20error_reportReal     ;And keep looping until done
+
+               ; --- Now attach the line number ---
+
+               LDR     R0,tsc_line             ;Get the line number
+               MOV     R2,#256                 ;Assume a big buffer
+               SWI     OS_ConvertInteger4      ;Attach that to the end
+
+               ; --- Finally throw the error at Termite ---
+
+               ADR     R0,tsc_misc             ;Point to error base
+               B       tsc_error               ;And return the error
+
+               GET     sh.errTable
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/express b/StraySrc/Libraries/Sapphire/sail/_s/express
new file mode 100644 (file)
index 0000000..6995bf6
--- /dev/null
@@ -0,0 +1,2461 @@
+;
+; express.s
+;
+; Evaluation of BASIC expressions
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.ctrl
+               GET     sh.divide
+               GET     sh.errNum
+               GET     sh.error
+               GET     sh.getToken
+               GET     sh.stracc
+               GET     sh.termite
+               GET     sh.termScript
+               GET     sh.tokenise
+               GET     sh.tokens
+               GET     sh.upcalls
+               GET     sh.mem
+               GET     sh.var
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         GETOP   $r,$prec,$branch,$cc
+               ALIGN
+$label
+               MOV$cc  $r,#($prec)<<24
+               ORR$cc  $r,$r,#($branch-exp__bTable)>>2
+               MEND
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+;----- Stack handling -------------------------------------------------------
+
+; --- exp__pushOp ---
+;
+; On entry:    R0 == operator thing to push
+;
+; On exit:     R0-R4 corrupted
+;
+; Use:         Pushes an operator onto the stack.
+
+exp__pushOp    ROUT
+
+               STMFD   R13!,{R14}
+               MOV     R3,R0                   ;Look after thing to push
+               ADR     R1,tsc_opStack          ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               ADD     R4,R1,#4                ;New used size
+               CMP     R4,R2                   ;Do we need more stack?
+               BGT     %10exp__pushOp          ;Yes -- jump ahead
+00exp__pushOp  STR     R4,tsc_opStkPtr         ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R0,R0,R4                ;Address to put next thing on
+               STR     R3,[R0,#-4]             ;Store the new operator
+               LDMFD   R13!,{PC}^
+
+10exp__pushOp  ADD     R1,R4,#255              ;Align to next size thing
+               BIC     R1,R1,#255              ;Finish the align
+               BL      mem_realloc             ;Yes -- get more space then
+               STR     R1,tsc_opStkSize        ;Store new size maybe
+               B       %00exp__pushOp          ;Branch back agin
+
+               LTORG
+
+; --- exp__popOp ---
+;
+; On entry:    --
+;
+; On exit:     R0 == value popped off
+;              R1-R4 corrupted
+;
+; Use:         Pops an operator from the stack.
+
+exp__popOp     ROUT
+
+               STMFD   R13!,{R14}
+               ADR     R1,tsc_opStack          ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               SUB     R4,R1,#4                ;The new size
+               ADD     R1,R4,#255              ;Align up again
+               BIC     R1,R1,#255              ;Aligned down
+               ADD     R1,R1,#256              ;At least this much
+               CMP     R1,R2                   ;Has this size changed?
+               BLLT    mem_realloc             ;Yes -- reduce memory reqs.
+               STRLT   R1,tsc_opStkSize        ;Store new size maybe
+               STR     R4,tsc_opStkPtr         ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               LDR     R0,[R0,R4]              ;Load the value off the stack
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- exp__pushVal ---
+;
+; On entry:    R0 == operator thing to push
+;              R1 == type of thing to push
+;
+; On exit:     R0-R5 corrupted
+;
+; Use:         Pushes an value onto the stack.
+
+exp__pushVal   ROUT
+
+               STMFD   R13!,{R5,R14}
+               MOV     R3,R0                   ;Look after thing to push
+               MOV     R4,R1
+               ADR     R1,tsc_calcStack        ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               ADD     R5,R1,#8                ;New used size
+               CMP     R5,R2
+               BGT     %10exp__pushVal
+00exp__pushVal STR     R5,tsc_calcStkPtr       ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R0,R0,R5                ;Address to put next thing on
+               STMDB   R0,{R3,R4}              ;Store the thing
+               LDMFD   R13!,{R5,PC}^
+
+10exp__pushVal ADD     R1,R5,#255              ;Align to next size thing
+               BIC     R1,R1,#255              ;Finish the align
+               BL      mem_realloc             ;Yes -- get more space then
+               STR     R1,tsc_calcStkSize      ;Store new size maybe
+               B       %00exp__pushVal
+
+               LTORG
+
+; --- exp__popVal ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1 == value popped off
+;              R2-R4 corrupted
+;
+; Use:         Pops a value from the stack.
+
+exp__popVal    ROUT
+
+               STMFD   R13!,{R14}
+               ADR     R1,tsc_calcStack        ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               SUB     R4,R1,#8                ;The new size
+               ADD     R1,R4,#255              ;Align up again
+               BIC     R1,R1,#255              ;Aligned down
+               ADD     R1,R1,#256              ;At least this much please
+               CMP     R1,R2                   ;Has this size changed?
+               BLLT    mem_realloc             ;Yes -- reduce memory reqs.
+               STRLT   R1,tsc_calcStkSize      ;Store new size maybe
+               STR     R4,tsc_calcStkPtr       ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R0,R0,R4                ;Point into the stack
+               LDMIA   R0,{R0,R1}              ;Load values from the stack
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- exp__popTwoVals ---
+;
+; On entry:    --
+;
+; On exit:     R0-R3 == values popped off
+;              R4 corrupted
+;
+; Use:         Pops two values from the stack.
+
+exp__popTwoVals        ROUT
+
+               STMFD   R13!,{R14}
+               ADR     R1,tsc_calcStack        ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               SUB     R4,R1,#16               ;The new size
+               ADD     R1,R4,#255              ;Align up again
+               BIC     R1,R1,#255              ;Aligned down
+               ADD     R1,R1,#256              ;At least his much
+               CMP     R1,R2                   ;Has this size changed?
+               BLLT    mem_realloc             ;Yes -- reduce memory reqs.
+               STRLT   R1,tsc_calcStkSize      ;Store new size maybe
+               STR     R4,tsc_calcStkPtr       ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R0,R0,R4                ;Point into the stack
+               LDMIA   R0,{R0-R3}              ;Load values from the stack
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- express_pop ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1 == value popped off
+;
+; Use:         Pops a value from the stack.
+
+               EXPORT  express_pop
+express_pop    ROUT
+
+               STMFD   R13!,{R2-R4,R14}        ;Stack registers
+               BL      exp__popVal             ;Get the value
+               LDMFD   R13!,{R2-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- express_popTwo ---
+;
+; On entry:    --
+;
+; On exit:     R0-R3 == two values popped from the stack
+;
+; Use:         Pops two values from the stack.
+
+               EXPORT  express_popTwo
+express_popTwo ROUT
+
+               STMFD   R13!,{R4,R14}           ;Stack registers
+               BL      exp__popTwoVals         ;Pop the values
+               LDMFD   R13!,{R4,PC}^           ;And return to caller
+
+               LTORG
+
+; --- express_push ---
+;
+; On entry:    R0,R1 == l/rvalue to push
+;
+; On exit:     --
+;
+; Use:         Pushes a value onto the expression stack.
+
+               EXPORT  express_push
+express_push   ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               BL      exp__pushVal            ;Do the pushing
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Space-saving type checking routines ----------------------------------
+
+; --- exp__chkTwoInts ---
+;
+; On entry:    R1,R3 == types of variable
+;
+; On exit:     --
+;
+; Use:         Ensures that R1 and R3 are both of type integer, and
+;              complains otherwise.
+
+exp__chkTwoInts        ROUT
+
+               CMP     R3,#vType_integer       ;Is second an integer?
+               MOVNE   R1,R3                   ;No -- fiddle the first then
+
+               ; Drop through here (yuk)
+
+; --- exp__chkInt ---
+;
+; On entry:    R1 == type of a variable
+;
+; On exit:     --
+;
+; Use:         Ensures that R1 is of type integer, and complains otherwise.
+
+exp__chkInt    ROUT
+
+               CMP     R1,#vType_integer       ;Is it an integer
+               MOVEQS  PC,R14                  ;Yes -- all OK -- return
+               MOV     R0,#err_numNeeded       ;No -- get the error
+               B       error_report            ;And complain at the user
+
+               LTORG
+
+; --- exp__popInt ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1 == value popped from the stack
+;              R2-R4 corrupted
+;
+; Use:         Pops a value from the stack and ensures that it is an
+;              integer.
+
+exp__popInt    STMFD   R13!,{R14}              ;Save the link for a bit
+               BL      exp__popVal             ;Pop a value from stack
+               LDMFD   R13!,{R14}              ;Restore link register
+               B       exp__chkInt             ;And check the value
+
+               LTORG
+
+; --- exp__popTwoInts ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1,R2,R3 == two integers popped from the calc stack
+;              R4 corrupted
+;
+; Use:         Pops two values from the stack and ensures that they are
+;              integers.
+
+exp__popTwoInts        ROUT
+
+               STMFD   R13!,{R14}              ;Save the link for a bit
+               BL      exp__popTwoVals         ;Pop two values from stack
+               LDMFD   R13!,{R14}              ;Restore link register
+               B       exp__chkTwoInts         ;And check the values
+
+               LTORG
+
+; --- exp__chkTwoStrs ---
+;
+; On entry:    R1,R3 == types of variable
+;
+; On exit:     --
+;
+; Use:         Ensures that R1 and R3 are both of type string, and
+;              complains otherwise.
+
+exp__chkTwoStrs        ROUT
+
+               CMP     R3,#vType_string        ;Is second an integer?
+               MOVNE   R1,R3                   ;No -- fiddle the first then
+
+               ; Drop through here (yuk)
+
+; --- exp__chkStr ---
+;
+; On entry:    R1 == type of a variable
+;
+; On exit:     --
+;
+; Use:         Ensures that R1 is of type string, and complains otherwise.
+
+exp__chkStr    ROUT
+
+               CMP     R1,#vType_string        ;Is it an integer
+               MOVEQS  PC,R14                  ;Yes -- all OK -- return
+               MOV     R0,#err_strNeeded       ;No -- get the error
+               B       error_report            ;And complain at the user
+
+               LTORG
+
+; --- exp__popStr ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1 == value popped from the stack
+;              R2-R4 corrupted
+;
+; Use:         Pops a value from the stack and ensures that it is an
+;              integer.
+
+exp__popStr    STMFD   R13!,{R14}              ;Save the link for a bit
+               BL      exp__popVal             ;Pop a value from stack
+               LDMFD   R13!,{R14}              ;Restore link register
+               B       exp__chkStr             ;And check the value
+
+               LTORG
+
+; --- exp__popTwoStrs ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1,R2,R3 == two integers popped from the calc stack
+;              R4 corrupted
+;
+; Use:         Pops two values from the stack and ensures that they are
+;              integers.
+
+exp__popTwoStrs        ROUT
+
+               STMFD   R13!,{R14}              ;Save the link for a bit
+               BL      exp__popTwoVals         ;Pop two values from stack
+               LDMFD   R13!,{R14}              ;Restore link register
+               B       exp__chkTwoStrs         ;And check the values
+
+               LTORG
+
+;----- Expression evaluation routines ---------------------------------------
+
+; --- express_fnCont ---
+;
+; On entry:    Involved
+;
+; On exit:     Similarly involved.
+;
+; Use:         We continue here after executing a function.
+
+               EXPORT  express_fnCont
+
+; --- express_read ---
+;
+; On entry:    R0 == 1 to read an lvalue, 2 to read ident, 0 otherwise
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0,R1 == value of expression
+;              R7, R8, R9 == lookahead token
+;              R0, R1 == result of expression
+;              R10 == moved on to first char after expression
+;
+; Use:         Reads an expression for the current position in the
+;              tokenised file.
+
+               EXPORT  express_read
+express_read   ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Stack registers
+               MOV     R6,#0                   ;Current flags word
+               CMP     R0,#1                   ;Reading an lvalue?
+               ORREQ   R6,R6,#eFlag__lval      ;Yes -- set the flag then
+               CMP     R0,#2                   ;Reading an ident?
+               ORREQ   R6,R6,#eFlag__parseLval ;Yes -- parse as lval then
+
+               GETOP   R0,255,exp__bExpEnd     ;Push a sentinel operand
+               BL      exp__pushOp             ;To separate this expression
+
+exp__mainLoop
+express_fnCont
+10express_read TST     R6,#eFlag__done         ;Have we finished this?
+               BNE     %70express_read         ;Yes -- jump ahead
+               TST     R6,#eFlag__op           ;Are we reading an op?
+               BNE     %50express_read         ;Yes -- jump ahead
+
+               ; --- Read an operand then ---
+
+               SUBS    R4,R9,#'_'              ;Is it an underscore?
+               SUBNE   R4,R9,#'A'              ;Or a capital letter?
+               CMP     R4,#26
+               SUBCS   R4,R9,#'a'              ;Or a lowercase letter?
+               CMPCS   R4,#26
+               BCC     exp__readIdent          ;Read an identifier
+
+               CMP     R9,#'!'                 ;Is it an indirection op?
+               CMPNE   R9,#'?'
+               CMPNE   R9,#'$'
+               BEQ     exp__indir              ;Yes -- jump ahead
+
+               TST     R6,#eFlag__lval         ;Are we reading an lvalue?
+               MOVNE   R0,#err_syntax          ;Yes -- get the error number
+               BNE     error_report            ;...and report the error
+
+               CMP     R9,#'"'                 ;Is it a quote?
+               BEQ     exp__string             ;Yes -- read string then
+
+               CMP     R9,#'('                 ;Is it a bracket?
+               BEQ     exp__par                ;Yes -- jump ahead
+
+               CMP     R9,#tok_fn              ;Is it a function call?
+               BEQ     exp__userFn             ;Yes -- handle that then
+
+               CMP     R9,#tok_rnd             ;Is this the RND fn?
+               BLEQ    getToken                ;Yes -- gobble that
+               BEQ     exp__doRnd              ;And deal with it then
+
+               CMP     R9,#'+'                 ;Is it a unary '+'?
+               BLEQ    getToken                ;...get another token
+               BEQ     %10express_read         ;...keep going around again
+               CMP     R9,#'-'                 ;Is it a unary '-'?
+               BEQ     exp__uMinus             ;Yes -- jump ahead then
+
+               CMP     R7,#tClass_pseud        ;Is this a pseudovariable?
+               BEQ     exp__pseud              ;Yes -- deal with it
+
+               CMP     R7,#tClass_fn           ;Is it a function then?
+               BEQ     exp__fn                 ;Yes -- deal with that
+
+               CMP     R7,#tClass_streamOp     ;Also check for stream ops
+               BEQ     exp__streamOp           ;Just for luck
+
+               CMP     R7,#tClass_multArg      ;Multiple parameter thing?
+               BEQ     exp__multArg            ;Yes -- deal with it then
+
+               CMP     R9,#'&'                 ;Start a hex number?
+               BEQ     exp__readHex            ;Yes -- jump ahead
+               CMP     R9,#'%'                 ;Start of a binary number?
+               BEQ     exp__readBin            ;Yes -- jump ahead
+               SUB     R14,R9,#'0'             ;Set up for a range check
+               CMP     R14,#10                 ;Is it a number?
+               BCC     exp__readDec            ;Read a decimal number
+
+               MOV     R0,#err_unknown         ;Get all-encompassing error
+               B       error_report            ;And report the error
+
+               LTORG
+
+               ; --- Handle a string ---
+
+exp__string    BL      stracc_ensure           ;Ensure stracc is big enough
+               MOV     R2,#0                   ;The initial length
+00             BL      getToken                ;Read the next token
+               CMP     R9,#&0a                 ;Is this a line end?
+               CMPNE   R9,#&ff                 ;Or an end of file?
+               MOVEQ   R0,#err_expQuote        ;Yes -- get error number
+               BEQ     error_report            ;And report it
+               CMP     R9,#'"'                 ;Is it a quote?
+               BEQ     %f05                    ;Yes -- branch ahead
+03             STRB    R9,[R0],#1              ;No -- store the byte
+               ADDS    R2,R2,#1<<24            ;...increment the length
+               BCC     %b00                    ;Keep looping for more
+               MOVCS   R0,#err_strTooLong      ;Get error message
+               BCS     error_report            ;and report it nicely
+
+05             BL      getToken                ;Get another token
+               CMP     R9,#'"'                 ;Is this a quote too?
+               BEQ     %b03                    ;Yes -- jump back upwards
+
+               ORR     R0,R1,R2,LSR #24        ;Get the rvalue word
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               BL      exp__pushVal            ;Push the value
+               ORR     R6,R6,#eFlag__op        ;Read an operator now
+               B       %10express_read         ;And jump with glee
+
+               ; --- Handle a function call ---
+
+exp__userFn    ORR     R6,R6,#eFlag__op        ;Expect operand next
+               BL      getToken                ;Gobble the token
+               B       ctrl_fn                 ;And handle it elsewhere
+
+               ; --- Handle an open bracket ---
+
+exp__par       GETOP   R0,253,exp__bPar        ;Do a bracket like thing
+               BL      exp__pushOp             ;Push that onto the stack
+               ADD     R6,R6,#1<<8             ;Bump the paren count
+               BL      getToken                ;Get another token
+               B       %10express_read         ;And read the first operand
+
+               ; --- Handle a unary minus ---
+
+exp__uMinus    GETOP   R0,1,exp__bUMinus       ;Do a unary minus
+               BL      exp__pushOp             ;Push that onto the stack
+               BL      getToken                ;Get another token
+               B       %10express_read         ;And read the first operand
+
+               ; --- Handle a pseudovariable ---
+
+exp__pseud     MOV     R0,R8                   ;Look after token index
+               BL      getToken                ;Move on to next token
+               ORR     R6,R6,#eFlag__op        ;Now expecting an operator
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,PC,R0,LSL #2         ;Dispatch on token index
+               B       %10express_read         ;And return to the top
+
+               B       exp__doFalse            ;Return 0
+               B       exp__doTime             ;Get the current time
+               B       exp__doTimeS            ;Read time as a string (ouch)
+               B       exp__doTrue             ;Return -1
+
+               ; --- Handle unary functions ---
+
+exp__fn                MOV     R0,#(exp__fns-exp__bTable)>>2
+               ADD     R0,R0,R8                ;Add on the token index
+               ORR     R0,R0,#1<<24            ;Use normal unary precedence
+               CMP     R9,#tok_strS            ;Is this STR$?
+               BLNE    exp__pushOp             ;Put that on the stack
+               BLNE    getToken                ;Get the next token
+               BNE     %10express_read         ;And go back up top
+
+               BL      getToken                ;Get another token
+               CMP     R9,#'~'                 ;Hex conversion?
+               ORREQ   R0,R0,#1<<16            ;Set a useful flag
+               BLEQ    getToken                ;And get another token
+               BL      exp__pushOp             ;Put that on the stack
+               B       %10express_read         ;And go back up top
+
+               ; --- Handle stream operations with irritating #s ---
+
+exp__streamOp  MOV     R1,R8                   ;Look after token index
+               BL      getToken                ;Get the next token
+               CMP     R9,#'#'                 ;Is next char a hash?
+               MOVNE   R0,#err_expHash         ;No -- complain then
+               BNE     error_report            ;And report an error
+               BL      getToken                ;Get the next token
+               MOV     R0,#(exp__streamOps-exp__bTable)>>2
+               ADD     R0,R0,R1                ;Add on the token index
+               ORR     R0,R0,#1<<24            ;Use normal unary precedence
+               BL      exp__pushOp             ;Put that on the stack
+               B       %10express_read         ;And go back up top
+
+               ; --- Deal with multiple parameter commands ---
+
+exp__multArg   MOV     R0,#(exp__multArgs-exp__bTable)>>2
+               ADD     R0,R0,R8                ;Add on the token index
+               ORR     R0,R0,#1<<24            ;Use normal unary precedence
+               BL      exp__pushOp             ;Put that on the stack
+               BL      getToken                ;Get the next token
+
+               GETOP   R0,254,exp__bMultArg    ;Get the operator value
+               TST     R6,#eFlag__commaOk      ;Are we allowing commas?
+               ORRNE   R0,R0,#1<<16            ;Yes -- set the flag then
+               BL      exp__pushOp             ;Put that on there
+               ORR     R6,R6,#eFlag__commaOk   ;Allow commas for a while
+               ADD     R6,R6,#1<<8             ;Increment the paren count
+
+               B       %10express_read         ;And go back up top
+
+               ; --- Deal with an indirection operator ---
+
+exp__indir     MOV     R0,#0                   ;Prepare a zero base
+               TST     R6,#eFlag__lval         ;Are we reading an lvalue?
+               MOVEQ   R1,#vType_integer       ;No -- call it an integer
+               MOVNE   R1,#vType_lvInt         ;Yes -- call it an int lval
+               BICNE   R6,R6,#eFlag__lval      ;Clear lvalue flag too
+               ORRNE   R6,R6,#eFlag__parseLval ;But carry on parsing one!
+               BL      exp__pushVal            ;Push that on the calc stack
+               CMP     R9,#'$'                 ;Is this a dollar?
+               MOVLT   R0,#(exp__bPling-exp__bTable)>>2
+               MOVEQ   R0,#(exp__bDollar-exp__bTable)>>2
+               MOVGT   R0,#(exp__bQuery-exp__bTable)>>2
+               ORR     R0,R0,#1<<24            ;Make it precedence 1
+               BL      exp__pushOp             ;Stick that on the op stack
+               BL      getToken                ;Get another token
+               B       %10express_read         ;And read the operand
+
+               ; --- Read a hexadecimal number ---
+
+exp__readHex   MOV     R0,#0                   ;Initial value is zero
+               BL      getToken                ;Get a first token
+               SUB     R14,R9,#'A'             ;Is this a letter
+               CMP     R14,#6                  ;If so, make sure it's OK
+               ADDCC   R14,R14,#10             ;And move on to 10-15
+               SUBCS   R14,R9,#'0'             ;Otherwise check for digit
+               CMPCS   R14,#10                 ;Make sure that's in range
+               MOVCS   R0,#err_badHex          ;If not, make an error
+               BCS     error_report            ;And stop doing this
+
+00express_read ADD     R0,R14,R0,LSL #4        ;Accumulate a result
+               BL      getToken                ;Get another token
+               SUB     R14,R9,#'A'             ;Is this a letter
+               CMP     R14,#6                  ;If so, make sure it's OK
+               ADDCC   R14,R14,#10             ;And move on to 10-15
+               SUBCS   R14,R9,#'0'             ;Otherwise check for digit
+               CMPCS   R14,#10                 ;Make sure that's in range
+               BCC     %b00express_read        ;If it was OK, go round more
+
+               MOV     R1,#vType_integer       ;Call it an integer
+               BL      exp__pushVal            ;Stick that on the val stack
+               TST     R6,#eFlag__parseLval    ;Parsing an lvalue?
+               ORRNE   R6,R6,#eFlag__done      ;Yes -- we're finished
+               ORR     R6,R6,#eFlag__op        ;Now look for binary operator
+               B       %10express_read         ;And read the operator
+
+               ; --- Read a binary number ---
+
+exp__readBin   MOV     R0,#0                   ;Initial value is zero
+               BL      getToken                ;Get a first token
+               SUB     R14,R9,#'0'             ;Otherwise check for digit
+               CMP     R14,#1                  ;Make sure that's in range
+               MOVHI   R0,#err_badHex          ;If not, make an error
+               BHI     error_report            ;And stop doing this
+
+00express_read ADC     R0,R0,R0                ;Accumulate a result
+               BL      getToken                ;Get another token
+               SUB     R14,R9,#'0'             ;Otherwise check for digit
+               CMP     R14,#1                  ;Make sure that's in range
+               BLS     %b00express_read        ;If it was OK, go round more
+
+               MOV     R1,#vType_integer       ;Call it an integer
+               BL      exp__pushVal            ;Stick that on the val stack
+               TST     R6,#eFlag__parseLval    ;Parsing an lvalue?
+               ORRNE   R6,R6,#eFlag__done      ;Yes -- we're finished
+               ORR     R6,R6,#eFlag__op        ;Now look for binary operator
+               B       %10express_read         ;And read the operator
+
+               ; --- Read a decimal number ---
+
+exp__readDec   MOV     R0,#0                   ;Initial value is zero
+
+00express_read ADD     R0,R0,R0,LSL #2         ;Multiply accumulator by 5
+               ADD     R0,R14,R0,LSL #1        ;Accumulate the result
+
+               BL      getToken                ;Get another token
+               SUB     R14,R9,#'0'             ;Otherwise check for digit
+               CMP     R14,#10                 ;Make sure that's in range
+               BCC     %b00express_read        ;If it was OK, go round more
+
+               MOV     R1,#vType_integer       ;Call it an integer
+               BL      exp__pushVal            ;Stick that on the val stack
+               TST     R6,#eFlag__parseLval    ;Parsing an lvalue?
+               ORRNE   R6,R6,#eFlag__done      ;Yes -- we're finished
+               ORR     R6,R6,#eFlag__op        ;Now look for binary operator
+               B       %10express_read         ;And read the operator
+
+               ; --- Read an identifier ---
+
+exp__readIdent ADR     R1,tsc_misc             ;Point to a nice block
+               MOV     R2,#vType_integer       ;The current variable type
+
+00express_read SUBS    R4,R9,#'_'              ;Is it an underscore?
+               SUBNE   R4,R9,#'0'              ;Or a number?
+               CMP     R4,#10
+               SUBCS   R4,R9,#'A'              ;Or a capital letter?
+               CMPCS   R4,#26
+               SUBCS   R4,R9,#'a'              ;Or a lowercase letter?
+               CMPCS   R4,#26
+               STRCCB  R9,[R1],#1              ;Yes -- store it away
+               BLCC    getToken                ;Read the next byte
+               MOVCS   R0,#err_unknown         ;Don't know this -- error!
+               BCS     error_report            ;So give a bogus error msg
+
+               CMP     R9,#'$'                 ;Is it a dollar sign?
+               MOVEQ   R2,#vType_string        ;It's a string now
+               CMPNE   R9,#'%'                 ;Or a percentage?
+               STREQB  R9,[R1],#1              ;Yes -- store it then
+               CMPNE   R9,#' '                 ;Just check for a space
+
+               BNE     %b00express_read        ;Go round for more
+
+               MOV     R14,#0                  ;The terminator
+               STRB    R14,[R1],#0             ;Store that in the var name
+               BL      getToken                ;Read the next token ready
+
+               ; --- Check for arrays ---
+
+               CMP     R9,#'('                 ;Is this an array?
+               BNE     %f05                    ;No -- skip on then
+               BL      getToken                ;Get another token
+               ADD     R2,R2,#vType_dimInt-vType_integer
+               MOV     R0,R2                   ;Put that in R2
+               ADR     R1,tsc_misc             ;Point to variable name
+               BL      var_find                ;Find the variable
+               LDR     R14,tsc_varTree         ;Find var tree anchor
+               LDR     R14,[R14,#0]            ;Grrr...
+               SUB     R3,R0,R14               ;Convert this to an offset
+               TST     R6,#eFlag__lval         ;Reading an lvalue?
+               ADDNE   R2,R2,#vType_lvIntArr-vType_dimInt
+
+               CMP     R9,#')'                 ;Is it a whole array?
+               BEQ     %f00                    ;Yes -- deal with that
+
+               ; --- Set up for subscripting the array ---
+
+               STMFD   R13!,{R2}               ;Save some registers
+               MOV     R0,R3                   ;Get the array's offset
+               BL      exp__pushOp             ;Stuff that on op stack (!)
+               LDMFD   R13!,{R0}               ;And get its type
+               BL      exp__pushOp             ;Stuff that on op stack too
+
+               GETOP   R0,254,exp__bSubscript  ;Get the operator value
+               TST     R6,#eFlag__commaOk      ;Are we allowing commas?
+               ORRNE   R0,R0,#1<<16            ;Yes -- set the flag then
+               TST     R6,#eFlag__lval         ;Are we reading an value?
+               ORRNE   R0,R0,#1<<17            ;Yes -- set that flag
+               BL      exp__pushOp             ;Put that on there
+               ORR     R6,R6,#eFlag__commaOk   ;Allow commas for a while
+               BIC     R6,R6,#eFlag__lval      ;Don't read as lvalues
+               ADD     R6,R6,#1<<8             ;Increment the paren count
+               B       %10express_read         ;Now read the subscripts
+
+               ; --- Just store the array lvalue ---
+
+00             BL      getToken                ;Skip over the bracket
+               MOV     R1,R2                   ;Get the type
+               MOV     R0,R3                   ;And the tree offset
+               BL      exp__pushVal            ;Stash it on the stack
+               ORR     R6,R6,#eFlag__op        ;Expect an operator
+               B       %10express_read         ;And go read that
+
+               ; --- Handle strings and things ---
+
+05             TST     R6,#eFlag__lval         ;Are we reading an lvalue?
+               BNE     %f20express_read        ;Yes -- jump ahead
+
+               TST     R6,#eFlag__parseLval    ;Parsing an lvalue?
+               ORRNE   R6,R6,#eFlag__done      ;Yes -- we're finished
+
+               ADR     R1,tsc_misc             ;Point to variable name
+               MOV     R0,R2                   ;Get the variable type too
+               BL      var_find                ;Try to find the variable
+
+               ; --- Do wildly different things with strings ---
+
+               CMP     R2,#vType_string        ;Is this a string
+               BNE     %f00                    ;No -- jump ahead then
+               LDR     R14,tsc_varTree         ;Load base of variable tree
+               LDR     R14,[R14]
+               SUB     R0,R0,R14               ;Get the offset of node
+               ADD     R0,R0,#4                ;Point to the actual word
+               MOV     R1,#vType_lvString      ;The variable type
+               BL      ctrl_load               ;Load the string into stracc
+               MOV     R0,R2                   ;Put rvalue into R0,R1
+               MOV     R1,R3
+               BL      exp__pushVal            ;Stack that nicely
+               ORR     R6,R6,#eFlag__op        ;Expect an operator
+               B       %10express_read         ;And keep on looking
+
+00express_read MOV     R1,R2                   ;Get the operand type
+               LDR     R0,[R0,#4]              ;Load the integer value
+               BL      exp__pushVal            ;Stack that nicely
+
+               ; --- Now try to cope with indirection ---
+
+               CMP     R9,#'!'                 ;Is this an indirection op?
+               CMPNE   R9,#'?'                 ;Or maybe a different one
+               ORRNE   R6,R6,#eFlag__op        ;No -- expect an operator
+               BNE     %10express_read         ;And go for that then
+
+               CMP     R9,#'?'                 ;Is this a '?' ?
+               MOVEQ   R0,#(exp__bQuery-exp__bTable)>>2
+               MOVNE   R0,#(exp__bPling-exp__bTable)>>2
+               ORR     R0,R0,#1<<24            ;Use unary op precedence
+               BL      exp__pushOp             ;Stick that on the stack
+               BL      getToken                ;Get another token
+               B       %10express_read         ;Return, still expecting val
+
+               ; --- We are reading an lvalue ---
+               ;
+               ; We only need to create the variable if there is not an
+               ; indirection operator following.
+
+20express_read CMP     R9,#'!'                 ;Is this an indirection op?
+               CMPNE   R9,#'?'                 ;Or maybe a different one
+               ORRNE   R6,R6,#eFlag__done      ;Yes -- we're finished
+               BIC     R6,R6,#eFlag__lval      ;Clear lvalue flag too
+               ORR     R6,R6,#eFlag__parseLval ;Parse an lvalue-ish now
+
+               ADR     R1,tsc_misc             ;Point to variable name
+               MOV     R0,R2                   ;Get the variable type too
+               BLNE    var_create              ;Create the variable maybe
+               BLEQ    var_find                ;Or maybe we just find it
+
+               ADR     R14,exp__indirTran      ;Point to the translation
+               LDRB    R1,[R14,R2]             ;Get the new type
+               LDRNE   R14,tsc_varTree         ;Get the tree address
+               LDRNE   R14,[R14]               ;Wimp_Extension is shitty
+               SUBNE   R0,R0,R14               ;Find the offset
+               ADDNE   R0,R0,#4                ;Point to the actual value
+               LDREQ   R0,[R0,#4]              ;If indirect op, load value
+               BL      exp__pushVal            ;Push on the new value
+
+               CMP     R9,#'?'                 ;Is this a '?' ?
+               MOVEQ   R0,#(exp__bQuery-exp__bTable)>>2
+               MOVNE   R0,#(exp__bPling-exp__bTable)>>2
+               CMPNE   R9,#'!'                 ;Or a '!' ?
+               ORREQ   R0,R0,#1<<24            ;Use unary op precedence
+               BLEQ    exp__pushOp             ;Stick that on the stack
+               BLEQ    getToken                ;Get a token if we need to
+
+               B       %10express_read         ;Return, still expecting val
+
+               ; --- Try reading an operator ---
+
+50express_read CMP     R9,#')'                 ;Is this a close bracket?
+               BEQ     exp__en                 ;Yes -- deal with that then
+
+               CMP     R9,#','                 ;Is it a comma?
+               BEQ     exp__comma              ;Yes -- deal with that
+
+               ADRL    R5,exp__opTable         ;Point to the op table
+               LDR     R0,[R5,R7,LSL #3]!      ;Load the precedence
+               CMP     R0,#0                   ;Is this reasonable?
+               ORREQ   R6,R6,#eFlag__done      ;No -- stop then
+               BEQ     %10express_read         ;Let things tidy up nicely
+
+               BL      exp__eval               ;Evaluate things on the stack
+               LDR     R5,[R5,#4]              ;Load the branch table offset
+               ORR     R0,R5,R0,LSL #24        ;Build the op stack entry
+               ADD     R0,R0,R8                ;Add on the op index
+               BL      exp__pushOp             ;Stick that on the stack
+               BL      getToken                ;Get another token
+               BIC     R6,R6,#eFlag__op        ;Expect another operand
+               B       %10express_read         ;And go round again
+
+               ; --- Handle a closing bracket ---
+
+exp__en                SUBS    R6,R6,#1<<8             ;Decrement paren counter
+               ORRLT   R6,R6,#eFlag__done      ;If no parens, then stop
+               BLT     %10express_read         ;It was someone else's `)'
+               BL      getToken                ;Get another token
+               MOV     R0,#252                 ;Stop at the dummy `(' op
+               BL      exp__eval               ;Force evaluation of that lot
+               BL      exp__popOp              ;Pop the dummy operator
+
+               ; --- Check for comma-separated pseudo-ops ---
+
+               MOV     R14,R0,LSR #24          ;Get the op precedence
+               CMP     R14,#254                ;Is it a cs-pseudo-op?
+               BNE     %10express_read         ;No -- keep going then
+
+               ; --- Reset the flags from the operator ---
+
+               BIC     R6,R6,#eFlag__lval+eFlag__commaOk
+               TST     R0,#1<<16               ;Is the comma-ok flag set?
+               ORRNE   R6,R6,#eFlag__commaOk   ;Yes -- then set it in R6
+               TST     R0,#1<<17               ;Is the lvalue flag set?
+               ORRNE   R6,R6,#eFlag__done+eFlag__lval
+
+               ; --- Now do the required processing ---
+
+               MOV     R5,R0,LSR #8            ;Get the number of arguments
+               ADD     R5,R5,#1                ;One less comman than subs
+               AND     R5,R5,#&FF              ;Clear the other bits
+               AND     R0,R0,#&FF              ;Also find jump entry
+               ADRL    R14,exp__bTable         ;Find the op table
+               ADD     PC,R14,R0,LSL #2        ;And dispatch
+
+               ; --- Handle a comma ---
+
+exp__comma     TST     R6,#eFlag__commaOk      ;Expecting a comma here?
+               ORREQ   R6,R6,#eFlag__done      ;No -- must be someone else's
+               BEQ     %10express_read         ;So let them handle it
+               BL      getToken                ;Gobble the comma char
+               MOV     R0,#253                 ;Evaluate up to pseudoop
+               BL      exp__eval               ;Do lots of evaluating
+               BL      exp__popOp              ;Pop the pseudoop
+               ADD     R0,R0,#1<<8             ;Bump the argument count
+               BL      exp__pushOp             ;Put the pseudoop back again
+               BIC     R6,R6,#eFlag__op        ;Read another operand
+               B       %10express_read         ;Now continue doing things
+
+               ; --- We have finished reading the expression ---
+
+70express_read MOV     R0,#254                 ;Choose a suitable prec.
+               BL      exp__eval               ;Do rest of evaluations
+               BL      exp__popOp              ;Pop of the expression
+
+               ; --- See if this was an evaluated string ---
+
+               AND     R14,R0,#&FF             ;Get the branch table offset
+               CMP     R14,#(exp__bEvalOp-exp__bTable)>>2
+               BEQ     exp__endEval            ;Yes -- continue doing that
+
+               LDMFD   R13!,{R0-R6,PC}^        ;Load some registers
+
+exp__indirTran DCB     vType_lvInt
+               DCB     vType_lvString
+               DCB     vType_lvIntArr
+               DCB     vType_lvStrArr
+
+               LTORG
+
+; --- exp__eval ---
+;
+; On entry:    R0 == precedence to look for
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R1-R4 corrupted
+;
+; Use:         Performs things
+
+exp__eval      ROUT
+
+               STMFD   R13!,{R0,R14}           ;Stack some registers
+00exp__eval    BL      exp__popOp              ;Pop an operator
+               LDR     R1,[R13,#0]             ;Load back thing
+               CMP     R1,R0,LSR #24           ;Compare the prec things
+               BLT     %10exp__eval            ;It's GE so jump ahead
+               MOV     R2,R0                   ;Put op thing in R2
+               AND     R0,R0,#&FF              ;Get the branch offset
+               ADR     R1,exp__bTable          ;Point to the table
+               ADD     PC,R1,R0,LSL #2         ;Branch to the do it routine
+exp__evalRet   BL      exp__pushVal            ;Push the returned value
+               B       %00exp__eval            ;And keep on going
+
+10exp__eval    BL      exp__pushOp             ;Push it back on again
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+; --- exp__doMultArg ---
+;
+; On entry:    R5 == number of subscripts provided
+;              R6 == flags
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == upcall block pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Subscripts an array of things to find just one of them.
+
+exp__doMultArg ROUT
+
+               BL      exp__popOp              ;Pop off the function
+               AND     R0,R0,#&FF              ;Get the branch offset
+               ADR     R1,exp__bTable          ;Point to the table
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R1,R0,LSL #2         ;Branch to the do it routine
+               BL      exp__pushVal            ;Push the returned value
+               B       exp__mainLoop           ;Go back to main loop
+
+               LTORG
+
+               ; --- A nice precedance table ----
+
+exp__opTable   DCD     0,0
+               DCD     25,(exp__andOps-exp__bTable)>>2
+               DCD     0,0
+               DCD     0,0
+               DCD     0,0
+               DCD     0,0
+               DCD     0,0
+               DCD     10,(exp__multOps-exp__bTable)>>2
+               DCD     30,(exp__orOps-exp__bTable)>>2
+               DCD     0,0
+               DCD     0,0
+               DCD     0,0
+               DCD     20,(exp__relOps-exp__bTable)>>2
+               DCD     15,(exp__addOps-exp__bTable)>>2
+               DCD     0,0
+               DCD     5,(exp__powOps-exp__bTable)>>2
+
+               ; --- The main dispatch table ---
+
+exp__bTable
+
+exp__andOps    B       exp__doAnd
+
+exp__multOps   B       exp__doDiv
+               B       exp__doMod
+               B       exp__doDiv
+               B       exp__doMult
+
+exp__orOps     B       exp__doXor
+               B       exp__doOr
+
+exp__relOps    B       exp__doEqual
+               B       exp__doLess
+               B       exp__doLessEq
+               B       exp__doNotEq
+               B       exp__doMore
+               B       exp__doMoreEq
+               B       exp__doLSL
+               B       exp__doASR
+               B       exp__doLSR
+
+exp__addOps    B       exp__doAdd
+               B       exp__doSub
+
+exp__fns       B       exp__doAbs
+               B       exp__doAsc
+               B       exp__doChrS
+               B       exp__doEval
+               B       exp__doLen
+               B       exp__doNot
+               B       exp__doOpenin
+               B       exp__doOpenout
+               B       exp__doOpenup
+               B       exp__doSgn
+               B       exp__doStrS
+               B       exp__doVal
+
+exp__streamOps B       exp__doBget
+               B       exp__doEof
+               B       exp__doExt
+               B       exp__doGetS
+               B       exp__doPtr
+
+exp__multArgs  B       exp__doInstr
+               B       exp__doLeftS
+               B       exp__doMidS
+               B       exp__doRightS
+               B       exp__doStringS
+
+exp__powOps    B       exp__doPow
+
+exp__bUMinus   B       exp__doUMinus
+exp__bPar      B       exp__doParen
+exp__bExpEnd   B       exp__doEndEval
+exp__bEvalOp   B       exp__doEndEval
+exp__bPling    B       exp__doPling
+exp__bQuery    B       exp__doQuery
+exp__bDollar   B       exp__doDollar
+
+exp__bSubscript        B       exp__doSubscript
+
+exp__bMultArg  B       exp__doMultArg
+
+; --- exp__doAdd ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Adds two things.
+
+exp__doAdd     ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               CMP     R1,#vType_integer       ;Is this an integer?
+               BNE     %10exp__doAdd           ;No -- onwards ho
+
+               CMP     R3,#vType_integer       ;Is this a integer too?
+               MOVNE   R0,#err_numNeeded       ;No -- get error number
+               BNE     error_report            ;...and report the error
+               ADD     R0,R0,R2                ;Add the numbers together
+               B       exp__evalRet            ;Jump back into eval loop
+
+               ; --- Concatenate strings ---
+
+10exp__doAdd   CMP     R1,#vType_string        ;This is a string I hope
+               MOVNE   R0,#err_arrayBad        ;Arrays are bad
+               BNE     error_report            ;So says my mum
+               CMP     R3,#vType_string        ;Is this a string too?
+               MOVNE   R0,#err_strNeeded       ;No -- get error number
+               BNE     error_report            ;...and report the error
+
+               MOV     R14,R2,LSL #24          ;Get the second string len
+               CMN     R14,R0,LSL #24          ;Is the string short enough?
+               ADDCC   R0,R0,R14,LSR #24       ;Add on second length
+               BCC     exp__evalRet            ;Finished -- return
+
+               MOV     R0,#err_strTooLong      ;String is too long
+               B       error_report
+
+               LTORG
+
+; --- exp__doSub ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Subtracts one thing from another thing.
+
+exp__doSub     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               SUB     R0,R0,R2                ;Subtract the things
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doMult ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Multiplies two things together.
+
+exp__doMult    ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MUL     R0,R2,R0                ;Multiply the things
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doDiv ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Divides one thing by another thing.
+
+exp__doDiv     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MOV     R1,R2                   ;Get the other thing to do
+               BL      divide                  ;Divide the things
+               MOV     R1,#vType_integer       ;Set the return type
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doMod ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Gives the remainder when one thing is divided by another
+;              thing.
+
+exp__doMod     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MOV     R1,R2                   ;Get the dividend ready
+               BL      divide                  ;Divide the things
+               MOV     R0,R1                   ;Get the remainder
+               MOV     R1,#vType_integer       ;Get the type of the thing
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doPow ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Raises one thing to the power of another thing.
+
+exp__doPow     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+
+               ; --- Check for some special cases ---
+
+               CMP     R0,#1                   ;Raising 1 ^ anything...
+               CMPNE   R2,#0                   ;And raising anything ^ 0...
+               MOVEQ   R0,#1                   ;Gives you 1
+               BEQ     exp__evalRet            ;And return to eval loop
+
+               CMP     R2,#0                   ;Is the exponent negative?
+               MOVLT   R0,#0                   ;Yes -- result is fractional
+               BLT     exp__evalRet            ;And return to eval loop
+
+               ; --- Now we use a cunning loop to make this quick ---
+               ;
+               ; Basically, we note that x^2y == (x^2)^y
+
+               MOV     R3,R0                   ;Look after the x value
+               MOV     R0,#1                   ;An initial multiplier
+
+10exp__doPow   MOVS    R2,R2,LSR #1            ;Get bottom bit
+               MULCS   R0,R3,R0                ;If set, do multiply
+               MUL     R14,R3,R3               ;Square thing to raise
+               MOV     R3,R14                  ;Can't do in one instr :-(
+               BNE     %10exp__doPow           ;If not finished, continue
+
+               B       exp__evalRet            ;Go back to eval loop
+
+               LTORG
+
+; --- exp__doAnd ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         ANDs two things.
+
+exp__doAnd     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               AND     R0,R0,R2                ;Do the AND op
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doOr ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         ORs two things.
+
+exp__doOr      ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               ORR     R0,R0,R2                ;Do the OR op
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doXor ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         XORs two things.
+
+exp__doXor     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               EOR     R0,R0,R2                ;Do the XOR op
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doPling ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Reads a word from a memory address.
+
+exp__doPling   ROUT
+
+               BL      exp__popTwoVals         ;Get next two values
+               CMP     R1,#vType_lvInt         ;We can cope with lvalues
+               BEQ     %50exp__doPling         ;If this is the case, be odd
+               BL      exp__chkTwoInts         ;Make sure we have integers
+               LDR     R0,[R0,R2]              ;Load the word
+               B       exp__evalRet            ;Jump back into eval loop
+
+50exp__doPling CMP     R3,#vType_integer       ;Make sure other val is int
+               MOVNE   R0,#err_numNeeded       ;If not, moan at the user
+               BNE     error_report            ;That's that done then
+               ADD     R0,R0,R2                ;Calculate the address
+               MOV     R1,#vType_lvWord        ;This is a word lvalue
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doQuery ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Reads a byte from a memory address.
+
+exp__doQuery   ROUT
+
+               BL      exp__popTwoVals         ;Get next two values
+               CMP     R1,#vType_lvInt         ;We can cope with lvalues
+               BEQ     %50exp__doQuery         ;If this is the case, be odd
+               BL      exp__chkTwoInts         ;Make sure we have integers
+               LDRB    R0,[R0,R2]              ;Load the byte
+               B       exp__evalRet            ;Jump back into eval loop
+
+50exp__doQuery CMP     R3,#vType_integer       ;Make sure other val is int
+               MOVNE   R0,#err_numNeeded       ;If not, moan at the user
+               BNE     error_report            ;That's that done then
+               ADD     R0,R0,R2                ;Calculate the address
+               MOV     R1,#vType_lvByte        ;This is a byte lvalue
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doDollar ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Reads a word from a memory address.
+
+exp__doDollar  ROUT
+
+               BL      exp__popTwoVals         ;Get next two values
+               CMP     R1,#vType_lvInt         ;We can cope with lvalues
+               BEQ     %50exp__doDollar        ;If this is the case, be odd
+               BL      exp__chkTwoInts         ;Make sure we have integers
+
+               ADD     R2,R0,R2                ;Point to the string
+               BL      stracc_ensure           ;Make sure there is room
+               MOV     R3,#0                   ;Number so far
+00             LDRB    R14,[R2],#1             ;Load a byte
+               CMP     R14,#13                 ;Is this the terminator?
+               BEQ     %10exp__doDollar        ;Yes -- jump ahead
+               STRB    R14,[R0],#1             ;No -- save it away
+               ADD     R3,R3,#1                ;Increment the length
+               CMP     R3,#255                 ;Are we at the maximum?
+               BLT     %b00                    ;No -- branch back then
+
+10             ORR     R0,R1,R3                ;Set up the lvalue
+               MOV     R1,#vType_string        ;This is a string
+               B       exp__evalRet            ;Jump back into eval loop
+
+               ; --- The lvalue form ---
+
+50exp__doDollar        CMP     R3,#vType_integer       ;Make sure other val is int
+               MOVNE   R0,#err_numNeeded       ;If not, moan at the user
+               BNE     error_report            ;That's that done then
+               ADD     R0,R0,R2                ;Calculate the address
+               MOV     R1,#vType_lvBytes       ;This is a bytes lvalue
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- RND ---
+
+exp__doRnd     ROUT
+
+               CMP     R9,#'('                 ;Do we have a bracket here?
+               MOVNE   R0,#-1                  ;No -- range here then
+               BLNE    exp__rng                ;And generate random number
+               ORRNE   R6,R6,#eFlag__op        ;Read operator next
+               BNE     exp__mainLoop           ;And go back up top
+               BL      getToken                ;Gobble the bracket
+
+               ; --- Start scanning for an RND multi-op ---
+
+               GETOP   R0,1,exp__rndArg        ;Get the operator value
+               BL      exp__pushOp             ;Put that on the stack
+
+               GETOP   R0,254,exp__bMultArg    ;Get the operator value
+               TST     R6,#eFlag__commaOk      ;Are we allowing commas?
+               ORRNE   R0,R0,#1<<16            ;Yes -- set the flag then
+               BL      exp__pushOp             ;Put that on there
+               BIC     R6,R6,#eFlag__commaOk   ;Disallow commas for a while
+               ADD     R6,R6,#1<<8             ;Increment the paren count
+               B       exp__mainLoop           ;And go back up top
+
+               LTORG
+
+; --- RND(arg) ---
+
+exp__rndArg    ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               BL      exp__popInt             ;Pop off the argument
+               CMP     R0,#0                   ;Is the value negative?
+               BLT     %50exp__rndArg          ;Yes -- deal with that
+               CMPNE   R0,#1                   ;Is it one then?
+               BEQ     %60exp__rndArg          ;Yes -- be odd then
+               BL      exp__rng                ;And generate random number
+               BL      exp__popVal             ;Pop the value off
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               ; --- Store a seed ---
+
+50exp__rndArg  STR     R0,tsc_rndSeed          ;Store the new seed
+               MOV     R14,#0                  ;Clear the top bit
+               STR     R14,tsc_rndSeed+4       ;Store that too
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               ; --- Request for FP random number ---
+
+60exp__rndArg  STMFD   R13!,{R5}               ;Save another register
+               MOV     R0,#0                   ;Return zero here
+               MOV     R1,#vType_integer       ;Say this is an integer
+               LDMFD   R13!,{R5,PC}^           ;And return
+
+               LTORG
+
+; --- exp__rng ---
+;
+; On entry:    R0 == maximum value for random number
+;
+; On exit:     --
+;
+; Use:         Stacks a random number between 1 and R0.
+
+exp__rng       ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save lots of registers
+               MOV     R3,R0                   ;Look after this
+               ADR     R14,tsc_rndSeed         ;Find the random seed
+               LDMIA   R14,{R0,R1}             ;Load that out
+               TST     R1,R1,LSR #1            ;Top bit into carry
+               MOVS    R2,R0,RRX               ;33-bit rotate right
+               ADC     R1,R1,R1                ;Carry into LSB of Rb
+               EOR     R2,R2,R0,LSL #12        ;(Involved!)
+               EOR     R0,R2,R2,LSR #20        ;(Similarly involved!)
+               STMIA   R14,{R0,R1}             ;Store new seed back
+               MOV     R1,R3                   ;Get maximum value again
+               BL      div_unsigned            ;Do the division we need
+               ADD     R0,R1,#1                ;Fit it into range
+               MOV     R1,#vType_integer       ;This is an integer
+               BL      exp__pushVal            ;Push it onto the stack
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               LTORG
+
+; --- Relational operators (and shifts) ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Does comparing.  Or shifting.  Depending.
+
+exp__doLess    ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVLT   R0,#-1                  ;It's less -- that's true
+               MOVGE   R0,#0                   ;It's more or equal, -- false
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doMore    ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVGT   R0,#-1                  ;It's more -- that's true
+               MOVLE   R0,#0                   ;It's less or equal, -- false
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doLessEq  ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVLE   R0,#-1                  ;It's less or equal -- true
+               MOVGT   R0,#0                   ;It's more -- that's false
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doMoreEq  ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVGE   R0,#-1                  ;It's more or equal -- true
+               MOVLT   R0,#0                   ;It's less -- that's false
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doEqual   ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVEQ   R0,#-1                  ;If equal, return TRUE
+               MOVNE   R0,#0                   ;Otherwise return FALSE
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doNotEq   ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVNE   R0,#-1                  ;If nonzero, return TRUE
+               MOVEQ   R0,#0                   ;Otherwise return FALSE
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doLSL     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MOV     R0,R0,LSL R2            ;Do the shift
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doLSR     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MOV     R0,R0,LSR R2            ;Do the shift
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doASR     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MOV     R0,R0,ASR R2            ;Do the shift
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doUMinus ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Negates a thing.
+
+exp__doUMinus  ROUT
+
+               BL      exp__popInt             ;Pop a val
+               RSB     R0,R0,#0                ;Negate the thing
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doSubscript ---
+;
+; On entry:    R5 == number of subscripts provided
+;              R6 == flags
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == upcall block pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Subscripts an array of things to find just one of them.
+
+exp__doSubscript ROUT
+
+               BL      exp__popOp              ;Read the array's type
+               STMFD   R13!,{R0}               ;Save that away
+               BL      exp__popOp              ;Now find the offset too
+               LDMFD   R13!,{R2}               ;Restore the type word
+               LDR     R14,tsc_varTree         ;Find the variable tree
+               LDR     R14,[R14,#0]            ;Grrr...
+               ADD     R3,R0,R14               ;Find the actual array
+
+               ; --- Do some preliminary checking ---
+
+               LDR     R14,[R3,#4]             ;Find number of subscripts
+               CMP     R14,R5                  ;Do they match up?
+               MOVNE   R0,#err_numSubs         ;No -- get an error
+               BNE     error_report            ;And report it
+
+               ; --- Now actually find the element ---
+
+               STMFD   R13!,{R2,R7-R10}        ;Save some more registers
+               ADD     R10,R3,#12              ;Point to subscripts
+               ADD     R10,R10,R5,LSL #2       ;Find topmost subscript
+               MOV     R9,R10                  ;Do this again
+               MOV     R8,#0                   ;Current element is 0
+               MOV     R7,R5                   ;Get the number of subscripts
+
+00             BL      exp__popInt             ;Read the next integer
+               LDR     R14,[R9,#-4]!           ;And load subscript size
+               CMP     R0,R14                  ;How does this compare?
+               MOVCS   R0,#err_subRange        ;Out of range -- get error
+               BCS     error_report            ;And report it
+               MLA     R8,R14,R8,R0            ;Accumulate subscript
+               SUBS    R7,R7,#1                ;Decrement my counter
+               BGT     %b00                    ;If more to go, keep on
+
+               ; --- Finally get an rvalue or lvalue as required ---
+
+               ADD     R0,R10,R8,LSL #2        ;Find the lvalue
+               LDMFD   R13!,{R1,R7-R10}        ;Restore system registers
+               LDR     R14,tsc_varTree         ;Find the variable tree
+               LDR     R14,[R14,#0]            ;Grrr...
+               SUB     R0,R0,R14               ;Yes -- turn into offset
+               TST     R6,#eFlag__lval         ;Reading an lvalue?
+               SUBNE   R1,R1,#vType_lvIntArr-vType_lvInt
+               SUBEQ   R1,R1,#vType_dimInt-vType_lvInt
+               BLEQ    ctrl_load               ;No -- load rvalue then
+               MOVEQ   R0,R2                   ;And shift results around
+               MOVEQ   R1,R3                   ;Because of strangeness
+               BL      exp__pushVal            ;Push the result
+               B       exp__mainLoop           ;Go back to main loop
+
+               LTORG
+
+; --- exp__doParen ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Complains.
+
+exp__doParen   ROUT
+
+               MOV     R0,#err_expBracket      ;Get the error message
+               B       error_report            ;And complain bitterly
+
+               LTORG
+
+; --- exp__doEndEval ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Complains.
+
+exp__doEndEval ROUT
+
+               MOV     R0,#err_erk             ;Get the error message
+               B       error_report            ;And complain bitterly
+
+               LTORG
+
+; --- exp__getString ---
+;
+; On entry:    R0 == buffer for string
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0 == length of string
+;
+; Use:         Reads a string argument, and copies it into tsc_misc.
+
+exp__getString ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Stack some register
+               MOV     R5,R0                   ;Look after address
+               BL      exp__popStr             ;Get a string
+               LDR     R1,tsc_stracc           ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+               MOV     R3,R0                   ;Look after the rvalue
+               MOV     R0,R5                   ;Point to a buffer
+               BL      termite_copyString      ;Copy the string over
+               MOV     R0,R3                   ;Put the rvalue back
+               BL      stracc_free             ;Won't need it any more
+               MOV     R0,R2                   ;Put the length in R0
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to caller
+
+               LTORG
+
+;----- Pseudovariables ------------------------------------------------------
+
+; --- TIME ---
+
+exp__doTime    STMFD   R13!,{R14}
+               SWI     OS_ReadMonotonicTime
+               LDR     R1,tsc_timeOff
+               SUB     R0,R0,R1
+               MOV     R1,#vType_integer
+               BL      exp__pushVal
+               LDMFD   R13!,{PC}^
+
+; --- TIME$ ---
+
+exp__doTimeS   STMFD   R13!,{R14}              ;Save some registers
+
+               ; --- First, read the system clock ---
+
+               SUB     R13,R13,#8              ;Get a nice block
+               MOV     R0,#14                  ;Read the system clock
+               MOV     R1,R13                  ;Point to the block
+               MOV     R14,#3                  ;Get the reason code
+               STRB    R14,[R1,#0]             ;Store in block
+               SWI     OS_Word                 ;Read the time then
+
+               ; -- Now put it into stracc ---
+
+               BL      stracc_ensure           ;Make sure we have room
+               MOV     R4,R1                   ;Remember the index
+               MOV     R1,R0                   ;Put the address in R1
+               MOV     R0,R13                  ;Point to time block
+               MOV     R2,#255                 ;Size of the buffer
+               ADR     R3,exp__timeFormat      ;Point to the format
+               SWI     OS_ConvertDateAndTime   ;Convert the date and time
+               ORR     R0,R4,#24               ;Set up the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               ADD     R13,R13,#8              ;Reclaim my stack
+               BL      exp__pushVal            ;Push on my value
+               LDMFD   R13!,{PC}^              ;Return the caller
+
+exp__timeFormat        DCB     "%W3,%DY %M3 %CE%YR.%24:%MI:%SE",0
+
+; --- FALSE ---
+
+exp__doFalse   MOV     R0,#0
+               MOV     R1,#vType_integer
+               B       exp__pushVal
+
+; --- TRUE ---
+
+exp__doTrue    MOV     R0,#-1
+               MOV     R1,#vType_integer
+               B       exp__pushVal
+
+;----- Functions ------------------------------------------------------------
+
+; --- EVAL ---
+
+exp__doEval    ROUT
+
+               ; --- Hack the stack ---
+               ;
+               ; We're called from exp__eval, which has stacked R0 and R14.
+               ; We pop these off the stack, and stuff them onto the op
+               ; stack instead.  Yukmeister.
+
+               LDMFD   R13!,{R0}               ;Get R0 off the stack
+               BL      exp__pushOp             ;Push that onto op stack
+               LDMFD   R13!,{R0}               ;And R14 off too
+               BL      exp__pushOp             ;Push that onto op stack
+               MOV     R0,R5                   ;We need to corrupt R5
+               BL      exp__pushOp             ;Push that onto op stack
+
+               ; --- Tokenise the string to evaluate ---
+
+               BL      stracc_ensure           ;Make space for tokenised
+               STMFD   R13!,{R0,R1}            ;Save the address away
+               BL      exp__popStr             ;Pop the string
+               LDR     R14,tsc_stracc          ;Load stracc anchor address
+               LDR     R14,[R14,#0]            ;Grrr....
+               MOV     R5,R0                   ;Remember this for a while
+               AND     R1,R0,#&FF              ;Get the string length
+               ADD     R0,R14,R0,LSR #8        ;Work out string address
+               LDMFD   R13!,{R2}               ;Load the address out
+               MOV     R3,#0                   ;Just tokenise the expression
+               BL      tokenise                ;Go and do that then
+               LDMFD   R13!,{R0}               ;Load the stracc rvalue
+               ADD     R0,R0,#&FF              ;Say it's very long
+               BL      stracc_added            ;And record that
+
+               ; --- Now save state on the op stack ---
+
+               STMFD   R13!,{R2}               ;Save the address again
+               MOV     R0,R5                   ;Save the stracc offset
+               BL      exp__pushOp             ;Stack that
+               MOV     R0,R6                   ;Save the eval flags
+               BL      exp__pushOp             ;Stack that
+               LDR     R0,tsc_oldAnchor        ;Load the old anchor
+               BL      exp__pushOp             ;Push that away too
+               LDR     R0,tsc_currAnchor       ;Load current file anchor
+               STR     R0,tsc_oldAnchor        ;This is now the old one
+               LDR     R0,[R0,#0]              ;Load the actual pointer
+               SUB     R0,R10,R0               ;Find the file offset
+               BL      exp__pushOp             ;Push that away too
+               LDR     R14,tsc_stracc          ;Input is now in stracc
+               STR     R14,tsc_currAnchor      ;This is the new anchor
+               LDMFD   R13!,{R10}              ;Load the new address
+               GETOP   R0,255,exp__bEvalOp     ;Create a pseudoop
+               BL      exp__pushOp             ;Stuff that on the stack
+               MOV     R6,#0                   ;Just read an expression
+               MOV     R9,#-1                  ;Make getToken happy
+               BL      getToken                ;Prime the first token
+               B       exp__mainLoop           ;And resume the main loop
+
+               LTORG
+
+; --- exp__endEval ---
+
+exp__endEval   ROUT
+
+               BL      exp__popOp              ;Pop the file offset
+               MOV     R10,R0                  ;Look after this
+               LDR     R14,tsc_oldAnchor       ;Load the previous anchor
+               STR     R14,tsc_currAnchor      ;This is now the current one
+               LDR     R14,[R14,#0]            ;Bodge for wimpextension
+               ADD     R10,R14,R10             ;Relocate the output pointer
+               BL      exp__popOp              ;And the anchor pointer
+               STR     R0,tsc_oldAnchor        ;Remember this now
+               SUB     R10,R10,#1              ;Quick hack now
+               MOV     R9,#-1                  ;Make getToken happy
+               BL      getToken                ;Prime lookahead token
+               BL      exp__popOp              ;Pop the express_read flags
+               MOV     R6,R0                   ;Re-instate them
+               BL      exp__popOp              ;Get the stracc offset
+               BL      stracc_free             ;Free *both* the strings
+               BL      exp__popOp              ;Get preserved R5 value
+               MOV     R5,R0                   ;Put that back nicely
+               BL      exp__popOp              ;Get stacked R14 value
+               STMFD   R13!,{R0}               ;Push that back on the stack
+               BL      exp__popOp              ;Get stacked R0 value
+               STMFD   R13!,{R0}               ;Push that back on the stack
+               BL      exp__popVal             ;Pop the result (odd)
+               B       exp__evalRet            ;Now leap back into routine
+
+               LTORG
+
+; --- VAL ---
+
+exp__doVal     ROUT
+
+               ADR     R0,tsc_misc             ;Point to a buffer
+               BL      exp__getString          ;Get a string
+               ADR     R1,tsc_misc             ;Point to the string
+
+               ; --- Scan the string ---
+               ;
+               ; We skip spaces, and stop at the first non space.
+               ; If that happens to be a minus sign, we remember that.
+
+00             LDRB    R14,[R1],#1             ;Read the character
+               CMP     R14,#0                  ;Are we at the end?
+               MOVEQ   R0,#0                   ;Yes -- get the rvalue
+               BEQ     %20exp__doVal           ;And jump ahead a bit
+               CMP     R14,#32                 ;Is this a space
+               BEQ     %b00                    ;Yes -- go round for more
+               CMP     R14,#'-'                ;Is it a minus sign?
+               SUBNE   R1,R1,#1                ;No -- backtrack then
+               MOV     R0,#10                  ;Read as base 10 by default
+               SWI     XOS_ReadUnsigned        ;Read the value
+               RSBEQ   R0,R2,#0                ;Negate if we should
+               MOVNE   R0,R2                   ;Otherwise don't bother
+               MOVVS   R0,#0                   ;Return 0 on an error
+20             MOV     R1,#vType_integer       ;This is an integer
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+;----- Arithmetic routine ---------------------------------------------------
+
+; --- ABS ---
+
+exp__doAbs     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               CMP     R0,#0                   ;Is the argument <0?
+               RSBLT   R0,R0,#0                ;Yes -- negate it then
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+; --- NOT ---
+
+exp__doNot     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MVN     R0,R0                   ;Invert the operand
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+; --- SGN ---
+
+exp__doSgn     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               CMP     R0,#0                   ;Compare argument with 0
+               MOVGT   R0,#1                   ;If bigger return 1
+               MOVLT   R0,#-1                  ;If smaller, return -1
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+;----- String associated routines -------------------------------------------
+
+; --- ASC ---
+
+exp__doAsc     ROUT
+
+               BL      exp__popStr             ;Get a string
+               BL      stracc_free             ;Won't need it any more
+               MOV     R1,#vType_integer       ;We will return an int
+               TST     R0,#&FF                 ;Is this a NULL string?
+               MOVEQ   R0,#-1                  ;Yes -- return -1 then
+               BEQ     exp__evalRet
+
+               LDR     R14,tsc_stracc          ;Loacte stracc
+               LDR     R14,[R14]
+               ADD     R14,R14,R0,LSR #8       ;Point to the string
+               LDRB    R0,[R14,#0]             ;Load a byte
+               B       exp__evalRet            ;Return this to caller
+
+; --- CHR$ ---
+
+exp__doChrS    ROUT
+
+               BL      exp__popInt             ;Pop an integer
+               MOV     R2,R0                   ;Look after the value
+               BL      stracc_ensure           ;Make sure there's space
+               MOVS    R14,R2,LSR #8           ;Check the value's OK
+               STREQB  R2,[R0,#0]              ;If so, store it
+               ORREQ   R1,R1,#1                ;And set length one
+               MOV     R0,R1                   ;Get the rvalue
+               MOV     R1,#vType_string        ;Say it's a string
+               BL      stracc_added            ;Say I've added it
+               B       exp__evalRet            ;And return to eval loop
+
+
+; --- LEN ---
+
+exp__doLen     ROUT
+
+               BL      exp__popStr             ;Get a string
+               BL      stracc_free             ;Won't need it any more
+               AND     R0,R0,#&FF              ;Get the length
+               MOV     R1,#vType_integer       ;This is an integer
+               B       exp__evalRet            ;Return to eval loop
+
+; --- STR$ ---
+
+exp__doStrS    ROUT
+
+               TST     R2,#(1<<16)             ;Is this a hex conversion?
+               BL      exp__popInt             ;Pop an integer
+               MOV     R3,R0                   ;Put it in R3
+               BL      stracc_ensure           ;Make sure we have room
+               MOV     R4,R1                   ;Look after the offset
+               BNE     %10exp__doStrS          ;If hex -- jump ahead
+
+
+               MOV     R1,R0                   ;Write result to here
+               MOV     R2,#255                 ;Buffer is big
+               MOVS    R0,R3                   ;Put the number in here
+               RSBLT   R0,R0,#0                ;If -ve, mak positive
+               MOVLT   R14,#'-'                ;...get a minus ready
+               STRLTB  R14,[R1],#1             ;Store in the buffer
+               SWI     OS_ConvertInteger4      ;Convert to a string
+               SUB     R14,R1,R0               ;Get the string length
+               ADDLT   R14,R14,#1              ;There may be a minus
+               ORR     R0,R4,R14               ;Get the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about it
+               B       exp__evalRet            ;Return to eval loop
+
+               ; --- We need to output as hex ---
+
+10exp__doStrS  ADR     R1,tsc_misc             ;Point to a nice buffer
+00             AND     R2,R3,#&F               ;Get teh remainder
+               MOV     R3,R3,LSR #4            ;Divide number by 16
+               ADD     R14,R2,#'0'             ;Turn into a digit
+               CMP     R14,#'9'+1              ;Is it too big for this?
+               ADDCS   R14,R14,#'A'-'9'-1      ;Yes -- turn into a letter
+               STRB    R14,[R1],#1             ;Save the next byte
+               CMP     R3,#0                   ;Have we finished now?
+               BNE     %b00                    ;Yes -- jump back then
+
+               ; --- Copy the digits over ---
+               ;
+               ; The characters are now in the buffer in reverse order
+
+               ADR     R2,tsc_misc             ;Point to the buffer
+               SUBS    R2,R1,R2                ;Get the number of chars
+               ORR     R4,R4,R2                ;Put that in the index
+00             LDRGTB  R14,[R1,#-1]!           ;Load out  byte
+               STRGTB  R14,[R0],#1             ;Store that in the buffer
+               SUBS    R2,R2,#1                ;Reduce the number count
+               BGT     %b00                    ;And keep on doing this
+
+               MOV     R0,R4                   ;Get the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about it
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+;----- File operations ------------------------------------------------------
+
+; --- OPENOUT ---
+
+exp__doOpenout ADR     R0,tsc_misc             ;Point to a buffer
+               BL      exp__getString          ;Get the string argument
+
+               MOV     R0,#&81                 ;The flags to open with
+               ADR     R1,tsc_misc             ;Point to the name
+               SWI     XOS_Find                ;Try to open the file
+               BVS     error_reportReal        ;Return possible error
+               BL      exp__opened             ;Remember we opened the file
+
+               MOV     R1,#vType_integer       ;We will return an int
+               B       exp__evalRet            ;Return this to caller
+
+               LTORG
+
+; --- OPENUP ---
+
+exp__doOpenup  ADR     R0,tsc_misc             ;Point to a buffer
+               BL      exp__getString          ;Get the string argument
+
+               MOV     R0,#&C7                 ;The flags to open with
+               ADR     R1,tsc_misc             ;Point to the name
+               SWI     XOS_Find                ;Try to open the file
+               BVS     error_reportReal        ;Return possible error
+               BL      exp__opened             ;Remember we opened the file
+
+               MOV     R1,#vType_integer       ;We will return an int
+               B       exp__evalRet            ;Return this to caller
+
+               LTORG
+
+; --- OPENIN ---
+
+exp__doOpenin  ADR     R0,tsc_misc             ;Point to a buffer
+               BL      exp__getString          ;Get the string argument
+
+               MOV     R0,#&47                 ;The flags to open with
+               ADR     R1,tsc_misc             ;Point to the name
+               SWI     XOS_Find                ;Try to open the file
+               BVS     error_reportReal        ;Return possible error
+               BL      exp__opened             ;Remember we opened the file
+
+               MOV     R1,#vType_integer       ;We will return an int
+               B       exp__evalRet            ;Return this to caller
+
+               LTORG
+
+; --- exp__opened ---
+;
+; On entry:    R0 == file handle
+;
+; On exit:     --
+;
+; Use:         Remembers that a file has been opened.  (Bit bashing code
+;              courtesy of the RISC OS 3.5 Keyboard Drivers, duplicated
+;              without permission.)
+
+exp__opened    ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADR     R1,tsc_files            ;Find file bit-array
+               MOV     R14,R0,LSR #5           ;Get word index
+               LDR     R14,[R1,R14,LSL #2]!    ;Load the word I want
+               MOV     R2,#(1<<31)             ;Set the top bit here
+               ORR     R14,R14,R2,ROR R0       ;Set the correct bit
+               STR     R14,[R1,#0]             ;Save the word back again
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Stream operations ----------------------------------------------------
+
+; --- BGET ---
+
+exp__doBget    ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MOV     R1,R0                   ;Put it in R1
+               SWI     XOS_BGet                ;Get a byte from the file
+               BVS     error_reportReal
+               MOV     R1,#vType_integer       ;It's an integer Jim
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+; --- EOF ---
+
+exp__doEof     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MOV     R1,R0                   ;Put it in R1
+               MOV     R0,#5                   ;Read EOF status
+               SWI     XOS_Args                ;Read it then
+               BVS     error_reportReal
+               MOVS    R0,R2                   ;Put result in R0
+               MOVNE   R0,#-1                  ;Make it -1 if TRUE
+               MOV     R1,#vType_integer       ;It's an integer Jim
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+; --- EXT ---
+
+exp__doExt     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MOV     R1,R0                   ;Put it in R1
+               MOV     R0,#2                   ;Read EOF status
+               SWI     XOS_Args                ;Read it then
+               BVS     error_reportReal
+               MOV     R0,R2                   ;Put result in R0
+               MOV     R1,#vType_integer       ;It's an integer Jim
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+; --- GET$ ---
+
+exp__doGetS    ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MOV     R4,R0                   ;Put it in R4
+               BL      stracc_ensure           ;Ensure there is enough space
+               MOV     R2,R0                   ;Remember the address
+               MOV     R3,R1                   ;And the offset
+               MOV     R1,R4                   ;Put file handle in R1
+               MOV     R4,#0                   ;The length so far
+00             SWI     XOS_BGet                ;Geta byte
+               BVS     error_reportReal        ;Report possible error
+               BCS     %10exp__doGetS          ;Undefined -- dropout
+               CMP     R0,#10                  ;Have we reached the end?
+               CMPNE   R0,#13
+               CMPNE   R0,#0
+               BEQ     %10exp__doGetS          ;Yes -- drop out
+               STRB    R0,[R2],#1              ;No -- store the byte
+               ADD     R4,R4,#1                ;And increment the count
+               CMP     R4,#255                 ;Have we read the maximum?
+               BLT     %b00                    ;No -- keep getting them
+
+10exp__doGetS  ORR     R0,R3,R4                ;Get the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               B       exp__evalRet            ;Return to eval loop
+
+; --- PTR ---
+
+exp__doPtr     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MOV     R1,R0                   ;Put it in R1
+               MOV     R0,#0                   ;Read EOF status
+               SWI     XOS_Args                ;Read it then
+               BVS     error_reportReal
+               MOV     R0,R2                   ;Put result in R0
+               MOV     R1,#vType_integer       ;It's an integer Jim
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+;---- Multiple argument things ----------------------------------------------
+
+; --- exp__midString ---
+;
+; On entry:    R1 == index into string
+;              R2 == number of chars needed
+;              String is in tsc_misc
+;
+; On exit:     R0, R1 == value to push
+;
+; Use:         Performs a string extraction on the string
+
+exp__midString ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link
+               ADR     R0,tsc_misc             ;Point to the string
+               ADD     R3,R0,R1                ;Copy from here
+               MOV     R4,R2                   ;Remember the length
+               BL      stracc_ensure           ;Make sure we have room
+               CMP     R2,#0                   ;Anything to copy?
+00             LDRGTB  R14,[R3],#1             ;Load a byte
+               STRGTB  R14,[R0],#1             ;Store it
+               SUBS    R2,R2,#1                ;Decrement the count
+               BGT     %b00                    ;Go round for more
+               ORR     R0,R1,R4                ;Get the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- LEFT$ ---
+
+exp__doLeftS   ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack registers
+               CMP     R5,#2                   ;Two of them?
+               MOVNE   R0,#err_leftSArgs       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               BL      exp__popInt             ;Get the number of chars
+               MOV     R2,R0                   ;Put that in R2
+               MOV     R1,#0                   ;From the beginning
+               ADR     R0,tsc_misc             ;Point to a buffer
+               BL      exp__getString          ;Get then string
+               CMP     R2,R0                   ;Are we getting too many?
+               MOVCS   R2,R0                   ;Yes -- get this many
+               BL      exp__midString          ;Do the mid$
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- MID$ ---
+
+exp__doMidS    ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack registers
+               CMP     R5,#2                   ;Two of them?
+               CMPNE   R5,#3                   ;Or maybe 3?
+               MOVNE   R0,#err_midSArgs        ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               CMP     R5,#2                   ;Just two args?
+               BEQ     %10exp__doMidS          ;Yes -- jump ahead
+
+               BL      exp__popTwoInts         ;Get the number of chars
+               SUBS    R1,R0,#1                ;Put index in R1
+               MOVLT   R1,#0                   ;Put it in range
+               ADR     R0,tsc_misc             ;Point to a buffer
+               BL      exp__getString          ;Get then string
+               CMP     R1,R0                   ;Is the index in range?
+               MOVGT   R1,R0                   ;No -- put it in range
+               SUB     R14,R0,R1               ;Get number of chars left
+               CMP     R2,R14                  ;Are we getting too many?
+               MOVCS   R2,R14                  ;Yes -- get this many
+               BL      exp__midString          ;Do the mid$
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               ; --- Deal with 2 arg variation ---
+
+10exp__doMidS  BL      exp__popInt             ;Get the index
+               SUB     R1,R0,#1                ;Put it in R1
+               ADR     R0,tsc_misc             ;Point to a buffer
+               BL      exp__getString          ;Get the string
+               CMP     R1,R0                   ;Are we in range?
+               MOVCS   R1,R0                   ;No -- we are now
+               SUB     R2,R0,R1                ;Get the number to get
+               BL      exp__midString          ;Do the mid$
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- RIGHT$ ---
+
+exp__doRightS  ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack registers
+               CMP     R5,#2                   ;Two of them?
+               MOVNE   R0,#err_rightSArgs      ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               BL      exp__popInt             ;Get the number
+               MOV     R2,R0                   ;Put it in R2
+               ADR     R0,tsc_misc             ;Point to the buffer
+               BL      exp__getString          ;Get the string
+               SUBS    R1,R0,R2                ;Work out the index
+               MOVLT   R1,#0                   ;If getting too many, reduce
+               MOVLT   R2,R0
+               BL      exp__midString          ;Do the mid$
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- STRING$ ---
+
+exp__doStringS ROUT
+
+               ; --- Make sure we have the right number of arguments ---
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack registers
+               CMP     R5,#2                   ;Two of them?
+               MOVNE   R0,#err_stringSArgs     ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ADR     R0,tsc_misc             ;Point to a buffer
+               BL      exp__getString          ;Copy the string into buffer
+               MOV     R5,R0                   ;Put length in R2
+               BL      exp__popInt             ;Pop an integer
+               MOV     R3,R0                   ;Put number in R3
+               MUL     R6,R5,R0                ;Get the overall length
+               CMP     R6,#255                 ;Is it too big?
+               MOVGT   R0,#err_strTooLong      ;Yes -- get error number
+               BGT     error_report            ;And report it happily
+
+               ; --- Now copy the string ---
+
+               CMP     R5,#0                   ;Is this a 0 length string?
+               MOVEQ   R0,#0                   ;Yes -- get rvalue
+               BEQ     %10exp__doStringS       ;And jump ahead
+
+               BL      stracc_ensure           ;Make sure we have room
+               MOV     R4,R1                   ;Look after the offset
+               MOV     R2,R5                   ;Keep copy of length
+
+00             ADR     R1,tsc_misc             ;Point to the string
+05             LDRB    R14,[R1],#1             ;Load a byte
+               STRB    R14,[R0],#1             ;Store it
+               SUBS    R2,R2,#1                ;Decrement the string length
+               BGT     %b05                    ;And go round for more
+               MOV     R2,R5                   ;Get the length back
+               SUBS    R3,R3,#1                ;Decrment other counter
+               BGT     %b00                    ;And go round for more
+
+               ORR     R0,R4,R6                ;Get the rvalue
+10             MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about it
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- INSTR ---
+
+exp__doInstr   ROUT
+
+               STMFD   R13!,{R5,R14}           ;Stack registers
+               CMP     R5,#2                   ;Two of them?
+               CMPNE   R5,#3                   ;Or maybe 3?
+               MOVNE   R0,#err_instrSArgs      ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               CMP     R5,#3                   ;Are there 3 args?
+               BLEQ    exp__popInt             ;Yes -- get it then
+               SUBEQ   R5,R0,#1                ;And reduce by 1
+               MOVNE   R5,#0                   ;Otherwise use 0
+
+               BL      exp__popTwoStrs         ;Get two strings
+               STMFD   R13!,{R0,R6-R9}         ;Stack nice stracc position
+               LDR     R14,tsc_stracc          ;Get the stracc anchor
+               LDR     R14,[R14]
+               AND     R1,R0,#&FF              ;Get a string length
+               ADD     R0,R14,R0,LSR #8        ;Point at the strings
+               AND     R3,R2,#&FF              ;Do this for...
+               ADD     R2,R14,R2,LSR #8        ;...both of them
+
+               SUB     R1,R1,R5                ;Get len of remaining string
+05             CMP     R1,R3                   ;Enough string for a match?
+               BLT     %90exp__doInstr         ;No match -- jump onwards
+               ADD     R6,R0,R5                ;Look after values
+               MOV     R7,R2
+               MOV     R9,R3                   ;Remember the length too
+00             SUBS    R9,R9,#1                ;Reduce length count
+               BLT     %95exp__doInstr         ;We have a match :-)
+               LDRB    R8,[R6],#1              ;Load a byte
+               LDRB    R14,[R7],#1             ;From both strings
+               CMP     R8,R14                  ;Do the bytes match?
+               BEQ     %b00                    ;Yes -- keep on comparing
+               ADD     R5,R5,#1                ;Increment the position
+               SUB     R1,R1,#1                ;Reduce length
+               B       %b05                    ;And keep on going
+
+               ; --- We return failure ---
+
+90             LDMFD   R13!,{R0,R6-R9}         ;Load back registers
+               BL      stracc_free             ;Free my strings
+               MOV     R0,#0                   ;No match
+               MOV     R1,#vType_integer       ;Return a string please
+               LDMFD   R13!,{R5,PC}^           ;Return to caller
+
+               ; --- Return success then ---
+
+95             LDMFD   R13!,{R0,R6-R9}         ;Load back registers
+               BL      stracc_free             ;Free my strings
+               ADD     R0,R5,#1                ;No match
+               MOV     R1,#vType_integer       ;Return a string please
+               LDMFD   R13!,{R5,PC}^           ;Return to caller
+
+               LTORG
+
+;----- Flags and things -----------------------------------------------------
+
+eFlag__commaOk EQU     (1<<0)                  ;We can cope with commas here
+eFlag__op      EQU     (1<<1)                  ;We are reading an operator
+eFlag__done    EQU     (1<<2)                  ;Finished reading expression
+eFlag__lval    EQU     (1<<3)                  ;Reading an lvalue
+eFlag__parseLval EQU   (1<<4)                  ;We are parsing an lvalue
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/getToken b/StraySrc/Libraries/Sapphire/sail/_s/getToken
new file mode 100644 (file)
index 0000000..07c0b73
--- /dev/null
@@ -0,0 +1,67 @@
+;
+; getToken.s
+;
+; The getting of the next token from the input file
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- getToken ---
+;
+; On entry:    R9 == previous token, or -1
+;              R10 == pointer into the tokenised buffer
+;              R12 == anchor block pointer
+;
+; On exit:     R7 == token class of token read
+;              R8 == index of token in token class
+;              R9 == new lookahead token
+;              R10 == moved on to the first character after the rvalue
+;
+; Use:         Tries to read an token from the current input line
+
+               EXPORT  getToken
+getToken       ROUT
+
+10getToken     CMP     R9,#10                  ;Is it a newline?
+               BEQ     %20getToken             ;A newline -- bump line count
+               LDRB    R9,[R10],#1             ;Load a byte
+               CMP     R9,#31                  ;Is it an implicit newline?
+               BEQ     %20getToken             ;Yes -- bump line counter
+
+15getToken     ADR     R8,tokClasses           ;Point to class table
+               LDR     R8,[R8,R9,LSL #1]
+               AND     R7,R8,#&FF
+               AND     R8,R8,#&FF00
+               MOV     R8,R8,LSR #8
+               MOVS    PC,R14                  ;Return to caller
+
+20getToken     LDR     R7,tsc_line             ;Yes -- get current line
+               ADD     R7,R7,#1                ;Increment line num
+               STR     R7,tsc_line             ;And save new line number
+               LDRB    R9,[R10],#1             ;Load a byte
+               CMP     R9,#31                  ;Should we ignore this char?
+               BEQ     %20getToken             ;Yes -- look for the next
+               B       %15getToken
+
+               GET     sh.tokClasses
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/interp b/StraySrc/Libraries/Sapphire/sail/_s/interp
new file mode 100644 (file)
index 0000000..70a8489
--- /dev/null
@@ -0,0 +1,255 @@
+;
+; interp.s
+;
+; Main entry point for the interpreter
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.ctrl
+               GET     sh.errNum
+               GET     sh.error
+               GET     sh.express
+               GET     sh.getToken
+               GET     sh.termScript
+               GET     sh.tokens
+               GET     sh.upcalls
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- interp_start ---
+;
+; On entry:    R12 == pointer to our anchor block
+;
+; On exit:     R7-R9 == next token
+;
+; Use:         Prepares for execution, and even does some too.
+
+               EXPORT  interp_start
+interp_start   ROUT
+
+               LDR     R10,tsc_tokAnchor       ;Load the anchor
+               LDR     R10,[R10]               ;I hate wimp_extension
+
+               MOV     R14,#1                  ;The current line number
+               STR     R14,tsc_line            ;Store it
+               MOV     R9,#-1                  ;Prepare for the first line
+               BL      getToken                ;Get the first token ready
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               STR     R0,tsc_timeSoFar        ;Remember this time
+               B       interp_exec             ;Do some execution
+
+               LTORG
+
+; --- interp_exec ---
+;
+; On entry:    R7-R9 == token to deal with
+;              R11 == offset in file to execute from
+;              R12 == pointer to the anchor block
+;
+; On exit:     R0 == type code (eg. 0 == we are still executing
+;              R7-R9 == next token to deal with
+;
+; Use:         Executes some of the file.
+
+               EXPORT  interp_exec
+interp_exec    ROUT
+
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               LDR     R14,tsc_timeSoFar       ;Load the time we started
+               SUB     R0,R0,R14               ;Thie we have been executing
+               CMP     R0,#5                   ;5cs up yet?
+               BCC     %10interp_exec          ;No -- keep on going then
+
+               ; --- Return control for a little while then ---
+
+00interp_exec  BL      tsc_wait                ;Yes -- wait some then
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               STR     R0,tsc_timeSoFar        ;Remember this time
+
+10interp_exec  CMP     R7,#tClass_instr        ;Is this an instruction?
+               BNE     %50interp_exec          ;No -- could be other things
+
+               ; --- We have an instruction ---
+
+               MOV     R0,R8                   ;Look after index
+               BL      getToken                ;Get the next tokem
+               ADD     PC,PC,R0,LSL #2         ;Branch to the correct code
+               DCB     "Jive"
+
+               ; --- The main dispatch table ---
+
+               B       ctrl_bput
+               B       ctrl_case
+               B       ctrl_close
+               ;B      ctrl_call               ;CALL
+               B       ctrl_data
+               B       ctrl_def
+               B       ctrl_dim
+               B       ctrl_end
+               B       ctrl_endproc
+               B       ctrl_endwhile
+               B       interp_next             ;ENDIF
+               B       interp_next             ;ENDCASE
+               B       ctrl_else
+               ;B      ctrl_error              ;ERROR
+               B       ctrl_for
+               B       ctrl_goto
+               B       ctrl_gosub
+               B       ctrl_if
+               B       ctrl_let
+               B       ctrl_local
+               B       ctrl_next
+               ;B      ctrl_oscli              ;OSCLI
+               B       ctrl_otherwise
+               B       ctrl_proc
+               B       ctrl_return
+               B       ctrl_repeat
+               B       ctrl_read
+               B       ctrl_restore
+               B       ctrl_swap
+               B       ctrl_sys
+               B       ctrl_until
+               B       ctrl_while
+               B       ctrl_when
+
+               ; --- Handle pseudo varaible and the like ---
+
+50interp_exec  SUBS    R4,R9,#'_'              ;Is it an underscore?
+               SUBNES  R4,R9,#'!'
+               SUBNES  R4,R9,#'?'
+               SUBNES  R4,R9,#'$'
+               SUBNE   R4,R9,#'A'              ;Or a capital letter?
+               CMP     R4,#26
+               SUBCS   R4,R9,#'a'              ;Or a lowercase letter?
+               CMPCS   R4,#26
+               BCC     ctrl_let                ;If so, assume assignment
+
+               CMP     R9,#tok_time            ;Is this a TIME pseudovar?
+               BLEQ    getToken                ;Yes -- done with this token
+               BEQ     ctrl_timeEq             ;Yes -- assign that then
+
+               CMP     R9,#tok_lnewlineS       ;Is this another pseudovar?
+               BLEQ    getToken                ;Yes -- done with this token
+               BEQ     termite_lnewline        ;Yes -- assign that then
+
+               CMP     R9,#tok_rnewlineS       ;Is this anotehr pseudovar?
+               BLEQ    getToken                ;Yes -- done with this token
+               BEQ     termite_rnewline        ;Yes -- assign that then
+
+               CMP     R7,#tClass_streamOp     ;Is it a streamOp?
+               BNE     %60interp_exec          ;No -- jump ahead
+
+               MOV     R0,R9                   ;Remember the tokoen
+               BL      getToken                ;Get another token
+               CMP     R9,#'#'                 ;Do we have a hash next?
+               MOVNE   R0,#err_expHash         ;No -- complain then
+               BNE     error_report            ;And report an error
+               BL      getToken                ;Get the next token
+               CMP     R0,#tok_ptr             ;Setting of pointer?
+               BEQ     ctrl_ptr                ;Yes -- do that then
+               CMP     R0,#tok_ext             ;Setting of extent?
+               BEQ     ctrl_ext                ;Yes -- do that
+               BNE     interp_next             ;Probably emtpy statement
+
+60interp_exec  CMP     R7,#tClass_multArg      ;A multiple argument thing?
+               BNE     %70interp_exec          ;No -- jump ahead
+
+               ; --- Deal with a multiple argument command ---
+
+               CMP     R9,#tok_leftS           ;Is it LEFT$?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     ctrl_leftS              ;Yes -- deal with it
+               CMP     R9,#tok_midS            ;Is it MID$?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     ctrl_midS               ;Yes -- deal with it
+               CMP     R9,#tok_rightS          ;Is it RIGHT$?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     ctrl_rightS             ;Yes -- deal with it
+               BNE     interp_next             ;Probably emtpy statement
+
+70interp_exec  CMP     R9,#'='                 ;Is it a return-from-fn?
+               BLEQ    getToken                ;Yes -- gobble it then
+               BEQ     ctrl_equals             ;Yes -- return then
+
+               CMP     R9,#'*'                 ;Is this a star command?
+               BNE     interp_next             ;Probably emtpy statement
+
+               ; --- We have a star command ---
+               ;
+               ; We copy the command into a buffer, until we reach
+               ; a terminating character.
+
+               ADR     R0,tsc_misc             ;Point to the destination
+00             BL      getToken                ;Get a token
+               CMP     R9,#10                  ;Is this the end of the line?
+               CMPNE   R9,#&FF                 ;Or the end of the file
+               STRNEB  R9,[R0],#1              ;No -- store the byte
+               BNE     %b00                    ;And keep on going
+
+               ; --- We have the string in the buffer ---
+
+               MOV     R14,#0                  ;We had better terminate it
+               STRB    R14,[R0],#1             ;By store a NULL char
+               ADR     R0,tsc_misc             ;Point to the command
+               SWI     Wimp_StartTask          ;Perform the command
+
+               B       interp_next             ;Just keep on goin' then
+
+               LTORG
+
+; --- interp_notImpl ---
+
+               EXPORT  interp_notImpl
+interp_notImpl MOV     R0,#err_lazy
+
+               B       error_report
+
+; --- interp_next ---
+;
+; On entry:    R7-R9 == token to deal with
+;              R11 == offset in file to execute from
+;              R12 == pointer to the anchor block
+;
+; On exit:     R0 == type code (eg. 0 == we are still executing)
+;              R7-R9 == next token to deal with
+;
+; Use:         Checks the next instruction and acts approriately.
+
+               EXPORT  interp_next
+interp_next    ROUT
+
+               CMP     R9,#10                  ;Is this newline?
+               LDR     R14,tsc_flags           ;Load the flags word
+               ORREQ   R14,R14,#tscFlag_nl     ;Newline just arrived
+               BICNE   R14,R14,#tscFlag_nl     ;Or maybe not
+               STR     R14,tsc_flags           ;Store the new flags back
+               CMPNE   R9,#':'                 ;Is this a ':'?
+               BLEQ    getToken                ;Either -- get a token
+               BEQ     interp_exec             ;...and keep on looping
+
+               CMP     R9,#tok_else            ;Is this an ELSE?
+               BLEQ    getToken                ;Yes -- read a token
+               BEQ     ctrl_else               ;...and branch to else ctrl
+               SUBS    R0,R9,#&FF              ;Is this the end?
+               BEQ     tsc_end                 ;Yes -- just end then
+               MOV     R0,#err_syntax          ;This is a synatx error
+               B       error_report            ;So report it
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/strBucket b/StraySrc/Libraries/Sapphire/sail/_s/strBucket
new file mode 100644 (file)
index 0000000..5dcb91f
--- /dev/null
@@ -0,0 +1,155 @@
+;
+; strBucket.s
+;
+; String bucket handling
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.mem
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- strBucket_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the string bucket.
+
+               EXPORT  strBucket_init
+strBucket_init ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Allocate the string bucket block ---
+
+               MOV     R0,#1024                ;Start off nice and big
+               BL      mem_alloc               ;Allocate the block
+               MOV     R1,#256                 ;Reserve space for the table
+               MOV     R2,#1024                ;Remember starting size
+               ADR     R14,tsc_bucket          ;Find the workspace part
+               STMIA   R14,{R0-R2}             ;Save this information away
+
+               ; --- Now initialise the bucket table ---
+
+               LDR     R0,[R0]                 ;Load actual block address
+               MOV     R1,#64                  ;We have 64 buckets to handle
+               MOV     R14,#0                  ;Clear them all to zero
+00             STR     R14,[R0],#4             ;Save the initial value
+               SUBS    R1,R1,#1                ;Decrement the counter
+               BNE     %00strBucket_init       ;And loop
+
+               LDMFD   R13!,{R0-R2,PC}^        ;Now return to caller
+
+               LTORG
+
+; --- strBucket_alloc ---
+;
+; On entry:    R0 == size of string to allocate
+;
+; On exit:     R0 == pointer to area to use (length at [R0,#-1])
+;              R1 == offset to that (for storing)
+;
+; Use:         Allocates space for a string of the given size.
+
+               EXPORT  strBucket_alloc
+strBucket_alloc        ROUT
+
+               ; --- Quick optimisation ---
+
+               SUBS    R1,R0,#0                ;Is this a null string?
+               MOVEQS  PC,R14                  ;Yes -- return zero then
+
+               STMFD   R13!,{R2,R3,R14}        ;Save some registers
+               MOV     R2,R0                   ;Look after length
+
+               ; --- Find the actual block length ---
+
+               ADD     R3,R2,#4                ;Add 1 byte for len, and...
+               BIC     R3,R3,#3                ;...word align
+
+               LDR     R0,tsc_bucket           ;Find the bucket anchor
+               LDR     R14,[R0]                ;WimpExt?  Bollocks more like
+               LDR     R1,[R14,R3]             ;Load the free list head
+               CMP     R1,#0                   ;Is this empty?
+               LDRNE   R0,[R14,R1]             ;Load the link from this blk
+               STRNE   R0,[R14,R3]             ;And stuff it in list head
+               ADDNE   R0,R14,R1               ;No -- work out address
+               BNE     %20strBucket_alloc      ;And skip ahead
+
+               ; --- Need to allocate more space ---
+
+               ADR     R14,tsc_bktPtr          ;Find the free pointer
+               LDMIA   R14,{R1,R14}            ;Load free ptr and size
+               ADD     R1,R1,R3                ;Add on the space we need
+               STR     R1,tsc_bktPtr           ;Store modified pointer
+               SUB     R3,R1,R3                ;Look after old offset
+               CMP     R1,R14                  ;Do we have enough?
+               BGT     %50strBucket_alloc      ;No -- get some more then
+10             MOV     R1,R3                   ;Find start of string space
+               LDR     R0,[R0]                 ;This is getting IRRITATING
+               ADD     R0,R0,R1                ;Get string block address
+
+               ; --- Set up the string ready for caller ---
+
+20             STRB    R2,[R0],#1              ;Save the length byte
+               ADD     R1,R1,#1                ;Bump the offset on
+               LDMFD   R13!,{R2,R3,PC}^        ;And return to caller
+
+               ; --- Extend the bucket area ---
+
+50             MOV     R14,#&FF                ;Build up 1023
+               ORR     R14,R14,#&300
+               ADD     R1,R1,R14               ;Add on chunking size
+               BIC     R1,R1,R14               ;And align nicely
+               BL      mem_realloc             ;Reallocate the area
+               STR     R1,tsc_bktSize          ;And save the new size
+               B       %10strBucket_alloc      ;And leap back again
+
+               LTORG
+
+; --- strBucket_free ---
+;
+; On entry:    R0 == offset of string to free
+;
+; On exit:     --
+;
+; Use:         Frees the memory the string took up.
+
+               EXPORT  strBucket_free
+strBucket_free ROUT
+
+               CMP     R0,#0                   ;Is this a bogus offset
+               MOVEQS  PC,R14                  ;Yes -- ignore it then
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               LDR     R1,tsc_bucket           ;Load the bucket anchor
+               LDR     R1,[R1]                 ;Spotted the pattern yet?
+               SUB     R0,R0,#1                ;Find the actual start offset
+               LDRB    R2,[R1,R0]              ;Load the length byte
+               ADD     R2,R2,#4                ;Add length byte and align
+               BIC     R2,R2,#3
+               LDR     R14,[R1,R2]             ;Load the list head
+               STR     R14,[R1,R0]             ;Save this in freed block
+               STR     R0,[R1,R2]              ;And make this the new head
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/stracc b/StraySrc/Libraries/Sapphire/sail/_s/stracc
new file mode 100644 (file)
index 0000000..a4a93bd
--- /dev/null
@@ -0,0 +1,116 @@
+;
+; stracc.s
+;
+; String accululator management
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.mem
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScrip$$Code|,CODE,READONLY
+
+; --- stracc_ensure ---
+;
+; On entry:    --
+;
+; On exit:     R0 == address of string to use
+;              R1 == offset of string from stracc, in upper 24 bits
+;
+; Use:         Ensures tha there are at least 256 bytes available in stracc,
+;              and then returns a pointer to them.
+
+               EXPORT  stracc_ensure
+stracc_ensure  ROUT
+
+               STMFD   R13!,{R2-R4,R14}        ;Stack registers
+               ADR     R0,tsc_stracc           ;Point to the data
+               LDMIA   R0,{R0,R2,R3}           ;Load out the data
+               SUB     R1,R3,R2                ;Look at how much is left
+               CMP     R1,#256                 ;Is there at least 256?
+               BLT     %f00                    ;No -- get some more
+05             LDR     R0,[R0]                 ;Point to the block
+               ADD     R0,R0,R2                ;Point at memory to use
+               MOV     R1,R2,LSL #8            ;Return offset to use
+               LDMFD   R13!,{R2-R4,PC}^        ;Return to caller
+
+00             LDR     R4,tsc_currAnchor       ;Load the current anchor
+               LDR     R14,[R4,#0]             ;Bop WimpExtention
+               SUB     R10,R10,R14             ;Convert R10 to offset
+               ADD     R3,R3,#512              ;No -- add on some then
+               MOV     R1,R3                   ;Put this size in R1
+               BL      mem_realloc             ;Reallocate the memory
+               STR     R3,tsc_straccSize       ;And store the new size
+               LDR     R14,[R4,#0]             ;Bop WimpExtention
+               ADD     R10,R10,R14             ;Turn R10 into address
+               B       %b05                    ;And leap back again
+
+               LTORG
+
+; --- stracc_added ---
+;
+; On entry:    R0 == rvalue of string added
+;
+; On exit:     --
+;
+; Use:         Informs stracc that a new string has been added.
+
+               EXPORT  stracc_added
+stracc_added   ROUT
+
+               STMFD   R13!,{R14}              ;Save registers
+               AND     R14,R0,#&FF             ;Get the string length
+               ADD     R14,R14,R0,LSR #8       ;Add on the offset
+               STR     R14,tsc_straccPtr       ;Store the new pointer
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- stracc_free ---
+;
+; On entry:    R0 == rvalue of string no longer needed
+;
+; On exit:     --
+;
+; Use:         Tells stracc that a string is no longer needed.
+
+               EXPORT  stracc_free
+stracc_free    ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack registers
+               AND     R14,R0,#&FF             ;Get the string length
+               MOV     R4,R0,LSR #8            ;Get the new offset
+               ADR     R14,tsc_stracc          ;Point to the stracc data
+               LDMIA   R14,{R0,R2,R3}          ;Load out the data
+               STR     R4,tsc_straccPtr        ;Store new offset
+               SUB     R14,R3,R4               ;Get free space size
+               SUBS    R14,R14,#512            ;Calc amount to take off
+               LDMLEFD R13!,{R0-R4,PC}^        ;And return to caller
+
+               SUB     R1,R3,R14               ;Work out new block size
+               LDR     R4,tsc_currAnchor       ;Load the current anchor
+               LDR     R14,[R4,#0]             ;Bop WimpExtention
+               SUB     R10,R10,R14             ;Convert R10 to offset
+               BL      mem_realloc             ;Reallocate as appropriate
+               STR     R1,tsc_straccSize       ;Store the new size
+               LDR     R14,[R4,#0]             ;Bop WimpExtention
+               ADD     R10,R10,R14             ;Convert R10 to address
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/termScript b/StraySrc/Libraries/Sapphire/sail/_s/termScript
new file mode 100644 (file)
index 0000000..f7faa92
--- /dev/null
@@ -0,0 +1,512 @@
+;
+; termScript.s
+;
+; Coroutine handling for Termite Script
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.ctrl
+               GET     sh.interp
+               GET     sh.mem
+               GET     sh.strBucket
+               GET     sh.termite
+               GET     sh.tree
+               GET     sh.tokenise
+               GET     sh.var
+
+;----- Code header ----------------------------------------------------------
+
+               AREA    |!!!TermScript$$Header|,CODE,READONLY
+
+               MOVS    PC,R14                  ;No initialisation reqd
+               MOVS    PC,R14                  ;No finalisation either
+               B       tsc__create             ;Create a new script
+               B       tsc__poll               ;Continue execution
+               B       termite_remoteInput     ;Some input's come for us
+               B       tsc__stop               ;Stop executing now
+               MOVS    PC,R14                  ;Misc operation
+               B       tsc_execEnd             ;End of an EXEC
+               B       tsc_getLine             ;Get line number
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- tsc__create ---
+;
+; On entry:    R2 == pointer to anchor for script file
+;              R3 == length of script file
+;              R4 == block with A% to H%
+;
+; On exit:     R0 == pointer to script handle (stack block)
+;
+; Use:         Sets up a new script session.
+
+tsc__create    ROUT
+
+               STMFD   R13!,{R1-R4,R12,R14}    ;Save some registers
+
+               ; --- Allocate an anchor/stack block ---
+
+               MOV     R0,#6                   ;Allocate memory
+               MOV     R3,#tsc_blkSize         ;Get the block's size
+               SWI     XOS_Module              ;Try to allocate the memory
+               BVS     %99tsc__create          ;If it failed, return error
+               MOV     R12,R2                  ;Point to block in R12
+
+               ; --- Set up the coroutine ready to start ---
+
+               ADD     R4,R12,#tsc_blkSize     ;Point to the very top
+               ADR     R3,tsc__start           ;Install a `return address'
+               MOV     R1,R11                  ;Pass upcall block pointer
+               STMFD   R4!,{R3}                ;Save `R11', `R12' and `R14'
+               SUB     R4,R4,#40               ;Leave `R1'-`R10' blank
+               STR     R4,tsc_R13              ;Save the initial stack ptr
+
+               ; --- Fill in the rest of the block ---
+
+               LDMIB   R13,{R0,R1}             ;Load the anchor and length
+               STMIB   R12,{R0,R1}             ;Save them in my block
+
+               MOV     R0,#512                 ;Initial size of var stack
+               STR     R0,tsc_varSize          ;Size of current stack
+               BL      mem_alloc               ;Try to allocate it
+               BVS     %99tsc__create          ;On error -- return
+               STR     R0,tsc_varTree          ;Store this anchor pointer
+               MOV     R14,#7*4                ;A nice NULL value
+               STR     R14,tsc_varPtr          ;Nothing on the stack yet
+               LDR     R0,[R0]                 ;Find block address
+
+               MOV     R14,#0                  ;Zero out the tree roots
+               MOV     R1,#7                   ;Seven type trees to clear
+10tsc__create  STR     R14,[R0],#4             ;Clear another one
+               SUBS    R1,R1,#1                ;Decrement the counter
+               BGT     %10tsc__create          ;And keep on going
+
+               MOV     R0,#256                 ;Space for the execution st.
+               BL      mem_alloc               ;Try to allocate it
+               BVS     %98tsc__create          ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#256                 ;Total size
+               ADR     R3,tsc_execStack        ;Point to the stack data
+               STMIA   R3,{R0-R2}              ;Store the information
+
+               MOV     R0,#256                 ;Space for the operators
+               BL      mem_alloc               ;Try to allocate it
+               BVS     %98tsc__create          ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#256                 ;Total size
+               ADR     R3,tsc_opStack          ;Point to the stack data
+               STMIA   R3,{R0-R2}              ;Store the information
+
+               MOV     R0,#256                 ;Space for the operands
+               BL      mem_alloc               ;Try to allocate it
+               BVS     %98tsc__create          ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#256                 ;Total size
+               ADR     R3,tsc_calcStack        ;Point to the stack data
+               STMIA   R3,{R0-R2}              ;Store the information
+
+               MOV     R0,#512                 ;Space for the operands
+               BL      mem_alloc               ;Try to allocate it
+               BVS     %98tsc__create          ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#512                 ;Total size
+               ADR     R3,tsc_stracc           ;Point to the stack data
+               STMIA   R3,{R0-R2}              ;Store the information
+
+               BL      strBucket_init          ;Set up the string handling
+
+               MOV     R14,#tscFlag_nl+tscFlag_echoLR+tscFlag_echoRL
+               STR     R14,tsc_flags           ;Store the new flags
+               MOV     R14,#0                  ;A NULL word
+               STR     R14,tsc_rmaList         ;No DIMed blocks yet
+               STR     R14,tsc_wForState       ;State of WATCHFOR
+               STR     R14,tsc_wForNumber      ;No strings being watched for
+               STR     R14,tsc_spool           ;No SPOOL handle
+
+               ; --- Now tokenise the file ---
+
+               LDR     R0,tsc_scSize           ;Load the script size
+               ADD     R0,R0,#8                ;Put the size in R0
+               BL      mem_alloc               ;Allocate a block
+               BVS     %98tsc__create          ;No -- return an error
+               STR     R0,tsc_tokAnchor        ;Store this anchor pointer
+               STR     R0,tsc_currAnchor       ;This is current anchor
+               STR     R0,tsc_oldAnchor        ;This is the `previous' one
+
+               LDR     R2,[R0,#0]              ;Get angry with WimpExt_Heap
+               ADR     R14,tsc_anchor          ;Find untokenised script
+               LDMIA   R14,{R0,R1}             ;Load them out
+               LDR     R0,[R0,#0]              ;Grrrr...
+               MOV     R3,#1                   ;Tokenise the whole file
+               BL      tokenise                ;Tokenise the file
+
+       [ 1=0
+               STMFD   R13!,{R0-R5}
+               MOV     R0,#10
+               ADR     R1,name
+               LDR     r2,=&FFF
+               LDR     R4,tsc_tokAnchor
+               LDR     R4,[R4]
+               LDR     R5,tsc_scSize
+               ADD     R5,R4,R5
+               SWI     OS_File
+               LDMFD   R13!,{R0-R5}
+       ]
+
+               ; --- Zero-init the file array ---
+
+               MOV     R14,#0                  ;Zero-init the array
+               MOV     R0,#8                   ;This many words to do
+               ADR     R1,tsc_files            ;Point to the array
+00             STR     R14,[R1],#4             ;Store
+               SUBS    R0,R0,#1                ;Decrement the counter
+               BGT     %b00                    ;And loop
+
+               ; --- Finsh setting up, and return ---
+
+               SWI     OS_ReadMonotonicTime    ;Read start time of program
+               STR     R0,tsc_timeOff          ;This is initial time offset
+               MOV     R1,#0                   ;Clear top bit
+               ADR     R14,tsc_rndSeed         ;Point to seed buffer
+               STMIA   R14,{R0,R1}             ;Save that away
+
+               STR     R1,tsc_errorS           ;ERROR$=""
+
+               MOV     R0,#2                   ;We want a string this big
+               BL      strBucket_alloc         ;Get it then
+               MOV     R14,#13                 ;Get char 13
+               STRB    R14,[R0],#1             ;Put in the string
+               MOV     R14,#10                 ;Get char 10
+               STRB    R14,[R0],#1             ;Put in the string
+               STR     R1,tsc_lnewline         ;Store the offset away
+
+               MOV     R0,#1                   ;We want a string this big
+               BL      strBucket_alloc         ;Get it then
+               MOV     R14,#13                 ;Get char 13
+               STRB    R14,[R0],#1             ;Put in the string
+               STR     R1,tsc_rnewline         ;Store the offset away
+
+               MOV     R14,#0                  ;Current data offset
+               STR     R14,tsc_dataPtr         ;Store that
+               MOV     R14,#1                  ;Current data line
+               STR     R14,tsc_dataLine        ;Store that too
+               BL      ctrl_findDATA           ;Set up the pointer
+
+               ; --- Copy over the A%-H% values ---
+
+               ADR     R1,tsc__varNames        ;Point to the names
+               MOV     R4,#8                   ;Number of vars to transfer
+               LDR     R2,[R13,#12]            ;Load te block ptr
+00             MOV     R0,#vType_integer       ;It's an integer
+               BL      var_create              ;Try to create it
+               LDR     R14,[R2],#4             ;Load the value to transfer
+               STR     R14,[R0,#4]             ;Store the value
+               ADD     R1,R1,#3                ;Point to the next name
+               SUBS    R4,R4,#1                ;Reduce the count
+               BGT     %00                     ;And keep on looking
+
+               MOV     R0,R12                  ;Return my block as handle
+               LDMFD   R13!,{R1-R4,R12,R14}    ;Unstack registers
+               BICS    PC,R14,#V_flag          ;And return without error
+
+               ; --- An error occured ---
+
+98tsc__create  MOV     R4,R0
+               LDR     R0,tsc_varTree          ;Load the stack anchor
+               BL      mem_free                ;Free it
+               MOV     R0,R4
+99tsc__create  LDMFD   R13!,{R1-R4,R12,R14}    ;Unstack registers
+               ORRS    PC,R14,#V_flag          ;Return error to caller
+
+tsc__varNames  DCB     "A%",0,"B%",0,"C%",0,"D%",0
+               DCB     "E%",0,"F%",0,"G%",0,"H%",0
+
+               LTORG
+
+; --- tsc__start ---
+;
+; On entry:    R11 == pointer to upcall block
+;              R12 == pointer to anchor block
+;
+; On exit:     via interpreter
+;
+; Use:         Starts the interpreter coroutine.
+
+tsc__start     ROUT
+
+               BL      interp_start            ;Start the interpreter
+               MOV     R0,#0                   ;Terminate the script
+               B       tsc_end                 ;By calling the closedown rtn
+
+               LTORG
+
+; --- tsc__stop ---
+;
+; On entry:    R0 == pointer to script anchor
+;
+; On exit:     --
+;
+; Use:         Stops a script from going.
+
+tsc__stop      ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers
+               MOV     R12,R0                  ;Put block in R12
+
+               ADR     R1,tsc_rszBlocks        ;Find the resizing blocks
+               ADR     R2,tsc_erszBlocks       ;Find the end of them
+10tsc__stop    LDR     R0,[R1],#12             ;Load the anchor
+               BL      mem_free                ;Free this block
+               CMP     R1,R2                   ;Finished yet?
+               BCC     %10tsc__stop            ;No -- loop
+
+               ; --- Now free DIMed RMA blocks ---
+
+               MOV     R0,#7                   ;Free blocks
+               LDR     R2,tsc_rmaList          ;Load the head of the list
+               CMP     R2,#0                   ;Is there one here?
+00             LDRNE   R3,[R2,#0]              ;Yes -- load the next link
+               SWINE   OS_Module               ;...free the block
+               MOVNE   R2,R3                   ;...put the next in R2
+               CMP     R2,#0                   ;Are there more to go?
+               BNE     %b00                    ;Yes -- do them then
+
+               ; --- Close any open files ---
+
+               MOV     R0,#0                   ;Close these files
+               MOV     R1,#0                   ;Start at file 1
+               ADR     R2,tsc_files            ;Point to file array
+00             TST     R1,#&1F                 ;Start new word?
+               LDREQ   R3,[R2],#4              ;Yes -- load new one then
+               MOVS    R3,R3,LSL #1            ;Shift word up by one
+               SWICS   OS_Find                 ;If set, close the file
+               ADD     R1,R1,#1                ;Increment file handle
+               CMP     R1,#&100                ;Finished yet?
+               BCC     %b00                    ;No -- keep looping
+
+               ; --- Close the SPOOL file ---
+
+               LDR     R1,tsc_spool            ;Load the current handle
+               CMP     R1,#0                   ;Are we spooling?
+               MOVNE   R0,#0                   ;Yes -- close current file
+               SWINE   XOS_Find                ;So do that then
+
+               ; --- Free the tokenised file ---
+
+               LDR     R0,tsc_tokAnchor        ;Load anchor of tok'ed file
+               BL      mem_free                ;Free that block
+
+               ; --- Free the anchor block ---
+
+               MOV     R2,R12                  ;Point to the anchor blk
+               MOV     R0,#7                   ;Free the anchor
+               SWI     XOS_Module              ;Do that then
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- tsc__poll ---
+;
+; On entry:    R0 == address of anchor block
+;
+; On exit:     R0 == event code
+;
+; Use:         Continues running the script for a while.
+
+tsc__poll      ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               MOV     R12,R0                  ;Put anchor block ptr away
+               BL      tsc__resume             ;Switch to other coroutine
+               LDMFD   R13!,{R12,R14}          ;Restore registers
+               ORRVSS  PC,R14,#V_flag          ;If error, return that
+               BICVCS  PC,R14,#V_flag          ;Else return no error
+
+               LTORG
+
+; --- tsc__resume ---
+;
+; On entry:    R0 == event code to pass to interpreter
+;              R1,R2 == other arguments to pass
+;
+; On exit:     R0, R1 == return values (passed to tsc_wait)
+;
+; Use:         Resumes the interpreter, giving it an event.
+
+tsc__resume    ROUT
+
+               STMFD   R13!,{R3-R12,R14}       ;Save main corout context
+               LDR     R14,tsc_R13             ;Load interpreter's R13
+               STR     R13,tsc_R13             ;Save our R13 away for a bit
+               MOV     R13,R14                 ;Switch to interpreter
+               LDMFD   R13!,{R1-R10,R14}       ;Restore interp registers
+               LDR     R0,tsc_currAnchor       ;Load the token anchor
+               LDR     R0,[R0]                 ;Thump thump thump
+               ADD     R10,R0,R10              ;Turn offset into address
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- tsc_wait ---
+;
+; On entry:    --
+;
+; On exit:     R0, R1, R2 == event and arguments from Termite
+;
+; Use:         Waits for some multitasking and gets something from Termite.
+
+               EXPORT  tsc_wait
+tsc_wait       ROUT
+
+               LDR     R0,tsc_currAnchor       ;Find tokenised file anchor
+               LDR     R0,[R0]                 ;Grrrrrrrr
+               SUB     R10,R10,R0              ;Turn this into an offset
+               STMFD   R13!,{R1-R10,R14}       ;Save interpreter's context
+               LDR     R14,tsc_R13             ;Load main routine's R13
+               STR     R13,tsc_R13             ;Save our R13 away for a bit
+               MOV     R13,R14                 ;Switch back to main routine
+               MOV     R0,#0                   ;Just continue for a while
+               LDMFD   R13!,{R3-R12,R14}       ;Restore Termite's regs
+               BICS    PC,R14,#V_flag          ;And return with no error
+
+               LTORG
+
+; --- tsc_end ---
+;
+; On entry:    R0 == pointer to script to chain (bit 30 set for exec),
+;                    0 to just end, or -1 to CLOSE
+;
+; On exit:     Doesn't, hopefully (except for exec?)
+;
+; Use:         Ends the script, optionally starting up another one.
+
+               EXPORT  tsc_end
+tsc_end                ROUT
+
+               STMFD   R13!,{R1-R10,R14}       ;Save interpreter's context
+               LDR     R14,tsc_currAnchor      ;Find tokenised file anchor
+               LDR     R14,[R14]               ;Grrrrrrrr
+               SUB     R10,R10,R14             ;Turn this into an offset
+               STR     R10,[R13,#36]           ;Store R10 value
+               LDR     R14,tsc_R13             ;Load main routine's R13
+               STR     R13,tsc_R13             ;Save our R13 away (useless)
+               MOV     R13,R14                 ;Switch back to main routine
+
+               MOV     R5,R0                   ;Look after the return type
+
+               ; --- Copy across A% to H% ---
+
+               ADR     R2,tsc_misc             ;Point to a misc block
+               ADRL    R1,tsc__varNames        ;Point to the names
+               MOV     R4,#8                   ;Number of vars to transfer
+00             MOV     R0,#vType_integer       ;It's an integer
+               BL      tree_find               ;Try to find it
+               MOVCC   R14,#0                  ;Not there -- use 0
+               LDRCS   R14,[R0,#4]             ;Otherwise load value
+               STR     R14,[R2],#4             ;Store the value
+               ADD     R1,R1,#3                ;Point tot he next name
+               SUBS    R4,R4,#1                ;Reduce the count
+               BGT     %00                     ;And keep on looking
+               ADR     R2,tsc_misc             ;Point to the block again
+               MOV     R0,R5                   ;Put return type in R0
+               MOV     R1,R6                   ;And file name in R1
+
+               ; --- Now return appropriately ---
+
+               MOV     R1,R5                   ;Get the string in R1
+               CMP     R1,#0                   ;Is it >0?
+               BLE     %10tsc_end              ;Nope -- jump ahead
+
+               TST     R1,#(1<<30)             ;Are we EXECing?
+               MOVEQ   R0,#2                   ;If chaining, return 2
+               MOVNE   R0,#3                   ;Otherwise return 3
+               BIC     R1,R1,#(1<<30)          ;Clear bit 30
+
+               B       %90tsc_end              ;Just return now
+
+10tsc_end      MOVEQ   R0,#1                   ;Else just end the script
+               MOVLT   R0,#4                   ;Or maybe finish, even
+90tsc_end      LDMFD   R13!,{R3-R12,R14}       ;Restore Termite's regs
+               BICS    PC,R14,#V_flag          ;And return with no error
+
+               LTORG
+
+; --- tsc_error ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     Doesn't, probably
+;
+; Use:         Returns an error to Termite.
+
+               EXPORT  tsc_error
+tsc_error      ROUT
+
+               STMFD   R13!,{R1-R10,R14}       ;Save interpreter's context
+               LDR     R14,tsc_R13             ;Load main routine's R13
+               STR     R13,tsc_R13             ;Save our R13 away (useless)
+               MOV     R13,R14                 ;Switch back to main routine
+               LDMFD   R13!,{R3-R12,R14}       ;Restore Termite's registers
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+; --- tsc_execEnd ---
+;
+; On entry:    R0 == parent handle
+;              R4 == 8 word block of A%-H%
+;              R11 == upcall block
+;
+; On exit:     --
+;
+; Use:         Update the parents A%-H%
+
+tsc_execEnd    ROUT
+
+               STMFD   R13!,{R0-R4,R12,R14}    ;Stack registers
+               MOV     R12,R0                  ;Put anchor in R12
+               ADRL    R1,tsc__varNames        ;Point to the names
+               MOV     R2,#8                   ;Number of vars to transfer
+00             MOV     R0,#vType_integer       ;It's an integer
+               BL      var_find                ;Try to create it
+               LDR     R14,[R4],#4             ;Load the value to transfer
+               STR     R14,[R0,#4]             ;Store the value
+               ADD     R1,R1,#3                ;Point to the next name
+               SUBS    R2,R2,#1                ;Reduce the count
+               BGT     %00                     ;And keep on looking
+
+               LDMFD   R13!,{R0-R4,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- tsc_getLine ---
+;
+; On entry:    R0 == handle
+;
+; On exit:     R0 == current line number
+;
+; Use:         Returns the current line number
+
+tsc_getLine    ROUT
+
+               LDR     R0,[R0,#:INDEX:tsc_line]
+               MOVS    PC,R14
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/termite b/StraySrc/Libraries/Sapphire/sail/_s/termite
new file mode 100644 (file)
index 0000000..176309a
--- /dev/null
@@ -0,0 +1,1590 @@
+;
+; termite.s
+;
+; Implementation of Termite specific instructions
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.ctrl
+               GET     sh.errNum
+               GET     sh.error
+               GET     sh.express
+               GET     sh.getToken
+               GET     sh.interp
+               GET     sh.stracc
+               GET     sh.strBucket
+               GET     sh.termscript
+               GET     sh.tokens
+               GET     sh.upcalls
+               GET     sh.var
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- termite_beep ---
+
+               EXPORT  termite_beep
+termite_beep   ROUT
+
+               TCALL   termite_makeBeep        ;Make a beep
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_break ---
+
+               EXPORT  termite_break
+termite_break  ROUT
+
+               TCALL   termite_sendBreak       ;Send the break
+               BL      termite__error          ;Handle possible error
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_call ---
+
+               EXPORT  termite_call
+termite_call   ROUT
+
+               BL      ctrl_setUpRegs          ;Set up the regs then
+
+               CMP     R10,#vType_integer      ;Is this an integer?
+               MOVNE   R0,#err_numNeeded       ;No -- get error number
+               BNE     error_report            ;...and report the error
+
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R9                   ;Execute the code
+
+               LDR     R9,=termite__retned     ;Point to some space
+               STMIA   R9!,{R0-R8}             ;Store returned registers
+               MOV     R14,PC,LSR #28          ;Get the flags
+               STMIA   R9,{R14}                ;Strore the flags too
+               LDMFD   R13!,{R7-R12}           ;Load back position info
+               LDMFD   R13!,{R0}               ;Load stracc offset
+               BL      stracc_free             ;Free any strings I had
+
+               ; --- We have now done the SWI instr ---
+
+               LDR     R0,=termite__retned     ;Point to the returned regs
+               BL      ctrl_resolveRegs        ;Do the other half now
+               B       interp_next             ;If flags -- return
+
+               LTORG
+
+; --- termite_chain ---
+
+               EXPORT  termite_chain
+termite_chain  ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,tsc_stracc           ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               ADR     R0,tsc_misc+8*4         ;Point to the misc buffer
+               BL      termite_copyString      ;Copy the string over
+               B       tsc_end                 ;End the script, and chain
+
+               LTORG
+
+; --- termite_close ---
+
+               EXPORT  termite_close
+termite_close  ROUT
+
+               MOV     R0,#-1                  ;Close the session
+               B       tsc_end                 ;Do that then
+
+               LTORG
+
+; --- termite_cls ---
+
+               EXPORT  termite_cls
+termite_cls    ROUT
+
+               TCALL   termite_clearScreen     ;Clear the screen
+               BL      termite__error          ;Handle possible error
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_download ---
+
+               EXPORT  termite_download
+termite_download ROUT
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               ; --- Null terminate this ---
+
+               MOV     R2,R0                   ;Look after the offset
+               MOV     R5,#0                   ;Useful, t' be sure
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Check for another string ---
+
+               CMP     R9,#','                 ;Do we have a comma?
+               MOVNE   R3,#0                   ;No -- use default then
+               BNE     %10termite_download     ;...and jump ahead
+
+               BL      getToken                ;Skip over the comma
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               ; --- Null terminate this ---
+
+               MOV     R3,R0                   ;Look after the offset
+               MOV     R5,#0                   ;Useful, t' be sure
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Do the download now ---
+
+10             LDR     R1,tsc_stracc           ;Load stracc address
+               MOV     R4,R2                   ;Look after the offet
+               ADD     R2,R1,R2                ;Point to protocal name
+               CMP     R3,#0                   ;Do we have a filename?
+               ADDNE   R3,R1,R3                ;Yes -- point to it then
+               TCALL   termite_downLoad        ;Do the download
+               BL      termite__error          ;Handle possible error
+               MOV     R0,R4                   ;Get offset of protocol name
+               BL      stracc_free             ;Free it now
+               B       interp_next             ;Do another instruction
+
+               LTORG
+
+; --- termite_error ---
+
+               EXPORT  termite_error
+termite_error  ROUT
+
+               CMP     R9,#tok_on              ;Is this an option?
+               CMPNE   R9,#tok_off
+               BEQ     %50termite_error        ;Yes -- jump ahead
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,tsc_stracc           ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,tsc_misc             ;Point to the misc buffer
+               MOV     R14,#1                  ;A sillu error number
+               STR     R14,[R0],#4             ;Store that
+               BL      termite_copyString      ;Copy the string over
+               ADR     R0,tsc_misc             ;Point to the misc buffer
+               B       tsc_error               ;Return the error
+
+               ; --- There was an option ---
+
+50termite_error        LDR     R0,tsc_flags            ;Load the flags word
+               CMP     R9,#tok_on              ;Turn on the errors?
+               ORREQ   R0,R0,#tscFlag_error    ;Yes -- set the bit then
+               BICEQ   R0,R0,#tscFlag_error    ;No -- clear it then
+               STR     R0,tsc_flags            ;Store the flags back
+               BL      getToken                ;Skip over the token
+               B       interp_next             ;Do the next one
+
+               LTORG
+
+; --- termite_exec ---
+
+               EXPORT  termite_exec
+termite_exec   ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,tsc_stracc           ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,tsc_misc+8*4         ;Point to the misc buffer
+               BL      termite_copyString      ;Copy the string over
+               MOV     R0,R5                   ;Get the rvalue
+               BL      stracc_free             ;Free the string from stracc
+               ADR     R0,tsc_misc+8*4         ;Point to the misc buffer
+               ORR     R0,R0,#(1<<30)          ;Make this into an exec
+               BL      tsc_end                 ;Exec new script
+               B       interp_next             ;Continue happily
+
+               LTORG
+
+; --- termite_finish ---
+
+               EXPORT  termite_finish
+termite_finish ROUT
+
+               TCALL   termite_finishSession   ;Finish the session
+               B       interp_next             ;And go round for more
+
+               LTORG
+
+; --- termite_hangup ---
+
+               EXPORT  termite_hangup
+termite_hangup ROUT
+
+               TCALL   termite_dropCarrier     ;Hang up the modem
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_lclear ---
+
+               EXPORT  termite_lclear
+termite_lclear ROUT
+
+               TCALL   termite_clearLocal      ;Clear the buffer
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_lecho ---
+
+               EXPORT  termite_lecho
+termite_lecho  ROUT
+
+               CMP     R9,#tok_off             ;Is this an option thingy?
+               CMPNE   R9,#tok_local
+               CMPNE   R9,#tok_remote
+               CMPNE   R9,#tok_both
+               BEQ     %50termite_lecho        ;Yes -- deal seperately
+
+               ; --- Just echo the result to the screen then ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read the next expression
+               BL      express_pop             ;Get the value in R0,R1
+               CMP     R1,#vType_integer       ;Is this an integer?
+               BEQ     %10termite_lecho        ;Yes -- jump ahead
+               CMP     R1,#vType_string        ;Or a string?
+               MOVNE   R0,#err_arrayBad
+               BNE     error_report
+
+               ; --- Display a string ---
+
+               LDR     R2,tsc_stracc           ;Get the stracc address
+               LDR     R2,[R2]
+               ADD     R2,R2,R0,LSR #8         ;Point to the string
+               AND     R3,R0,#&FF              ;Get the length
+               BL      termite__doSpool        ;Maybe spool this lot
+               TCALL   termite_sendLocal       ;Write out the message
+               BL      termite__error          ;Handle possible error
+               BL      stracc_free             ;Free the string from stracc
+               B       %20termite_lecho        ;Jump ahead
+
+               ; --- Display an integer on the screen ---
+
+10termite_lecho        ADR     R1,tsc_misc             ;Point to a nice buffer
+               MOV     R2,#256                 ;The buffer is big
+               SWI     OS_ConvertInteger4      ;Convert the number to a str
+               SUB     R3,R1,R0                ;Get the length
+               MOV     R2,R0                   ;Point at the block
+               BL      termite__doSpool        ;Maybe spool this lot
+               TCALL   termite_sendLocal       ;Write out the message
+               BL      termite__error          ;Handle possible error
+
+               ; --- Maybe write out the return char ---
+
+20termite_lecho        CMP     R9,#';'                 ;Is there a semicolon now?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     interp_next             ;...read another instr
+
+               LDR     R2,tsc_bucket           ;Get the bucket anchor
+               LDR     R2,[R2]
+               LDR     R0,tsc_lnewline         ;Load the newline offset
+               CMP     R0,#0                   ;Is there one?
+               BEQ     interp_next             ;No -- stop here then
+               ADD     R2,R2,R0                ;Point to the string
+               LDRB    R3,[R2,#-1]             ;Load out the length
+               BL      termite__doSpool        ;Maybe spool this lot
+               TCALL   termite_sendLocal       ;Write out the terminator
+               BL      termite__error          ;Handle possible error
+               B       interp_next             ;And read another instruction
+
+               ; --- Handle the options ---
+
+50termite_lecho        LDR     R0,tsc_flags            ;Load the flags word
+               BIC     R0,R0,#tscFlag_echoLR+tscFlag_echoLL
+               CMP     R9,#tok_local           ;Do we require local echoing?
+               CMPNE   R9,#tok_both
+               ORREQ   R0,R0,#tscFlag_echoLL   ;Yes -- set the flag
+               CMP     R9,#tok_remote          ;Do we require remote echos?
+               CMPNE   R9,#tok_both
+               ORREQ   R0,R0,#tscFlag_echoLR   ;Yes -- set the flag
+               STR     R0,tsc_flags            ;Store back the flags word
+               BL      getToken                ;Get another token
+
+               B       interp_next             ;Keep on going then!
+
+               LTORG
+
+; -- termite_linput ---
+
+               EXPORT  termite_linput
+termite_linput ROUT
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it in
+
+               ; --- Now enter a string reading loop ---
+
+               BL      stracc_ensure           ;Make sure that there's room
+               MOV     R2,R0                   ;Look after address
+               MOV     R4,R0                   ;Twice
+               MOV     R5,#0                   ;The length so far
+               MOV     R3,#1                   ;Length of buffer to echo
+
+00
+               TCALL   termite_readLocal       ;Read a byte from the buffer
+               CMP     R0,#-1                  ;Was there one?
+               BLEQ    tsc_wait                ;No -- wait for it then
+               LDREQ   R2,tsc_stracc
+               LDREQ   R2,[R2]
+               ADDEQ   R2,R2,R1,LSR #8
+               ADDEQ   R2,R2,R5
+               BEQ     %b00
+               CMP     R0,#127                 ;Is this a delete?
+               CMPNE   R0,#8
+               BEQ     %f05                    ;Yes -- deal with that then
+               CMP     R0,#32                  ;Was it valid?
+               STRGEB  R0,[R2,#0]              ;Yes -- store the byte
+               BLGE    termite_doLEcho         ;Echo the buffer
+               ADDGE   R2,R2,#1                ;Increment the pointer
+               ADDGE   R5,R5,#1                ;Increment the length
+               CMP     R0,#13                  ;Are we finished?
+               CMPNE   R5,#256
+               BLT     %b00                    ;No -- get some more then
+               B       %f10                    ;Finished -- jump ahead
+
+               ; --- Do a delete operation ---
+
+05             CMP     R5,#0                   ;Is the buffer empty?
+               BLE     %b00                    ;Yes -- do nothing
+               MOV     R14,#8                  ;Get a backspace
+               STRB    R14,[R2,#0]             ;Store it...
+               STRB    R14,[R2,#2]             ;In two places
+               MOV     R14,#32                 ;And a space too
+               STRB    R14,[R2,#1]             ;Put that in the middle
+               MOV     R3,#3                   ;Send 3 characters
+               BLGE    termite_doLEcho         ;Echo the buffer
+               SUB     R2,R2,#1                ;Reduce the address
+               SUB     R5,R5,#1                ;And the number of chars
+               MOV     R3,#1                   ;Put R3 back to 1
+               B       %b00                    ;Join main loop again
+
+               ; --- We have finished reading the string ---
+
+10             ORR     R0,R1,R5                ;Get the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               MOV     R3,R1                   ;Move these up a little
+               MOV     R2,R0
+               BL      express_pop             ;Get my lvalue off
+               BL      ctrl_store              ;Store this away
+               B       interp_next             ;Do another command
+
+               LTORG
+
+; --- termite_lnewline ---
+
+               EXPORT  termite_lnewline
+termite_lnewline ROUT
+
+               CMP     R9,#'='                 ;Next char must be `='
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the equals sign
+
+               LDR     R0,tsc_lnewline         ;Get existing offset
+               BL      strBucket_free          ;Free it
+               MOV     R0,#0                   ;Prepare to read rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop it off the stack
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_strNeeded       ;No -- get error number
+               BNE     error_report            ;And report the error
+               BL      termite__storeStr       ;Store in the bucket
+               STR     R0,tsc_lnewline         ;Store the new offset
+               B       interp_next             ;And do the next instruction
+
+; --- termite_log ---
+
+               EXPORT  termite_log
+termite_log    ROUT
+
+               ; --- Load the first parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,tsc_stracc           ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;Look after the rvalue
+               ADR     R0,tsc_misc             ;Point to the misc buffer
+               BL      termite_copyString      ;Copy the string over
+               TCALL   termite_logFileAdd      ;Add the string to the log
+               BL      termite__error          ;Handle possible error
+               MOV     R0,R5                   ;Get the rvalue back
+               BL      stracc_free             ;Free it from stracc
+               B       interp_next             ;Return to main loop
+
+               LTORG
+
+; --- termite_newsession ---
+
+               EXPORT  termite_newsession
+termite_newsession ROUT
+
+               ; --- Read the base name ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_numNeeded       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ; --- NULL terminate it ---
+               ;
+               ; We rely on the fact that there can't be anything else
+               ; after this string.  It is also important that we remember
+               ; the stracc offset of this string, so that all the strings
+               ; can be removed from stracc in one go.
+
+               MOV     R3,R1                   ;Look after the offset
+               MOV     R5,#0                   ;Useful, t' be sure
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Read the sub-style name ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_numNeeded       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ; --- NULL terminate it ---
+
+               MOV     R6,R1                   ;Look after the offset
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ADD     R4,R1,#(1<<8)           ;The next string will go here
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Now we keep on adding strings to the list ---
+
+05             CMP     R9,#','                 ;Do we have a comma?
+               BNE     %50termite_newsession   ;No -- do the deed then
+               BL      getToken                ;Skip over the comma
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the string
+               CMP     R1,#vType_dimStr        ;Is this a string array?
+               BEQ     %10termite_newsession   ;Yes -- jump ahead
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_strNeeded       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ; --- We have a string then ---
+
+               CMP     R0,#0                   ;Does it have a length?
+               BEQ     %05termite_newsession   ;No -- find another one then
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+               B       %05termite_newsession   ;Find another string
+
+               ; --- We have a string array ---
+
+10             MOV     R3,R0                   ;Look after rvalue
+               MOV     R2,#0                   ;Start from the beginning
+15             MOV     R1,R3                   ;Put it in R1
+               BL      termite__enumArray      ;Get an element
+               BCC     %05termite_newsession   ;No more, get another string
+               ANDS    R14,R0,#&FF             ;Get the length
+               BEQ     %15termite_newsession   ;Zero -- get another one then
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+               B       %15termite_newsession   ;Find another element
+
+               ; --- All the strings are in stracc now ---
+               ;
+               ; First, we terminate the list
+
+50             BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Now, point to the strings ---
+
+               LDR     R5,tsc_stracc           ;Load stracc anchor
+               LDR     R5,[R5]
+               ADD     R0,R5,R3,LSR #8         ;Point to the base name
+               ADD     R1,R5,R6,LSR #8         ;Point to the sub-style
+               ADD     R2,R5,R4,LSR #8         ;Point to strings
+
+               TCALL   termite_newSession      ;Open the session
+               BL      termite__error          ;Handle possible error
+
+               MOV     R0,R3                   ;Put the offset in R0
+               BL      stracc_free             ;Free all those strings!
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+; --- termite_oscli ---
+
+               EXPORT  termite_oscli
+termite_oscli  ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,tsc_stracc           ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,tsc_misc             ;Point to the misc buffer
+               BL      termite_copyString      ;Copy the string over
+               SWI     Wimp_StartTask          ;Do the command
+               MOV     R0,R5                   ;Get the rvalue back
+               BL      stracc_free             ;Free the string from stracc
+               B       interp_next             ;Continue happily
+
+               LTORG
+
+; --- termite_rclear ---
+
+               EXPORT  termite_rclear
+termite_rclear ROUT
+
+               TCALL   termite_clearRemote     ;Clear the buffer
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_recho ---
+
+               EXPORT  termite_recho
+termite_recho  ROUT
+
+               CMP     R9,#tok_off             ;Is this an option thingy?
+               CMPNE   R9,#tok_local
+               CMPNE   R9,#tok_remote
+               CMPNE   R9,#tok_both
+               BEQ     %50termite_recho        ;Yes -- deal seperately
+
+               ; --- Just echo the result to the screen then ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read the next expression
+               BL      express_pop             ;Get the value in R0,R1
+               CMP     R1,#vType_integer       ;Is this an integer?
+               BEQ     %10termite_recho        ;Yes -- jump ahead
+               CMP     R1,#vType_string        ;Or a string?
+               MOVNE   R0,#err_arrayBad
+               BNE     error_report
+
+               ; --- Display a string ---
+
+               LDR     R2,tsc_stracc           ;Get the stracc address
+               LDR     R2,[R2]
+               ADD     R2,R2,R0,LSR #8         ;Point to the string
+               AND     R3,R0,#&FF              ;Get the length
+               TCALL   termite_sendRemote      ;Write out the message
+               BL      termite__error          ;Handle possible error
+               BL      stracc_free             ;Free the string from stracc
+               B       %20termite_recho        ;Maybe write out return char
+
+               ; --- Display an integer on the screen ---
+
+10termite_recho        ADR     R1,tsc_misc             ;Point to a nice buffer
+               MOV     R2,#256                 ;The buffer is big
+               SWI     OS_ConvertInteger4      ;Convert the number to a str
+               SUB     R3,R1,R0                ;Get the length
+               MOV     R2,R0                   ;Point at the block
+               TCALL   termite_sendRemote      ;Write out the message
+               BL      termite__error          ;Handle possible error
+
+               ; --- Maybe write out the return char ---
+
+20termite_recho        CMP     R9,#';'                 ;Is there a semicolon now?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     interp_next             ;...read another instr
+
+               LDR     R2,tsc_bucket           ;Get the bucket anchor
+               LDR     R2,[R2]
+               LDR     R0,tsc_rnewline         ;Load the newline offset
+               CMP     R0,#0                   ;Is there one?
+               BEQ     interp_next             ;No -- stop here then
+               ADD     R2,R2,R0                ;Point to the string
+               LDRB    R3,[R2,#-1]             ;Load out the length
+               TCALL   termite_sendRemote      ;Write out the terminator
+               BL      termite__error          ;Handle possible error
+               B       interp_next             ;And read another instruction
+
+               ; --- Handle the options ---
+
+50termite_recho        LDR     R0,tsc_flags            ;Load the flags word
+               BIC     R0,R0,#tscFlag_echoRR+tscFlag_echoRL
+               CMP     R9,#tok_local           ;Do we require local echoing?
+               CMPNE   R9,#tok_both
+               ORREQ   R0,R0,#tscFlag_echoRL   ;Yes -- set the flag
+               CMP     R9,#tok_remote          ;Do we require remote echos?
+               CMPNE   R9,#tok_both
+               ORREQ   R0,R0,#tscFlag_echoRR   ;Yes -- set the flag
+               STR     R0,tsc_flags            ;Store back the flags word
+               BL      getToken                ;Get another token
+
+               B       interp_next             ;Keep on going then!
+
+               LTORG
+
+; --- termite_report ---
+
+               EXPORT  termite_report
+termite_report ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,tsc_stracc           ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,tsc_misc             ;Point to the misc buffer
+               BL      termite_copyString      ;Copy the string over
+               TCALL   termite_printMessage    ;Report the message
+               MOV     R0,R5                   ;Get the rvalue back
+               BL      stracc_free             ;Free the string from stracc
+               B       interp_next             ;Continue happily
+
+               LTORG
+
+; --- termite_rinput ---
+
+               EXPORT  termite_rinput
+termite_rinput ROUT
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it in
+
+               ; --- Now enter a string reading loop ---
+
+               BL      stracc_ensure           ;Make sure that there's room
+               MOV     R2,R0                   ;Look after address
+               MOV     R4,R0                   ;Twice
+               MOV     R5,#0                   ;The length so far
+               MOV     R3,#1                   ;Length of buffer to echo
+
+00
+               TCALL   termite_checkCarrier    ;Get current carrier state
+               CMP     R0,#0                   ;Is there one?
+               MOVEQ   R0,#0                   ;No, return ""
+               BEQ     %90termite_rinput       ;And jump ahead
+
+               TCALL   termite_readRemote      ;Read a byte from the buffer
+               CMP     R0,#-1                  ;Was there one?
+               BLEQ    tsc_wait                ;No -- wait for it then
+               LDREQ   R2,tsc_stracc
+               LDREQ   R2,[R2]
+               ADDEQ   R2,R2,R1,LSR #8
+               ADDEQ   R2,R2,R5
+               BEQ     %b00
+               CMP     R0,#127                 ;Is this a delete?
+               CMPNE   R0,#8
+               BEQ     %f05                    ;Yes -- deal with that then
+               CMP     R0,#32                  ;Was it valid?
+               STRGEB  R0,[R2,#0]              ;Yes -- store the byte
+               BLGE    termite_doREcho         ;Echo the buffer
+               ADDGE   R2,R2,#1                ;Increment the pointer
+               ADDGE   R5,R5,#1                ;Increment the length
+               CMP     R0,#13                  ;Are we finished?
+               CMPNE   R5,#256
+               BLT     %b00                    ;No -- get some more then
+               B       %f10                    ;Finished -- jump ahead
+
+               ; --- Do a delete operation ---
+
+05             CMP     R5,#0                   ;Is the buffer empty?
+               BLE     %b00                    ;Yes -- do nothing
+               MOV     R14,#8                  ;Get a backspace
+               STRB    R14,[R2,#0]             ;Store it...
+               STRB    R14,[R2,#2]             ;In two places
+               MOV     R14,#32                 ;And a space too
+               STRB    R14,[R2,#1]             ;Put that in the middle
+               MOV     R3,#3                   ;Send 3 characters
+               BLGE    termite_doREcho         ;Echo the buffer
+               SUB     R2,R2,#1                ;Reduce the address
+               SUB     R5,R5,#1                ;And the number of chars
+               MOV     R3,#1                   ;Put R3 back to 1
+               B       %b00                    ;Join main loop again
+
+               ; --- We have finished reading the string ---
+
+10             ORR     R0,R1,R5                ;Get the rvalue
+90             MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               MOV     R3,R1                   ;Move these up a little
+               MOV     R2,R0
+               BL      express_pop             ;Get my lvalue off
+               BL      ctrl_store              ;Store this away
+               B       interp_next             ;Do another command
+
+               LTORG
+
+; --- termite_rnewline ---
+
+               EXPORT  termite_rnewline
+termite_rnewline ROUT
+
+               CMP     R9,#'='                 ;Next char must be `='
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the equals sign
+
+               LDR     R0,tsc_rnewline         ;Get existing offset
+               BL      strBucket_free          ;Free it
+               MOV     R0,#0                   ;Prepare to read rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop it off the stack
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_strNeeded       ;No -- get error number
+               BNE     error_report            ;And report the error
+               BL      termite__storeStr       ;Store inthe bucket
+               STR     R0,tsc_rnewline         ;Store the new offset
+               B       interp_next             ;And do the next instruction
+
+; --- termite_spool ---
+
+               EXPORT  termite_spool
+termite_spool  ROUT
+
+               CMP     R9,#10                  ;Is this a newline?
+               CMPNE   R9,#':'                 ;Or a colon
+               CMPNE   R9,#&FF                 ;Or the end of the file?
+               CMPNE   R9,#tok_else            ;Or an else
+               BEQ     %50                     ;Yes -- turn off spooling
+
+               ; --- Turn on spooling ---
+               ;
+               ; Ooh, spooling, I really dig you.
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read the expression
+               BL      express_pop             ;Pop the result
+               CMP     R1,#vType_string        ;Do we have a string?
+               MOVNE   R0,#err_strNeeded       ;No -- moan at thick user
+               BNE     error_report            ;Do that then
+
+               ; --- Copy the string to the misc buffer ---
+
+               LDR     R1,tsc_stracc           ;Find the stracc buffer
+               LDR     R1,[R1,#0]              ;Load the pointer out
+               MOV     R2,R0                   ;Look after the rvalue
+               ADD     R0,R1,R0,LSR #8         ;Find the string base
+               AND     R1,R2,#&FF              ;And get the length
+               ADR     R3,tsc_misc             ;Point to destination buffer
+00             LDRB    R14,[R0],#1             ;Load byte from string
+               STRB    R14,[R3],#1             ;Store in destination
+               SUBS    R1,R1,#1                ;Decrement the counter
+               BGT     %b00                    ;And carry on going
+               MOV     R14,#0                  ;Terminate the string
+               STRB    R14,[R3],#1             ;Stick that on the end
+
+               MOV     R0,R2                   ;Find the string rvalue
+               BL      stracc_free             ;Remove it from stracc
+
+               ; --- Make sure we're not spooling right now ---
+
+               LDR     R1,tsc_spool            ;Load the current handle
+               CMP     R1,#0                   ;Are we spooling?
+               MOVNE   R0,#0                   ;Yes -- close current file
+               SWINE   XOS_Find                ;So do that then
+
+               ; --- Now open the file ---
+
+               MOV     R0,#&8F                 ;Give me lots of errors
+               ADR     R1,tsc_misc             ;Point to the buffer
+               SWI     XOS_Find                ;Find a file handle for it
+               BVS     error_reportReal        ;If failed, report the error
+               STR     R0,tsc_spool            ;Save the file handle
+               B       interp_next             ;Now do another instruction
+
+               ; --- Close the current file ---
+
+50termite_spool        LDR     R1,tsc_spool            ;Load the current handle
+               CMP     R1,#0                   ;Are we spooling?
+               MOVNE   R0,#0                   ;Yes -- close current file
+               SWINE   XOS_Find                ;So do that then
+               BVS     error_reportReal
+               MOV     R14,#0                  ;Get a zero value
+               STR     R14,tsc_spool           ;Clear the file handle
+               B       interp_next             ;Now do another instruction
+
+               LTORG
+
+; --- termite_syscall ---
+
+               EXPORT  termite_syscall
+termite_syscall        ROUT
+
+               BL      ctrl_setUpRegs          ;Set up the regs then
+
+               CMP     R10,#vType_string       ;Is this a string?
+               LDREQ   R14,tsc_stracc          ;Yes -- load the stracc addr#
+               LDREQ   R14,[R14]               ;Grrrr...
+               ADDEQ   R9,R14,R9,LSR #8        ;Point to the string
+               MOVEQ   R14,PC                  ;Yes -- set up return address
+               ADDEQ   PC,R11,#termite_sysNumString
+               BVS     error_reportReal        ;Report possible error
+               CMPNE   R10,#vType_integer      ;Is this an integer?
+               MOVNE   R0,#err_arrayBad        ;No -- get error number
+               BNE     error_report            ;...and report the error
+
+               TCALL   termite_sysCall         ;Call the call then!
+
+               ADR     R10,termite__retned     ;Point to some space
+               STMIA   R10!,{R0-R8}            ;Store returned registers
+               MOV     R14,PC,LSR #28          ;Get the flags
+               STMIA   R10!,{R14}              ;Strore the flags too
+
+               ; --- Convert the string if needed ---
+
+               LDMFD   R13!,{R7-R12}           ;Load back position info
+               LDMFD   R13!,{R0}               ;Load stracc offset
+               BL      stracc_free             ;Free any strings I had
+
+               ; --- We have now done the SYSCALL instr ---
+
+               ADR     R0,termite__retned      ;Point to the returned regs
+               BL      ctrl_resolveRegs        ;Do the other half now
+               B       interp_next             ;No error -- happy
+
+termite__retned        DCD     0,0,0,0,0,0,0,0,0,0,0   ;For SYSCALL, CALL
+
+               LTORG
+
+; --- termite_upload ---
+
+               EXPORT  termite_upload
+termite_upload ROUT
+
+               ; --- Read the protocol name ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_numNeeded       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ; --- NULL terminate it ---
+               ;
+               ; We rely on the fact that there can't be anything else
+               ; after this string.  It is also important that we remember
+               ; the stracc offset of this string, so that all the strings
+               ; can be removed from stracc in one go.
+
+
+               MOV     R3,R1                   ;Look after the offset
+               MOV     R5,#0                   ;Useful, t' be sure
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ADD     R4,R1,#(1<<8)           ;The next string will go here
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Now we keep on adding strings to the list ---
+
+05             CMP     R9,#','                 ;Do we have a comma?
+               BNE     %50termite_upload       ;No -- do the deed then
+               BL      getToken                ;Skip over the comma
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the string
+               CMP     R1,#vType_dimStr        ;Is this a string array?
+               BEQ     %10termite_upload       ;Yes -- jump ahead
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_strNeeded       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ; --- We have a string then ---
+
+               CMP     R0,#0                   ;Does it have a length?
+               BEQ     %05termite_upload       ;No -- find another one then
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+               B       %05termite_upload       ;Find another string
+
+               ; --- We have a string array ---
+
+10             MOV     R3,R0                   ;Look after rvalue
+               MOV     R2,#0                   ;Start from the beginning
+15             MOV     R1,R3                   ;Put it in R1
+               BL      termite__enumArray      ;Get an element
+               BCC     %05termite_upload       ;No more, get another string
+               ANDS    R14,R0,#&FF             ;Get the length
+               BEQ     %15termite_upload       ;Zero -- get another one then
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+               B       %15termite_upload       ;Find another element
+
+               ; --- All the strings are in stracc now ---
+               ;
+               ; First, we terminate the list
+
+50             BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Now, point to the strings ---
+
+               LDR     R1,tsc_stracc           ;Load stracc anchor
+               LDR     R1,[R1]
+               MOV     R5,R3                   ;Look after offset
+               ADD     R2,R1,R3,LSR #8         ;Point to the protocol name
+               ADD     R3,R1,R4,LSR #8         ;Point to files to upload
+
+               TCALL   termite_upLoad          ;Upload the files
+               BL      termite__error          ;Handle possible error
+
+               MOV     R0,R5                   ;Put the offset in R0
+               BL      stracc_free             ;Free all those strings!
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+; --- termite_wait ---
+
+               EXPORT  termite_wait
+termite_wait   ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_integer       ;Is this an integer
+               MOVNE   R0,#err_numNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               MOV     R1,R0                   ;Remember this time
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               ADD     R1,R1,R0                ;Return after this time
+
+               ; --- Now enter a waiting loop ---
+
+00             SWI     OS_ReadMonotonicTime    ;Read the current time
+               CMP     R0,R1                   ;Have we finished waiting?
+               BLCC    tsc_wait                ;No -- wait some more
+               BCC     %b00                    ;...and keep on looping
+
+               B       interp_next             ;Go round for next command
+
+               LTORG
+
+; --- termite_watchfor ---
+
+               EXPORT  termite_watchfor
+termite_watchfor ROUT
+
+               ; --- See if we are ending the WATCHFOR ---
+
+               CMP     R9,#tok_end             ;Are we ending it?
+               BEQ     %70termite_watchfor     ;Yes -- jump ahead
+
+               ; --- First, we must set up strings ---
+               ;
+               ; We actually store the strings in the strBucket.
+               ; In the string list, we have a word for the pointer into
+               ; the string list, and a byte for the match position so far.
+
+               MOV     R5,#0                   ;Number so far
+               ADR     R3,tsc_wForStrings      ;Point to the block
+               MOV     R4,#0                   ;For the match position
+               STR     R5,tsc_wForState        ;Reset the state to 0
+
+10             CMP     R5,#32                  ;Are we at the maximum?
+               MOVGE   R0,#err_WFTooMany       ;Yes -- get error number
+               BEQ     error_report            ;And report the error
+
+               ; --- Now read the strings one at a time ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off this value
+               CMP     R1,#vType_dimStr        ;Is this a string array?
+               BNE     %19termite_watchfor     ;No -- jump ahead
+
+               ; --- We have a string array ---
+
+               MOV     R1,R0                   ;Put the array in R1
+               MOV     R2,#0                   ;Start from the beginning
+00             BL      termite__enumArray      ;Get the next string
+               BCC     %15termite_watchfor     ;No more -- jump ahead
+               BL      termite__storeStr       ;Store the string
+               CMP     R9,#&7e                 ;Are we case insensitive?
+               ORREQ   R0,R0,#(1<<31)          ;Yes -- set the flag
+               STMIA   R3!,{R0,R4}             ;Store information
+               ADD     R5,R5,#1                ;Increment the counter
+               B       %b00                    ;And keep doing this
+
+               ; --- The array has finished ---
+
+15             CMP     R9,#&7e                 ;Should we skip a token?
+               BLEQ    getToken                ;Yes - do that then
+               B       %25termite_watchfor     ;Jump ahead a little
+
+               ; --- See if it's a string then ---
+
+19             CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_strNeeded       ;No -- get the error
+               BNE     error_report            ;And then report it
+
+               ; --- We have a string in stracc ---
+
+               CMP     R9,#&7e                 ;Case insensitive? (#'~')
+               BLEQ    getToken                ;Yes -- skip over it
+20             BL      termite__storeStr       ;Put it in the bucket
+               ORREQ   R0,R0,#(1<<31)          ;Set the top bit for insens
+               STMIA   R3!,{R0,R4}             ;Store inforamtion
+               ADD     R5,R5,#1                ;Increment the counter
+
+               ; --- Do any more we have ---
+
+25             CMP     R9,#','                 ;Do we have a comma
+               BLEQ    getToken                ;Yes -- skip over it
+               BEQ     %10termite_watchfor     ;...and then go round
+               STR     R5,tsc_wForNumber       ;Store the number of strings
+
+               ; --- Now we must check the ring buffer ---
+               ;
+               ; We keep taking bytes off until either a match is achieved,
+               ; we have read 255 chars or there are no more in the
+               ; buffer.  In any case we then on the buffer.
+               ; If we have 255 chars we simply start all over again.
+
+               ADR     R2,tsc_misc             ;Point to the buffer
+               MOV     R3,#0                   ;Number read so far
+00
+               TCALL   termite_readRemote      ;Get a byte
+               CMP     R0,#-1                  ;Was there a byte?
+               BEQ     %50termite_watchfor     ;No -- jump ahead
+               ADD     R3,R3,#1                ;Increment the count
+               STRB    R0,[R2],#1              ;Store it in the buffer
+               BL      termite__checkWF        ;Does this make a match?
+               BCS     %50termite_watchfor     ;Yes -- jump ahead
+               CMP     R3,#255                 ;Have we had 255 bytes now?
+               BNE     %b00                    ;No -- keep on going then
+
+               ; --- Send on the buffer ---
+
+               ADR     R2,tsc_misc             ;Point to the buffer
+               BL      termite_doREcho         ;Echo it appropriately
+               MOV     R3,#0                   ;Reset the count to 0
+               B       %b00                    ;And start all over again
+
+               ; --- We have stopped reading bytes ---
+               ;
+               ; Either we ran out of bytes, or we got a match,
+               ; for either case we do the same thing
+
+50             ADR     R2,tsc_misc             ;Point to the buffer
+               BL      termite_doREcho         ;Echo it appropriately
+               B       interp_next             ;Do the next instruction
+
+               ; --- We are ending the watchfor ---
+
+70             BL      getToken                ;Gobble up the END
+               BL      termite__endWF          ;End the WATCHFOR
+               B       interp_next             ;Do the next command
+
+               LTORG
+
+; --- termite__endWF ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Ends a WATCHFOR condition.
+
+termite__endWF ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some regsiters
+               ADR     R1,tsc_wForStrings      ;Point to the string list
+               LDR     R2,tsc_wForNumber       ;Get the number of strings
+               CMP     R2,#0                   ;Are there any?
+               BEQ     %f05                    ;No -- jump ahead then
+               MOV     R3,R2,LSL #3            ;Multiply by 8
+               ADD     R1,R1,R3                ;Point just past the last one
+00             LDR     R0,[R1,#-8]!            ;Load out an offset
+               BIC     R0,R0,#(1<<31)          ;Clear the flag
+               BL      strBucket_free          ;Remove the string
+               SUBS    R2,R2,#1                ;Reduce the count
+               BGT     %b00                    ;And free the rest
+
+05             STR     R2,tsc_wForNumber       ;Make that clear
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- termite__checkWF ---
+;
+; On entry:    R0 == byte to check
+;
+; On exit:     CS if that byte caused a match,
+;              CC otherwise
+;
+; Use:         Tests all the strings in the WATCHFOR list, to see if
+;              the character caused a match.  If it did, then WATCH
+;              is set.
+
+termite__checkWF ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Stack registers
+               LDR     R1,tsc_bucket           ;Load the bucket anchor
+               LDR     R1,[R1,#0]              ;Point to it
+               ADR     R2,tsc_wForStrings      ;Point to the strings
+               LDR     R3,tsc_wForNumber       ;Load the number of strings
+
+               ; --- Get the information on the string ---
+
+00             LDR     R7,[R2],#4              ;Load the offset
+               CMP     R7,#0                   ;Is this one blank?
+               ADDEQ   R2,R2,#4                ;Yes -- skip over position
+               BEQ     %10termite__checkWF     ;Zero length -- ignore
+               BICS    R4,R7,#(1<<31)          ;Clear the 'insens' bit
+               LDR     R5,[R2],#4              ;Load position so far
+               ADD     R4,R1,R4                ;Point to the string
+               LDRB    R6,[R4,#-1]             ;Load the string length
+               ADD     R4,R4,R5                ;Point to the character
+
+               ; --- Now do the comparison ---
+
+02             LDRB    R14,[R4,#0]             ;Load the next byte
+               MOV     R9,R0                   ;Put byte to comapre in R8
+               TST     R7,#(1<<31)             ;Case insensitive?
+               ORRNE   R9,R9,#32               ;Yes -- make lower case
+               ORRNE   R14,R14,#32             ;Both of them
+               CMP     R9,R14                  ;Are they the same?
+               BEQ     %05termite__checkWF     ;Yes -- jump ahead
+               CMP     R5,#0                   ;Was that the first char?
+               SUB     R4,R4,R5                ;Point to the string start
+               MOV     R5,#0                   ;Put it back to 0
+               BNE     %02termite__checkWF     ;No --  test first char
+               STR     R5,[R2,#-4]             ;...store that back
+               B       %10termite__checkWF     ;...jump ahead
+
+               ; --- The characters matched ---
+
+05             ADD     R5,R5,#1                ;Increment position
+               CMP     R5,R6                   ;Has the string been done?
+               BEQ     %20termite__checkWF     ;Yes -- we jump ahead then
+               STR     R5,[R2,#-4]             ;Store the new position
+
+               ; --- Move onto the next string ---
+
+10             SUBS    R3,R3,#1                ;Decrement the string count
+               BGT     %00termite__checkWF     ;And keep on looking
+               LDMFD   R13!,{R0-R9,R14}        ;Load back registers
+               BICS    PC,R14,#C_flag          ;And return to caller
+
+               ; --- We found a matching string ---
+
+20             LDR     R14,tsc_wForNumber      ;Get teh number of strings
+               SUB     R14,R14,R3              ;Get index-1
+               ADD     R14,R14,#1              ;Get the index
+               STR     R14,tsc_wForState       ;Store as the state
+               BL      termite__endWF          ;End the current watchfor
+               LDMFD   R13!,{R0-R9,R14}        ;Load back registers
+               ORRS    PC,R14,#C_flag          ;And return to caller
+
+               LTORG
+
+; --- termite_remoteInput ---
+;
+; On entry:    R0 == handle of script
+;              R2 == buffer containing bytes read
+;              R3 == number of bytes in buffer
+;              R11 == upcall block
+;
+; On exit:     R2 == new buffer containing bytes to put into ring buffer
+;              R3 == number of bytes in this buffer
+;
+; Use:         If we are not doing a watchfor, then this call will return
+;              immediately, resulting in all the buffer being sent
+;              to the ring buffer.
+;              If we are in a watchfor, then all data received, up until
+;              a match, is echoed immediatley, and not sent to the buffer.
+
+               EXPORT  termite_remoteInput
+termite_remoteInput ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               LDR     R14,[R0,#:INDEX:tsc_wForNumber]
+               CMP     R14,#0                  ;Are we in a WATCHFOR?
+               LDMEQFD R13!,{PC}^              ;No -- return AQAP then
+
+               STMFD   R13!,{R0,R4,R5,R12}     ;Stack some more registers
+               MOV     R12,R0                  ;Put workspace in R12
+               MOV     R4,R2                   ;Look after buffer address
+               MOV     R5,R3                   ;Remember number of bytes
+
+               ; --- Scan the buffer ---
+
+00             LDRB    R0,[R4],#1              ;Load a byte
+               SUB     R5,R5,#1                ;Reduce the count
+               BL      termite__checkWF        ;Does this cause a match
+               BCS     %10termite_remoteInput  ;We have a match
+               CMP     R5,#0                   ;Have we finished?
+               BGT     %b00                    ;More to go -- loop
+
+               ; -- Send this buffer then ---
+
+               BL      termite_doREcho         ;Send the buffer
+               MOV     R3,#0                   ;Put nothing in the buffer
+               B       %90termite_remoteInput  ;And return to caller
+
+               ; --- We got a match ---
+
+10             SUB     R3,R3,R5                ;Get number to send
+               BL      termite_doREcho         ;Send the buffer
+               MOV     R3,R5                   ;Get bytes left
+               MOV     R2,R4                   ;Point to rest of buffer
+
+90             LDMFD   R13!,{R0,R4,R5,R12,PC}^ ;Return to caller
+
+               LTORG
+
+;----- Utility routines -----------------------------------------------------
+
+; --- termite_copyString ---
+;
+; On entry:    R0 == buffer to copy string to
+;              R1 == point to the string
+;              R2 == length of string to copy
+;
+; On exit:     --
+;
+; Use:         Copies the string into the buffer.
+
+               EXPORT  termite_copyString
+termite_copyString ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack registers
+               CMP     R2,#0                   ;Is this a short string?
+00             LDRGTB  R14,[R1],#1             ;Load a character
+               STRGTB  R14,[R0],#1             ;And then store it
+               SUBS    R2,R2,#1                ;Reduce the count
+               BGT     %b00                    ;And keep on goin'
+               MOV     R14,#0                  ;Get a terminator
+               STRB    R14,[R0],#1             ;Store the byte and return
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- termite_doLEcho ---
+;
+; On entry:    R2 == pointer to the buffer
+;              R3 == number of bytes to send
+;
+; On exit:     --
+;
+; Use:         Echos the buffer to local and remote according to the
+;              current flags, assuming the buffer came from the local input
+
+               EXPORT  termite_doLEcho
+termite_doLEcho        ROUT
+
+               STMFD   R13!,{R0,R3,R14}        ;Stack some registers
+               LDR     R0,tsc_flags            ;Load the flags word
+               TST     R0,#tscFlag_echoLR      ;Should we echo to remote?
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               ADDNE   PC,R11,#termite_sendRemote ;...and send the bytes
+               TST     R0,#tscFlag_echoLL      ;Should we echo to local?
+               BLNE    termite__doSpool        ;Yes -- check for spooling
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               ADDNE   PC,R11,#termite_sendLocal ;...and send the bytes
+               LDMFD   R13!,{R0,R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- termite_doREcho ---
+;
+; On entry:    R2 == pointer to the buffer
+;              R3 == number of bytes to send
+;
+; On exit:     --
+;
+; Use:         Echos the buffer to local and remote according to the
+;              current flags, assuming the buffer came from remote input
+
+               EXPORT  termite_doREcho
+termite_doREcho        ROUT
+
+               STMFD   R13!,{R0,R3,R14}        ;Stack some registers
+               LDR     R0,tsc_flags            ;Load the flags word
+               TST     R0,#tscFlag_echoRR      ;Should we echo to remote?
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               ADDNE   PC,R11,#termite_sendRemote ;...and send the bytes
+               TST     R0,#tscFlag_echoRL      ;Should we echo to local?
+               BLNE    termite__doSpool        ;Yes -- check for spooling
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               ADDNE   PC,R11,#termite_sendLocal ;...and send the bytes
+               LDMFD   R13!,{R0,R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- termite__doSpool ---
+;
+; On entry:    R2 == pointer to data to spool
+;              R3 == size of the data
+;
+; On exit:     --
+;
+; Use:         Maybe writes the data to the current spool file.
+
+termite__doSpool ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               LDR     R1,tsc_spool            ;Load the spool handle
+               CMP     R1,#0                   ;Is spooling enabled?
+               MOVNE   R0,#2                   ;Yes -- write to the file
+               SWINE   XOS_GBPB                ;Do the write
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+; --- termite__storeStr ---
+;
+; On entry:    R0 == rvalue of string
+;
+; On exit:     R0 == offset into bucket of string
+;
+; Use:         Puts the string in stracc, into the string bucket.
+
+termite__storeStr ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack some registers
+               MOV     R2,R0                   ;Put the string in R2
+               MOV     R4,R0                   ;And in R4
+               ANDS    R0,R2,#&FF              ;Get the length
+               MOVEQ   R0,#0                   ;Zero length, get a zero
+               BEQ     %90termite__storeStr    ;And return to caller
+               BL      strBucket_alloc         ;Allocate the bucket
+               LDR     R3,tsc_stracc           ;Load the bucket anchor
+               LDR     R3,[R3]                 ;This is getting annoying
+               ADD     R3,R3,R2,LSR #8         ;Point to the string
+               AND     R2,R2,#&FF              ;Get the length
+00             LDRB    R14,[R3],#1             ;Load a character
+               STRB    R14,[R0],#1             ;Copy it over
+               SUBS    R2,R2,#1                ;Reduce the counter
+               BGT     %b00                    ;Keep on looping
+               MOV     R0,R4                   ;Put the rvalue in R0
+               BL      stracc_free             ;Remove it from stracc
+               MOV     R0,R1                   ;Return offset in R0
+
+90             LDMFD   R13!,{R1-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- termite__enumArray ---
+;
+; On entry:    R1 == offset of array definition
+;              R2 == item to read next
+;
+; On exit:     CS if item found, and
+;                R0 == rvalue of item
+;                R2 == updated
+;              CC otherwise
+;
+; Use:         Goes through an string array, returning each item.
+
+termite__enumArray ROUT
+
+               STMFD   R13!,{R1,R3,R4,R14}     ;Stack registers
+               LDR     R3,tsc_varTree          ;Point at the tree
+               LDR     R3,[R3]
+               ADD     R0,R3,R1                ;Point at the array
+               MOV     R4,R2                   ;Remember the count
+               LDR     R14,[R0,#8]             ;Load number of items
+               CMP     R2,R14                  ;Have we finished?
+               BEQ     %95termite__enumArray   ;Yes -- return then
+
+               LDR     R14,[R0,#4]             ;Load number of subscripts
+               ADD     R0,R0,#12               ;Point to them
+               ADD     R0,R0,R14,LSL #2        ;Point past them
+               ADD     R0,R0,R2,LSL #2         ;Point at the item
+               SUB     R0,R0,R3                ;Make that an offset
+               MOV     R1,#vType_lvString      ;The item is a string
+               BL      ctrl_load               ;Load it out
+               MOV     R0,R2                   ;Put the rvalue in R0
+               ADD     R2,R4,#1                ;Increment the item pos
+
+               LDMFD   R13!,{R1,R3,R4,R14}     ;Load back registers
+               ORRS    PC,R14,#C_flag          ;And return success
+
+95             LDMFD   R13!,{R1,R3,R4,R14}     ;Load back registers
+               BICS    PC,R14,#C_flag          ;And return failure
+
+               LTORG
+
+; --- termite__error ---
+;
+; On entry:    V flag and R0 determine error condition
+;
+; On exit:     --
+;
+; Use:         This call will generate an error, if ERROR ON has been
+;              done, or set the ERROR$ variable otherwise.
+
+termite__error ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save regiters
+               LDR     R1,tsc_flags            ;Load the fags word
+               BVS     %50termite__error       ;Jump ahead if there's an err
+
+               ; --- There was no error ---
+
+               TST     R1,#tscFlag_error       ;Do we generate errors?
+               BNE     %90termite__error       ;Yes -- just return then
+
+               ; --- Put a NULL string into ERROR$ ---
+
+               LDR     R0,tsc_errorS           ;Get the exesting offset
+               BL      strBucket_free          ;Free it
+               MOV     R0,#0                   ;Get a 0 length string
+               STR     R0,tsc_errorS           ;Save that away
+               B       %90termite__error       ;Return to caller
+
+               ; --- There was an error ---
+
+50             TST     R1,#tscFlag_error       ;Do we generate errors?
+               BNE     error_reportReal        ;Yes -- report the error then
+
+               ; --- Copy the string into ERROR$ ---
+
+               ADD     R2,R0,#4                ;Put string pointer in R2
+               LDR     R0,tsc_errorS           ;Get the exesting offset
+               BL      strBucket_free          ;Free it
+               MOV     R1,R2                   ;Point to the string
+               MOV     R0,#0                   ;Current sting length
+00             LDRB    R14,[R1],#1             ;Load a byte
+               CMP     R14,#0                  ;Is it a NULL one?
+               ADDNE   R0,R0,#1                ;No -- increment the length
+               BNE     %b00                    ;And keep on going
+
+               ; --- Now copy over the string ---
+
+               BL      strBucket_alloc         ;We need this much room
+               STR     R1,tsc_errorS           ;Store this offset away
+00             LDRB    R14,[R2],#1             ;Load a byte from string
+               CMP     R14,#0                  ;Is this the end?
+               STRNE   R14,[R0],#1             ;No -- store in ERROR$
+               BNE     %b00                    ;And keep doing this
+
+               ; --- Return to caller ---
+
+90             LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/tokenise b/StraySrc/Libraries/Sapphire/sail/_s/tokenise
new file mode 100644 (file)
index 0000000..40fb65a
--- /dev/null
@@ -0,0 +1,563 @@
+;
+; tokenise.s
+;
+; Tokenise a Termite script
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.tokens
+               GET     sh.var
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- tokenise ---
+;
+; On entry:    R0 == pointer to source buffer
+;              R1 == size of source text
+;              R2 == pointer to destination buffer
+;              R3 == flags:
+;                      bit 0 == start reading a statement
+;              R11 == pointer to Termite upcall block
+;              R12 == pointer to script anchor
+;
+; On exit:     May return an error
+;
+; Use:         Tokenises a Termite script into an output buffer.
+
+               EXPORT  tokenise
+tokenise       ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Save some registers
+               MOV     R10,R2                  ;Point to output buffer
+               MOV     R7,R0                   ;Point to input buffer
+               ADD     R8,R7,R1                ;Point to input buffer limit
+               ADR     R9,tsc_misc             ;Point to temporary buffer
+               ANDS    R14,R3,#1               ;Awaiting a statement?
+               MOVNE   R6,#tState__stmt        ;Yes -- select that state
+               MOVEQ   R6,#tState__dunno       ;No -- normal scanning state
+               MOVNE   R14,#1                  ;We start on line 1
+               STR     R14,[R13,#-8]!          ;Save this initial value
+
+               ; --- Ok, start lexing ---
+
+               MOV     R3,#0                   ;No flags set yet
+00tokenise     CMP     R7,R8                   ;Finished yet?
+               BHI     %10tokenise             ;Yes -- stop then
+               LDRB    R0,[R7],#1              ;No -- load the next byte
+               MOVEQ   R0,#-1                  ;Yes -- get an EOF character
+
+               MOV     R14,PC
+               ADD     PC,PC,R6,LSL #2         ;And leap off into oblivion
+               B       %00tokenise
+
+               B       tok__stmt
+               B       tok__dunno
+               B       tok__string
+               B       tok__dblQte
+               B       tok__star
+               B       tok__decimal
+               B       tok__hex
+               B       tok__ident
+               B       tok__keyWord
+               B       tok__label
+               B       tok__expLab
+               B       tok__lineCmt
+               B       tok__blkCmt
+               B       tok__cmtStar
+
+               ; --- Tidy up if we've finished ---
+
+10tokenise     MOV     R14,#255                ;Mark the end of the script
+               STRB    R14,[R10],#1            ;Save that on the end
+               ADD     R13,R13,#8              ;Restore the stack pointer
+               LDMFD   R13!,{R0-R10,R14}       ;And return to caller
+               BICS    PC,R14,#V_flag
+
+               LTORG
+
+; --- tok__error ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     --
+;
+; Use:         Reports an error during tokenising.
+
+tok__error     ROUT
+
+               ADD     R13,R13,#12             ;Restore the stack pointer
+               LDMFD   R13!,{R1-R10,R14}       ;Restore registers too
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- tok__incLineNo ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Increments the current line number.
+
+tok__incLineNo ROUT
+
+               LDR     R1,[R13,#0]             ;Yes -- load line number
+               CMP     R1,#0                   ;Are we scanning a file?
+               ADDNE   R1,R1,#1                ;Increment it
+               STRNE   R1,[R13,#0]             ;And store it back
+               MOVS    PC,R14
+
+               LTORG
+
+; --- tok__stmt ---
+
+tok__stmt      ROUT
+
+               CMP     R0,#'*'                 ;Is this a *command?
+               STREQB  R0,[R10],#1             ;Yes -- store the * character
+               MOVEQ   R6,#tState__star        ;And read a star command
+               MOVEQS  PC,R14                  ;And return to caller
+
+               CMP     R0,#'.'                 ;Is this a label
+               ORREQ   R3,R3,#tFlag__readDot   ;We've just read a dot
+               MOVEQ   R6,#tState__label       ;Read a label, please
+               MOVEQ   R4,#0                   ;No character read yet
+               MOVEQS  PC,R14                  ;And return to caller
+
+               ; Drop through to dunno
+
+; --- tok__dunno ---
+
+tok__dunno     ROUT
+
+               ; --- Ignore whitespace ---
+               ;
+               ; Other states will have dealt with this as necessary already
+               ; so we don't need to bother.
+
+               MOV     R2,R14                  ;Preserve the link
+               CMP     R0,#10                  ;Is it a newline
+               STREQB  R0,[R10],#1             ;Yes -- store it in buffer
+               BLEQ    tok__incLineNo          ;Increment the line number
+               MOVEQ   R6,#tState__stmt        ;And start a new statement
+               CMPNE   R0,#' '                 ;Is it a space
+               CMPNE   R0,#9                   ;Or a tab?
+               MOVEQS  PC,R2                   ;Yes -- don't do anything
+               MOV     R14,R2                  ;Put the link back
+
+               ; --- Now find an appropriate state ---
+
+               CMP     R0,#'/'                 ;Is this a slash?
+               STREQ   R6,[R13,#4]             ;Yes -- save old state away
+
+               SUBS    R1,R0,#'+'              ;Check for strange chars
+               SUBNES  R1,R0,#'-'              ;Check for strange chars
+               SUBNES  R1,R0,#'*'              ;Check for strange chars
+               SUBNES  R1,R0,#'/'              ;Check for strange chars
+               SUBNES  R1,R0,#'<'              ;Check for strange chars
+               SUBNES  R1,R0,#'>'              ;Check for strange chars
+               SUBNE   R1,R0,#'A'              ;Otherwise check uppercase
+               CMP     R1,#26                  ;Is it in the right range?
+               SUBCC   R7,R7,#1                ;Yes -- backtrack one char
+               MOVCC   R6,#tState__keyWord     ;And read a keyword
+               MOVCC   R5,#0                   ;Entry in state table
+               MOVCC   R4,#0                   ;No characters read yet
+               MOVCC   R2,#0                   ;No token discovered yet
+               MOVCCS  PC,R14                  ;And return to caller
+
+               MOV     R6,#tState__dunno       ;Read char, so not new stmt
+
+               CMP     R0,#'"'                 ;Is it a string?
+               STREQB  R0,[R10],#1             ;Yes -- store opening quote
+               MOVEQ   R6,#tState__string      ;And read a string literal
+               MOVEQS  PC,R14                  ;And return to caller
+
+               SUB     R1,R0,#'0'              ;Check if it's a digit
+               CMP     R1,#10                  ;Is it in the right range?
+               STRCCB  R0,[R10],#1             ;Yes -- store digit
+               MOVCC   R6,#tState__decimal     ;And read a decimal number
+               MOVCCS  PC,R14                  ;And return to caller
+
+               CMP     R0,#'&'                 ;Also check for hex numbers
+               STREQB  R0,[R10],#1             ;Yes -- store the ampersand
+               MOVEQ   R6,#tState__hex         ;And read a hex number
+               MOVEQS  PC,R14                  ;And return to caller
+
+               SUBS    R1,R0,#'_'              ;Is this an underscore?
+               SUBNE   R1,R0,#'a'              ;Check if it's a lowercase
+               CMP     R1,#26                  ;Is it in the right range?
+               STRCCB  R0,[R10],#1             ;Yes -- store the character
+               MOVCC   R6,#tState__ident       ;And read an identifier
+               MOVCCS  PC,R14                  ;And return to caller
+
+               CMP     R0,#':'                 ;Is this a colon?
+               STREQB  R0,[R10],#1             ;Yes -- store the character
+               MOVEQ   R6,#tState__stmt        ;And start a new statement
+               MOVEQS  PC,R14                  ;And return to caller
+
+               STRB    R0,[R10],#1
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- tok__star ---
+
+tok__star      ROUT
+
+               MOV     R2,R14                  ;Preserve the link
+               STRB    R0,[R10],#1             ;Save the character
+               CMP     R0,#10                  ;Is this a newline?
+               MOVEQ   R6,#tState__stmt        ;Start a new statement
+               BLEQ    tok__incLineNo          ;Increment the line number
+               MOVS    PC,R2                   ;And return to caller
+
+               LTORG
+
+; --- tok__string ---
+
+tok__string    ROUT
+
+               STRB    R0,[R10],#1             ;Save the character
+               CMP     R0,#'"'                 ;Is it another quote?
+               MOVEQ   R6,#tState__dblQte      ;Yes -- change state
+               MOVEQS  PC,R14                  ;And return
+               MOV     R2,R14                  ;Preserve the link
+               CMP     R0,#10                  ;Is it newline?
+               MOVEQ   R6,#tState__stmt        ;Yes -- change state
+               BLEQ    tok__incLineNo          ;...increment line number
+               MOVS    PC,R2                   ;And return
+
+               LTORG
+
+; --- tok__dblQte ---
+
+tok__dblQte    ROUT
+
+               CMP     R0,#'"'                 ;Is this a 2nd quote?
+               MOVEQ   R6,#tState__string      ;Yes -- go back to string
+               STREQB  R0,[R10],#1             ;..and store it away
+               SUBNE   R7,R7,#1                ;Otherwise backtrack
+               MOVNE   R6,#tState__dunno       ;..and enter dunno state
+               MOVS    PC,R14
+
+               LTORG
+
+; --- tok__decimal ---
+
+tok__decimal   ROUT
+
+               SUB     R1,R0,#'0'              ;Set up for range check
+               CMP     R1,#10                  ;Are we in range?
+               STRCCB  R0,[R10],#1             ;Yes -- store the number
+               MOVCCS  PC,R14                  ;And return
+
+               ; --- A bit of bodgery now ---
+               ;
+               ; This hackery introduces a space between two numbers, which
+               ; would otherwise severely upset something like
+               ;
+               ;    DIM a%!24 64
+
+tok__numHack   CMP     R0,#&20                 ;Is this a space?
+               BNE     %f00                    ;No -- just stop normally
+               LDRB    R1,[R7,#0]              ;Get the next byte
+               SUB     R1,R1,#'0'              ;Is it a digit?
+               CMP     R1,#10                  ;Quick check
+               STRCCB  R0,[R10],#1             ;Yes -- store the space
+00             SUB     R7,R7,#1                ;Backtrack a little
+               MOV     R6,#tState__dunno       ;...and change state
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- tok__hex ---
+
+tok__hex       ROUT
+
+               SUB     R1,R0,#'a'              ;Set up for range check
+               CMP     R1,#6                   ;Are we in range?
+               SUBCC   R0,R0,#'a'-'A'          ;Force to uppercase
+               SUBCS   R1,R0,#'0'
+               CMPCS   R1,#10
+               SUBCS   R1,R0,#'A'
+               CMPCS   R1,#6
+               STRCCB  R0,[R10],#1             ;Yes -- store the number
+               MOVCCS  PC,R14                  ;And return
+
+               ; --- Hack as above ---
+
+               B       tok__numHack            ;Use hacking code above
+
+               LTORG
+
+; --- tok__ident ---
+
+tok__ident     ROUT
+
+               CMP     R0,#'$'                 ;Is it a dollar sign?
+               CMPNE   R0,#'%'                 ;Or a percentage?
+               STREQB  R0,[R10],#1             ;Yes -- store it then
+               MOVEQ   R6,#tState__dunno       ;Change state
+               MOVEQS  PC,R14                  ;And return to caller
+
+               SUBS    R1,R0,#'_'              ;Is it an underscore?
+               SUBNE   R1,R0,#'0'              ;Or a number?
+               CMP     R1,#10
+               SUBCS   R1,R0,#'A'              ;Or a capital letter?
+               CMPCS   R1,#26
+               SUBCS   R1,R0,#'a'              ;Or a lowercase letter?
+               CMPCS   R1,#26
+               MOVCS   R1,#' '                 ;If not valid, append space
+               MOVCC   R1,R0                   ;Otherwise write character
+               STRB    R1,[R10],#1             ;Store a character
+               SUBCS   R7,R7,#1                ;No -- backtrack a little
+               MOVCS   R6,#tState__dunno       ;...and change state
+               MOVS    PC,R14                  ;Return to caller
+
+; --- tok__label ---
+
+tok__label     ROUT
+
+               SUBS    R1,R0,#'_'              ;Is it an underscore?
+               SUBNE   R1,R0,#'0'              ;Or a number?
+               CMP     R1,#10
+               SUBCS   R1,R0,#'A'              ;Or a capital letter?
+               CMPCS   R1,#26
+               SUBCS   R1,R0,#'a'              ;Or a lowercase letter?
+               CMPCS   R1,#26
+               BCS     %05tok__label           ;No -- do other things then
+
+               TST     R3,#tFlag__readDot + tFlag__readDEF
+               STREQB  R0,[R10],#1             ;No -- store the number
+               STRNEB  R0,[R9],#1              ;Otherwise store in scratch
+               MOVS    PC,R14                  ;...and return
+
+               ; --- Are we defining this label? ---
+
+05tok__label   TST     R3,#tFlag__readDot + tFlag__readDEF
+               SUBEQ   R7,R7,#1                ;No -- backtrack a little
+               MOVEQ   R6,#tState__dunno       ;...change state
+               MOVEQS  PC,R14                  ;...and return
+
+               ; --- Create the variable then ---
+
+               STMFD   R13!,{R3,R14}           ;Preserve R3 and link
+               MOV     R14,#0                  ;Terminate scratch buffer
+               STRB    R14,[R9],#1             ;To make things nice
+               TST     R3,#tFlag__readDot      ;Have we just read a dot?
+               MOVNE   R0,#vType_label         ;Yes -- create a label
+               BNE     %10tok__label           ;...and jump ahead
+               TST     R3,#tFlag__readFN       ;Is this a DEFFN?
+               MOVNE   R0,#vType_fn            ;Yes -- define one of these
+               MOVEQ   R0,#vType_proc          ;No -- define a DEFPROC then
+10tok__label   ADR     R9,tsc_misc             ;Point to scratch start
+               MOV     R1,R9                   ;Point to label name
+               MOV     R2,R10                  ;Get the file address
+               LDR     R3,[R13,#8]             ;Load the line number
+               CMP     R3,#0                   ;Are we scanning the file?
+               BLNE    var_create              ;Create the variable
+               LDMVSFD R13!,{R3,R14}           ;If it failed, unstack...
+               BVS     tok__error              ;...and die horridly
+
+               SUB     R7,R7,#1                ;No -- backtrack a little
+               MOV     R6,#tState__dunno       ;...change state
+               LDMFD   R13!,{R3,R14}           ;Restore flags word
+               BIC     R3,R3,#tFlag__readDot + tFlag__readDEF
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- tok__expLab ---
+
+               ROUT
+
+tok__expLab    CMP     R0,#' '                 ;Is it a space?
+               CMPNE   R0,#9                   ;Or a TAB char?
+               SUBNE   R7,R7,#1                ;No -- backtrack a little
+               MOVNE   R6,#tState__label       ;...we are reading a label
+               MOVS    PC,R14                  ;Return
+
+               LTORG
+
+; --- tok__lineCmt ---
+
+tok__lineCmt   ROUT
+
+               MOV     R2,R14                  ;Preserve the link
+               CMP     R0,#10                  ;Is this a newline?
+               STREQB  R0,[R10],#1             ;Save the newline character
+               MOVEQ   R6,#tState__stmt        ;Start a new statement
+               BLEQ    tok__incLineNo          ;Increment the line number
+               MOVS    PC,R2                   ;And return to caller
+
+               LTORG
+
+; --- tok__blkCmt ---
+
+tok__blkCmt    ROUT
+
+               MOV     R2,R14                  ;Preserve the link
+               CMP     R0,#10                  ;Is this a newline?
+               MOVEQ   R0,#31                  ;Yes -- insert a weird char
+               STREQB  R0,[R10],#1             ;Put it in the buffer
+               BLEQ    tok__incLineNo          ;Increment the line number
+               MOVEQS  PC,R2                   ;And return
+               CMP     R0,#'*'                 ;Is it a star?
+               MOVEQ   R6,#tState__cmtStar     ;Yes -- change mode then
+               MOVS    PC,R2                   ;Return to caller
+
+               LTORG
+
+; --- tok__cmtStar ---
+
+tok__cmtStar   ROUT
+
+               MOV     R2,R14                  ;Preserve the link
+               CMP     R0,#10                  ;Is this a newline?
+               MOVEQ   R1,#31                  ;Yes -- insert a weird char
+               STREQB  R1,[R10],#1             ;Put it in the buffer
+               BLEQ    tok__incLineNo          ;Increment the line number
+               CMP     R0,#'/'                 ;Is the comment over now?
+               LDREQ   R6,[R13,#4]             ;Yes -- load previous state
+               CMPNE   R0,#'*'                 ;Is it still a star?
+               MOVNE   R6,#tState__blkCmt      ;No -- change state back
+               MOVS    PC,R2                   ;And return to caller
+
+               LTORG
+
+; --- tok__keyWord ---
+
+tok__keyWord   ROUT
+
+               STMFD   R13!,{R14}
+               ADR     R1,tokTable             ;Point to the toaken table
+               ADD     R1,R1,R5,LSR #16        ;Point into the table
+               CMP     R0,#'.'                 ;Is this a dot?
+               BEQ     %18tok__keyWord         ;Yes -- jump ahead then
+               ADD     R4,R4,#1                ;Increment char count
+10tok__keyWord LDR     R14,[R1],#4             ;Load LSB
+               CMP     R14,#0                  ;Is this the end?
+               BEQ     %15tok__keyWord         ;Yes -- jump ahead
+               CMP     R0,R14,LSR #24          ;Is this a match?
+               BNE     %10tok__keyWord         ;No -- keep looking
+
+               BIC     R14,R14,#&FF000000      ;Clear char to match byte
+               MOVS    R0,R14,LSR #16          ;Get the token byte
+               MOVNE   R2,R0                   ;This is a token
+               MOVNE   R4,#0                   ;So clear backtrack count
+               MOVS    R5,R14,LSL #16          ;Shift it up a bit
+               LDMNEFD R13!,{PC}^              ;And return to caller
+
+               ; --- Come to the end of the line ---
+
+15tok__keyWord SUB     R7,R7,R4                ;Do the backtracking
+               CMP     R2,#0                   ;Did we find a token?
+               MOVEQ   R6,#tState__ident       ;No -- read an identifier
+               LDMEQFD R13!,{PC}^              ;Bad luck then
+
+               ; --- We have found a match ---
+
+11tok__keyWord LDMFD   R13!,{R14}              ;Restore return address
+               MOV     R5,R2                   ;Get the matched token
+
+               ; --- Skip over REMS ---
+
+               CMP     R5,#tok_rem             ;Check for REM statements
+               CMPNE   R5,#tok_DD              ;Or a // comment
+               MOVEQ   R6,#tState__lineCmt     ;Introduces line comments
+               MOVEQS  PC,R14                  ;Return if it was one
+
+               CMP     R5,#tok_DT              ;Is it a /* comment?
+               MOVEQ   R6,#tState__blkCmt      ;Yes -- it's a block comment
+               MOVEQS  PC,R14                  ;And return to caller
+
+               ; --- Set up various flags and things ---
+
+17tok__keyWord STRB    R5,[R10],#1             ;Store in the block
+
+               BIC     R3,R3,#tFlag__readFN+tFlag__readPROC
+               CMP     R5,#tok_proc            ;Is this a PROC?
+               ORREQ   R3,R3,#tFlag__readPROC  ;Yes -- remember this
+               CMP     R5,#tok_fn              ;Or a FN?
+               ORREQ   R3,R3,#tFlag__readFN    ;Yes -- remember this
+               TST     R3,#tFlag__readPROC+tFlag__readFN
+               MOVNE   R6,#tState__label       ;If either -- change state
+               MOVNES  PC,R14                  ;...and return
+
+               BIC     R3,R3,#tFlag__readDEF   ;No -- clear DEF flag
+               CMP     R5,#tok_def             ;Was it a DEF then?
+               ORREQ   R3,R3,#tFlag__readDEF   ;Yes -- set the def flag
+
+               ; --- Are we expecting a label next? ---
+
+               CMP     R5,#tok_goto            ;Is there a label next?
+               CMPNE   R5,#tok_gosub
+               CMPNE   R5,#tok_restore
+               MOVEQ   R6,#tState__expLab      ;Yes -- change state
+               MOVEQ   R4,#0                   ;...No characters read yet
+               BIC     R3,R3,#tFlag__readDot   ;We are not expecting a dot
+               MOVEQS  PC,R14                  ;...and return
+
+               ; --- Return to caller ---
+
+               MOV     R6,#tState__dunno       ;Change state back again
+               MOVS    PC,R14                  ;And return to caller
+
+               ; --- User has abbreviated key word ---
+
+18tok__keyWord ADR     R0,tokTable             ;Point to the table
+19tok__keyWord LDR     R5,[R1,#0]              ;Load the next index
+               MOVS    R4,R5,LSL #16           ;Shift it up a bit
+               ADDNE   R1,R0,R4,LSR #16        ;If more to go -- point
+               BNE     %19tok__keyWord         ;...and keep on looping
+               BIC     R2,R5,#&FF000000        ;Clear the match char
+               MOV     R2,R2,LSR #16           ;And get the final token
+               B       %11tok__keyWord         ;Deal with the key word
+
+               GET     sh.tokTable
+
+               LTORG
+
+               ; --- States for the tokeniser ---
+
+               ^       0
+tState__stmt   #       1                       ;Start of a new statement
+tState__dunno  #       1                       ;Not sure what to expect
+tState__string #       1                       ;Tokenising a string
+tState__dblQte #       1                       ;Checking for double quotes
+tState__star   #       1                       ;Processing a *command
+tState__decimal        #       1                       ;Reading a decimal/bin number
+tState__hex    #       1                       ;Reading a hex number
+tState__ident  #       1                       ;Processing an identifier
+tState__keyWord        #       1                       ;Checking for keywords
+tState__label  #       1                       ;Reading a label
+tState__expLab #       1                       ;Waiting for a label
+tState__lineCmt        #       1                       ;Skipping a line comment
+tState__blkCmt #       1                       ;Skipping a block comment
+tState__cmtStar        #       1                       ;Found star in block comment
+
+               ; --- Flags ---
+
+tFlag__readDot EQU     (1<<0)                  ;Creating a label
+tFlag__readDEF EQU     (1<<1)                  ;We're doing a def
+tFlag__readFN  EQU     (1<<5)                  ;Just read a FN
+tFlag__readPROC        EQU     (1<<6)                  ;Just read a PROC
+
+;----- Workspace ------------------------------------------------------------
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/tree b/StraySrc/Libraries/Sapphire/sail/_s/tree
new file mode 100644 (file)
index 0000000..c1e2c0b
--- /dev/null
@@ -0,0 +1,215 @@
+;
+; tree.s
+;
+; Another attempt at symbol table management
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.mem
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- tree_add ---
+;
+; On entry:    R0 == type number
+;              R1 == address of name
+;              R2 == size of user data
+;
+; On exit:     R0 == address of user data in new node
+;              CS if node already exists, else CC
+;              May return an error
+;
+; Use:         Adds a node into a symbol table tree.
+
+               EXPORT  tree_add
+tree_add       ROUT
+
+               BIC     R14,R14,#V_flag         ;Assume no errors for now
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+
+               ; --- Find a suitable place for the node ---
+
+               LDR     R5,tsc_varTree          ;Load base address of tree
+               LDR     R5,[R5]                 ;Because it's an anchor addr
+               ADD     R3,R5,R0,LSL #2         ;Find the appropriate root
+
+               ; --- Keep on until we find a leaf ---
+
+10tree_add     LDR     R4,[R3,#0]              ;Load this offset
+               CMP     R4,#0                   ;Was this a leaf item?
+               BEQ     %20tree_add             ;Yes -- then we found the end
+               ADD     R4,R5,R4                ;Convert this to an address
+               LDR     R0,[R4,#tNode_name]     ;Find this node's name offset
+               ADD     R0,R5,R0                ;Convert this to an address
+               BL      str_cmp                 ;Compare the strings
+               ADDLT   R3,R4,#tNode_right      ;Less -- go right
+               ADDGT   R3,R4,#tNode_left       ;More -- go left
+               BNE     %10tree_add             ;If not a match, continue
+               ADD     R0,R4,#tNode_user       ;Point to node's user data
+               LDMFD   R13!,{R1-R5,R14}        ;Restore caller's registers
+               ORRS    PC,R14,#C_flag          ;And tell him it was there
+
+               ; --- Insert a new node ---
+
+20tree_add     SUB     R3,R3,R5                ;Convert to an offset
+               MOV     R4,R1                   ;Look after the name address
+21tree_add     LDRB    R14,[R1],#1             ;Load a byte from the name
+               CMP     R14,#32                 ;Is this the end yet?
+               BCS     %21tree_add             ;No -- keep on going
+               SUB     R1,R1,R4                ;Work out the string length
+               ADD     R1,R1,#3+8              ;Now word align this size
+               BIC     R1,R1,#3                ;Tum te tum te tum
+               ADD     R2,R2,R1                ;Work out how much I need
+
+               ; --- Extend the block ---
+
+               ADR     R14,tsc_varPtr          ;Find the block sizes
+               LDMIA   R14,{R0,R1}             ;Load used and total length
+               ADD     R0,R0,R2                ;How much do I actually need?
+               STR     R0,tsc_varPtr           ;Save the updated value
+               SUB     R2,R0,R2                ;And get the original offset
+               ADD     R0,R0,#255              ;Align this to chunk size
+               BIC     R0,R0,#255              ;Pom pom pe pom pom...
+               CMP     R0,R1                   ;Do we have enough?
+               BLS     %30tree_add             ;Yes -- that's OK then
+
+               ; --- Allocate some more memory ---
+
+               MOV     R1,R0                   ;Get the new size I want
+               LDR     R0,tsc_varTree          ;Find the block's anchor
+               BL      mem_realloc             ;Make the block bigger
+               BVS     %90tree_add             ;If it failed, give up
+               STR     R1,tsc_varSize          ;Save the new size away
+
+               ; --- Now we're ready to go ---
+
+30tree_add     MOV     R1,R2                   ;Look after this offset
+               LDR     R5,tsc_varTree          ;Find the tree base
+               LDR     R5,[R5]                 ;Irritating WimpExtension
+               ADD     R2,R5,R2                ;Turn offset into address
+35tree_add     LDRB    R14,[R4],#1             ;Load a byte of the name
+               CMP     R14,#32                 ;Is this the end yet?
+               MOVCC   R14,#0                  ;Yes -- store final 0
+               STRB    R14,[R2],#1             ;Store this byte away
+               BCS     %35tree_add             ;And keep on going
+               ADD     R2,R2,#3                ;Word align output ptr
+               BIC     R2,R2,#3                ;Yawn-o-matic on a stick
+
+               SUB     R14,R2,R5               ;Work out the current offset
+               STR     R14,[R5,R3]             ;Link this node into the tree
+               MOV     R3,R1                   ;Find the string offset
+               MOV     R0,#0                   ;Zero the left hand offset
+               MOV     R1,#0                   ;And the right hand one
+               STMIA   R2,{R0,R1,R3}           ;Fill in this node
+               ADD     R0,R2,#tNode_user       ;Find the user data
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack caller's registers
+               BICS    PC,R14,#C_flag          ;Say it wasn't there before
+
+               ; --- Something went badly wrong ---
+
+90tree_add     LDMFD   R13!,{R1-R5,R14}        ;Unstack caller's registers
+               ORRS    PC,R14,#V_flag          ;Return the error
+
+               LTORG
+
+; --- tree_find ---
+;
+; On entry:    R0 == type number
+;              R1 == pointer to the name
+;
+; On exit:     CS if the variable was found, and
+;                R0 == pointer to the variable block
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Tries to find a node with the given type and name in
+;              the symbol tree.
+
+               EXPORT  tree_find
+tree_find      ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+
+               ; --- Find a suitable place for the node ---
+
+               LDR     R5,tsc_varTree          ;Load base address of tree
+               LDR     R5,[R5]                 ;Because it's an anchor addr
+               ADD     R3,R5,R0,LSL #2         ;Find the appropriate root
+
+               ; --- Keep on until we find a leaf ---
+
+10tree_find    LDR     R4,[R3,#0]              ;Load this offset
+               CMP     R4,#0                   ;Was this a leaf item?
+               BEQ     %20tree_find            ;Yes -- then we found the end
+               ADD     R4,R5,R4                ;Convert this to an address
+               LDR     R0,[R4,#tNode_name]     ;Find this node's name offset
+               ADD     R0,R5,R0                ;Convert this to an address
+               BL      str_cmp                 ;Compare the strings
+               ADDLT   R3,R4,#tNode_right      ;Less -- go right
+               ADDGT   R3,R4,#tNode_left       ;More -- go left
+               BNE     %10tree_find            ;If not a match, continue
+
+               ADD     R0,R4,#tNode_user       ;Point to node's user data
+               LDMFD   R13!,{R1-R5,R14}        ;Restore caller's registers
+               ORRS    PC,R14,#C_flag          ;And tell him it was there
+
+               ; --- Something went badly wrong ---
+
+20tree_find    LDMFD   R13!,{R1-R5,R14}        ;Unstack caller's registers
+               BICS    PC,R14,#C_flag          ;Return `not found'
+
+               LTORG
+
+; --- str_cmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         Case-sensitively compares two strings.  You can use the
+;              normal ARM condition codes after the compare, so you can
+;              treat this fairly much like a normal CMP.
+
+               EXPORT  str_cmp
+str_cmp                ROUT
+
+               STMFD   R13!,{R0,R1,R3,R4,R14}
+00str_cmp      LDRB    R3,[R0],#1              ;Get a character from A
+               LDRB    R4,[R1],#1              ;And one from B
+               CMP     R3,#&20                 ;Is that the end of A?
+               MOVLT   R3,#0                   ;Yes -- pretend it's null
+               CMP     R4,#&20                 ;Is that the end of B?
+               MOVLT   R4,#0                   ;Yes -- pretend it's null
+               CMP     R3,R4                   ;How do they match up?
+               LDMNEFD R13!,{R0,R1,R3,R4,PC}   ;If NE, return condition
+               CMP     R3,#0                   ;Is this the end?
+               BNE     %00str_cmp              ;No -- loop again
+               LDMFD   R13!,{R0,R1,R3,R4,PC}   ;Return to caller
+
+               LTORG
+
+               ; --- Tree node format ---
+
+               ^       0
+tNode_left     #       4                       ;Left branch offset
+tNode_right    #       4                       ;Right branch offset
+tNode_user     #       0                       ;Start of user data area
+tNode_name     #       4                       ;Offset of name in table
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/value b/StraySrc/Libraries/Sapphire/sail/_s/value
new file mode 100644 (file)
index 0000000..3a81b28
--- /dev/null
@@ -0,0 +1,294 @@
+;
+; value.s
+;
+; Table drive expression evaluator for TermScript
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Termscript$$Code|,CODE,READONLY
+
+; --- val_readExp ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R7, R8, R9 == lookahead token
+;              R0, R1 == result of expression
+;              R10 == moved on to first char after expression
+;
+; Use:         Reads an expression for the current point in the tokenised
+;              file, and returns it's result. The implementation is
+;              table driven and should be very fast.
+
+               EXPORT  val_readExp
+val_readExp    ROUT
+
+10val_readExp  BL      val__operand
+               BLCS    val__operator
+               BCS     val_readExp
+
+               ; --- Now work out the result ---
+
+               BL      val__copyRest           ;Copy rest of tokens over
+
+
+               LTORG
+
+; --- val__operand ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0 corrupted
+;              R7, R8, R9 == lookahead token
+;              R10 modified appropriately
+;              CS if operand found,
+;              CC otherwise
+;
+; Use:         Reads an operand from the input, and does appropriate
+;              stack like things with it.
+
+val__operand   ROUT
+
+               STMFD   R13!,{R14}              ;Stack registers
+00val__operand CMP     R9,#'&'                 ;Start a hex number?
+               BEQ     %10val__operand         ;Yes -- jump ahead
+               CMP     R9,#'%'                 ;Start of a binary number?
+               BEQ     %20val__operand         ;Yes -- jump ahead
+               CMP     R9,#'!'                 ;An indirection operand?
+               CMPNE   R9,#'?'
+               CMPNE   R9,#'$'
+               BEQ     %40val__operand         ;Yes -- jump ahead
+               CMP     R9,#'+'                 ;Unary operator then?
+               CMPNE   R9,#'-'
+               BEQ     %50val__operand         ;Yes -- jump ahead
+               CMPNE   R9,#'('                 ;A nice bracket?
+               BEQ     %60val__operand         ;Yes -- jump ahead
+               SUB     R14,R9,#'0'             ;Set up for a range check
+               CMP     R14,#10                 ;Is it a digit?
+               MOVCC   R0,#0                   ;Yes -- set up accumulator
+               BCC     %30val__operand         ;Yes -- deal with that
+               B       %70val__operand         ;Assume it's an identifier
+
+               ; --- Read a hex number ---
+
+10val__operand BL      getToken                ;Get another token
+               MOV     R0,#0                   ;The number so far
+               SUB     R14,R9,#'A'             ;Check if it's a letter
+               CMP     R14,#6                  ;But only A-F
+               ADDCC   R14,R14,#10             ;If so, add 10 on
+               SUBCS   R14,R9,#'0'             ;Otherwise check for digit
+               CMPCS   R14,#10                 ;Make sure it's OK
+               BCC     %12val__operand         ;And jump head
+               MOV     R0,#err_badHex          ;Point to error message
+               B       error_report            ;And return the error
+
+11val__operand SUB     R14,R9,#'A'             ;Check if it's a letter
+               CMP     R14,#6                  ;But only A-F
+               ADDCC   R14,R14,#10             ;If so, add 10 on
+               SUBCS   R14,R9,#'0'             ;Otherwise check for digit
+               CMPCS   R14,#10                 ;Make sure it's OK
+               BCS     %35val__readSimple      ;No -- that's it then
+
+12val__operand ADD     R0,R14,R0,LSL #4        ;Multiply by 16 and add digit
+               BL      getToken                ;Load a character
+               B       %11val__readSimple      ;Keep on reading more
+
+               ; --- Read a binary number ---
+
+20val__operand BL      getToken                ;Get another token
+               MOV     R0,#0                   ;The number so far
+               SUB     R14,R9,#'0'             ;Set up for a range check
+               CMP     R14,#1                  ;Is it a digit
+               BLS     %22val__readSimple      ;Yes -- jump ahead
+               MOV     R0,#err_badBinary       ;Point to error message
+               B       error_report            ;And return the error
+
+21val__operand SUB     R14,R9,#'0'             ;Set up for a range check
+               CMP     R14,#1                  ;Is it a digit
+               BHI     %35val__readSimple      ;Nope -- jump ahead then
+
+22val__operand ADC     R0,R0,R0                ;Multiply by 2
+               BL      getToken                ;Load a character
+               B       %21val__readSimple      ;Keep on reading more
+
+               ; --- Read a decimal number ---
+
+30val__operand SUB     R14,R9,#'0'             ;Set up for a range check
+               CMP     R14,#10                 ;Is it a digit
+               BCS     %35val__readSimple      ;Nope -- jump ahead then
+
+32val__operand ADD     R0,R0,R0,LSL #2         ;Multiply by 5
+               ADD     R0,R14,R0,LSL #1        ;And then by 2 (* 10)
+               BL      getToken                ;Load the next token
+               B       %30val__readSimple      ;Keep on reading more
+
+               ; --- Finished reading a number ---
+
+35val__operand BL      val__stackNumber        ;Put a number on the stack
+               B       %90val__operand         ;Jump ahead
+
+               ; --- Read an indirection operator ---
+
+40val__operand MOV     R0,#0                   ;Get the offset ready
+               BL      val__stackNumber        ;Put it on the stack
+               BL      val__stackToken         ;And put operator on too
+               BL      getToken                ;Get the next token
+               B       %00val__operand         ;Need another operand
+
+               ; --- Deal with unary signs ---
+
+50val__operand CMP     R9,#'-'                 ;Is is a unary minus
+               BLEQ    val__stackToken         ;Yes -- put it on the stack
+               BL      getToken                ;Get another token
+               B       %00val__operand         ;Need another operand
+
+               ; --- We have just read a '(' ---
+
+60val__operand BL      val__stackToken         ;Stackit immediately
+               BL      getToken                ;Get another token
+               B       %00val__operand         ;Need another operand
+
+               ; --- Assume it's an identifier then ---
+
+70val__operand ADR     R1,tsc_misc             ;Point to a nice block
+               MOV     R0,#vType_integer       ;The current variable type
+
+75val__operand SUBS    R14,R9,#'_'             ;Is it an underscore?
+               SUBNE   R14,R9,#'0'             ;Or a number?
+               CMP     R14,#10
+               SUBCS   R14,R9,#'A'             ;Or a capital letter?
+               CMPCS   R14,#26
+               SUBCS   R14,R9,#'a'             ;Or a lowercase letter?
+               CMPCS   R14,#26
+               STRCCB  R9,[R1],#1              ;Yes -- store it away
+               BLCC    getToken                ;Read the next byte
+               BCS     %95val_readLvalue       ;Ouch -- not an identifier
+
+               CMP     R9,#'$'                 ;Is it a dollar sign?
+               MOVEQ   R0,#vType_string        ;It's a string now
+               CMPNE   R9,#'%'                 ;Or a percentage?
+               STREQB  R9,[R2],#1              ;Yes -- store it then
+               CMPNE   R9,#' '                 ;Just check for a space
+
+               BNE     %75val_readLvalue       ;Go round for more
+
+               MOV     R14,#0                  ;The terminator
+               STRB    R14,[R1],#0             ;Store that in the var name
+               BL      getToken                ;Read the next token ready
+
+               ; --- The identifier name is in the buffer ---
+
+               ADR     R1,tsc_misc             ;Point to the name
+               BL      var_find                ;Try to find the variable
+               MOVCC   R0,#err_unknown         ;Not there, get the error
+               BCC     error_report            ;And report a possible error
+
+               LDR     R1,[R0,#0]              ;Load out the variable type
+               LDR     R0,[R0,#4]              ;Load out the value
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BLEQ    val__stackInteger       ;Yes -- stack it
+               BLNE    val__stackString        ;No -- it's a string then
+
+90val__operand LDMFD   R13!,{R14}              ;Load back registers
+               ORRS    PC,R14,#C_flag          ;We found an operand
+
+95val__operand LDMFD   R13!,{R14}              ;Load back registers
+               BICS    PC,R14,#C_flag          ;No operand was found
+
+               LTORG
+
+; --- val__operator ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R7, R8, R9 == lookahead token
+;              R10 modified appropriately
+;              CS if operator found,
+;              CC otherwise
+;
+; Use:         Reads an operator from the input, and does appropriate
+;              stack like things with it.
+
+               ROUT
+
+val__operator  STMFD   R13!,{R14}              ;Stack registers
+00val__operator        CMP     R9,#')'                 ;Is it a close bracket?
+               BEQ     %10val__operator        ;Yes -- jump ahead
+               ; --- Make sure we recognise it ---
+
+               CMP     R9,#'!'                 ;An indirection operator?
+               CMPNE   R9,#'?'
+               CMPNE   R7,#tClass__andOp
+               CMPNE   R7,#tClass__orOp
+               CMPNE   R7,#tClass__addOp
+               CMPNE   R7,#tClass__multOp
+               CMPNE   R7,#tClass__relOp
+               BNE     %95val__operator        ;Nope -- just return
+               BL      val__stackToken         ;Stack this token
+               BL      getToken                ;Get another one
+               B       %90val__operator        ;And return success
+
+               ; --- We have read a ')' ---
+
+               BL      val__stackToken         ;Stack this token
+               BL      getToken                ;Get another one
+               B       %00val__operator        ;We expect another operator
+
+90val__operator        LDMFD   R13!,{R14}              ;Load back registers
+               ORRS    PC,R14,#C_flag          ;We found an operand
+
+95val__operator        LDMFD   R13!,{R14}              ;Load back registers
+               BICS    PC,R14,#C_flag          ;No operand was found
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+val__precTable DCD     val__andOp-val__precTable
+               DCD     0
+               DCD     0
+               DCD     0
+               DCD     val__multOp-val__precTable
+               DCD     val__orOp-val__precTable
+               DCD     0
+               DCD     val__relOp-val__precTable
+               DCD     val__addOp-val__precTable
+               DCD     0
+
+               ; --- The precedence tables ---
+               ;
+               ; Each byte indicates whether or not the given type of
+               ; toke has a higher or lower precedence than another type.
+               ; The order of the bytes is:
+               ;
+               ; and,-,-,-,mult,or,-,-,rel,add,-
+
+val__andOp     DCB      0, 0, 0, 0,-1, 1, 0, 0,-1,-1, 0
+val__multOp    DCB      1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0
+val__orOp      DCB     -1, 0, 0, 0,-1, 0, 0, 0,-1,-1, 0
+val__relOp     DCB      1, 0, 0, 0,-1, 1, 0, 0, 0,-1, 0
+val__addOp     DCB      1, 0, 0, 0,-1, 1, 0, 0, 1, 0, 0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_s/var b/StraySrc/Libraries/Sapphire/sail/_s/var
new file mode 100644 (file)
index 0000000..2a2d117
--- /dev/null
@@ -0,0 +1,189 @@
+;
+; var.s
+;
+; Variable handling
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.errNum
+               GET     sh.error
+               GET     sh.tree
+
+;----- Other definitions ----------------------------------------------------
+
+var__chunkSize EQU     256                     ;Chunck size of var stack
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- var_create ---
+;
+; On entry:    R0 == type of variable
+;              R1 == pointer to variable name
+;              R12 == pointer to the anchor block
+;              Other registers depend on the type
+;              vType_label, vType_proc, vType_fn:
+;                R2 == file offset of label of DEF
+;                R3 == line number of label or DEF
+;              vType_dimInt, vType_dimStr:
+;                R2 == pointer to subscript block (in *reverse* order)
+;                R3 == number of subscripts
+;                R4 == number of items to create
+;
+; On exit:     R0 == pointer to the variable
+;
+; Use:         Tries to find the variable given, and return a pointer
+;              to it if it is found. Otherwise it will try to create the
+;              variable and return a pointer to the new one.
+
+               EXPORT  var_create
+var_create     ROUT
+
+               ADD     PC,PC,R0,LSL #2         ;Branch to correct dispatcher
+               DCB     "TMA!"                  ;A little padding
+
+               B       var__normal
+               B       var__normal
+               B       var__dim
+               B       var__dim
+               B       var__label
+               B       var__label
+               B       var__label
+
+               LTORG
+
+; --- var_find ---
+;
+; On entry:    R0 == type of the variable
+;              R1 == name of the variable
+;
+; On exit:     CS if the variable was found, and
+;                R0 == pointer to the variable block
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Tries to find the given variable in the current tree.
+
+               EXPORT  var_find
+var_find       ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,R0                   ;Look after the type
+               BL      tree_find               ;Find the variable
+               LDMCSFD R13!,{R2,PC}^           ;If found, return now
+               CMP     R2,#vType_dimInt        ;Is it an integer array?
+               CMPNE   R2,#vType_dimStr        ;Or a string array?
+               MOVEQ   R0,#err_ukArray         ;Yes -- find `unknown array'
+               MOVNE   R0,#err_unknown         ;No -- use `unknown var'
+               B       error_report            ;And report it to the world
+
+               LTORG
+
+;----- Variable creation routines -------------------------------------------
+;
+; On entry:    R0 == variable type
+;              R1 == address of variable name
+
+; --- var__normal ---
+
+var__normal    ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack registers
+
+               ; --- Allocate space for the variable ---
+
+               MOV     R2,#8                   ;Variable requires 16 bytes
+               BL      tree_add                ;Add it to the symbol table
+               BVS     var__error              ;Return possible error
+
+               MOV     R14,#0                  ;Initialise the value
+               STRCC   R14,[R0,#4]             ;Set this up nicely
+               LDMFD   R13!,{R1-R4,PC}^        ;And return to caller
+
+; --- var__dim ---
+
+var__dim       ROUT
+
+               STMFD   R13!,{R1-R6,R14}        ;Stack registers
+               ADD     R5,R2,R3,LSL #2         ;Look after subscript block
+               MOV     R2,#12                  ;Room for name + num of subs
+               ADD     R2,R2,R3,LSL #2         ;Add room for sizes
+               ADD     R2,R2,R4,LSL #2         ;And subscripts themselves
+               BL      tree_add                ;Try to allocate space
+               BVS     var__error              ;Barf on error
+               STR     R3,[R0,#4]              ;Store number of subscripts
+               STR     R4,[R0,#8]              ;Store total number of items
+               ADD     R6,R0,#12               ;Point to the first size
+
+               ; --- Set up the subscript sizes ---
+
+00             LDR     R14,[R5,#-4]!           ;Load the subscript size
+               STR     R14,[R6],#4             ;Store that in the block
+               SUBS    R3,R3,#1                ;Reduce subscript count
+               BGT     %b00                    ;Keep filling in block
+
+               ; --- Initialise all the entries ---
+
+               MOV     R14,#0                  ;Initialiser
+00             STR     R14,[R6],#4             ;Set entry to 0
+               SUBS    R4,R4,#1                ;Reduce the item count
+               BGT     %b00                    ;Keep on initialising
+
+               LDMFD   R13!,{R1-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- var__label ---
+
+var__label     ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack registers
+               LDR     R14,tsc_tokAnchor       ;Find anchor of t'ised file
+               LDR     R14,[R14]               ;I hate WimpExt_Heap
+               SUB     R4,R2,R14               ;Make the address an offset
+
+               ; --- Allocate space for the variable ---
+
+               MOV     R2,#12                  ;Variable requires 16 bytes
+               BL      tree_add                ;Add it to the symbol table
+               BVS     var__error              ;Return possible error
+
+               ; --- Fill in the block ---
+
+               MOV     R2,R4                   ;Get the file offset
+               STMIB   R0,{R2,R3}              ;Store the informtion
+               LDMFD   R13!,{R1-R4,PC}^        ;Unstack registers
+
+var__error     MOV     R0,#err_noMem           ;Get the error number
+               B       error_report            ;And report the error
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ; --- Variable types ---
+
+               ^       0
+vType_integer  #       1                       ;Integer
+vType_string   #       1                       ;String
+vType_dimInt   #       1                       ;DIM of integers
+vType_dimStr   #       1                       ;DIM of strings
+vType_label    #       1                       ;Label
+vType_proc     #       1                       ;Procedure name
+vType_fn       #       1                       ;Function name
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/anchor b/StraySrc/Libraries/Sapphire/sail/_sh/anchor
new file mode 100644 (file)
index 0000000..529bff7
--- /dev/null
@@ -0,0 +1,99 @@
+;
+; anchor.sh
+;
+; Layout of anchor blocks
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:anchor__dfn
+               GBLL    anchor__dfn
+
+               ; --- Anchor block contents ---
+
+               ^       0,R12
+
+tsc_R13                #       4                       ;Saved R13 (stack pointer)
+tsc_anchor     #       4                       ;Pointer to block anchor
+tsc_scSize     #       4                       ;Size of script file
+tsc_tokAnchor  #       4                       ;Ptr to tokenised file anchor
+tsc_currAnchor #       4                       ;Current anchor for input
+tsc_oldAnchor  #       4                       ;Previous anchor for input
+tsc_flags      #       4                       ;A nice flags word
+tsc_timeOff    #       4                       ;OS_ReadMonotonicTime-TIME
+tsc_line       #       4                       ;Current line number
+tsc_timeSoFar  #       4                       ;Time execution started
+tsc_rndSeed    #       8                       ;Random number seed
+tsc_rmaList    #       4                       ;List of blocks from RMA
+tsc_spool      #       4                       ;File handle for SPOOL
+tsc_files      #       32                      ;Files-open flags
+tsc_errorS     #       4                       ;Offset of ERROR$
+
+               ; --- Newline characters ---
+
+tsc_rnewline   #       4                       ;Offset of rnewline string
+tsc_lnewline   #       4                       ;Offset of lnewline string
+
+               ; --- DATA information ---
+
+tsc_dataPtr    #       4                       ;Current DATA pointer
+tsc_dataLine   #       4                       ;Current data line
+
+               ; --- WATCHFOR data ---
+
+tsc_wForState  #       4                       ;Current state of watchfor
+tsc_wForNumber #       4                       ;Number we are looking for
+tsc_wForStrings        #       32*8                    ;A word+byte for each lvalue
+
+               ; --- Resizing blocks ---
+
+tsc_rszBlocks  #       0
+
+tsc_varTree    #       4                       ;The variable stack anchor
+tsc_varPtr     #       4                       ;Where to create the next var
+tsc_varSize    #       4                       ;Current size if the stack
+
+tsc_execStack  #       4                       ;Anchor of execution stack
+tsc_execStkPtr #       4                       ;Pointer into stack
+tsc_execStkSize        #       4                       ;Size of the stack
+
+tsc_opStack    #       4                       ;Anchor of execution stack
+tsc_opStkPtr   #       4                       ;Pointer into stack
+tsc_opStkSize  #       4                       ;Size of the stack
+
+tsc_calcStack  #       4                       ;Anchor of execution stack
+tsc_calcStkPtr #       4                       ;Pointer into stack
+tsc_calcStkSize        #       4                       ;Size of the stack
+
+tsc_stracc     #       4                       ;Anchor of execution stack
+tsc_straccPtr  #       4                       ;Pointer into stack
+tsc_straccSize #       4                       ;Size of the stack
+
+tsc_bucket     #       4                       ;String bucket anchor
+tsc_bktPtr     #       4                       ;Free pointer for bucket
+tsc_bktSize    #       4                       ;Current size of bucket block
+
+tsc_erszBlocks #       0
+
+tsc_misc       #       256                     ;A big buffer for things
+
+tsc_blkSize    EQU     2048                    ;Enough space for a stack
+
+               [       {VAR}-tsc_R13+1024>tsc_blkSize
+               !       1,"tsc_blkSize is too small"
+               ]
+
+tscFlag_nl     EQU     (1<<0)                  ;We have just read a newline
+
+tscFlag_echoRL EQU     (1<<1)                  ;Echo remote input locally
+tscFlag_echoRR EQU     (1<<2)                  ;Echo remote input remotely
+tscFlag_echoLL EQU     (1<<3)                  ;Echo local input locally
+tscFlag_echoLR EQU     (1<<4)                  ;Echo local input remotely
+tscFlag_watch  EQU     (1<<5)                  ;We are doing a watchfor
+tscFlag_error  EQU     (1<<6)                  ;We are generating errors
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/ctrl b/StraySrc/Libraries/Sapphire/sail/_sh/ctrl
new file mode 100644 (file)
index 0000000..6479065
--- /dev/null
@@ -0,0 +1,289 @@
+;
+; ctrl.sh
+;
+; Control flow handling
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  ctrl_let
+;  ctrl_timeEq
+;  ctrl_for
+;  ctrl_next
+;  ctrl_repeat
+;  ctrl_until
+;  ctrl_while
+;  ctrl_endwhile
+;  ctrl_gosub
+;  ctrl_return
+;  ctrl_if
+;  ctrl_else
+;  ctrl_goto
+;  ctrl_case
+;  ctrl_when
+;  ctrl_otherwise
+;  ctrl_end
+;  ctrl_swap
+;  ctrl_ptr
+;  ctrl_ext
+;  ctrl_close
+;  ctrl_bput
+;  ctrl_findDATA
+;  ctrl_read
+;  ctrl_restore
+;  ctrl_sys
+;  ctrl_setUpRegs
+;  ctrl_resolveRegs
+;  ctrl_fn
+;  ctrl_equals
+;  ctrl_proc
+;  ctrl_endproc
+;  ctrl_data
+;  ctrl_def
+;  ctrl_local
+;  ctrl_leftS
+;  ctrl_midS
+;  ctrl_rightS
+;  ctrl_dim
+;  ctrl_store
+;  ctrl_load
+;  ctrl_compare
+
+               [       :LNOT::DEF:ctrl__dfn
+               GBLL    ctrl__dfn
+
+; --- ctrl_let ---
+
+               IMPORT  ctrl_let
+
+; --- ctrl_timeEq ---
+
+               IMPORT  ctrl_timeEq
+
+; --- ctrl_for ---
+
+               IMPORT  ctrl_for
+
+; --- ctrl_next ---
+
+               IMPORT  ctrl_next
+
+; --- ctrl_repeat ---
+
+               IMPORT  ctrl_repeat
+
+; --- ctrl_until ---
+
+               IMPORT  ctrl_until
+
+; --- ctrl_while ---
+
+               IMPORT  ctrl_while
+
+; --- ctrl_endwhile ---
+
+               IMPORT  ctrl_endwhile
+
+; --- ctrl_gosub ---
+
+               IMPORT  ctrl_gosub
+
+; --- ctrl_return ---
+
+               IMPORT  ctrl_return
+
+; --- ctrl_if ---
+
+               IMPORT  ctrl_if
+
+; --- ctrl_else ---
+
+               IMPORT  ctrl_else
+
+; --- ctrl_goto ---
+
+               IMPORT  ctrl_goto
+
+; --- ctrl_case ---
+
+               IMPORT  ctrl_case
+
+; --- ctrl_when ---
+
+               IMPORT  ctrl_when
+
+; --- ctrl_otherwise ---
+
+               IMPORT  ctrl_otherwise
+
+; --- ctrl_end ---
+
+               IMPORT  ctrl_end
+
+; --- ctrl_swap ---
+
+               IMPORT  ctrl_swap
+
+; --- ctrl_ptr ---
+
+               IMPORT  ctrl_ptr
+
+; --- ctrl_ext ---
+
+               IMPORT  ctrl_ext
+
+; --- ctrl_close ---
+
+               IMPORT  ctrl_close
+
+; --- ctrl_bput ---
+
+               IMPORT  ctrl_bput
+
+; --- ctrl__findDATA ---
+;
+; On entry:    All the normal things
+;
+; On exit:     R0 == *address* in file of next DATA
+;
+; Use:         Sets the internal data pointer to the first DATA statement
+;              fromthe current position.
+
+               IMPORT  ctrl_findDATA
+
+; --- ctrl_read ---
+
+               IMPORT  ctrl_read
+
+; --- ctrl_restore ---
+
+               IMPORT  ctrl_restore
+
+; --- ctrl_sys ---
+
+               IMPORT  ctrl_sys
+
+; --- ctrl_setUpRegs ---
+;
+; On entry:    R7-R10 == position info
+;
+; On exit:     R0-R8 set up for sys call
+;              R9,R10 == rvalue of first parameter
+;              On the stack:
+;                new position info, R7-R12
+;                place to stracc free
+;
+; Use:         Sets up all the registers as required by a SYS or SYSCALL
+;              command.
+
+               IMPORT  ctrl_setUpRegs
+
+; --- ctrl_resolveRegs ---
+;
+; On entry:    R0 == pointer to register block
+;
+; On exit:     CS if flags were required, CC otherwise
+;
+; Use:         Resolves the registers returned from a SYS or SYSCALL
+;              into the appropriate variables.  The code assumes that
+;              we have possibly just read a TO command, and goes on
+;              from there.
+
+               IMPORT  ctrl_resolveRegs
+
+; --- FN ---
+;
+; OK, maybe it shouldn't be here.  I don't really care.
+;
+; Hack warning:        This is a hack.  We unwind express_read's stack and stuff
+;              them away somewhere completely different.
+
+               IMPORT  ctrl_fn
+
+; --- = ---
+
+               IMPORT  ctrl_equals
+
+; --- PROC ---
+
+               IMPORT  ctrl_proc
+
+; --- ENDPROC ---
+
+               IMPORT  ctrl_endproc
+
+; --- DATA ---
+
+               IMPORT  ctrl_data
+
+; --- DEF  ---
+
+               IMPORT  ctrl_def
+
+; --- LOCAL ---
+
+               IMPORT  ctrl_local
+
+; --- ctrl_leftS ---
+
+               IMPORT  ctrl_leftS
+
+; --- ctrl_midS ---
+
+               IMPORT  ctrl_midS
+
+; --- ctrl_rightS ---
+
+               IMPORT  ctrl_rightS
+
+; --- ctrl_dim ---
+
+               IMPORT  ctrl_dim
+
+; --- ctrl_store ---
+;
+; On entry:    R0,R1 == lvalue to store in
+;              R2,R3 == rvalue to write
+;
+;              If bit 31 of R1 is set, then for strings only, the old
+;              string is NOT removed from the stracc. This is
+;              so that variables can be restored after a procedure.
+;
+; On exit:     --
+;
+; Use:         Stores an rvalue into an lvalue.
+
+               IMPORT  ctrl_store
+
+; --- ctrl_load ---
+;
+; On entry:    R0,R1 == lvalue to read
+;
+; On exit:     R2,R3 == rvalue read from lvalue
+;
+; Use:         Loads the current value of the given lvalue.
+
+               IMPORT  ctrl_load
+
+; --- ctrl_compare ---
+;
+; On entry:    R0,R1 == thing to compare
+;              R2,R3 == thing to compare the other thing with
+;
+; On exit:     The flags indicate the result of the comparison
+;
+; Use:         Compares two things.  Note that R3 contains the dominant
+;              type. If it is comparing strings, the string in R0,R1
+;              will be removed from stracc.
+
+               IMPORT  ctrl_compare
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/divide b/StraySrc/Libraries/Sapphire/sail/_sh/divide
new file mode 100644 (file)
index 0000000..dfbb4b9
--- /dev/null
@@ -0,0 +1,57 @@
+;
+; divide.sh
+;
+; Various routines of a division-related nature (MDW/TMA)
+;
+; © 1994 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  divide
+;  div_unsigned
+
+               [       :LNOT::DEF:divide__dfn
+               GBLL    divide__dfn
+
+; --- divide ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         A standard divide routine.  Fairly speedy, hopefully.
+;              The results are always such that
+;
+;                      |quotient| <= |(divisor/dividend)|,
+;
+;                      |remainder| < |divisor|
+;
+;              and
+;
+;                      quotient * divisor + remainder == dividend
+
+               IMPORT  divide
+
+; --- div_unsigned ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         As for divide, except that it considers its operands to be
+;              unsigned.
+
+               IMPORT  div_unsigned
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/errNum b/StraySrc/Libraries/Sapphire/sail/_sh/errNum
new file mode 100644 (file)
index 0000000..e3e3bdf
--- /dev/null
@@ -0,0 +1,78 @@
+;
+; errNum.sh
+;
+; Define error numbers (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:errNum__dfn
+               GBLL    errNum__dfn
+
+               ^       0
+err_numNeeded  #       1
+err_strNeeded  #       1
+err_arrayBad   #       1
+err_expBracket #       1
+err_expHash    #       1
+err_expQuote   #       1
+err_expEq      #       1
+err_expComma   #       1
+err_badHex     #       1
+err_badBinary  #       1
+err_unknown    #       1
+err_divZero    #       1
+err_noMem      #       1
+err_syntax     #       1
+err_mistake    #       1
+err_strTooLong #       1
+err_eqInFor    #       1
+err_badForVar  #       1
+err_expTo      #       1
+err_zStep      #       1
+err_noFor      #       1
+err_noRepeat   #       1
+err_expEndwhile        #       1
+err_noWhile    #       1
+err_expEndif   #       1
+err_expOf      #       1
+err_afterCase  #       1
+err_expEndcase #       1
+err_expLabel   #       1
+err_noLabel    #       1
+err_badDim     #       1
+err_dimKet     #       1
+err_reDim      #       1
+err_numSubs    #       1
+err_subRange   #       1
+err_ukArray    #       1
+err_rgetInWatch        #       1
+err_rgetSInWatch       #       1
+err_lgetInWatch        #       1
+err_lgetSInWatch       #       1
+err_rinkeyInWatch      #       1
+err_rinkeySInWatch     #       1
+err_linkeyInWatch      #       1
+err_linkeySInWatch     #       1
+err_stringSArgs        #       1
+err_leftSArgs  #       1
+err_rightSArgs #       1
+err_midSArgs   #       1
+err_instrSArgs #       1
+err_badArgs    #       1
+err_noProc     #       1
+err_badCall    #       1
+err_notInSub   #       1
+err_notInProc  #       1
+err_notInFn    #       1
+err_WFTooMany  #       1
+err_sysTooManyI        #       1
+err_sysTooManyO        #       1
+err_outOfDATA  #       1
+err_realloc    #       1
+err_lazy       #       1
+err_erk                #       1
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/errTable b/StraySrc/Libraries/Sapphire/sail/_sh/errTable
new file mode 100644 (file)
index 0000000..11c7649
--- /dev/null
@@ -0,0 +1,141 @@
+;
+; errTable.sh
+;
+; Define error messages table (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:errTable__dfn
+               GBLL    errTable__dfn
+
+errTable
+               DCD     err__msg0-errTable
+               DCD     err__msg1-errTable
+               DCD     err__msg2-errTable
+               DCD     err__msg3-errTable
+               DCD     err__msg4-errTable
+               DCD     err__msg5-errTable
+               DCD     err__msg6-errTable
+               DCD     err__msg7-errTable
+               DCD     err__msg8-errTable
+               DCD     err__msg9-errTable
+               DCD     err__msg10-errTable
+               DCD     err__msg11-errTable
+               DCD     err__msg12-errTable
+               DCD     err__msg13-errTable
+               DCD     err__msg14-errTable
+               DCD     err__msg15-errTable
+               DCD     err__msg16-errTable
+               DCD     err__msg17-errTable
+               DCD     err__msg18-errTable
+               DCD     err__msg19-errTable
+               DCD     err__msg20-errTable
+               DCD     err__msg21-errTable
+               DCD     err__msg22-errTable
+               DCD     err__msg23-errTable
+               DCD     err__msg24-errTable
+               DCD     err__msg25-errTable
+               DCD     err__msg26-errTable
+               DCD     err__msg27-errTable
+               DCD     err__msg28-errTable
+               DCD     err__msg29-errTable
+               DCD     err__msg30-errTable
+               DCD     err__msg31-errTable
+               DCD     err__msg32-errTable
+               DCD     err__msg33-errTable
+               DCD     err__msg34-errTable
+               DCD     err__msg35-errTable
+               DCD     err__msg36-errTable
+               DCD     err__msg37-errTable
+               DCD     err__msg38-errTable
+               DCD     err__msg39-errTable
+               DCD     err__msg40-errTable
+               DCD     err__msg41-errTable
+               DCD     err__msg42-errTable
+               DCD     err__msg43-errTable
+               DCD     err__msg44-errTable
+               DCD     err__msg45-errTable
+               DCD     err__msg46-errTable
+               DCD     err__msg47-errTable
+               DCD     err__msg48-errTable
+               DCD     err__msg49-errTable
+               DCD     err__msg50-errTable
+               DCD     err__msg51-errTable
+               DCD     err__msg52-errTable
+               DCD     err__msg53-errTable
+               DCD     err__msg54-errTable
+               DCD     err__msg55-errTable
+               DCD     err__msg56-errTable
+               DCD     err__msg57-errTable
+               DCD     err__msg58-errTable
+               DCD     err__msg59-errTable
+               DCD     err__msg60-errTable
+               DCD     err__msg61-errTable
+
+err__msg0      DCB     "Type mismatch: Number needed",0
+err__msg1      DCB     "Type mismatch: String needed",0
+err__msg2      DCB     "Whole array reference is invalid in this context",0
+err__msg3      DCB     "Missing )",0
+err__msg4      DCB     "Missing #",0
+err__msg5      DCB     "Missing """,0
+err__msg6      DCB     "Missing =",0
+err__msg7      DCB     "Missing ,",0
+err__msg8      DCB     "Bad hex",0
+err__msg9      DCB     "Bad binary",0
+err__msg10     DCB     "Unknown or missing variable",0
+err__msg11     DCB     "Division by zero",0
+err__msg12     DCB     "Out of memory",0
+err__msg13     DCB     "Syntax error",0
+err__msg14     DCB     "Mistake",0
+err__msg15     DCB     "String too long",0
+err__msg16     DCB     "Missing = in FOR",0
+err__msg17     DCB     "Bad FOR control variable",0
+err__msg18     DCB     "Missing TO",0
+err__msg19     DCB     "The step cannot be zero",0
+err__msg20     DCB     "Not in a FOR loop",0
+err__msg21     DCB     "Not in a REPEAT loop",0
+err__msg22     DCB     "Missing ENDWHILE",0
+err__msg23     DCB     "Not in a WHILE loop",0
+err__msg24     DCB     "Missing ENDIF",0
+err__msg25     DCB     "Missing OF",0
+err__msg26     DCB     "CASE..OF statement must be the last thing on a line",0
+err__msg27     DCB     "Missing ENDCASE",0
+err__msg28     DCB     "Missing label",0
+err__msg29     DCB     "Unknown label",0
+err__msg30     DCB     "Bad DIM statement",0
+err__msg31     DCB     "No end of dimension list )",0
+err__msg32     DCB     "Arrays cannot be redimensioned",0
+err__msg33     DCB     "Incorrect number of subscripts",0
+err__msg34     DCB     "Subscript out of range",0
+err__msg35     DCB     "Unknown array",0
+err__msg36     DCB     "Can't use RGET while in a WATCHFOR state",0
+err__msg37     DCB     "Can't use RGET$ while in a WATCHFOR state",0
+err__msg38     DCB     "Can't use LGET while in a WATCHFOR state",0
+err__msg39     DCB     "Can't use LGET$ while in a WATCHFOR state",0
+err__msg40     DCB     "Can't use RINKEY while in a WATCHFOR state",0
+err__msg41     DCB     "Can't use RINKEY$ while in a WATCHFOR state",0
+err__msg42     DCB     "Can't use LINKEY while in a WATCHFOR state",0
+err__msg43     DCB     "Can't use LINKEY$ while in a WATCHFOR state",0
+err__msg44     DCB     "Wrong number of arguments passed to STRING$",0
+err__msg45     DCB     "Wrong number of arguments passed to LEFT$",0
+err__msg46     DCB     "Wrong number of arguments passed to RIGHT$",0
+err__msg47     DCB     "Wrong number of arguments passed to MID$",0
+err__msg48     DCB     "Wrong number of arguments passed to INSTR",0
+err__msg49     DCB     "Arguments of function/procedure incorrect",0
+err__msg50     DCB     "No such function/procedure",0
+err__msg51     DCB     "Bad call of function/procedure",0
+err__msg52     DCB     "Not in a subroutine",0
+err__msg53     DCB     "Not in a procedure",0
+err__msg54     DCB     "Not in a function",0
+err__msg55     DCB     "Too many strings passed to WATCHFOR",0
+err__msg56     DCB     "Too many input parameters to SYS/SYSCALL",0
+err__msg57     DCB     "Too many output parameters to SYS/SYSCALL",0
+err__msg58     DCB     "Out of DATA",0
+err__msg59     DCB     "mem_realloc not implemented",0
+err__msg60     DCB     "Not yet implemented",0
+err__msg61     DCB     "The script interpreter has gone wrong",0
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/error b/StraySrc/Libraries/Sapphire/sail/_sh/error
new file mode 100644 (file)
index 0000000..5c451ca
--- /dev/null
@@ -0,0 +1,45 @@
+;
+; error.sh
+;
+; Generation and handling of errors
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  error_report
+;  error_reportReal
+
+               [       :LNOT::DEF:error__dfn
+               GBLL    error__dfn
+
+; --- error_report ---
+;
+; On entry:    R0 == error number
+;
+; On exit:     doesn't -- reports error to Termite
+;
+; Use:         Reports an error, attaching the error number etc. and
+;              terminating the script.
+
+               IMPORT  error_report
+
+; --- error_reportReal ---
+;
+; On entry:    R0 == error block
+;
+; On exit:     doesn't -- reports error to Termite
+;
+; Use:         Reports an error, attaching the error number etc. and
+;              terminating the script.
+
+               IMPORT  error_reportReal
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/express b/StraySrc/Libraries/Sapphire/sail/_sh/express
new file mode 100644 (file)
index 0000000..c08ea21
--- /dev/null
@@ -0,0 +1,84 @@
+;
+; express.sh
+;
+; Evaluation of BASIC expressions
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  express_pop
+;  express_popTwo
+;  express_push
+;  express_fnCont
+;  express_read
+
+               [       :LNOT::DEF:express__dfn
+               GBLL    express__dfn
+
+; --- express_pop ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1 == value popped off
+;
+; Use:         Pops a value from the stack.
+
+               IMPORT  express_pop
+
+; --- express_popTwo ---
+;
+; On entry:    --
+;
+; On exit:     R0-R3 == two values popped from the stack
+;
+; Use:         Pops two values from the stack.
+
+               IMPORT  express_popTwo
+
+; --- express_push ---
+;
+; On entry:    R0,R1 == l/rvalue to push
+;
+; On exit:     --
+;
+; Use:         Pushes a value onto the expression stack.
+
+               IMPORT  express_push
+
+; --- express_fnCont ---
+;
+; On entry:    Involved
+;
+; On exit:     Similarly involved.
+;
+; Use:         We continue here after executing a function.
+
+               IMPORT  express_fnCont
+
+; --- express_read ---
+;
+; On entry:    R0 == 1 to read an lvalue, 2 to read ident, 0 otherwise
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0,R1 == value of expression
+;              R7, R8, R9 == lookahead token
+;              R0, R1 == result of expression
+;              R10 == moved on to first char after expression
+;
+; Use:         Reads an expression for the current position in the
+;              tokenised file.
+
+               IMPORT  express_read
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/getToken b/StraySrc/Libraries/Sapphire/sail/_sh/getToken
new file mode 100644 (file)
index 0000000..8ed647a
--- /dev/null
@@ -0,0 +1,39 @@
+;
+; getToken.sh
+;
+; The getting of the next token from the input file
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  getToken
+
+               [       :LNOT::DEF:getToken__dfn
+               GBLL    getToken__dfn
+
+; --- getToken ---
+;
+; On entry:    R8 == lookahead token
+;              R9 == current line number
+;              R10 == evaluation stack pointer
+;              R11 == pointer into the tokenised buffer
+;              R12 == anchor block pointer
+;
+; On exit:     R8 == new lookahead token
+;              R11 == moved on to the first character after the rvalue
+;              CC if the EOF char has not been reached,
+;              CS otherwise
+;
+; Use:         Tries to read an token from the current input line
+
+               IMPORT  getToken
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/interp b/StraySrc/Libraries/Sapphire/sail/_sh/interp
new file mode 100644 (file)
index 0000000..e805d48
--- /dev/null
@@ -0,0 +1,65 @@
+;
+; interp.sh
+;
+; Main entry point for the interpreter
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  interp_start
+;  interp_exec
+;  interp_notImpl
+;  interp_next
+
+               [       :LNOT::DEF:interp__dfn
+               GBLL    interp__dfn
+
+; --- interp_start ---
+;
+; On entry:    R12 == pointer to our anchor block
+;
+; On exit:     R7-R9 == next token
+;
+; Use:         Prepares for execution, and even does some too.
+
+               IMPORT  interp_start
+
+; --- interp_exec ---
+;
+; On entry:    R7-R9 == token to deal with
+;              R11 == offset in file to execute from
+;              R12 == pointer to the anchor block
+;
+; On exit:     R0 == type code (eg. 0 == we are still executing
+;              R7-R9 == next token to deal with
+;
+; Use:         Executes some of the file.
+
+               IMPORT  interp_exec
+
+; --- interp_notImpl ---
+
+               IMPORT  interp_notImpl
+
+; --- interp_next ---
+;
+; On entry:    R7-R9 == token to deal with
+;              R11 == offset in file to execute from
+;              R12 == pointer to the anchor block
+;
+; On exit:     R0 == type code (eg. 0 == we are still executing
+;              R7-R9 == next token to deal with
+;
+; Use:         Checks the next instruction and acts approriately.
+
+               IMPORT  interp_next
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/mem b/StraySrc/Libraries/Sapphire/sail/_sh/mem
new file mode 100644 (file)
index 0000000..8afab9c
--- /dev/null
@@ -0,0 +1,60 @@
+;
+; mem.sh
+;
+; Generic memory allocation for TermScript
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  mem_alloc
+;  mem_free
+;  mem_realloc
+
+               [       :LNOT::DEF:mem__dfn
+               GBLL    mem__dfn
+
+; --- mem_alloc ---
+;
+; On entry:    R0 == size of block to allocate
+;
+; On exit:     R0 == pointer to anchor for that block
+;              May return an error
+;
+; Use:         Tries to allocate a block of memory, and returns a pointer
+;              to the anchor for that block. All very unusual really,
+;              but we blame Wimp_Extension which allocates anchors for
+;              you in an utterley horrible way.
+
+
+               IMPORT  mem_alloc
+
+; --- mem_free ---
+;
+; On entry:    R0 == anchor of the block to free
+;
+; On exit:     --
+;
+; Use:         Frees the block.
+
+               IMPORT  mem_free
+
+; --- mem_realloc ---
+;
+; On entry:    R0 == pointer to block anchor
+;              R1 == new size requested
+;
+; On exit:     May return an error
+;
+; Use:         Resizes a block
+
+               IMPORT  mem_realloc
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/strBucket b/StraySrc/Libraries/Sapphire/sail/_sh/strBucket
new file mode 100644 (file)
index 0000000..f78fcff
--- /dev/null
@@ -0,0 +1,55 @@
+;
+; strBucket.sh
+;
+; String bucket handling
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  strBucket_init
+;  strBucket_alloc
+;  strBucket_free
+
+               [       :LNOT::DEF:strBucket__dfn
+               GBLL    strBucket__dfn
+
+; --- strBucket_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the string bucket.
+
+               IMPORT  strBucket_init
+
+; --- strBucket_alloc ---
+;
+; On entry:    R0 == size of string to allocate
+;
+; On exit:     R0 == pointer to area to use (length at [R0,#-1])
+;              R1 == offset to that (for storing)
+;
+; Use:         Allocates space for a string of the given size.
+
+               IMPORT  strBucket_alloc
+
+; --- strBucket_free ---
+;
+; On entry:    R0 == offset of string to free
+;
+; On exit:     --
+;
+; Use:         Frees the memory the string took up.
+
+               IMPORT  strBucket_free
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/stracc b/StraySrc/Libraries/Sapphire/sail/_sh/stracc
new file mode 100644 (file)
index 0000000..c2efadd
--- /dev/null
@@ -0,0 +1,56 @@
+;
+; stracc.sh
+;
+; String accululator management
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  stracc_ensure
+;  stracc_added
+;  stracc_free
+
+               [       :LNOT::DEF:stracc__dfn
+               GBLL    stracc__dfn
+
+; --- stracc_ensure ---
+;
+; On entry:    --
+;
+; On exit:     R0 == address of string to use
+;              R1 == offset of string from stracc, in upper 24 bits
+;
+; Use:         Ensures tha there are at least 256 bytes available in stracc,
+;              and then returns a pointer to them.
+
+               IMPORT  stracc_ensure
+
+; --- stracc_added ---
+;
+; On entry:    R0 == rvalue of string added
+;
+; On exit:     --
+;
+; Use:         Informs stracc that a new string has been added.
+
+               IMPORT  stracc_added
+
+; --- stracc_free ---
+;
+; On entry:    R0 == rvalue of string no longer needed
+;
+; On exit:     --
+;
+; Use:         Tells stracc that a string is no longer needed.
+
+               IMPORT  stracc_free
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/termScript b/StraySrc/Libraries/Sapphire/sail/_sh/termScript
new file mode 100644 (file)
index 0000000..999d929
--- /dev/null
@@ -0,0 +1,68 @@
+;
+; termScript.sh
+;
+; Coroutine handling for Termite Script
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  tsc_wait
+;  tsc_end
+;  tsc_error
+
+               [       :LNOT::DEF:termScript__dfn
+               GBLL    termScript__dfn
+
+; --- tsc_wait ---
+;
+; On entry:    --
+;
+; On exit:     R0, R1, R2 == event and arguments from Termite
+;
+; Use:         Waits for some multitasking and gets something from Termite.
+
+               IMPORT  tsc_wait
+
+; --- tsc_end ---
+;
+; On entry:    R0 == pointer to script to chain, 0 to just end, or -1 for
+;                    FINISH
+;
+; On exit:     Doesn't, hopefully
+;
+; Use:         Ends the script, optionally starting up another one.
+
+               IMPORT  tsc_end
+
+; --- tsc_error ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     Doesn't, probably
+;
+; Use:         Returns an error to Termite.
+
+               IMPORT  tsc_error
+
+               ; --- Event codes returned by tsc_wait ---
+
+               ^       0
+
+tscEvent_poll  #       1                       ;Nothing interesting happened
+
+tscEvent_serial        #       1                       ;Serial input received
+                                               ;R1 == address of block
+                                               ;R2 == size of block
+
+tscEvent_key   #       1                       ;User pressed a key
+                                               ;R1 == key number (from WIMP)
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/termite b/StraySrc/Libraries/Sapphire/sail/_sh/termite
new file mode 100644 (file)
index 0000000..4779ffc
--- /dev/null
@@ -0,0 +1,219 @@
+;
+; termite.sh
+;
+; Implementation of Termite specific instructions
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  termite_beep
+;  termite_break
+;  termite_call
+;  termite_chain
+;  termite_close
+;  termite_cls
+;  termite_download
+;  termite_error
+;  termite_exec
+;  termite_finish
+;  termite_hangup
+;  termite_lclear
+;  termite_lecho
+;  termite_linput
+;  termite_lnewline
+;  termite_log
+;  termite_newsession
+;  termite_oscli
+;  termite_rclear
+;  termite_recho
+;  termite_report
+;  termite_rinput
+;  termite_rnewline
+;  termite_spool
+;  termite_syscall
+;  termite_upload
+;  termite_wait
+;  termite_watchfor
+;  termite_remoteInput
+;  termite_copyString
+;  termite_doLEcho
+;  termite_doREcho
+
+               [       :LNOT::DEF:termite__dfn
+               GBLL    termite__dfn
+
+; --- termite_beep ---
+
+               IMPORT  termite_beep
+
+; --- termite_break ---
+
+               IMPORT  termite_break
+
+; --- termite_call ---
+
+               IMPORT  termite_call
+
+; --- termite_chain ---
+
+               IMPORT  termite_chain
+
+; --- termite_close ---
+
+               IMPORT  termite_close
+
+; --- termite_cls ---
+
+               IMPORT  termite_cls
+
+; --- termite_download ---
+
+               IMPORT  termite_download
+
+; --- termite_error ---
+
+               IMPORT  termite_error
+
+; --- termite_exec ---
+
+               IMPORT  termite_exec
+
+; --- termite_finish ---
+
+               IMPORT  termite_finish
+
+; --- termite_hangup ---
+
+               IMPORT  termite_hangup
+
+; --- termite_lclear ---
+
+               IMPORT  termite_lclear
+
+; --- termite_lecho ---
+
+               IMPORT  termite_lecho
+
+; -- termite_linput ---
+
+               IMPORT  termite_linput
+
+; --- termite_lnewline ---
+
+               IMPORT  termite_lnewline
+
+; --- termite_log ---
+
+               IMPORT  termite_log
+
+; --- termite_newsession ---
+
+               IMPORT  termite_newsession
+
+; --- termite_oscli ---
+
+               IMPORT  termite_oscli
+
+; --- termite_rclear ---
+
+               IMPORT  termite_rclear
+
+; --- termite_recho ---
+
+               IMPORT  termite_recho
+
+; --- termite_report ---
+
+               IMPORT  termite_report
+
+; --- termite_rinput ---
+
+               IMPORT  termite_rinput
+
+; --- termite_rnewline ---
+
+               IMPORT  termite_rnewline
+
+; --- termite_spool ---
+
+               IMPORT  termite_spool
+
+; --- termite_syscall ---
+
+               IMPORT  termite_syscall
+
+; --- termite_upload ---
+
+               IMPORT  termite_upload
+
+; --- termite_wait ---
+
+               IMPORT  termite_wait
+
+; --- termite_watchfor ---
+
+               IMPORT  termite_watchfor
+
+; --- termite_remoteInput ---
+;
+; On entry:    R0 == handle of script
+;              R2 == buffer containing bytes read
+;              R3 == number of bytes in buffer
+;              R11 == upcall block
+;
+; On exit:     R2 == new buffer containing bytes to put into ring buffer
+;              R3 == number of bytes in this buffer
+;
+; Use:         If we are not doing a watchfor, then this call will return
+;              immediately, resulting in all the buffer being sent
+;              to the ring buffer.
+;              If we are in a watchfor, then all data received, up until
+;              a match, is echoed immediatley, and not sent to the buffer.
+
+               IMPORT  termite_remoteInput
+
+; --- termite_copyString ---
+;
+; On entry:    R0 == buffer to copy string to
+;              R1 == point to the string
+;              R2 == length of string to copy
+;
+; On exit:     --
+;
+; Use:         Copies the string into the buffer.
+
+               IMPORT  termite_copyString
+
+; --- termite_doLEcho ---
+;
+; On entry:    R2 == pointer to the buffer
+;              R3 == number of bytes to send
+;
+; On exit:     --
+;
+; Use:         Echos the buffer to local and remote according to the
+;              current flags, assuming the buffer came from the local input
+
+               IMPORT  termite_doLEcho
+
+; --- termite_doREcho ---
+;
+; On entry:    R2 == pointer to the buffer
+;              R3 == number of bytes to send
+;
+; On exit:     --
+;
+; Use:         Echos the buffer to local and remote according to the
+;              current flags, assuming the buffer came from remote input
+
+               IMPORT  termite_doREcho
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/tokClasses b/StraySrc/Libraries/Sapphire/sail/_sh/tokClasses
new file mode 100644 (file)
index 0000000..815ce14
--- /dev/null
@@ -0,0 +1,272 @@
+;
+; tokClasses.sh
+;
+; Token class and index tables (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:tokClasses__dfn
+               GBLL    tokClasses__dfn
+
+tokClasses
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     7,3
+               DCB     13,0
+               DCB     0,0
+               DCB     13,1
+               DCB     0,0
+               DCB     7,2
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     12,1
+               DCB     12,0
+               DCB     12,4
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     15,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     1,0
+               DCB     2,0
+               DCB     2,1
+               DCB     3,0
+               DCB     4,0
+               DCB     5,0
+               DCB     3,1
+               DCB     3,2
+               DCB     6,0
+               DCB     3,3
+               DCB     3,4
+               DCB     2,2
+               DCB     3,5
+               DCB     3,6
+               DCB     3,7
+               DCB     3,8
+               DCB     3,9
+               DCB     7,0
+               DCB     3,10
+               DCB     3,11
+               DCB     3,12
+               DCB     3,13
+               DCB     3,14
+               DCB     3,15
+               DCB     3,16
+               DCB     3,17
+               DCB     2,3
+               DCB     3,18
+               DCB     6,1
+               DCB     4,1
+               DCB     8,0
+               DCB     3,19
+               DCB     4,2
+               DCB     3,20
+               DCB     6,2
+               DCB     3,21
+               DCB     6,3
+               DCB     9,0
+               DCB     3,22
+               DCB     4,3
+               DCB     3,23
+               DCB     3,24
+               DCB     3,25
+               DCB     10,0
+               DCB     3,26
+               DCB     3,27
+               DCB     10,1
+               DCB     2,4
+               DCB     3,28
+               DCB     2,5
+               DCB     2,6
+               DCB     3,29
+               DCB     6,4
+               DCB     6,5
+               DCB     3,30
+               DCB     6,6
+               DCB     3,31
+               DCB     10,2
+               DCB     7,1
+               DCB     3,32
+               DCB     3,33
+               DCB     2,7
+               DCB     11,0
+               DCB     5,1
+               DCB     11,1
+               DCB     8,1
+               DCB     2,8
+               DCB     2,9
+               DCB     2,10
+               DCB     3,34
+               DCB     3,35
+               DCB     4,4
+               DCB     3,36
+               DCB     3,37
+               DCB     3,38
+               DCB     3,39
+               DCB     3,40
+               DCB     3,41
+               DCB     11,2
+               DCB     5,2
+               DCB     3,42
+               DCB     3,43
+               DCB     10,3
+               DCB     2,11
+               DCB     2,12
+               DCB     3,44
+               DCB     9,1
+               DCB     6,7
+               DCB     6,8
+               DCB     6,9
+               DCB     11,3
+               DCB     2,13
+               DCB     3,45
+               DCB     2,14
+               DCB     10,4
+               DCB     3,46
+               DCB     3,47
+               DCB     3,48
+               DCB     11,4
+               DCB     6,10
+               DCB     6,11
+               DCB     11,5
+               DCB     6,12
+               DCB     3,49
+               DCB     3,50
+               DCB     2,15
+               DCB     3,51
+               DCB     6,13
+               DCB     3,52
+               DCB     3,53
+               DCB     3,54
+               DCB     12,2
+               DCB     12,3
+               DCB     12,5
+               DCB     12,6
+               DCB     12,7
+               DCB     12,8
+               DCB     11,6
+               DCB     11,7
+               DCB     14,0
+               DCB     14,1
+               DCB     14,2
+               DCB     14,3
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/tokNames b/StraySrc/Libraries/Sapphire/sail/_sh/tokNames
new file mode 100644 (file)
index 0000000..3f10d76
--- /dev/null
@@ -0,0 +1,262 @@
+;
+; tokNames.sh
+;
+; Number-to-name table for tokens (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:tokNames__dfn
+               GBLL    tokNames__dfn
+
+tokNames       DCD     tn__0
+               DCD     tn__1
+               DCD     tn__2
+               DCD     tn__3
+               DCD     tn__4
+               DCD     tn__5
+               DCD     tn__6
+               DCD     tn__7
+               DCD     tn__8
+               DCD     tn__9
+               DCD     tn__10
+               DCD     tn__11
+               DCD     tn__12
+               DCD     tn__13
+               DCD     tn__14
+               DCD     tn__15
+               DCD     tn__16
+               DCD     tn__17
+               DCD     tn__18
+               DCD     tn__19
+               DCD     tn__20
+               DCD     tn__21
+               DCD     tn__22
+               DCD     tn__23
+               DCD     tn__24
+               DCD     tn__25
+               DCD     tn__26
+               DCD     tn__27
+               DCD     tn__28
+               DCD     tn__29
+               DCD     tn__30
+               DCD     tn__31
+               DCD     tn__32
+               DCD     tn__33
+               DCD     tn__34
+               DCD     tn__35
+               DCD     tn__36
+               DCD     tn__37
+               DCD     tn__38
+               DCD     tn__39
+               DCD     tn__40
+               DCD     tn__41
+               DCD     tn__42
+               DCD     tn__43
+               DCD     tn__44
+               DCD     tn__45
+               DCD     tn__46
+               DCD     tn__47
+               DCD     tn__48
+               DCD     tn__49
+               DCD     tn__50
+               DCD     tn__51
+               DCD     tn__52
+               DCD     tn__53
+               DCD     tn__54
+               DCD     tn__55
+               DCD     tn__56
+               DCD     tn__57
+               DCD     tn__58
+               DCD     tn__59
+               DCD     tn__60
+               DCD     tn__61
+               DCD     tn__62
+               DCD     tn__63
+               DCD     tn__64
+               DCD     tn__65
+               DCD     tn__66
+               DCD     tn__67
+               DCD     tn__68
+               DCD     tn__69
+               DCD     tn__70
+               DCD     tn__71
+               DCD     tn__72
+               DCD     tn__73
+               DCD     tn__74
+               DCD     tn__75
+               DCD     tn__76
+               DCD     tn__77
+               DCD     tn__78
+               DCD     tn__79
+               DCD     tn__80
+               DCD     tn__81
+               DCD     tn__82
+               DCD     tn__83
+               DCD     tn__84
+               DCD     tn__85
+               DCD     tn__86
+               DCD     tn__87
+               DCD     tn__88
+               DCD     tn__89
+               DCD     tn__90
+               DCD     tn__91
+               DCD     tn__92
+               DCD     tn__93
+               DCD     tn__94
+               DCD     tn__95
+               DCD     tn__96
+               DCD     tn__97
+               DCD     tn__98
+               DCD     tn__99
+               DCD     tn__100
+               DCD     tn__101
+               DCD     tn__102
+               DCD     tn__103
+               DCD     tn__104
+               DCD     tn__105
+               DCD     tn__106
+               DCD     tn__107
+               DCD     tn__108
+               DCD     tn__109
+               DCD     tn__110
+               DCD     tn__111
+               DCD     tn__112
+               DCD     tn__113
+               DCD     tn__114
+               DCD     tn__115
+               DCD     tn__116
+               DCD     tn__117
+               DCD     tn__118
+               DCD     tn__119
+               DCD     tn__120
+               DCD     tn__121
+               DCD     tn__122
+
+tn__0          DCB     "AND",0
+tn__1          DCB     "ABS",0
+tn__2          DCB     "ASC",0
+tn__3          DCB     "BEEP",0
+tn__4          DCB     "BGET",0
+tn__5          DCB     "BOTH",0
+tn__6          DCB     "BPUT",0
+tn__7          DCB     "BREAK",0
+tn__8          DCB     "CARRIER",0
+tn__9          DCB     "CASE",0
+tn__10         DCB     "CHAIN",0
+tn__11         DCB     "CHR$",0
+tn__12         DCB     "CLOSE",0
+tn__13         DCB     "CLS",0
+tn__14         DCB     "CALL",0
+tn__15         DCB     "DATA",0
+tn__16         DCB     "DEF",0
+tn__17         DCB     "DIV",0
+tn__18         DCB     "DIM",0
+tn__19         DCB     "DOWNLOAD",0
+tn__20         DCB     "END",0
+tn__21         DCB     "ENDPROC",0
+tn__22         DCB     "ENDWHILE",0
+tn__23         DCB     "ENDIF",0
+tn__24         DCB     "ENDCASE",0
+tn__25         DCB     "ELSE",0
+tn__26         DCB     "EVAL",0
+tn__27         DCB     "ERROR",0
+tn__28         DCB     "ERROR$",0
+tn__29         DCB     "EOF",0
+tn__30         DCB     "EOR",0
+tn__31         DCB     "EXEC",0
+tn__32         DCB     "EXT",0
+tn__33         DCB     "FOR",0
+tn__34         DCB     "FALSE",0
+tn__35         DCB     "FINISH",0
+tn__36         DCB     "FINISHED",0
+tn__37         DCB     "FN",0
+tn__38         DCB     "GOTO",0
+tn__39         DCB     "GET$",0
+tn__40         DCB     "GOSUB",0
+tn__41         DCB     "HANGUP",0
+tn__42         DCB     "IF",0
+tn__43         DCB     "INSTR(",0
+tn__44         DCB     "LCLEAR",0
+tn__45         DCB     "LECHO",0
+tn__46         DCB     "LEFT$(",0
+tn__47         DCB     "LEN",0
+tn__48         DCB     "LET",0
+tn__49         DCB     "LINKEY",0
+tn__50         DCB     "LINKEY$",0
+tn__51         DCB     "LINPUT",0
+tn__52         DCB     "LGET",0
+tn__53         DCB     "LGET$",0
+tn__54         DCB     "LOCAL",0
+tn__55         DCB     "LNEWLINE$",0
+tn__56         DCB     "LOG",0
+tn__57         DCB     "MID$(",0
+tn__58         DCB     "MOD",0
+tn__59         DCB     "NEWSESSION",0
+tn__60         DCB     "NEXT",0
+tn__61         DCB     "NOT",0
+tn__62         DCB     "OF",0
+tn__63         DCB     "OFF",0
+tn__64         DCB     "ON",0
+tn__65         DCB     "OR",0
+tn__66         DCB     "OPENIN",0
+tn__67         DCB     "OPENOUT",0
+tn__68         DCB     "OPENUP",0
+tn__69         DCB     "OSCLI",0
+tn__70         DCB     "OTHERWISE",0
+tn__71         DCB     "PTR",0
+tn__72         DCB     "PROC",0
+tn__73         DCB     "RCLEAR",0
+tn__74         DCB     "RETURN",0
+tn__75         DCB     "REPEAT",0
+tn__76         DCB     "READ",0
+tn__77         DCB     "RECHO",0
+tn__78         DCB     "REM",0
+tn__79         DCB     "REMOTE",0
+tn__80         DCB     "REPORT",0
+tn__81         DCB     "RESTORE",0
+tn__82         DCB     "RIGHT$(",0
+tn__83         DCB     "RINKEY",0
+tn__84         DCB     "RINKEY$",0
+tn__85         DCB     "RINPUT",0
+tn__86         DCB     "RND",0
+tn__87         DCB     "RGET",0
+tn__88         DCB     "RGET$",0
+tn__89         DCB     "RNEWLINE$",0
+tn__90         DCB     "STEP",0
+tn__91         DCB     "SGN",0
+tn__92         DCB     "SPOOL",0
+tn__93         DCB     "STR$",0
+tn__94         DCB     "STRING$(",0
+tn__95         DCB     "SWAP",0
+tn__96         DCB     "SYS",0
+tn__97         DCB     "SYSCALL",0
+tn__98         DCB     "THEN",0
+tn__99         DCB     "TIME",0
+tn__100                DCB     "TIME$",0
+tn__101                DCB     "TO",0
+tn__102                DCB     "TRUE",0
+tn__103                DCB     "UNTIL",0
+tn__104                DCB     "UPLOAD",0
+tn__105                DCB     "VAL",0
+tn__106                DCB     "WAIT",0
+tn__107                DCB     "WATCH",0
+tn__108                DCB     "WATCHFOR",0
+tn__109                DCB     "WHILE",0
+tn__110                DCB     "WHEN",0
+tn__111                DCB     "<=",0
+tn__112                DCB     "<>",0
+tn__113                DCB     ">=",0
+tn__114                DCB     "<<",0
+tn__115                DCB     ">>",0
+tn__116                DCB     ">>>",0
+tn__117                DCB     "/*",0
+tn__118                DCB     "//",0
+tn__119                DCB     "+=",0
+tn__120                DCB     "-=",0
+tn__121                DCB     "*=",0
+tn__122                DCB     "/=",0
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/tokTable b/StraySrc/Libraries/Sapphire/sail/_sh/tokTable
new file mode 100644 (file)
index 0000000..e574645
--- /dev/null
@@ -0,0 +1,943 @@
+;
+; tokTable.sh
+;
+; State table for lexical analysis (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:tokTable__dfn
+               GBLL    tokTable__dfn
+
+               MACRO
+$label         TOKTBL  $char,$next,$token
+$label
+               [       "$next"="0"
+               DCW     0
+               |
+               DCW     $next-kt0
+               ]
+               [       "$token"<>""
+               DCB     $token
+               |
+               DCB     0
+               ]
+               DCB     $char
+               MEND
+
+tokTable
+kt0            TOKTBL  'A',kt1
+               TOKTBL  'B',kt2
+               TOKTBL  'C',kt3
+               TOKTBL  'D',kt4
+               TOKTBL  'E',kt5
+               TOKTBL  'F',kt6
+               TOKTBL  'G',kt7
+               TOKTBL  'H',kt8
+               TOKTBL  'I',kt9
+               TOKTBL  'L',kt10
+               TOKTBL  'M',kt11
+               TOKTBL  'N',kt12
+               TOKTBL  'O',kt13
+               TOKTBL  'P',kt14
+               TOKTBL  'R',kt15
+               TOKTBL  'S',kt16
+               TOKTBL  'T',kt17
+               TOKTBL  'U',kt18
+               TOKTBL  'V',kt19
+               TOKTBL  'W',kt20
+               TOKTBL  '=',0,'='
+               TOKTBL  '<',kt21,'<'
+               TOKTBL  '>',kt22,'>'
+               TOKTBL  '/',kt23,'/'
+               TOKTBL  '+',kt24,'+'
+               TOKTBL  '-',kt25,'-'
+               TOKTBL  '*',kt26,'*'
+               TOKTBL  '^',0,'^'
+               TOKTBL  0,0
+
+kt26           TOKTBL  '=',0,tok_TE
+               TOKTBL  0,0
+
+kt25           TOKTBL  '=',0,tok_ME
+               TOKTBL  0,0
+
+kt24           TOKTBL  '=',0,tok_PE
+               TOKTBL  0,0
+
+kt23           TOKTBL  '*',0,tok_DT
+               TOKTBL  '/',0,tok_DD
+               TOKTBL  '=',0,tok_DE
+               TOKTBL  0,0
+
+kt22           TOKTBL  '=',0,tok_GE
+               TOKTBL  '>',kt27,tok_GG
+               TOKTBL  0,0
+
+kt27           TOKTBL  '>',0,tok_GGG
+               TOKTBL  0,0
+
+kt21           TOKTBL  '=',0,tok_LE
+               TOKTBL  '>',0,tok_LG
+               TOKTBL  '<',0,tok_LL
+               TOKTBL  0,0
+
+kt20           TOKTBL  'A',kt28
+               TOKTBL  'H',kt29
+               TOKTBL  0,0
+
+kt29           TOKTBL  'I',kt30
+               TOKTBL  'E',kt31
+               TOKTBL  0,0
+
+kt31           TOKTBL  'N',0,tok_when
+               TOKTBL  0,0
+
+kt30           TOKTBL  'L',kt32
+               TOKTBL  0,0
+
+kt32           TOKTBL  'E',0,tok_while
+               TOKTBL  0,0
+
+kt28           TOKTBL  'I',kt33
+               TOKTBL  'T',kt34
+               TOKTBL  0,0
+
+kt34           TOKTBL  'C',kt35
+               TOKTBL  0,0
+
+kt35           TOKTBL  'H',kt36,tok_watch
+               TOKTBL  0,0
+
+kt36           TOKTBL  'F',kt37
+               TOKTBL  0,0
+
+kt37           TOKTBL  'O',kt38
+               TOKTBL  0,0
+
+kt38           TOKTBL  'R',0,tok_watchfor
+               TOKTBL  0,0
+
+kt33           TOKTBL  'T',0,tok_wait
+               TOKTBL  0,0
+
+kt19           TOKTBL  'A',kt39
+               TOKTBL  0,0
+
+kt39           TOKTBL  'L',0,tok_val
+               TOKTBL  0,0
+
+kt18           TOKTBL  'N',kt40
+               TOKTBL  'P',kt41
+               TOKTBL  0,0
+
+kt41           TOKTBL  'L',kt42
+               TOKTBL  0,0
+
+kt42           TOKTBL  'O',kt43
+               TOKTBL  0,0
+
+kt43           TOKTBL  'A',kt44
+               TOKTBL  0,0
+
+kt44           TOKTBL  'D',0,tok_upload
+               TOKTBL  0,0
+
+kt40           TOKTBL  'T',kt45
+               TOKTBL  0,0
+
+kt45           TOKTBL  'I',kt46
+               TOKTBL  0,0
+
+kt46           TOKTBL  'L',0,tok_until
+               TOKTBL  0,0
+
+kt17           TOKTBL  'H',kt47
+               TOKTBL  'I',kt48
+               TOKTBL  'O',0,tok_to
+               TOKTBL  'R',kt49
+               TOKTBL  0,0
+
+kt49           TOKTBL  'U',kt50
+               TOKTBL  0,0
+
+kt50           TOKTBL  'E',0,tok_true
+               TOKTBL  0,0
+
+kt48           TOKTBL  'M',kt51
+               TOKTBL  0,0
+
+kt51           TOKTBL  'E',kt52,tok_time
+               TOKTBL  0,0
+
+kt52           TOKTBL  '$',0,tok_timeS
+               TOKTBL  0,0
+
+kt47           TOKTBL  'E',kt53
+               TOKTBL  0,0
+
+kt53           TOKTBL  'N',0,tok_then
+               TOKTBL  0,0
+
+kt16           TOKTBL  'T',kt54
+               TOKTBL  'G',kt55
+               TOKTBL  'P',kt56
+               TOKTBL  'W',kt57
+               TOKTBL  'Y',kt58
+               TOKTBL  0,0
+
+kt58           TOKTBL  'S',kt59,tok_sys
+               TOKTBL  0,0
+
+kt59           TOKTBL  'C',kt60
+               TOKTBL  0,0
+
+kt60           TOKTBL  'A',kt61
+               TOKTBL  0,0
+
+kt61           TOKTBL  'L',kt62
+               TOKTBL  0,0
+
+kt62           TOKTBL  'L',0,tok_syscall
+               TOKTBL  0,0
+
+kt57           TOKTBL  'A',kt63
+               TOKTBL  0,0
+
+kt63           TOKTBL  'P',0,tok_swap
+               TOKTBL  0,0
+
+kt56           TOKTBL  'O',kt64
+               TOKTBL  0,0
+
+kt64           TOKTBL  'O',kt65
+               TOKTBL  0,0
+
+kt65           TOKTBL  'L',0,tok_spool
+               TOKTBL  0,0
+
+kt55           TOKTBL  'N',0,tok_sgn
+               TOKTBL  0,0
+
+kt54           TOKTBL  'E',kt66
+               TOKTBL  'R',kt67
+               TOKTBL  0,0
+
+kt67           TOKTBL  '$',0,tok_strS
+               TOKTBL  'I',kt68
+               TOKTBL  0,0
+
+kt68           TOKTBL  'N',kt69
+               TOKTBL  0,0
+
+kt69           TOKTBL  'G',kt70
+               TOKTBL  0,0
+
+kt70           TOKTBL  '$',kt71
+               TOKTBL  0,0
+
+kt71           TOKTBL  '(',0,tok_stringS
+               TOKTBL  0,0
+
+kt66           TOKTBL  'P',0,tok_step
+               TOKTBL  0,0
+
+kt15           TOKTBL  'C',kt72
+               TOKTBL  'E',kt73
+               TOKTBL  'I',kt74
+               TOKTBL  'N',kt75
+               TOKTBL  'G',kt76
+               TOKTBL  0,0
+
+kt76           TOKTBL  'E',kt77
+               TOKTBL  0,0
+
+kt77           TOKTBL  'T',kt78,tok_rget
+               TOKTBL  0,0
+
+kt78           TOKTBL  '$',0,tok_rgetS
+               TOKTBL  0,0
+
+kt75           TOKTBL  'D',0,tok_rnd
+               TOKTBL  'E',kt79
+               TOKTBL  0,0
+
+kt79           TOKTBL  'W',kt80
+               TOKTBL  0,0
+
+kt80           TOKTBL  'L',kt81
+               TOKTBL  0,0
+
+kt81           TOKTBL  'I',kt82
+               TOKTBL  0,0
+
+kt82           TOKTBL  'N',kt83
+               TOKTBL  0,0
+
+kt83           TOKTBL  'E',kt84
+               TOKTBL  0,0
+
+kt84           TOKTBL  '$',0,tok_rnewlineS
+               TOKTBL  0,0
+
+kt74           TOKTBL  'G',kt85
+               TOKTBL  'N',kt86
+               TOKTBL  0,0
+
+kt86           TOKTBL  'K',kt87
+               TOKTBL  'P',kt88
+               TOKTBL  0,0
+
+kt88           TOKTBL  'U',kt89
+               TOKTBL  0,0
+
+kt89           TOKTBL  'T',0,tok_rinput
+               TOKTBL  0,0
+
+kt87           TOKTBL  'E',kt90
+               TOKTBL  0,0
+
+kt90           TOKTBL  'Y',kt91,tok_rinkey
+               TOKTBL  0,0
+
+kt91           TOKTBL  '$',0,tok_rinkeyS
+               TOKTBL  0,0
+
+kt85           TOKTBL  'H',kt92
+               TOKTBL  0,0
+
+kt92           TOKTBL  'T',kt93
+               TOKTBL  0,0
+
+kt93           TOKTBL  '$',kt94
+               TOKTBL  0,0
+
+kt94           TOKTBL  '(',0,tok_rightS
+               TOKTBL  0,0
+
+kt73           TOKTBL  'T',kt95
+               TOKTBL  'P',kt96
+               TOKTBL  'A',kt97
+               TOKTBL  'C',kt98
+               TOKTBL  'M',kt99,tok_rem
+               TOKTBL  'S',kt100
+               TOKTBL  0,0
+
+kt100          TOKTBL  'T',kt101
+               TOKTBL  0,0
+
+kt101          TOKTBL  'O',kt102
+               TOKTBL  0,0
+
+kt102          TOKTBL  'R',kt103
+               TOKTBL  0,0
+
+kt103          TOKTBL  'E',0,tok_restore
+               TOKTBL  0,0
+
+kt99           TOKTBL  'O',kt104
+               TOKTBL  0,0
+
+kt104          TOKTBL  'T',kt105
+               TOKTBL  0,0
+
+kt105          TOKTBL  'E',0,tok_remote
+               TOKTBL  0,0
+
+kt98           TOKTBL  'H',kt106
+               TOKTBL  0,0
+
+kt106          TOKTBL  'O',0,tok_recho
+               TOKTBL  0,0
+
+kt97           TOKTBL  'D',0,tok_read
+               TOKTBL  0,0
+
+kt96           TOKTBL  'E',kt107
+               TOKTBL  'O',kt108
+               TOKTBL  0,0
+
+kt108          TOKTBL  'R',kt109
+               TOKTBL  0,0
+
+kt109          TOKTBL  'T',0,tok_report
+               TOKTBL  0,0
+
+kt107          TOKTBL  'A',kt110
+               TOKTBL  0,0
+
+kt110          TOKTBL  'T',0,tok_repeat
+               TOKTBL  0,0
+
+kt95           TOKTBL  'U',kt111
+               TOKTBL  0,0
+
+kt111          TOKTBL  'R',kt112
+               TOKTBL  0,0
+
+kt112          TOKTBL  'N',0,tok_return
+               TOKTBL  0,0
+
+kt72           TOKTBL  'L',kt113
+               TOKTBL  0,0
+
+kt113          TOKTBL  'E',kt114
+               TOKTBL  0,0
+
+kt114          TOKTBL  'A',kt115
+               TOKTBL  0,0
+
+kt115          TOKTBL  'R',0,tok_rclear
+               TOKTBL  0,0
+
+kt14           TOKTBL  'T',kt116
+               TOKTBL  'R',kt117
+               TOKTBL  0,0
+
+kt117          TOKTBL  'O',kt118
+               TOKTBL  0,0
+
+kt118          TOKTBL  'C',0,tok_proc
+               TOKTBL  0,0
+
+kt116          TOKTBL  'R',0,tok_ptr
+               TOKTBL  0,0
+
+kt13           TOKTBL  'F',kt119,tok_of
+               TOKTBL  'N',0,tok_on
+               TOKTBL  'R',0,tok_or
+               TOKTBL  'P',kt120
+               TOKTBL  'S',kt121
+               TOKTBL  'T',kt122
+               TOKTBL  0,0
+
+kt122          TOKTBL  'H',kt123
+               TOKTBL  0,0
+
+kt123          TOKTBL  'E',kt124
+               TOKTBL  0,0
+
+kt124          TOKTBL  'R',kt125
+               TOKTBL  0,0
+
+kt125          TOKTBL  'W',kt126
+               TOKTBL  0,0
+
+kt126          TOKTBL  'I',kt127
+               TOKTBL  0,0
+
+kt127          TOKTBL  'S',kt128
+               TOKTBL  0,0
+
+kt128          TOKTBL  'E',0,tok_otherwise
+               TOKTBL  0,0
+
+kt121          TOKTBL  'C',kt129
+               TOKTBL  0,0
+
+kt129          TOKTBL  'L',kt130
+               TOKTBL  0,0
+
+kt130          TOKTBL  'I',0,tok_oscli
+               TOKTBL  0,0
+
+kt120          TOKTBL  'E',kt131
+               TOKTBL  0,0
+
+kt131          TOKTBL  'N',kt132
+               TOKTBL  0,0
+
+kt132          TOKTBL  'I',kt133
+               TOKTBL  'O',kt134
+               TOKTBL  'U',kt135
+               TOKTBL  0,0
+
+kt135          TOKTBL  'P',0,tok_openup
+               TOKTBL  0,0
+
+kt134          TOKTBL  'U',kt136
+               TOKTBL  0,0
+
+kt136          TOKTBL  'T',0,tok_openout
+               TOKTBL  0,0
+
+kt133          TOKTBL  'N',0,tok_openin
+               TOKTBL  0,0
+
+kt119          TOKTBL  'F',0,tok_off
+               TOKTBL  0,0
+
+kt12           TOKTBL  'E',kt137
+               TOKTBL  'O',kt138
+               TOKTBL  0,0
+
+kt138          TOKTBL  'T',0,tok_not
+               TOKTBL  0,0
+
+kt137          TOKTBL  'W',kt139
+               TOKTBL  'X',kt140
+               TOKTBL  0,0
+
+kt140          TOKTBL  'T',0,tok_next
+               TOKTBL  0,0
+
+kt139          TOKTBL  'S',kt141
+               TOKTBL  0,0
+
+kt141          TOKTBL  'E',kt142
+               TOKTBL  0,0
+
+kt142          TOKTBL  'S',kt143
+               TOKTBL  0,0
+
+kt143          TOKTBL  'S',kt144
+               TOKTBL  0,0
+
+kt144          TOKTBL  'I',kt145
+               TOKTBL  0,0
+
+kt145          TOKTBL  'O',kt146
+               TOKTBL  0,0
+
+kt146          TOKTBL  'N',0,tok_newsession
+               TOKTBL  0,0
+
+kt11           TOKTBL  'I',kt147
+               TOKTBL  'O',kt148
+               TOKTBL  0,0
+
+kt148          TOKTBL  'D',0,tok_mod
+               TOKTBL  0,0
+
+kt147          TOKTBL  'D',kt149
+               TOKTBL  0,0
+
+kt149          TOKTBL  '$',kt150
+               TOKTBL  0,0
+
+kt150          TOKTBL  '(',0,tok_midS
+               TOKTBL  0,0
+
+kt10           TOKTBL  'C',kt151
+               TOKTBL  'E',kt152
+               TOKTBL  'I',kt153
+               TOKTBL  'G',kt154
+               TOKTBL  'O',kt155
+               TOKTBL  'N',kt156
+               TOKTBL  0,0
+
+kt156          TOKTBL  'E',kt157
+               TOKTBL  0,0
+
+kt157          TOKTBL  'W',kt158
+               TOKTBL  0,0
+
+kt158          TOKTBL  'L',kt159
+               TOKTBL  0,0
+
+kt159          TOKTBL  'I',kt160
+               TOKTBL  0,0
+
+kt160          TOKTBL  'N',kt161
+               TOKTBL  0,0
+
+kt161          TOKTBL  'E',kt162
+               TOKTBL  0,0
+
+kt162          TOKTBL  '$',0,tok_lnewlineS
+               TOKTBL  0,0
+
+kt155          TOKTBL  'C',kt163
+               TOKTBL  'G',0,tok_log
+               TOKTBL  0,0
+
+kt163          TOKTBL  'A',kt164
+               TOKTBL  0,0
+
+kt164          TOKTBL  'L',0,tok_local
+               TOKTBL  0,0
+
+kt154          TOKTBL  'E',kt165
+               TOKTBL  0,0
+
+kt165          TOKTBL  'T',kt166,tok_lget
+               TOKTBL  0,0
+
+kt166          TOKTBL  '$',0,tok_lgetS
+               TOKTBL  0,0
+
+kt153          TOKTBL  'N',kt167
+               TOKTBL  0,0
+
+kt167          TOKTBL  'K',kt168
+               TOKTBL  'P',kt169
+               TOKTBL  0,0
+
+kt169          TOKTBL  'U',kt170
+               TOKTBL  0,0
+
+kt170          TOKTBL  'T',0,tok_linput
+               TOKTBL  0,0
+
+kt168          TOKTBL  'E',kt171
+               TOKTBL  0,0
+
+kt171          TOKTBL  'Y',kt172,tok_linkey
+               TOKTBL  0,0
+
+kt172          TOKTBL  '$',0,tok_linkeyS
+               TOKTBL  0,0
+
+kt152          TOKTBL  'C',kt173
+               TOKTBL  'F',kt174
+               TOKTBL  'N',0,tok_len
+               TOKTBL  'T',0,tok_let
+               TOKTBL  0,0
+
+kt174          TOKTBL  'T',kt175
+               TOKTBL  0,0
+
+kt175          TOKTBL  '$',kt176
+               TOKTBL  0,0
+
+kt176          TOKTBL  '(',0,tok_leftS
+               TOKTBL  0,0
+
+kt173          TOKTBL  'H',kt177
+               TOKTBL  0,0
+
+kt177          TOKTBL  'O',0,tok_lecho
+               TOKTBL  0,0
+
+kt151          TOKTBL  'L',kt178
+               TOKTBL  0,0
+
+kt178          TOKTBL  'E',kt179
+               TOKTBL  0,0
+
+kt179          TOKTBL  'A',kt180
+               TOKTBL  0,0
+
+kt180          TOKTBL  'R',0,tok_lclear
+               TOKTBL  0,0
+
+kt9            TOKTBL  'F',0,tok_if
+               TOKTBL  'N',kt181
+               TOKTBL  0,0
+
+kt181          TOKTBL  'S',kt182
+               TOKTBL  0,0
+
+kt182          TOKTBL  'T',kt183
+               TOKTBL  0,0
+
+kt183          TOKTBL  'R',kt184
+               TOKTBL  0,0
+
+kt184          TOKTBL  '(',0,tok_instr
+               TOKTBL  0,0
+
+kt8            TOKTBL  'A',kt185
+               TOKTBL  0,0
+
+kt185          TOKTBL  'N',kt186
+               TOKTBL  0,0
+
+kt186          TOKTBL  'G',kt187
+               TOKTBL  0,0
+
+kt187          TOKTBL  'U',kt188
+               TOKTBL  0,0
+
+kt188          TOKTBL  'P',0,tok_hangup
+               TOKTBL  0,0
+
+kt7            TOKTBL  'O',kt189
+               TOKTBL  'E',kt190
+               TOKTBL  0,0
+
+kt190          TOKTBL  'T',kt191
+               TOKTBL  0,0
+
+kt191          TOKTBL  '$',0,tok_getS
+               TOKTBL  0,0
+
+kt189          TOKTBL  'T',kt192
+               TOKTBL  'S',kt193
+               TOKTBL  0,0
+
+kt193          TOKTBL  'U',kt194
+               TOKTBL  0,0
+
+kt194          TOKTBL  'B',0,tok_gosub
+               TOKTBL  0,0
+
+kt192          TOKTBL  'O',0,tok_goto
+               TOKTBL  0,0
+
+kt6            TOKTBL  'O',kt195
+               TOKTBL  'A',kt196
+               TOKTBL  'I',kt197
+               TOKTBL  'N',0,tok_fn
+               TOKTBL  0,0
+
+kt197          TOKTBL  'N',kt198
+               TOKTBL  0,0
+
+kt198          TOKTBL  'I',kt199
+               TOKTBL  0,0
+
+kt199          TOKTBL  'S',kt200
+               TOKTBL  0,0
+
+kt200          TOKTBL  'H',kt201,tok_finish
+               TOKTBL  0,0
+
+kt201          TOKTBL  'E',kt202
+               TOKTBL  0,0
+
+kt202          TOKTBL  'D',0,tok_finished
+               TOKTBL  0,0
+
+kt196          TOKTBL  'L',kt203
+               TOKTBL  0,0
+
+kt203          TOKTBL  'S',kt204
+               TOKTBL  0,0
+
+kt204          TOKTBL  'E',0,tok_false
+               TOKTBL  0,0
+
+kt195          TOKTBL  'R',0,tok_for
+               TOKTBL  0,0
+
+kt5            TOKTBL  'N',kt205
+               TOKTBL  'L',kt206
+               TOKTBL  'V',kt207
+               TOKTBL  'R',kt208
+               TOKTBL  'O',kt209
+               TOKTBL  'X',kt210
+               TOKTBL  0,0
+
+kt210          TOKTBL  'E',kt211
+               TOKTBL  'T',0,tok_ext
+               TOKTBL  0,0
+
+kt211          TOKTBL  'C',0,tok_exec
+               TOKTBL  0,0
+
+kt209          TOKTBL  'F',0,tok_eof
+               TOKTBL  'R',0,tok_eor
+               TOKTBL  0,0
+
+kt208          TOKTBL  'R',kt212
+               TOKTBL  0,0
+
+kt212          TOKTBL  'O',kt213
+               TOKTBL  0,0
+
+kt213          TOKTBL  'R',kt214,tok_error
+               TOKTBL  0,0
+
+kt214          TOKTBL  '$',0,tok_errorS
+               TOKTBL  0,0
+
+kt207          TOKTBL  'A',kt215
+               TOKTBL  0,0
+
+kt215          TOKTBL  'L',0,tok_eval
+               TOKTBL  0,0
+
+kt206          TOKTBL  'S',kt216
+               TOKTBL  0,0
+
+kt216          TOKTBL  'E',0,tok_else
+               TOKTBL  0,0
+
+kt205          TOKTBL  'D',kt217,tok_end
+               TOKTBL  0,0
+
+kt217          TOKTBL  'P',kt218
+               TOKTBL  'W',kt219
+               TOKTBL  'I',kt220
+               TOKTBL  'C',kt221
+               TOKTBL  0,0
+
+kt221          TOKTBL  'A',kt222
+               TOKTBL  0,0
+
+kt222          TOKTBL  'S',kt223
+               TOKTBL  0,0
+
+kt223          TOKTBL  'E',0,tok_endcase
+               TOKTBL  0,0
+
+kt220          TOKTBL  'F',0,tok_endif
+               TOKTBL  0,0
+
+kt219          TOKTBL  'H',kt224
+               TOKTBL  0,0
+
+kt224          TOKTBL  'I',kt225
+               TOKTBL  0,0
+
+kt225          TOKTBL  'L',kt226
+               TOKTBL  0,0
+
+kt226          TOKTBL  'E',0,tok_endwhile
+               TOKTBL  0,0
+
+kt218          TOKTBL  'R',kt227
+               TOKTBL  0,0
+
+kt227          TOKTBL  'O',kt228
+               TOKTBL  0,0
+
+kt228          TOKTBL  'C',0,tok_endproc
+               TOKTBL  0,0
+
+kt4            TOKTBL  'A',kt229
+               TOKTBL  'E',kt230
+               TOKTBL  'I',kt231
+               TOKTBL  'O',kt232
+               TOKTBL  0,0
+
+kt232          TOKTBL  'W',kt233
+               TOKTBL  0,0
+
+kt233          TOKTBL  'N',kt234
+               TOKTBL  0,0
+
+kt234          TOKTBL  'L',kt235
+               TOKTBL  0,0
+
+kt235          TOKTBL  'O',kt236
+               TOKTBL  0,0
+
+kt236          TOKTBL  'A',kt237
+               TOKTBL  0,0
+
+kt237          TOKTBL  'D',0,tok_download
+               TOKTBL  0,0
+
+kt231          TOKTBL  'V',0,tok_div
+               TOKTBL  'M',0,tok_dim
+               TOKTBL  0,0
+
+kt230          TOKTBL  'F',0,tok_def
+               TOKTBL  0,0
+
+kt229          TOKTBL  'T',kt238
+               TOKTBL  0,0
+
+kt238          TOKTBL  'A',0,tok_data
+               TOKTBL  0,0
+
+kt3            TOKTBL  'A',kt239
+               TOKTBL  'H',kt240
+               TOKTBL  'L',kt241
+               TOKTBL  0,0
+
+kt241          TOKTBL  'O',kt242
+               TOKTBL  'S',0,tok_cls
+               TOKTBL  0,0
+
+kt242          TOKTBL  'S',kt243
+               TOKTBL  0,0
+
+kt243          TOKTBL  'E',0,tok_close
+               TOKTBL  0,0
+
+kt240          TOKTBL  'A',kt244
+               TOKTBL  'R',kt245
+               TOKTBL  0,0
+
+kt245          TOKTBL  '$',0,tok_chrS
+               TOKTBL  0,0
+
+kt244          TOKTBL  'I',kt246
+               TOKTBL  0,0
+
+kt246          TOKTBL  'N',0,tok_chain
+               TOKTBL  0,0
+
+kt239          TOKTBL  'R',kt247
+               TOKTBL  'S',kt248
+               TOKTBL  'L',kt249
+               TOKTBL  0,0
+
+kt249          TOKTBL  'L',0,tok_call
+               TOKTBL  0,0
+
+kt248          TOKTBL  'E',0,tok_case
+               TOKTBL  0,0
+
+kt247          TOKTBL  'R',kt250
+               TOKTBL  0,0
+
+kt250          TOKTBL  'I',kt251
+               TOKTBL  0,0
+
+kt251          TOKTBL  'E',kt252
+               TOKTBL  0,0
+
+kt252          TOKTBL  'R',0,tok_carrier
+               TOKTBL  0,0
+
+kt2            TOKTBL  'E',kt253
+               TOKTBL  'G',kt254
+               TOKTBL  'O',kt255
+               TOKTBL  'P',kt256
+               TOKTBL  'R',kt257
+               TOKTBL  0,0
+
+kt257          TOKTBL  'E',kt258
+               TOKTBL  0,0
+
+kt258          TOKTBL  'A',kt259
+               TOKTBL  0,0
+
+kt259          TOKTBL  'K',0,tok_break
+               TOKTBL  0,0
+
+kt256          TOKTBL  'U',kt260
+               TOKTBL  0,0
+
+kt260          TOKTBL  'T',0,tok_bput
+               TOKTBL  0,0
+
+kt255          TOKTBL  'T',kt261
+               TOKTBL  0,0
+
+kt261          TOKTBL  'H',0,tok_both
+               TOKTBL  0,0
+
+kt254          TOKTBL  'E',kt262
+               TOKTBL  0,0
+
+kt262          TOKTBL  'T',0,tok_bget
+               TOKTBL  0,0
+
+kt253          TOKTBL  'E',kt263
+               TOKTBL  0,0
+
+kt263          TOKTBL  'P',0,tok_beep
+               TOKTBL  0,0
+
+kt1            TOKTBL  'N',kt264
+               TOKTBL  'B',kt265
+               TOKTBL  'S',kt266
+               TOKTBL  0,0
+
+kt266          TOKTBL  'C',0,tok_asc
+               TOKTBL  0,0
+
+kt265          TOKTBL  'S',0,tok_abs
+               TOKTBL  0,0
+
+kt264          TOKTBL  'D',0,tok_and
+               TOKTBL  0,0
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/tokenise b/StraySrc/Libraries/Sapphire/sail/_sh/tokenise
new file mode 100644 (file)
index 0000000..8c3db02
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; tokenise.sh
+;
+; Tokenise a Termite script
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  tokenise
+
+               [       :LNOT::DEF:tokenise__dfn
+               GBLL    tokenise__dfn
+
+; --- tokenise ---
+;
+; On entry:    R11 == pointer to Termite upcall block
+;              R12 == pointer to script anchor
+;
+; On exit:     May return an error
+;
+; Use:         Tokenises a Termite script into an output buffer.
+
+               IMPORT  tokenise
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/tokens b/StraySrc/Libraries/Sapphire/sail/_sh/tokens
new file mode 100644 (file)
index 0000000..3a3067c
--- /dev/null
@@ -0,0 +1,156 @@
+;
+; tokens.sh
+;
+; Define constants for the tokens (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:tokens__dfn
+               GBLL    tokens__dfn
+
+               ^       &80
+tok_and                #       1
+tok_abs                #       1
+tok_asc                #       1
+tok_beep       #       1
+tok_bget       #       1
+tok_both       #       1
+tok_bput       #       1
+tok_break      #       1
+tok_carrier    #       1
+tok_case       #       1
+tok_chain      #       1
+tok_chrS       #       1
+tok_close      #       1
+tok_cls                #       1
+tok_call       #       1
+tok_data       #       1
+tok_def                #       1
+tok_div                #       1
+tok_dim                #       1
+tok_download   #       1
+tok_end                #       1
+tok_endproc    #       1
+tok_endwhile   #       1
+tok_endif      #       1
+tok_endcase    #       1
+tok_else       #       1
+tok_eval       #       1
+tok_error      #       1
+tok_errorS     #       1
+tok_eof                #       1
+tok_eor                #       1
+tok_exec       #       1
+tok_ext                #       1
+tok_for                #       1
+tok_false      #       1
+tok_finish     #       1
+tok_finished   #       1
+tok_fn         #       1
+tok_goto       #       1
+tok_getS       #       1
+tok_gosub      #       1
+tok_hangup     #       1
+tok_if         #       1
+tok_instr      #       1
+tok_lclear     #       1
+tok_lecho      #       1
+tok_leftS      #       1
+tok_len                #       1
+tok_let                #       1
+tok_linkey     #       1
+tok_linkeyS    #       1
+tok_linput     #       1
+tok_lget       #       1
+tok_lgetS      #       1
+tok_local      #       1
+tok_lnewlineS  #       1
+tok_log                #       1
+tok_midS       #       1
+tok_mod                #       1
+tok_newsession #       1
+tok_next       #       1
+tok_not                #       1
+tok_of         #       1
+tok_off                #       1
+tok_on         #       1
+tok_or         #       1
+tok_openin     #       1
+tok_openout    #       1
+tok_openup     #       1
+tok_oscli      #       1
+tok_otherwise  #       1
+tok_ptr                #       1
+tok_proc       #       1
+tok_rclear     #       1
+tok_return     #       1
+tok_repeat     #       1
+tok_read       #       1
+tok_recho      #       1
+tok_rem                #       1
+tok_remote     #       1
+tok_report     #       1
+tok_restore    #       1
+tok_rightS     #       1
+tok_rinkey     #       1
+tok_rinkeyS    #       1
+tok_rinput     #       1
+tok_rnd                #       1
+tok_rget       #       1
+tok_rgetS      #       1
+tok_rnewlineS  #       1
+tok_step       #       1
+tok_sgn                #       1
+tok_spool      #       1
+tok_strS       #       1
+tok_stringS    #       1
+tok_swap       #       1
+tok_sys                #       1
+tok_syscall    #       1
+tok_then       #       1
+tok_time       #       1
+tok_timeS      #       1
+tok_to         #       1
+tok_true       #       1
+tok_until      #       1
+tok_upload     #       1
+tok_val                #       1
+tok_wait       #       1
+tok_watch      #       1
+tok_watchfor   #       1
+tok_while      #       1
+tok_when       #       1
+tok_LE         #       1
+tok_LG         #       1
+tok_GE         #       1
+tok_LL         #       1
+tok_GG         #       1
+tok_GGG                #       1
+tok_DT         #       1
+tok_DD         #       1
+tok_PE         #       1
+tok_ME         #       1
+tok_TE         #       1
+tok_DE         #       1
+
+               ^       1
+tClass_andOp   #       1
+tClass_fn      #       1
+tClass_instr   #       1
+tClass_streamOp        #       1
+tClass_option  #       1
+tClass_pseud   #       1
+tClass_multOp  #       1
+tClass_orOp    #       1
+tClass_odd     #       1
+tClass_multArg #       1
+tClass_noise   #       1
+tClass_relOp   #       1
+tClass_addOp   #       1
+tClass_assign  #       1
+tClass_powOp   #       1
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/tree b/StraySrc/Libraries/Sapphire/sail/_sh/tree
new file mode 100644 (file)
index 0000000..a79401e
--- /dev/null
@@ -0,0 +1,66 @@
+;
+; tree.sh
+;
+; Another attempt at symbol table management
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  tree_add
+;  tree_find
+;  str_cmp
+
+               [       :LNOT::DEF:tree__dfn
+               GBLL    tree__dfn
+
+; --- tree_add ---
+;
+; On entry:    R0 == type number
+;              R1 == address of name
+;              R2 == size of user data
+;
+; On exit:     R0 == address of user data in new node
+;              CS if node already exists, else CC
+;              May return an error
+;
+; Use:         Adds a node into a symbol table tree.
+
+               IMPORT  tree_add
+
+; --- tree_find ---
+;
+; On entry:    R0 == type number
+;              R1 == pointer to the name
+;
+; On exit:     CS if the variable was found, and
+;                R0 == pointer to the variable block
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Tries to find a node with the given type and name in
+;              the symbol tree.
+
+               IMPORT  tree_find
+
+; --- str_cmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         Case-sensitively compares two strings.  You can use the
+;              normal ARM condition codes after the compare, so you can
+;              treat this fairly much like a normal CMP.
+
+               IMPORT  str_cmp
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/upcalls b/StraySrc/Libraries/Sapphire/sail/_sh/upcalls
new file mode 100644 (file)
index 0000000..ad450b1
--- /dev/null
@@ -0,0 +1,112 @@
+;
+; termScript.sh
+;
+; Definitions for the Termite script interface
+;
+; © 1995 Straylight
+;
+
+;----- Termite entry points -------------------------------------------------
+
+                       ^       0
+termite_makeBeep       #       4               ;Bleep at the user
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_sendRemote     #       4               ;Send data to serial port
+                                               ;Entry: R2 == ptr to block
+                                               ;       R3 == size of block
+                                               ;Exit:  --
+
+termite_reportMessage  #       4               ;Report non-multitaskingly
+                                               ;Entry: R0 == ptr to message
+                                               ;Exit:  --
+
+termite_printMessage   #       4               ;Report multitaskingly
+                                               ;Entry: R0 == ptr to message
+                                               ;Exit:  --
+
+termite_sendLocal      #       4               ;Queue bogus input data
+                                               ;Entry: R2 == ptr to block
+                                               ;       R3 == size (0-256)
+                                               ;Exit:  --
+
+termite_logFileAdd     #       4               ;Add to session log
+                                               ;Entry: R0 == ptr to message
+                                               ;Exit:  --
+
+termite_clearScreen    #       4               ;Clear session window
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_downLoad       #       4               ;Download file or files
+                                               ;Entry: R2 == protocol name
+                                               ;       R3 == dir/file, or 0
+                                               ;Exit:  --
+
+termite_upLoad         #       4               ;Upload file or files
+                                               ;Entry: R2 == protocol name
+                                               ;       R3 == list of files
+                                               ;Exit:  --
+
+termite_checkCarrier   #       4               ;Checks for a carrier
+                                               ;Entry: --
+                                               ;Exit:  R0 == 0 if no carrier
+
+termite_sysCall                #       4               ;Performs a SWI
+                                               ;Entry: R0-R8 params 2-10
+                                               ;       R9 param 1
+                                               ;Exit: ???
+
+termite_readRemote     #       4               ;Gets a byte from the buffer
+                                               ;Entry: --
+                                               ;Exit:  R0 == byte, or -1
+
+termite_readLocal      #       4               ;Gets a byte from the buffer
+                                               ;Entry: --
+                                               ;Exit:  R0 == byte, or -1
+
+termite_clearRemote    #       4               ;Clears the input buffer
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_clearLocal     #       4               ;Clears the input buffer
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_sendBreak      #       4               ;Sends a break to the modem
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_dropCarrier    #       4               ;Drops the carrier
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_finishSession  #       4               ;Finishes the current session
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_newSession     #       4               ;Createsa new session
+                                               ;Entry: R0 == base style name
+                                               ;       R1 == style name
+                                               ;       R2 == see spec!
+                                               ;Exit:  --
+
+termite_checkFinished  #       4               ;Check the session is finish
+                                               ;Entry: --
+                                               ;Exit:  R0 == not, 1 == is
+
+termite_sysNumString   #       4               ;Convert string to number
+                                               ;Entry: R9 == SYSCALL string
+                                               ;Exit:  SYSCALL number, or VS
+
+               MACRO
+$label         TCALL   $call
+$label         MOV     R14,PC
+               ADD     PC,R11,#$call
+               MEND
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
+
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/value b/StraySrc/Libraries/Sapphire/sail/_sh/value
new file mode 100644 (file)
index 0000000..31abf60
--- /dev/null
@@ -0,0 +1,74 @@
+;
+; value.sh
+;
+; r/value evaluation
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  val_readExp
+;  val__readP1
+;  val_readLvalue
+
+               [       :LNOT::DEF:value__dfn
+               GBLL    value__dfn
+
+; --- val_readExp ---
+;
+; On entry:    R8 == lookahead token
+;              R9 == current line number
+;              R10 == pointer into the tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor block pointer
+;
+; On exit:     R0 == value of the rvalue
+;              R1 == type of the variable
+;              R8 == new lookahead token
+;              R11 == moved on to the first character after the rvalue
+;              May return an error
+;
+; Use:         Tries to read an rvalue from the current program location.
+
+               IMPORT  val_readExp
+
+; --- val__readP1 ---
+;
+; On entry:    R9 == current line number
+;              R10 == pointer into the tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor block pointer
+;
+; On exit:     R0 == next character to look at
+;
+; Use:         Evaluates a precedence 4 type expression and store the
+;              result on the stack.  The first unused character is
+;              placed in R0.
+
+               IMPORT  val__readP1
+
+; --- val_readLvalue ---
+;
+; On entry:    R7 == 0 to read as an rvalue, 1 for lvalue
+;              R8 == next token to read
+;              R9 == current line number
+;              R10 == pointer into the tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor block pointer
+;
+; On exit:     R0 == pointer to the variable block if R7 == 1
+;              R8 == new next token to read
+;              May return an error
+;
+; Use:         Tries to read an lvalue from the current program location.
+
+               IMPORT  val_readLvalue
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/_sh/var b/StraySrc/Libraries/Sapphire/sail/_sh/var
new file mode 100644 (file)
index 0000000..65afd97
--- /dev/null
@@ -0,0 +1,76 @@
+;
+; var.sh
+;
+; Variable handling
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  var_create
+;  var_find
+
+               [       :LNOT::DEF:var__dfn
+               GBLL    var__dfn
+
+; --- var_create ---
+;
+; On entry:    R0 == type of variable
+;              R1 == pointer to variable name
+;              R2 == file address of label or DEF
+;              R3 == line number of label or DEF
+;              R12 == pointer to the anchor block
+;
+; On exit:     R0 == pointer to the variable
+;              May return an error
+;
+; Use:         Tries to find the variable given, and return a pointer
+;              to it if it is found. Otherwise it will try to create the
+;              variable and return a pointer to the new one.
+
+               IMPORT  var_create
+
+; --- var_find ---
+;
+; On entry:    R0 == type of the variable
+;              R1 == name of the variable
+;
+; On exit:     CS if the variable was found, and
+;                R0 == pointer to the variable block
+;              CC otherwise
+;
+; Use:         Tries to find the given variable in the current tree.
+
+               IMPORT  var_find
+
+;----- Workspace ------------------------------------------------------------
+
+               ; --- Variable types ---
+
+               ^       0
+vType_integer  #       1                       ;Integer
+vType_string   #       1                       ;String
+vType_dimInt   #       1                       ;DIM of integers
+vType_dimStr   #       1                       ;DIM of strings
+vType_label    #       1                       ;Label
+vType_proc     #       1                       ;Procedure name
+vType_fn       #       1                       ;Function name
+
+               ; --- Lvalue types ---
+
+vType_lvInt    #       1                       ;Integer variable lvalue
+vType_lvString #       1                       ;String variable lvalue
+vType_lvWord   #       1                       ;Word lvalue (from `!' op)
+vType_lvByte   #       1                       ;Byte lvalue (from `?' op)
+vType_lvBytes  #       1                       ;String lvalue (from `$' op)
+vType_lvIntArr #       1                       ;Integer array lvalue
+vType_lvStrArr #       1                       ;String array lvalue
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/errgen,ffb b/StraySrc/Libraries/Sapphire/sail/errgen,ffb
new file mode 100644 (file)
index 0000000..597fb8f
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/sail/errgen,ffb differ
diff --git a/StraySrc/Libraries/Sapphire/sail/s/ctrl b/StraySrc/Libraries/Sapphire/sail/s/ctrl
new file mode 100644 (file)
index 0000000..caac640
--- /dev/null
@@ -0,0 +1,3222 @@
+;
+; ctrl.s
+;
+; Control flow handling
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.divide
+               GET     sh.errNum
+               GET     sh.error
+               GET     sh.express
+               GET     sh.getToken
+               GET     sh.interp
+               GET     sh.mem
+               GET     sh.stracc
+               GET     sh.strBucket
+               GET     sh.termite
+               GET     sh.termscript
+               GET     sh.tokens
+               GET     sh.tree
+               GET     sh.var
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+;----- Execution stack handling ---------------------------------------------
+
+; --- ctrl__pushFrame ---
+;
+; On entry:    R0 == type of frame to create
+;
+; On exit:     R0 == address of frame data to fill in
+;
+; Use:         Creates a new frame of the given type on the execution stack.
+
+ctrl__pushFrame        ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+               MOV     R3,R0                   ;Look after thing to push
+               ADR     R14,ctrl__frSize        ;Point to frame size table
+               LDRB    R4,[R14,R3]             ;Load the frame size
+               ADR     R1,sail_execStack       ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               ADD     R5,R1,R4                ;New used size
+               ADD     R1,R5,#255              ;Align to next size thing
+               BIC     R1,R1,#255              ;Finish the align
+               CMP     R1,R2                   ;Has it got too big?
+               BLGT    mem_realloc             ;Yes -- get more space then
+               STRGT   R1,sail_execStkSize     ;Store new size maybe
+               STR     R5,sail_execStkPtr      ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R0,R0,R5                ;Address to put next thing on
+               STR     R3,[R0,#-4]             ;Store the new frame type
+               SUB     R0,R0,R4                ;And return frame base addr
+               LDMFD   R13!,{R1-R5,PC}^        ;And return to caller
+
+               LTORG
+
+; --- ctrl__peekFrame ---
+;
+; On entry:    --
+;
+; On exit:     R0 == type of topmost frame
+;              R1 == base address of frame
+;
+; Use:         Returns the type of the topmost frame, so a routine can
+;              work out if it needs to be removed.
+
+ctrl__peekFrame        ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               ADR     R0,sail_execStack       ;Point to stack info block
+               LDMIA   R0,{R0,R1}              ;Load anchor addr and sp
+               LDR     R0,[R0]                 ;WimpExt_Heap's oddness again
+               ADD     R14,R0,R1               ;Find top of the stack
+               LDR     R0,[R14,#-4]            ;Load the frame type
+               ADR     R1,ctrl__frSize         ;Find the frame size table
+               LDRB    R1,[R1,R0]              ;Load the size of this entry
+               SUB     R1,R14,R1               ;Find base of this frame
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- ctrl__popFrame ---
+;
+; On entry:    --
+;
+; On exit:     R0 == frame type
+;              R1 == base address of frame
+;
+; Use:         Pops the top stack frame off the execution stack.  A pointer
+;              to the frame's data is returned; this data is *still on
+;              the stack*, so be careful about pushing more on.
+
+ctrl__popFrame ROUT
+
+               STMFD   R13!,{R2-R5,R14}        ;Save some registers
+               ADR     R1,sail_execStack       ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+               LDR     R14,[R0]                ;Load the actual base address
+               ADD     R14,R14,R1              ;Find the top of the stack
+               LDR     R3,[R14,#-4]            ;Load type of top frame
+               ADR     R14,ctrl__frSize        ;Point to frame size table
+               LDRB    R5,[R14,R3]             ;And get the frame size
+
+               SUB     R4,R1,R5                ;The new size
+               ADD     R1,R4,#255              ;Align up again
+               BIC     R1,R1,#255              ;Aligned down
+               ADD     R1,R1,#256              ;At more than we need
+               CMP     R1,R2                   ;Has this size changed?
+               BLLT    mem_realloc             ;Yes -- reduce memory reqs.
+               STRLT   R1,sail_execStkSize     ;Store new size maybe
+               STR     R4,sail_execStkPtr      ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R1,R0,R4                ;Find the frame base address
+               MOV     R0,R3                   ;And get the frame type
+               LDMFD   R13!,{R2-R5,PC}^        ;And return to caller
+
+               LTORG
+
+ctrl__frSize   DCB     cFor__size+4
+               DCB     cWhile__size+4
+               DCB     cRepeat__size+4
+
+               DCB     cGosub__size+4
+               DCB     cLocal__size+4
+               DCB     cReturn__size+4
+               DCB     cProc__size+4
+               DCB     cFn__size+4
+               DCB     cDead__size+4
+
+;----- Command handlers -----------------------------------------------------
+
+; --- ctrl_let ---
+
+               EXPORT  ctrl_let
+ctrl_let       ROUT
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Leave that on the stack
+               CMP     R9,#'='                 ;Is this an assignment op?
+               BNE     %10ctrl_let             ;No -- maybe more complex
+               BL      getToken                ;Get another token
+               MOV     R0,#0                   ;Read a general expression
+               BL      express_read            ;Read that nicely
+
+               BL      express_popTwo          ;Pop two values off the stack
+               BL      ctrl_store              ;Stuff one into the other
+               B       interp_next             ;Move on to next instruction
+
+               ; --- Try other assignment ops then ---
+
+10             CMP     R7,#tClass_assign       ;Is it an assign op?
+               MOVNE   R0,#err_mistake         ;No -- that's a mistake
+               BNE     error_report            ;So complain at someone
+
+               ; --- Read the rvalue ---
+
+               MOV     R6,R8                   ;Look after the index
+               BL      getToken                ;Get another token
+               BL      express_pop             ;Pop off the lvalue
+               BL      ctrl_load               ;Load it's value
+               STMFD   R13!,{R0,R1}            ;Look after the lvalue
+               MOV     R0,#0                   ;Read a general expression
+               BL      express_read            ;Read that nicely
+               BL      express_pop             ;Pop the rvalue
+               MOV     R4,R0                   ;Look after rvalue
+               MOV     R5,R1
+               LDMFD   R13!,{R0,R1}            ;Load the lvalue back
+
+               ADD     PC,PC,R6,LSL #2         ;Jump to the right routine
+               DCB     "TMA!"
+
+               B       %20ctrl_let             ;+=
+               B       %30ctrl_let             ;-=
+               B       %40ctrl_let             ;*=
+               B       %50ctrl_let             ;/=
+
+               ; --- The operations ---
+               ;
+               ; Addition.
+
+20             CMP     R3,#vType_string
+               BEQ     %25ctrl_let
+               CMP     R3,#vType_integer
+               MOVNE   R0,#err_arrayBad
+               BNE     error_report
+               CMP     R5,#vType_integer
+               MOVNE   R0,#err_numNeeded
+               BNE     error_report
+               ADD     R2,R2,R4
+               BL      ctrl_store
+               B       interp_next
+
+25             CMP     R5,#vType_string        ;This is a string I hope
+               MOVNE   R0,#err_strNeeded       ;No -- get error number
+               BNE     error_report            ;...and report the error
+
+               MOV     R14,R4,LSL #24          ;Get the second string len
+               CMN     R14,R2,LSL #24          ;Is the string short enough?
+               ADDCC   R2,R2,R14,LSR #24       ;Add on second length
+               BLCC    ctrl_store
+               BCC     interp_next
+
+               MOV     R0,#err_strTooLong      ;String is too long
+               B       error_report
+
+               ; --- Subtraction ---
+
+30             CMP     R3,#vType_integer
+               CMPEQ   R5,#vType_integer
+               MOVNE   R0,#err_numNeeded
+               BNE     error_report
+               SUB     R2,R2,R4
+               BL      ctrl_store
+               B       interp_next
+
+               ; --- Multiplication ---
+
+40             CMP     R3,#vType_integer
+               CMPEQ   R5,#vType_integer
+               MOVNE   R0,#err_numNeeded
+               BNE     error_report
+               MUL     R2,R4,R2
+               BL      ctrl_store
+               B       interp_next
+
+               ; --- Division ---
+
+50             CMP     R3,#vType_integer
+               CMPEQ   R5,#vType_integer
+               MOVNE   R0,#err_numNeeded
+               BNE     error_report
+               STMFD   R13!,{R0,R1}
+               MOV     R0,R2
+               MOV     R1,R4
+               BL      divide
+               MOV     R2,R0
+               LDMFD   R13!,{R0,R1}
+               BL      ctrl_store
+               B       interp_next
+
+               LTORG
+
+; --- ctrl_timeEq ---
+
+               EXPORT  ctrl_timeEq
+ctrl_timeEq    ROUT
+
+               CMP     R9,#'='                 ;Next char must be `='
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the equals sign
+               MOV     R0,#0                   ;Read the expression
+               BL      express_read
+               BL      express_pop             ;Pop the result
+               CMP     R1,#vType_integer       ;It must be an integer
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+               MOV     R1,R0                   ;Look after this result
+               SWI     OS_ReadMonotonicTime    ;Find the current real time
+               SUB     R0,R0,R1                ;Work out the correct offset
+               STR     R0,sail_timeOff         ;Store it away nicely
+               B       interp_next             ;And read another instruction
+
+               LTORG
+
+; --- ctrl_for ---
+
+               EXPORT  ctrl_for
+ctrl_for       ROUT
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Leave that on the stack
+               CMP     R9,#'='                 ;We now need an equals
+               MOVNE   R0,#err_eqInFor         ;If we don't have it, moan
+               BNE     error_report
+               BL      getToken                ;Skip over the equals sign
+               MOV     R0,#0                   ;Read the base value
+               BL      express_read
+               CMP     R9,#tok_to              ;Make sure we have a TO
+               MOVNE   R0,#err_expTo           ;If we don't have it, moan
+               BNE     error_report
+               BL      getToken                ;Skip over the TO token
+               MOV     R0,#0                   ;Read the end value
+               BL      express_read
+               CMP     R9,#tok_step            ;Is there a STEP?
+               BLEQ    getToken                ;Yes -- get another token
+               MOVEQ   R0,#0                   ;...read another rvalue
+               BLEQ    express_read
+               BLEQ    express_pop             ;...and get this value
+               MOVNE   R0,#1                   ;Otherwise use sensible value
+               MOVNE   R1,#vType_integer
+
+               ; --- Create the stack frame ---
+
+               STMFD   R13!,{R0,R1}            ;Save step again for a bit
+               MOV     R0,#cFrame__for         ;Create a FOR loop frame
+               BL      ctrl__pushFrame         ;Stick that on the stack
+               MOV     R4,R0                   ;Look after the frame pointer
+               LDMFD   R13!,{R0,R1}            ;Load the step value again
+               CMP     R1,#vType_integer       ;Check it's an integer
+               BNE     ctrl__notAnInt          ;If not, complain
+               STR     R0,[R4,#cFor__step]     ;Save the step away
+
+               BL      express_pop             ;Find the end marker
+               CMP     R1,#vType_integer       ;Check it's an integer
+               BNE     ctrl__notAnInt          ;If not, complain
+               STR     R0,[R4,#cFor__end]      ;Stuff that in the end pos
+
+               BL      express_popTwo          ;Get ctrl var and start pos
+               CMP     R1,#vType_lvInt         ;Ensure lvalue is integral
+               CMPNE   R1,#vType_lvWord
+               CMPNE   R1,#vType_lvByte
+               MOVNE   R0,#err_badForVar       ;If not, find suitable error
+               BNE     error_report            ;And tell the user
+               BL      ctrl_store              ;Initialise it nicely
+               ADD     R14,R4,#cFor__lval      ;Find the lvalue position
+               STMIA   R14,{R0,R1}             ;Save that away too
+
+               ADD     R14,R4,#cFor__resume    ;Point to resume buffer
+               LDR     R1,sail_tokAnchor       ;Find anchor of script buff
+               LDR     R1,[R1]                 ;SODDING WIMPEXTENSION!!!
+               SUB     R1,R10,R1               ;Work out current offset
+               LDR     R0,sail_line            ;Get the current line number
+               STMIA   R14,{R0,R1}             ;Save these in the frame
+
+               B       interp_next             ;Move on to next instruction
+
+               LTORG
+
+; --- ctrl_next ---
+
+               EXPORT  ctrl_next
+ctrl_next      ROUT
+
+               ; --- First check for identifier ---
+               ;
+               ; If there is one, we need to search for a specific FOR
+               ; frame.  Otherwise any old one will do.
+
+               SUBS    R14,R9,#'_'             ;Is this an identifier?
+               SUBNE   R14,R9,#'A'             ;No -- check for uppercase
+               CMP     R14,#26
+               SUBCS   R14,R9,#'a'             ;No -- check for lowercase
+               CMPCS   R14,#26
+
+               ; --- Read the lvalue given ---
+
+               MOVCC   R0,#1                   ;Read an lvalue
+               BLCC    express_read            ;And put it on the stack
+               BLCC    express_pop             ;Get it in registers
+               MOVCS   R1,#-1                  ;Otherwise get bogus value
+               MOV     R2,R0                   ;Look after the lvalue
+               MOV     R3,R1                   ;And the type
+10             MOV     R0,#cFrame__for         ;Look for a FOR frame
+               BL      ctrl__findFrame         ;Try to find the frame
+               MOVCC   R0,#err_noFor           ;Complain if we hit routine
+               BCC     error_report
+               ADD     R14,R1,#cFor__lval      ;Find the lvalue
+               LDMIA   R1,{R4,R5}              ;Load them out nicely
+               CMP     R2,R4                   ;Now check for a match
+               CMPEQ   R3,R5                   ;Check the type too
+               CMPNE   R3,#-1                  ;Or maybe we don't care
+               BLNE    ctrl__popFrame          ;No match -- discard frame
+               BNE     %10ctrl_next            ;And loop back round
+
+               ; --- Now step the variable ---
+
+               MOV     R6,R1                   ;Look after frame base
+               MOV     R0,R4                   ;Get the original lvalue back
+               MOV     R1,R5                   ;And its type
+               BL      ctrl_load               ;Load the current value
+               LDR     R4,[R6,#cFor__step]     ;Load the step size
+               ADD     R2,R2,R4                ;Bump the loop counter
+               BL      ctrl_store              ;Save the modified counter
+               LDR     R14,[R6,#cFor__end]     ;Find the end limit
+               CMP     R4,#0                   ;Are we going backwards?
+               SUBGT   R14,R2,R14              ;Yes -- subtract this way
+               SUBLT   R14,R14,R2              ;Otherwise the other way
+               CMP     R14,#0                  ;Now which way do we go?
+               BGT     %50ctrl_next            ;Finished the loop -- stop
+
+               ; --- Now resume from the FOR loop ---
+
+               ADD     R14,R6,#cFor__resume    ;Find the resume point
+               LDMIA   R14,{R0,R1}             ;Load the line and offset
+               STR     R0,sail_line            ;Save the line counter
+               LDR     R14,sail_tokAnchor      ;Find the anchor of the file
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R1              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrack to read prev token
+               MOV     R9,#0                   ;Give bogus current token
+               BL      getToken                ;Read this token
+               B       interp_next             ;And continue merrily
+
+               ; --- Now see if there's more loops to close ---
+
+50ctrl_next    BL      ctrl__popFrame          ;Remove defunct FOR frame
+               CMP     R9,#','                 ;Do we have more loops?
+               BLEQ    getToken                ;Yes -- skip the comma
+               BEQ     ctrl_next               ;And close them too
+
+               B       interp_next             ;Finished this instruction
+
+               LTORG
+
+; --- ctrl_repeat ---
+
+               EXPORT  ctrl_repeat
+ctrl_repeat    ROUT
+
+               MOV     R0,#cFrame__repeat      ;Create a REPEAT frame
+               BL      ctrl__pushFrame         ;Stick that on the stack
+               LDR     R2,sail_tokAnchor       ;Find anchor of script buff
+               LDR     R2,[R2]                 ;SODDING WIMPEXTENSION!!!
+               SUB     R2,R10,R2               ;Work out current offset
+               LDR     R1,sail_line            ;Get the current line number
+               STMIA   R0,{R1,R2}              ;Save these in the frame
+               B       interp_exec             ;Get the next instruction
+
+               LTORG
+
+; --- ctrl_until ---
+
+               EXPORT  ctrl_until
+ctrl_until     ROUT
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read an expression
+               BL      express_pop             ;Read it then
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- complain then
+               MOV     R2,R0                   ;Look after the result
+
+               ; --- Find the REPEAT frame ---
+
+               MOV     R0,#cFrame__repeat      ;Look for a REPEAT frame
+               BL      ctrl__findFrame         ;Try to find the frame
+               MOVCC   R0,#err_noRepeat        ;Complain if we hit routine
+               BCC     error_report
+
+               CMP     R2,#0                   ;Should we REPEAT?
+               BLNE    ctrl__popFrame          ;No -- pop the repeat frame
+               BNE     interp_next             ;No -- just continue then
+
+               ; --- Go back to the REPEAT ---
+
+               LDMIA   R1,{R0,R1}              ;Load the line and offset
+               STR     R0,sail_line            ;Save the line counter
+               LDR     R14,sail_tokAnchor      ;Find the anchor of the file
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R1              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrack to read prev token
+               MOV     R9,#-1                  ;Give bogus current token
+               BL      getToken                ;Read this token
+               B       interp_exec             ;And continue merrily
+
+               LTORG
+
+; --- ctrl_while ---
+
+               EXPORT  ctrl_while
+ctrl_while     ROUT
+
+               ; --- Push a while frame on the stack ---
+
+               MOV     R0,#cFrame__while       ;Create a REPEAT frame
+               BL      ctrl__pushFrame         ;Stick that on the stack
+               LDR     R2,sail_tokAnchor       ;Find anchor of script buff
+               LDR     R2,[R2]                 ;SODDING WIMPEXTENSION!!!
+               SUB     R2,R10,R2               ;Work out current offset
+               LDR     R1,sail_line            ;Get the current line number
+               STMIA   R0,{R1,R2}              ;Save these in the frame
+
+               ; --- Read the expression ---
+
+               MOV     R0,#0                   ;Read an expression
+               BL      express_read            ;Read it ithen
+               BL      express_pop             ;Pop the resut
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- that's bad then
+               CMP     R0,#0                   ;Is is FALSE?
+               BNE     interp_exec             ;No -- continue then
+
+               ; --- Scan for the first ENDWHILE then ---
+
+               MOV     R2,#0                   ;Keep a nesting count
+               LDR     R4,sail_line            ;Get current line number
+10ctrl_while   BL      getToken                ;Get another token
+               CMP     R9,#&FF                 ;Reached the end yet?
+               BEQ     %90ctrl_while           ;If so, moan about ENDWHILE
+               CMP     R9,#tok_while           ;Is it a WHILE token?
+               ADDEQ   R2,R2,#1                ;Yes -- bump nesting count
+
+               CMP     R9,#tok_endwhile        ;Yes -- check for ENDWHILE
+               SUBEQ   R2,R2,#1                ;Yes -- decrement nesting
+               CMP     R2,#0                   ;Have we dropped out?
+               BGE     %10ctrl_while           ;No -- loop
+
+               ; --- We found the ENDWHILE ---
+
+               BL      getToken                ;Get the next token
+               BL      ctrl__popFrame          ;Get rid of my WHILE frame
+               B       interp_next             ;And execute from here
+
+               ; --- We fell off the end -- oops ---
+
+90ctrl_while   STR     R4,sail_line            ;Save bogus line back
+               MOV     R0,#err_expEndwhile     ;Hmm... should have had an...
+               B       error_report            ;ENDWHILE somewhere
+
+               LTORG
+
+; --- ctrl_endwhile ---
+
+               EXPORT  ctrl_endwhile
+ctrl_endwhile  ROUT
+
+               ; --- Find the ENDWHILE frame ---
+
+               MOV     R0,#cFrame__while       ;Look for a REPEAT frame
+               BL      ctrl__findFrame         ;Try to find the frame
+               MOVCC   R0,#err_noWhile         ;Complain if we hit routine
+               BCC     error_report
+
+               ; --- Remember where we are ---
+
+               LDR     R2,sail_line            ;Get the line number
+               MOV     R3,R10                  ;And our position
+
+               ; --- Go back to the WHILE ---
+
+               LDMIA   R1,{R0,R1}              ;Load the line and offset
+               STR     R0,sail_line            ;Save the line counter
+               LDR     R14,sail_tokAnchor      ;Find the anchor of the file
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R1              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrack to read prev token
+               MOV     R9,#-1                  ;Give bogus current token
+               BL      getToken                ;Read this token
+
+               ; --- Now read the expression ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the value
+               CMP     R0,#0                   ;Should we go from here?
+               BNE     interp_exec             ;Yes -- execute then
+
+               ; --- Execute from the ENDWHILE ---
+
+               BL      ctrl__popFrame          ;Pop the WHILE frame
+               SUB     R10,R3,#1               ;Set R10 up
+               STR     R2,sail_line            ;Store the line number
+               MOV     R9,#-1                  ;Make getToken happy
+               BL      getToken                ;Get a token then
+               B       interp_next             ;And execute happily
+
+               LTORG
+
+; --- ctrl__readLabel ---
+;
+; On entry:    --
+;
+; On exit:     CS if there was a label and,
+;                R0 == pointer to the label node
+;                R1, R2 corrupted
+;              CC otherwise
+;
+; Use:         Reads a label fromthe current position, and looks it
+;              up inthe symbol table.
+
+ctrl__readLabel        ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link
+
+               ADR     R2,sail_misc            ;Point to a nice buffer
+               SUBS    R14,R9,#'_'             ;Is it a valid characer?
+               SUBNE   R14,R9,#'A'
+               CMP     R14,#26
+               SUBCS   R14,R9,#'a'
+               CMPCS   R14,#26
+               SUBCS   R14,R9,#'0'
+               CMPCS   R14,#10
+               BCS     %90ctrl__readLabel      ;No -- bark then
+               STRB    R9,[R2],#1              ;And store in the buffer
+
+10             BL      getToken                ;Get the next character
+               SUBS    R14,R9,#'_'             ;Is it a valid characer?
+               SUBNE   R14,R9,#'A'
+               CMP     R14,#26
+               SUBCS   R14,R9,#'a'
+               CMPCS   R14,#26
+               SUBCS   R14,R9,#'0'
+               CMPCS   R14,#10
+               STRCCB  R9,[R2],#1              ;Yes -- store in the buffer
+               BCC     %10ctrl__readLabel      ;...and keep on looping
+
+               MOV     R14,#0
+               STRB    R14,[R2],#1
+
+               ; --- Now find the node ---
+
+               MOV     R0,#vType_label         ;This is a label
+               ADR     R1,sail_misc            ;Point at the name
+               BL      tree_find               ;Try to find it
+               MOVCC   R0,#err_noLabel         ;Not there -- complain
+               BCC     error_report
+
+               LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#C_flag          ;Return 'label here'
+
+               ; --- The label was bad --
+
+90             LDMFD   R13!,{R14}              ;Load the link back
+               BICS    PC,R14,#C_flag          ;Return 'no label'
+
+               LTORG
+
+; --- ctrl_gosub ---
+
+               EXPORT  ctrl_gosub
+ctrl_gosub     ROUT
+
+               ; --- Read the label ---
+
+               BL      ctrl__readLabel         ;Read a label
+               BCC     %90ctrl_gosub           ;No there -- barf
+               MOV     R3,R0                   ;Look after node address
+
+               ; --- Push a GOSUB frame ---
+
+               MOV     R0,#cFrame__gosub       ;Create a REPEAT frame
+               BL      ctrl__pushFrame         ;Stick that on the stack
+               LDR     R2,sail_tokAnchor       ;Find anchor of script buff
+               LDR     R2,[R2]                 ;SODDING WIMPEXTENSION!!!
+               SUB     R2,R10,R2               ;Work out current offset
+               LDR     R1,sail_line            ;Get the current line number
+               STMIA   R0,{R1,R2}              ;Save these in the frame
+
+               ; --- Branch off somewhere ---
+
+               LDMIB   R3,{R0,R1}              ;Load out address/line
+               STR     R1,sail_line            ;Store the line number
+               LDR     R1,sail_tokAnchor       ;Load anchor address
+               LDR     R1,[R1,#0]              ;WimpExtension is bollocks
+               MOV     R9,#-1                  ;Don't confuse getToken
+               ADD     R10,R0,R1               ;This is where we are
+               BL      getToken                ;Prime the lookahead token
+               LDR     R14,sail_flags          ;Load the flags word
+               BIC     R14,R14,#tscFlag_nl     ;Clear the newline flag
+               STR     R14,sail_flags          ;Store the flasg back
+               B       interp_exec             ;Execute from here!
+
+90ctrl_gosub   MOV     R0,#err_expLabel        ;Get the error number
+               B       error_report            ;Report the error
+
+               LTORG
+
+; --- ctrl_return ---
+
+               EXPORT  ctrl_return
+ctrl_return    ROUT
+
+               MOV     R0,#cFrame__gosub       ;Look for a GOSUB frame
+               BL      ctrl__findFrame         ;Try to find the frame
+               MOVCC   R0,#err_notInSub        ;Complain if not a GOSUB
+               BCC     error_report
+               BL      ctrl__popFrame          ;Pop off the frame
+               LDMIA   R1,{R0,R1}              ;Load the line and offset
+               STR     R0,sail_line            ;Save the line counter
+               LDR     R14,sail_tokAnchor      ;Find the anchor of the file
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R1              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrac a little
+               MOV     R9,#-1                  ;Give bogus current token
+               BL      getToken                ;Read this token
+               B       interp_next             ;And continue merrily
+
+; --- ctrl_if ---
+
+               EXPORT  ctrl_if
+ctrl_if                ROUT
+
+               LDR     R14,sail_flags          ;Load the flags word
+               BIC     R14,R14,#tscFlag_nl     ;Clear the newline flag
+               STR     R14,sail_flags          ;Store the flasg back
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read
+               BL      express_pop             ;Get that value
+               CMP     R1,#vType_integer       ;It must be an integer
+               MOVNE   R0,#err_numNeeded       ;Isn't -- get error
+               BNE     error_report            ;And report the error
+               CMP     R0,#0                   ;Should we execute this?
+               BEQ     %10ctrl_if              ;No -- look for the else
+
+               CMP     R9,#tok_then            ;Is there a THEN here?
+               BLEQ    getToken                ;Yes -- skip over it then
+               B       interp_exec             ;And just execute from here
+
+               ; --- Look for an ELSE statement ---
+
+10ctrl_if      CMP     R9,#tok_then            ;Do we have a THEN then?
+               BNE     %30ctrl_if              ;No -- search line for else
+
+               BL      getToken                ;Get another token
+               CMP     R9,#&0a                 ;Is this a return?
+               BNE     %30ctrl_if              ;No -- search line then
+
+               ; --- Now look for ELSE ... ENDIF structure ---
+
+               MOV     R3,#0                   ;My counter thing
+               LDR     R4,sail_line            ;Get the current line
+
+20ctrl_if      MOV     R2,R9                   ;Remmber the previous char
+               BL      getToken                ;Skip over the return
+               CMP     R9,#&FF                 ;Is this the end of file?
+               BEQ     %50ctrl_if              ;Yes -- jump ahead
+               CMP     R2,#&0a                 ;Was prev a newline?
+               CMPNE   R9,#&0a                 ;Or even this one?
+               BNE     %20ctrl_if              ;Neither -- keep looping
+
+               CMP     R2,#tok_then            ;Did we just read a then
+               ADDEQ   R3,R3,#1                ;Yes -- increment the count
+               BEQ     %20ctrl_if              ;And keep on looping
+
+               CMP     R9,#tok_else            ;Or an else?
+               CMPEQ   R3,#0                   ;Yes -- at bottom level?
+               CMPNE   R9,#tok_endif           ;Is this an endif?
+               SUBEQ   R3,R3,#1                ;Yes -- decrement the count
+               CMP     R3,#0                   ;Are we ready to execute?
+               BGE     %20ctrl_if              ;No -- loop then
+
+               BL      getToken                ;Get the next token
+               B       interp_next             ;Execute from here!
+
+               ; --- Search on the same line ---
+
+30ctrl_if      MOV     R0,R9                   ;Look after this char
+               CMP     R9,#&FF                 ;At end of file?
+               BLNE    getToken                ;No -- read next token
+               CMPNE   R0,#tok_else            ;Stop at ELSE tokens
+               CMPNE   R0,#&0a                 ;And at line end
+               BNE     %30ctrl_if              ;If not, loop back again
+               B       interp_exec             ;And carry on going
+
+               ; -- Missing ENDIF ---
+
+50ctrl_if      STR     R4,sail_line            ;Store original line number
+               MOV     R0,#err_expEndif        ;Get the error number
+               B       error_report            ;And report the error
+
+               LTORG
+
+; --- ctrl_else ---
+
+               EXPORT  ctrl_else
+ctrl_else      ROUT
+
+               LDR     R0,sail_flags           ;Load the flags word
+               TST     R0,#tscFlag_nl          ;Have we just had a newline?
+               BNE     %20ctrl_else            ;Yes -- look for an ENDIF
+
+               ; --- Search for the line end ---
+
+10ctrl_else    MOV     R0,R9                   ;Look after old token
+               CMP     R9,#&FF                 ;Is this the EOF
+               BLNE    getToken                ;No - get a token
+               CMP     R0,#&0a                 ;Was it the line end?
+               BNE     %10ctrl_else            ;No -- keep on looking
+               B       interp_next             ;Execute from here
+
+               ; --- Look for an ENDIF ---
+
+20ctrl_else    MOV     R3,#0                   ;My counter thing
+               LDR     R4,sail_line            ;Get the current line
+               MOV     R2,#0                   ;Dummy previous char
+               B       %45ctrl_else
+
+40ctrl_else    MOV     R2,R9                   ;Remember the previous token
+               BL      getToken                ;Get a new one
+45ctrl_else    CMP     R9,#&FF                 ;Is this the end of file?
+               BEQ     %50ctrl_else            ;Yes -- jump ahead
+               CMP     R2,#&0a                 ;Was prev a newline?
+               CMPNE   R9,#&0a                 ;Or even this one?
+               BNE     %40ctrl_else            ;Neither -- keep looping
+
+               CMP     R2,#tok_then            ;Did we just read a then
+               ADDEQ   R3,R3,#1                ;Yes -- increment the count
+               BEQ     %40ctrl_else            ;And keep on looping
+
+               CMP     R9,#tok_endif           ;Is this an endif?
+               SUBEQ   R3,R3,#1                ;Yes -- decrement the count
+               CMP     R3,#0                   ;Are we ready to execute?
+               BGE     %40ctrl_else            ;No -- loop then
+
+               BL      getToken                ;Get the next token
+               B       interp_next             ;Execute from here!
+
+               ; -- Missing ENDIF ---
+
+50ctrl_else    STR     R4,sail_line            ;Store original line number
+               MOV     R0,#err_expEndif        ;Get the error number
+               B       error_report            ;And report the error
+
+               LTORG
+
+; --- ctrl_goto ---
+
+               EXPORT  ctrl_goto
+ctrl_goto      ROUT
+
+               BL      ctrl__readLabel         ;Read the label
+               BCC     %90ctrl_goto            ;Not there -- barf
+
+               LDMIB   R0,{R0,R1}              ;Load out address/line
+               STR     R1,sail_line            ;Store the line number
+               LDR     R1,sail_tokAnchor       ;Load anchor address
+               LDR     R1,[R1,#0]              ;WimpExtension is bollocks
+               MOV     R9,#-1                  ;Don't confuse getToken
+               ADD     R10,R0,R1               ;This is where we are
+               BL      getToken                ;Prime the lookahead token
+               LDR     R14,sail_flags          ;Load the flags word
+               BIC     R14,R14,#tscFlag_nl     ;Clear the newline flag
+               STR     R14,sail_flags          ;Store the flasg back
+               B       interp_exec             ;Execute from here!
+
+90ctrl_goto    MOV     R0,#err_expLabel        ;Get the error number
+               B       error_report            ;Report the error
+
+               LTORG
+
+; --- ctrl_case ---
+
+               EXPORT  ctrl_case
+ctrl_case      ROUT
+
+               MOV     R0,#0                   ;Read the comparand
+               BL      express_read
+               BL      express_pop             ;Read the value of that
+               CMP     R1,#vType_integer       ;Is it an integer?
+               CMPNE   R1,#vType_string        ;Or a string?
+               MOVNE   R0,#err_arrayBad        ;No -- then point to error
+               BNE     error_report            ;And report the error
+               MOV     R2,R0                   ;Look after compare value
+               MOV     R3,R1                   ;And the type too, please
+
+               CMP     R9,#tok_of              ;We pointlessly expect `OF'
+               MOVNE   R0,#err_expOf           ;If not there, complain
+               BNE     error_report
+               BL      getToken                ;Get the next token
+               CMP     R9,#&0A                 ;This must be the line end
+               MOVNE   R0,#err_afterCase       ;If not, complain annoyingly
+               BNE     error_report
+
+               ; --- Now keep an eye out for WHENs and OTHERWISEs ---
+
+               MOV     R5,#0                   ;Keep a nesting count
+               LDR     R6,sail_line            ;Get current line number
+10ctrl_case    MOV     R4,R9                   ;Look after previous char
+               BL      getToken                ;Get another token
+               CMP     R9,#&FF                 ;Reached the end yet?
+               BEQ     %90ctrl_case            ;If so, moan about ENDCASE
+               CMP     R9,#tok_case            ;Is it a CASE token?
+               ADDEQ   R5,R5,#1                ;Yes -- bump nesting count
+               CMP     R4,#&0A                 ;Was previous newline?
+               BNE     %10ctrl_case            ;No -- nothing doing here
+
+               CMP     R5,#0                   ;At bottom nesting level?
+               CMPEQ   R9,#tok_otherwise       ;Yes -- check for OTHERWISE
+               CMPNE   R9,#tok_endcase         ;Or maybe an ENDCASE?
+               SUBEQ   R5,R5,#1                ;Yes -- decrement nesting
+               CMP     R5,#0                   ;Have we dropped out?
+               BLLT    getToken                ;Yes -- get the next token
+               BLT     %80ctrl_case            ;Yes -- start executing
+               CMPEQ   R9,#tok_when            ;Now check for a W
+               BNE     %10ctrl_case            ;No -- loop
+               BL      getToken                ;Get another token
+
+               ; --- Found a WHEN -- check for a match ---
+
+11ctrl_case    MOV     R0,#0                   ;Read an rvalue
+               BL      express_read
+               BL      express_pop             ;Get result from the stack
+               BL      ctrl_compare            ;Compare the values
+               BEQ     %15ctrl_case            ;Match -- skip other exprs
+               CMP     R1,#vType_string        ;Did we load a string?
+               BLEQ    stracc_free             ;Yes -- reomve the string
+               CMP     R9,#','                 ;Comma next?
+               BLEQ    getToken                ;Yes -- skip it
+               BEQ     %11ctrl_case            ;And try next expression
+               B       %10ctrl_case            ;Otherwise hope we get lucky
+
+               ; --- Skip other expressions ---
+               ;
+               ; BASIC allows extreme bogosity here, and so shall we.
+
+15ctrl_case    CMP     R1,#vType_string        ;Did we load a string?
+               BLEQ    stracc_free             ;Yes -- reomve the string
+00             CMP     R5,#0                   ;Are we quoted?
+               CMPEQ   R9,#':'                 ;No -- check for colon
+               CMPNE   R9,#&0A                 ;Newline?
+               BEQ     %80ctrl_case            ;Yes -- let it rip
+               CMP     R9,#'"'                 ;Is this a quote?
+               EOREQ   R5,R5,#1                ;Yes -- toggle quoted bit
+               BL      getToken                ;Get another token
+               B       %b00                    ;And keep going
+
+               ; --- Return to interp_next, removing str from stracc ---
+
+80ctrl_case    CMP     R3,#vType_string        ;Were we dealing with a str?
+               MOVEQ   R0,R2                   ;Yes -- put it in R0
+               BLEQ    stracc_free             ;...and remove it from stracc
+               B       interp_next             ;Keep on interpreting
+
+               ; --- We fell off the end -- oops ---
+
+90ctrl_case    STR     R6,sail_line            ;Save bogus line back
+               MOV     R0,#err_expEndcase      ;Hmm... should have had an...
+               B       error_report            ;ENDCASE somewhere
+
+               LTORG
+
+; --- ctrl_when ---
+
+               EXPORT  ctrl_when
+
+; --- ctrl_otherwise ---
+
+               EXPORT  ctrl_otherwise
+
+ctrl_when      ROUT
+ctrl_otherwise
+
+               MOV     R3,#0                   ;My counter thing
+               LDR     R4,sail_line            ;Get the current line
+               MOV     R2,#0                   ;Dummy previous char
+               B       %45ctrl_when
+
+40ctrl_when    MOV     R2,R9                   ;Remember the previous token
+               BL      getToken                ;Get a new one
+45ctrl_when    CMP     R9,#&FF                 ;Is this the end of file?
+               BEQ     %50ctrl_when            ;Yes -- jump ahead
+               CMP     R9,#tok_case            ;Did we just read a CASE
+               ADDEQ   R3,R3,#1                ;Yes -- increment the count
+               BEQ     %40ctrl_when            ;And keep on looping
+               CMP     R2,#&0a                 ;Was prev a newline?
+               CMPEQ   R9,#tok_endcase         ;Is this an endcase?
+               SUBEQ   R3,R3,#1                ;Yes -- decrement the count
+               CMP     R3,#0                   ;Are we ready to execute?
+               BGE     %40ctrl_when            ;No -- loop then
+
+               BL      getToken                ;Get the next token
+               B       interp_next             ;Execute from here!
+
+               ; -- Missing ENDCASE ---
+
+50ctrl_when    STR     R4,sail_line            ;Store original line number
+               MOV     R0,#err_expEndcase      ;Get the error number
+               B       error_report            ;And report the error
+
+               LTORG
+
+; --- ctrl_end ---
+
+               EXPORT  ctrl_end
+ctrl_end       ROUT
+
+               MOV     R0,#0
+               B       sail_end
+
+               LTORG
+
+; --- ctrl_swap ---
+
+               EXPORT  ctrl_swap
+ctrl_swap      ROUT
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read
+               CMP     R9,#','                 ;Do we have a comma?
+               MOVNE   R0,#err_expComma        ;No -- get the error number
+               BNE     error_report            ;And report the error
+               BL      getToken                ;Skip over the comma
+               MOV     R0,#1                   ;Read another lvalue
+               BL      express_read
+               BL      express_popTwo          ;Pop off the two lvalues
+
+               ; --- Swap the contents of the lvalues ---
+
+10ctrl_swap    MOV     R4,R2                   ;Look after parm 2
+               MOV     R5,R3
+               BL      ctrl_load               ;Load the parameter
+               STMFD   R13!,{R2,R3}            ;Store rvalue
+               STMFD   R13!,{R0,R1}            ;And lvalue
+               MOV     R0,R4                   ;Get the second one
+               MOV     R1,R5
+               BL      ctrl_load               ;Load it's value too
+               LDMFD   R13!,{R0,R1}            ;Get back lvalue
+               BL      ctrl_store              ;Store rvalue in lvalue
+               MOV     R0,R4                   ;Get the second one
+               MOV     R1,R5
+               LDMFD   R13!,{R2,R3}            ;Load rvalue
+               BL      ctrl_store              ;Complete the swap
+               B       interp_next             ;All over and happy
+
+               LTORG
+
+; --- ctrl_ptr ---
+
+               EXPORT  ctrl_ptr
+ctrl_ptr       ROUT
+
+               MOV     R0,#2                   ;Read an rvalue ident
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_integer       ;Is this a string?
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+               MOV     R3,R0                   ;Remember file handle
+
+               CMP     R9,#'='                 ;Next char must be `='
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the equals sign
+               MOV     R0,#0                   ;Read the expression
+               BL      express_read
+               BL      express_pop             ;Pop the result
+               CMP     R1,#vType_integer       ;It must be an integer
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+
+               MOV     R2,R0                   ;Put pointer in R2
+               MOV     R1,R3                   ;And handle in R1
+               MOV     R0,#1                   ;Write pointer
+               SWI     XOS_Args                ;Write the pointer
+               BVS     sail_error              ;Report possible error
+
+               B       interp_next             ;And read another instruction
+
+               LTORG
+
+; --- ctrl_ext ---
+
+               EXPORT  ctrl_ext
+ctrl_ext       ROUT
+
+               MOV     R0,#2                   ;Read an rvalue ident
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_integer       ;Is this a string?
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+               MOV     R3,R0                   ;Remember file handle
+
+               CMP     R9,#'='                 ;Next char must be `='
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the equals sign
+               MOV     R0,#0                   ;Read the expression
+               BL      express_read
+               BL      express_pop             ;Pop the result
+               CMP     R1,#vType_integer       ;It must be an integer
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+
+               MOV     R2,R0                   ;Put extent in R2
+               MOV     R1,R3                   ;And handle in R1
+               MOV     R0,#3                   ;Write pointer
+               SWI     XOS_Args                ;Write the extent
+               BVS     sail_error              ;Report possible error
+
+               B       interp_next             ;And read another instruction
+
+               LTORG
+
+; --- ctrl_close ---
+
+               EXPORT  ctrl_close
+ctrl_close     ROUT
+
+               MOV     R0,#2                   ;Read an rvalue ident
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_integer       ;Is this a string?
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+               MOV     R1,R0                   ;Remember file handle
+               MOV     R0,#0                   ;Close file
+               SWI     XOS_Find                ;Close it then
+               BVS     interp_next             ;And read another instr
+
+               AND     R0,R0,#&FF              ;Make sure this is a byte
+               ADR     R1,sail_files           ;Find file bit-array
+               MOV     R14,R0,LSR #5           ;Get word index
+               LDR     R14,[R1,R14,LSL #2]!    ;Load the word I want
+               MOV     R2,#(1<<31)             ;Set the top bit here
+               BIC     R14,R14,R2,ROR R0       ;Clear the correct bit
+               STR     R14,[R1,#0]             ;Save the word back again
+               B       interp_next             ;And read another instr
+
+               LTORG
+
+; --- ctrl_bput ---
+
+               EXPORT  ctrl_bput
+ctrl_bput      ROUT
+
+               ; --- First, make sure we have a hash ---
+
+               CMP     R9,#'#'                 ;We must have a hash
+               MOVNE   R0,#err_expHash         ;No -- complain then
+               BNE     error_report            ;And report an error
+               BL      getToken                ;Get the next token
+
+               ; --- Now read the channel number ---
+
+               MOV     R0,#2                   ;Read an rvalue ident
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_integer       ;Is this a string?
+               BNE     ctrl__notAnInt          ;So if it isn't, complain
+               MOV     R3,R0                   ;Remember file handle
+
+               ; --- Skip over the comma ---
+
+               CMP     R9,#','                 ;Next char must be `,'
+               MOVNE   R0,#err_expComma        ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Now we read an expression ---
+
+               MOV     R0,#0                   ;Read the expression
+               BL      express_read
+               BL      express_pop             ;Pop the result
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BEQ     %10ctrl_bput            ;Yes -- jump ahead
+               CMP     R1,#vType_string        ;Make sure it is a string
+               MOVNE   R0,#err_arrayBad        ;Nope -- get error message
+               BNE     error_report            ;So if it isn't, complain
+
+               ; --- Write a string to the file ---
+
+               MOV     R5,R0                   ;Look after the value
+               LDR     R1,sail_stracc          ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R4,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R1,R3                   ;Get the file handle
+               CMP     R2,#0                   ;Is this a short string?
+00             LDRGTB  R0,[R4],#1              ;Load a character
+               SWIGT   XOS_BPut                ;Put the byte
+               BVS     error_reportReal        ;Report possible error
+               SUBS    R2,R2,#1                ;Reduce the count
+               BGT     %b00                    ;And keep on goin'
+
+               MOV     R0,R5                   ;Put the string in R0
+               BL      stracc_free             ;Free it from stracc
+
+               CMP     R9,#';'                 ;Is there a semicolon now?
+               BLEQ    getToken                ;Yes -- get a token
+               MOVNE   R0,#10                  ;Get a terminator
+               SWINE   XOS_BPut                ;Put the byte
+               B       interp_next             ;And read another instruction
+
+               ; --- Just write a character ---
+
+10             MOV     R1,R3                   ;Get the file handle
+               SWI     XOS_BPut                ;Put the byte
+               BVS     error_reportReal        ;Report possible error
+               B       interp_next             ;And read another instruction
+
+               LTORG
+
+;----- Odds and sods --------------------------------------------------------
+
+; --- ctrl_error ---
+
+               EXPORT  ctrl_error
+ctrl_error     ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,sail_stracc          ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,sail_misc            ;Point to the misc buffer
+               MOV     R14,#1                  ;A sillu error number
+               STR     R14,[R0],#4             ;Store that
+               BL      ctrl_copyString         ;Copy the string over
+               ADR     R0,sail_misc            ;Point to the misc buffer
+               B       sail_error              ;Return the error
+
+               LTORG
+
+; --- ctrl_oscli ---
+
+               EXPORT  ctrl_oscli
+ctrl_oscli     ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,sail_stracc          ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,sail_misc            ;Point to the misc buffer
+               BL      ctrl_copyString         ;Copy the string over
+               SWI     OS_CLI                  ;Do the command
+               MOV     R0,R5                   ;Get the rvalue back
+               BL      stracc_free             ;Free the string from stracc
+               B       interp_next             ;Continue happily
+
+               LTORG
+
+
+
+;----- DATA and the like ----------------------------------------------------
+
+; --- ctrl__findDATA ---
+;
+; On entry:    All the normal things
+;
+; On exit:     R0 == *address* in file of next DATA
+;
+; Use:         Sets the internal data pointer to the first DATA statement
+;              fromthe current position.
+
+               EXPORT  ctrl_findDATA
+ctrl_findDATA  ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               LDR     R0,sail_dataPtr         ;Load the current position
+               LDR     R1,sail_tokAnchor       ;Load the anchor
+               LDR     R1,[R1]
+               ADD     R0,R1,R0                ;Point into the file
+               LDR     R2,sail_dataLine                ;Line number of DATA
+
+               ; --- Search the file for DATA, or EOF ---
+
+00             LDRB    R14,[R0],#1             ;Load a byte
+               CMP     R14,#10                 ;Are we at a return?
+               ADDEQ   R2,R2,#1                ;Yes -- inc line number
+               CMP     R14,#&FF                ;Is this the EOF?
+               SUBEQ   R0,R0,#1                ;Yes -- point to it
+               CMPNE   R14,#tok_data           ;Did we read a DATA?
+               BNE     %b00                    ;No -- keep on looking
+
+90             SUB     R1,R0,R1                ;Get it as an offset
+               STR     R1,sail_dataPtr         ;Save this away then
+               STR     R2,sail_dataLine                ;And the line number
+               LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- ctrl_read ---
+
+               EXPORT  ctrl_read
+ctrl_read      ROUT
+
+               ; --- Point at the current position ---
+
+               LDR     R4,sail_dataPtr         ;Load the current position
+               LDR     R5,sail_tokAnchor       ;Load the anchor
+               LDR     R5,[R5]
+               ADD     R4,R5,R4                ;Point into the file
+
+00ctrl_read    LDRB    R14,[R4,#0]             ;Load the byte there
+               CMP     R14,#&FF                ;Is it the EOF?
+               MOVEQ   R0,#err_outOfDATA       ;Yes -- get error num
+               BEQ     error_report            ;And report the error
+               CMP     R14,#10                 ;Are we at the line end?
+               BLEQ    ctrl_findDATA           ;Yes -- find next data
+               MOVEQ   R4,R0                   ;...put ptr in R0
+               BEQ     %00ctrl_read            ;...and start again
+               CMP     R14,#','                ;Is it a comma?
+               ADDEQ   R4,R4,#1                ;Yes -- skip over it
+
+               ; --- Read an rvalue from this position ---
+
+               LDR     R6,sail_line            ;Load the line number
+               STMFD   R13!,{R6-R10}           ;Stack position details
+               MOV     R10,R4                  ;Point just before data
+               LDR     R14,sail_dataLine       ;Get the line number
+               STR     R14,sail_line           ;Store as actual line
+               MOV     R9,#-1                  ;Make getToken happy
+               BL      getToken                ;Get a token
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get it off the stack
+               LDR     R14,sail_line           ;Get line number
+               STR     R14,sail_dataLine       ;Store as DATA line number
+               SUB     R4,R10,#1               ;Restore data pointer
+               LDMFD   R13!,{R6-R10}           ;Load back position
+               STR     R6,sail_line            ;Restore line number
+               MOV     R2,R0                   ;Put rvalue in R2,R3
+               MOV     R3,R1
+
+               ; --- We are hopefully pointing at some data ---
+
+               MOV     R0,#1                   ;Prepare to read an lvalue
+               BL      express_read            ;Read one then
+               BL      express_pop             ;Get it off the stack
+               BL      ctrl_store              ;Store the rvalue
+
+               SUB     R14,R4,R5               ;Get data pointer as offset
+               STR     R14,sail_dataPtr                ;Store this away
+               CMP     R9,#','                 ;Should we read more?
+               BLEQ    getToken                ;Yes -- skip over the comma
+               BEQ     %00ctrl_read            ;..and loop back again
+
+               B       interp_next             ;Do next instruction
+
+               LTORG
+
+; --- ctrl_restore ---
+
+               EXPORT  ctrl_restore
+ctrl_restore   ROUT
+
+               BL      ctrl__readLabel         ;Read the label
+               MOVCC   R0,#0                   ;Not there -- offset is 0
+               MOVCC   R1,#1                   ;Line is 1
+               LDMCSIB R0,{R0,R1}              ;Load out address/line
+
+               STR     R0,sail_dataPtr         ;Save the data pointer
+               STR     R1,sail_dataLine                ;And the line number
+               BL      ctrl_findDATA           ;Find the DATA
+               B       interp_next             ;And do the next instruction
+
+               LTORG
+
+;----- SYS and friends ------------------------------------------------------
+
+; --- ctrl_call ---
+
+               EXPORT  ctrl_call
+ctrl_call      ROUT
+
+               BL      ctrl_setUpRegs          ;Set up the regs then
+
+               CMP     R10,#vType_integer      ;Is this an integer?
+               MOVNE   R0,#err_numNeeded       ;No -- get error number
+               BNE     error_report            ;...and report the error
+
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R9                   ;Execute the code
+
+               ADRL    R9,ctrl__returned       ;Point to some space
+               STMIA   R9!,{R0-R8}             ;Store returned registers
+               MOV     R14,PC,LSR #28          ;Get the flags
+               STMIA   R9,{R14}                ;Strore the flags too
+               LDMFD   R13!,{R7-R12}           ;Load back position info
+               LDMFD   R13!,{R0}               ;Load stracc offset
+               BL      stracc_free             ;Free any strings I had
+
+               ; --- We have now done the SWI instr ---
+
+               ADRL    R0,ctrl__returned       ;Point to the returned regs
+               BL      ctrl_resolveRegs        ;Do the other half now
+               B       interp_next             ;If flags -- return
+
+               LTORG
+
+; --- ctrl_sys ---
+
+               EXPORT  ctrl_sys
+ctrl_sys       ROUT
+
+               BL      ctrl_setUpRegs          ;Set up the registers
+               STMFD   R13!,{R0-R8}            ;Stack these registers
+
+               CMP     R10,#vType_integer      ;Did user use an integer?
+               MOVEQ   R0,R9                   ;Yes -- use that then
+               BEQ     %10ctrl_sys             ;And jump ahead
+
+               ; --- Convert the name to a number ---
+
+               LDR     R1,sail_stracc          ;Load the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R9,LSR #8         ;Point to the name
+               SWI     XOS_SWINumberFromString ;Convert it then
+               BVS     error_reportReal        ;Report possible error
+
+               ; --- We have the SWI number in R0 ---
+               ;
+               ; We build the following instructions on the stack:
+               ;
+               ;       SWI     <R0>
+               ;       MOV     PC,R14
+
+10             ORR     R9,R0,#&EF000000        ;Build the SWI instruction
+               LDR     R10,=&E1A0F00E          ;Get the MOV instr too
+               LDMFD   R13!,{R0-R8}            ;Load the registers
+               SUB     R13,R13,#8              ;Make some room
+               STMIA   R13,{R9,R10}            ;Stack code
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R13                  ;Call my code
+
+               ADD     R13,R13,#8              ;Get rid of my code
+               ADR     R9,ctrl__returned       ;Point to some space
+               STMIA   R9!,{R0-R8}             ;Store returned registers
+               MOV     R14,PC,LSR #28          ;Get the flags
+               STMIA   R9,{R14}                ;Strore the flags too
+               LDMFD   R13!,{R7-R12}           ;Load back position info
+               LDMFD   R13!,{R0}               ;Load stracc offset
+               BL      stracc_free             ;Free any strings I had
+
+               ; --- We have now done the SWI instr ---
+
+               ADR     R0,ctrl__returned       ;Point to the returned regs
+               BL      ctrl_resolveRegs        ;Do the other half now
+               B       interp_next             ;Do the next instruction
+
+ctrl__returned DCD     0,0,0,0,0,0,0,0,0,0,0
+
+               LTORG
+
+; --- ctrl_setUpRegs ---
+;
+; On entry:    R7-R10 == position info
+;
+; On exit:     R0-R8 set up for sys call
+;              R9,R10 == rvalue of first parameter
+;              On the stack:
+;                new position info, R7-R12
+;                place to stracc free
+;
+; Use:         Sets up all the registers as required by a SYS or SYSCALL
+;              command.
+
+               EXPORT  ctrl_setUpRegs
+ctrl_setUpRegs ROUT
+
+               MOV     R3,R14                  ;Look after the link
+               BL      stracc_ensure           ;Get current stracc offset
+               STMFD   R13!,{R1}               ;Put it on the stack
+               MOV     R5,#0                   ;Might be useful
+
+               ; --- Read the complusory argument ---
+
+               MOV     R0,#0                   ;It's an rvalue
+               BL      express_read            ;Read the expression
+               BL      express_pop             ;Pop it
+               BL      express_push            ;Push it again
+
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BEQ     %f00                    ;Yes -- go round again then
+               CMP     R1,#vType_string        ;Was it a string?
+               MOVNE   R0,#err_arrayBad        ;No -- get error number
+               BNE     error_report            ;And report the error
+               BL      stracc_ensure           ;If it was -- ensure room
+               STRB    R5,[R0,#0]              ;...store a terminator
+               AND     R0,R0,#3                ;Get the alignment
+               RSB     R0,R0,#4
+               ORR     R0,R1,R0                ;...set up the rvalue
+               BL      stracc_added            ;Tell stracc about this
+
+               ; --- Now read all other parameters ---
+
+00             MOV     R2,#0                   ;Mask of regs read
+               MOV     R4,#0                   ;Number we have read
+00             CMP     R9,#','                 ;Do we have a comma?
+               BNE     %10ctrl_setUpRegs       ;No -- we have finshed then
+05             ADD     R4,R4,#1                ;Increment the counter
+               CMP     R4,#8                   ;Have we read 8?
+               MOVEQ   R0,#err_sysTooManyI     ;Yes -- get error number
+               BEQ     error_report            ;And report the error
+               BL      getToken                ;Skip over the comma
+               CMP     R9,#','                 ;Another comma?
+               MOVEQ   R2,R2,LSL #1            ;Yes -- shift R2 along
+               BEQ     %b05                    ;And go back for more
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               MOV     R2,R2,LSL #1            ;Shift R2 along
+               ORR     R2,R2,#1                ;And set the bit
+               BL      express_pop             ;Get it off the stack
+               BL      express_push            ;Oh -- better not!
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BEQ     %b00                    ;Yes -- go round again then
+               CMP     R1,#vType_string        ;Was it a string?
+               MOVNE   R0,#err_arrayBad        ;No -- get error number
+               BNE     error_report            ;And report the error
+               BL      stracc_ensure           ;If it was -- ensure room
+               STRB    R5,[R0]                 ;...store a terminator
+               AND     R0,R0,#3                ;Get the alignment
+               RSB     R0,R0,#4
+               ORR     R0,R1,R0                ;...set up the rvalue
+               BL      stracc_added            ;Tell stracc about this
+               B       %b00                    ;And go round for more
+
+               ; --- We have read the input parameters ---
+               ;
+               ; We must put the position infor on the stack before
+               ; the link here, so that it remains on the stack at return
+               ; time.
+
+10             STMFD   R13!,{R7-R12}           ;Stack position info
+               STMFD   R13!,{R3}               ;And then stack the link!
+               LDR     R9,sail_stracc          ;Load the stracc anchor
+               LDR     R9,[R9]                 ;Get it's address
+               MOV     R10,R2                  ;Put the mask in R10
+
+               ; --- Now transfer the info to R0-R8 ---
+               ;
+               ; Each routine is padded to eight bytes, for niceness (?)
+               ; To start, we set everything to
+
+               MOV     R14,R4                  ;Look after number of regs
+               MOV     R0,#0
+               MOV     R1,#0
+               MOV     R2,#0
+               MOV     R3,#0
+               MOV     R4,#0
+               MOV     R5,#0
+               MOV     R6,#0
+               MOV     R7,#0
+               MOV     R8,#0
+
+               CMP     R14,#0                  ;Read no registers?
+               BEQ     %30ctrl_setUpRegs       ;Indeed -- jump ahead then
+               RSB     R14,R14,#9              ;Make R4 right
+               ADD     R14,R14,R14,LSL #1      ;Multiply by 3
+               ADDS    PC,PC,R14,LSL #3        ;Jump to the routine (*24)
+               DCB     "TMA!"                  ;Pad pad pad pad...
+
+28             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %27ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R8,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R8,R0                   ;No -- it's an integer then
+
+27             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %26ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R7,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R7,R0                   ;No -- it's an integer then
+
+26             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %25ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R6,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R6,R0                   ;No -- it's an integer then
+
+25             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %24ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R5,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R5,R0                   ;No -- it's an integer then
+
+24             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %23ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R4,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R4,R0                   ;No -- it's an integer then
+
+23             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %22ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R3,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R3,R0                   ;No -- it's an integer then
+
+22             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %21ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R2,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R2,R0                   ;No -- it's an integer then
+
+21             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %20ctrl_setUpRegs       ;No go -- jump ahead then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R1,R9,R0,LSR #8         ;Yes -- point to string
+               MOVNE   R1,R0                   ;No -- it's an integer then
+
+20             MOVS    R10,R10,LSR #1          ;Shift the mask down a little
+               BCC     %30ctrl_setUpRegs       ;No go -- jump ahead then
+               STMFD   R13!,{R1}               ;Stack R1
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Was it a string?
+               ADDEQ   R0,R9,R0,LSR #8         ;Yes -- point to string
+               LDMFD   R13!,{R1}               ;Restore R1
+
+               ; --- All the registers are now set up, phew! ---
+
+30             STMFD   R13!,{R0,R1}            ;Stack some registers
+               BL      express_pop             ;Get off first arg!
+               MOV     R9,R0                   ;Put rvalue in R9,R10
+               MOV     R10,R1
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- ctrl_resolveRegs ---
+;
+; On entry:    R0 == pointer to register block
+;
+; On exit:     CS if flags were required, CC otherwise
+;
+; Use:         Resolves the registers returned from a SYS or SYSCALL
+;              into the appropriate variables.  The code assumes that
+;              we have possibly just read a TO command, and goes on
+;              from there.
+
+               EXPORT  ctrl_resolveRegs
+ctrl_resolveRegs ROUT
+
+               ; --- See if we require register return ---
+
+               CMP     R9,#tok_to              ;Do we have a TO?
+               MOVNES  PC,R14                  ;No -- return PDQ then
+
+               STMFD   R13!,{R0-R6,R14}        ;Stack registers
+               BL      getToken                ;Skip over the TO
+               MOV     R4,R0                   ;Put the block in R4
+               MOV     R5,#0                   ;Number read so far
+               ADD     R6,R4,#9*4              ;Point tothe flags
+
+00             CMP     R9,#':'                 ;Is this the end?
+               CMPNE   R9,#10
+               CMPNE   R9,#&FF
+               CMPNE   R9,#tok_else
+               BEQ     %90ctrl_resolveRegs     ;Yes -- return then
+               CMP     R9,#','                 ;Do we skip this one?
+               ADDEQ   R4,R4,#4                ;Yes -- go onto next reg
+               ADDEQ   R5,R5,#1                ;We have done this many
+               CMP     R5,#9                   ;Is this reg 9?
+               MOVEQ   R0,#err_sysTooManyO     ;Yes -- get error number
+               BEQ     error_report            ;And report then error
+               CMP     R9,#','                 ;Compare again with comma
+               BLEQ    getToken                ;Yes -- skip the comma
+               BEQ     %b00                    ;Keep on going
+
+               ; --- We must read one then ---
+               ;
+               ; Actually, we may be reading the flags too.
+
+               CMP     R9,#';'                 ;Do we have a semicolon?
+               BEQ     %30ctrl_resolveRegs     ;Yes -- deal with it then
+
+               MOV     R0,#1                   ;We are reading an lvalue
+               BL      express_read            ;Read it
+               BL      express_pop             ;Pop it off the stack
+               BL      ctrl_load               ;Load the value
+               CMP     R3,#vType_integer       ;Is it an integer?
+               BEQ     %20ctrl_resolveRegs     ;Yes -- jump ahead
+
+               CMP     R3,#vType_string        ;Is it a string then?
+               MOVNE   R0,#err_arrayBad        ;No -- get error number
+               BNE     error_report            ;And report the error
+
+               ; --- We have to return a string ---
+
+               STMFD   R13!,{R0,R1}            ;Look after the lvalue
+               MOV     R0,R2                   ;Put the rvalue in R0
+               BL      stracc_free             ;Free the string from stracc
+
+               LDR     R2,[R4,#0]              ;Load the string address
+               BL      stracc_ensure           ;Make sure we have room
+               MOV     R3,#0                   ;Length so far
+
+10             LDRB    R14,[R2],#1             ;Load a byte
+               CMP     R14,#0                  ;Is it 0?
+               STRNEB  R14,[R0],#1             ;No -- store it then
+               ADDNE   R3,R3,#1                ;...increment the length
+               BNE     %b10                    ;And go round for more
+
+               ORR     R0,R1,R3                ;Create the rvalue
+               BL      stracc_added            ;Tell stracc about this
+               MOV     R2,R0                   ;Put rvalue in R2 too
+               MOV     R3,#vType_string        ;This is a string
+               LDMFD   R13!,{R0,R1}            ;Load the lvalue back
+               BL      ctrl_store              ;Store the new value
+               B       %b00                    ;Go round again
+
+               ; --- It's just an integer then ---
+
+20             LDR     R2,[R4,#0]              ;Load the integer
+               BL      ctrl_store              ;Store this result
+               B       %b00                    ;Go round again
+
+               ; --- We must read the flags ---
+
+30             BL      getToken                ;Skip over the ';'
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get it off the stack
+               BL      ctrl_load               ;Load the current value
+               CMP     R3,#vType_integer       ;Is it an integer?
+               MOVNE   R0,#err_numNeeded       ;No -- get error number
+               BNE     error_report            ;And report the error
+               LDR     R2,[R6,#0]              ;Load the flags word
+               BL      ctrl_store              ;Store the new value
+               LDMFD   R13!,{R0-R6,R14}        ;Load back registers
+               ORRS    PC,R14,#C_flag          ;Return with C set
+
+90             LDMFD   R13!,{R0-R6,R14}        ;Load back registers
+               BICS    PC,R14,#C_flag          ;Return with C clear
+
+               LTORG
+
+;----- Function/Procedure call ----------------------------------------------
+
+; --- FN ---
+;
+; OK, maybe it shouldn't be here.  I don't really care.
+;
+; Hack warning:        This is a hack.  We unwind express_read's stack and stuff
+;              them away somewhere completely different.
+
+               EXPORT  ctrl_fn
+ctrl_fn                ROUT
+
+               ; --- First we need to make a FN frame ---
+               ;
+               ; This involves taking a copy of express_read's stack and
+               ; stuffing it into the frame so we can restore it afterwards.
+               ; This basically means that we can recurse mightily without
+               ; using any R13 stack space.  Huzzah!
+
+               MOV     R0,#cFrame__fn          ;Get the frame type
+               BL      ctrl__pushFrame         ;Push the frame
+               LDR     R14,sail_oldAnchor      ;Load the old anchor address
+               STR     R14,[R0,#cFn__anchor]   ;Save it in the frame
+               STR     R6,[R0,#cFn__flags]     ;Save express_read's flags
+               STMFD   R13!,{R0}               ;Save some register
+               BL      stracc_ensure           ;Get current strac position
+               LDMFD   R13!,{R0}               ;Load registers back again
+               STR     R1,[R0,#cFn__stracc]    ;Save this away
+               LDR     R14,sail_currAnchor     ;Load the current anchor
+               STR     R14,sail_oldAnchor      ;Save this as the old one
+               LDR     R14,sail_tokAnchor      ;Now we work from the file
+               STR     R14,sail_currAnchor     ;So set this as current one
+
+               ADD     R14,R0,#cFn__stack+32   ;Find the stack copy bit
+               LDMFD   R13!,{R1-R4}            ;Load some registers
+               STMFD   R14!,{R1-R4}            ;Save them into the frame
+               LDMFD   R13!,{R1-R4}            ;Load some registers again
+               STMFD   R14!,{R1-R4}            ;Save them into the frame
+
+               ; --- Now get on with the business of calling ---
+
+               LDR     R1,sail_execStack       ;Load the stack anchor
+               LDR     R1,[R1,#0]              ;Tycho bops WimpExtension
+               SUB     R6,R0,R1                ;Turn into an offset
+
+               ; --- Substitute the arguments ---
+
+               MOV     R0,#vType_fn            ;This is a FN
+               BL      ctrl__subArgs           ;Substitute the args
+
+               LDR     R0,sail_execStack       ;Load the stack anchor
+               LDR     R0,[R0,#0]              ;Tycho bops WimpExtension
+               ADD     R0,R0,R6                ;Point to my frame
+               STMIA   R0,{R3,R4}              ;Save the return point away
+
+               B       interp_exec             ;Execute next instruction
+
+               LTORG
+
+; --- = ---
+
+               EXPORT  ctrl_equals
+ctrl_equals    ROUT
+
+               ; --- First, evaluate the argument ---
+
+               MOV     R0,#0                   ;Get an rvalue for it
+               BL      express_read            ;Read the expression
+               CMP     R9,#&0A                 ;Now at end of line?
+               CMPNE   R9,#':'                 ;Or end of statement (weird)
+               CMPNE   R9,#&FF                 ;Or end of file?
+               CMPNE   R9,#tok_else            ;Or an ElSE?
+               MOVNE   R0,#err_syntax          ;No -- that's a cock-up
+               BNE     error_report            ;So be righteous about it
+
+               ; --- If the result is a string, copy it ---
+
+               BL      express_pop             ;Pop off the result
+               MOV     R4,R0                   ;Put the rvalue in R4
+               MOV     R5,R1                   ;And the type in R5
+               CMP     R5,#vType_string        ;Is it a string?
+               BNE     %10ctrl_equals          ;No -- jump ahead
+
+               ; --- Copy the string elsewhere ---
+               ;
+               ; We do this since there may be local strings that are
+               ; removed from stracc, underneath the result.
+
+               LDR     R1,sail_stracc          ;Load stracc's anchor
+               LDR     R1,[R1]                 ;Load the address
+               ADD     R1,R1,R4,LSR #8         ;Point to the string
+
+               ADR     R0,sail_misc            ;Point to a misc buffer
+               ANDS    R2,R4,#&FF              ;Get the length
+               BEQ     %10ctrl_equals          ;Nothin' doin', jump
+
+00             LDRB    R14,[R1],#1             ;Load a byte
+               STRB    R14,[R0],#1             ;Store a byte
+               SUBS    R2,R2,#1                ;Reduce counter
+               BNE     %b00                    ;Do this lots
+               MOV     R0,R4                   ;Put the rvalue in R0
+               BL      stracc_free             ;Free the string
+
+               ; --- Find the frame thing ---
+
+10ctrl_equals  MOV     R0,#cFrame__fn          ;Search for a FN frame
+               BL      ctrl__unwind            ;Look for one of these then
+               MOVCC   R0,#err_notInFn         ;Get possible error num
+               BCC     error_report            ;And report the error
+               MOV     R6,R1                   ;Look after frame address
+
+               ; --- Put stracc in the right place ---
+
+               LDR     R0,[R6,#cFn__stracc]    ;Load the offset
+               BL      stracc_free             ;Okaydokey
+
+               ; --- Reset other things ---
+
+               LDMIA   R1,{R0,R1}              ;Load the line and offset
+               STR     R1,sail_line            ;Save the line counter
+               LDR     R14,sail_oldAnchor      ;Find the anchor of the file
+               STR     R14,sail_currAnchor     ;This is the current one
+               LDR     R1,[R6,#cFn__anchor]    ;Load the saved anchor
+               STR     R1,sail_oldAnchor       ;This is the old one
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R0              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrack a little
+               MOV     R9,#-1                  ;Give bogus current token
+               BL      getToken                ;Read this token
+
+               ; --- Put a string result back on stracc ---
+
+               MOV     R0,R4                   ;Get the rvalue
+               MOV     R1,R5                   ;And the type
+               CMP     R1,#vType_string        ;Was it a string?
+               BNE     %20ctrl_equals          ;No -- jump ahead
+
+               ; --- Copy the result back into stracc ---
+
+               BL      stracc_ensure           ;Make sure we have room
+               ADR     R2,sail_misc            ;Point to our string
+               ANDS    R3,R4,#&FF              ;Get the length
+               BEQ     %15ctrl_equals          ;Very short -- jump
+00             LDRB    R14,[R2],#1             ;Load a byte
+               STRB    R14,[R0],#1             ;Store a byte
+               SUBS    R3,R3,#1                ;Reduce a counter
+               BNE     %b00                    ;Lots more please
+
+15             ANDS    R3,R4,#&FF              ;Get the length again
+               ORR     R0,R1,R3                ;Put the rvalue in R0
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+20             BL      express_push            ;Push this result
+
+               ; --- Now we need to return to express_read ---
+               ;
+               ; Hack warning: This is a hack.
+
+               ADD     R14,R6,#cFn__stack      ;Find stack contents
+               LDMFD   R14!,{R0-R3}            ;Load contents out
+               STMFD   R13!,{R0-R3}            ;Stuff them back on the stack
+               LDMFD   R14!,{R0-R3}
+               STMFD   R13!,{R0-R3}
+               LDR     R6,[R6,#cFn__flags]     ;Restore express_read's flags
+               B       express_fnCont          ;And resume horridly
+
+               LTORG
+
+; --- PROC ---
+
+               EXPORT  ctrl_proc
+ctrl_proc      ROUT
+
+               ; --- First, we push a PROC frame onto the stack ---
+
+               MOV     R0,#cFrame__proc        ;Push on this type
+               BL      ctrl__pushFrame         ;Push on the frame
+               LDR     R14,sail_oldAnchor      ;Get the old anchor
+               STR     R14,[R0,#cProc__anchor] ;Save it in the frame
+               LDR     R14,sail_tokAnchor      ;Args must be in the file
+               STR     R14,sail_oldAnchor      ;So read them from there
+               STMFD   R13!,{R0}               ;Save some register
+               BL      stracc_ensure           ;Get current strac position
+               LDMFD   R13!,{R0}               ;Load registers back again
+               STR     R1,[R0,#cProc__stracc]  ;Save this away
+               LDR     R1,sail_execStack       ;Load the stack anchor
+               LDR     R1,[R1,#0]              ;Tycho bops WimpExtension
+               SUB     R6,R0,R1                ;Turn into an offset
+
+               ; --- Substitute the arguments ---
+
+               MOV     R0,#vType_proc          ;This is a PROC
+               BL      ctrl__subArgs           ;Substitute the args
+
+               LDR     R0,sail_execStack       ;Load the stack anchor
+               LDR     R0,[R0,#0]              ;Tycho bops WimpExtension
+               ADD     R0,R0,R6                ;Point to my frame
+               STMIA   R0,{R3,R4}              ;Save the return point away
+               LDR     R14,[R0,#cProc__anchor] ;Load anchor we saved above
+               STR     R14,sail_oldAnchor      ;Re-instate this again
+
+               B       interp_exec             ;Execute next instruction
+
+               LTORG
+
+; --- ENDPROC ---
+
+               EXPORT  ctrl_endproc
+ctrl_endproc   ROUT
+
+               MOV     R0,#cFrame__proc        ;Search for a PROC frame
+               BL      ctrl__unwind            ;Look for one of these then
+               MOVCC   R0,#err_notInProc       ;Get possible error num
+               BCC     error_report            ;And report the error
+
+               LDR     R0,[R1,#cProc__stracc]  ;Load the offset
+               BL      stracc_free             ;Okaydokey
+
+               LDMIA   R1,{R0,R1}              ;Load the line and offset
+               STR     R1,sail_line            ;Save the line counter
+               LDR     R14,sail_tokAnchor      ;Find the anchor of the file
+               LDR     R14,[R14]               ;Pointless instruction
+               ADD     R10,R14,R0              ;Get the new offset
+               SUB     R10,R10,#1              ;Backtrac a little
+               MOV     R9,#-1                  ;Give bogus current token
+               BL      getToken                ;Read this token
+               B       interp_next             ;And continue merrily
+
+               LTORG
+
+; --- DATA ---
+
+               EXPORT  ctrl_data
+ctrl_data
+
+; --- DEF  ---
+
+               EXPORT  ctrl_def
+
+ctrl_def       ROUT
+
+               ; --- Simply search for a newline! ---
+
+00             CMP     R9,#10                  ;Is this a newline?
+               CMPNE   R9,#&FF                 ;Or the EOF?
+               BNE     getToken                ;No -- get another token
+               BNE     %b00                    ;...get another one then
+               B       interp_next             ;And carry on as before
+
+               LTORG
+
+; --- LOCAL ---
+
+               EXPORT  ctrl_local
+ctrl_local     ROUT
+
+               ; --- We read lots of lvalues, and create local frames ---
+
+00             MOV     R0,#cFrame__local       ;We want a local frame
+               BL      ctrl__pushFrame         ;Create the frame then
+               MOV     R5,R0                   ;Look after the address
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Go to it then
+               BL      express_pop             ;Pop it off
+               BL      ctrl_load               ;Load its value out
+               STMIA   R5,{R0-R3}              ;Store this in the frame
+
+               CMP     R9,#','                 ;Do we have a comma now?
+               BLEQ    getToken                ;Yes -- gobble it up
+               BEQ     %b00                    ;...and do another one
+
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+; --- ctrl__subArgs ---
+;
+; On entry:    R0 == type of routine to find
+;
+; On exit:     R3 == offset of return point
+;              R4 == line number of return point
+;              R0-R2, R5 corrupted
+;
+; Use:         Performs argument substitution.  The next token to read
+;              should be the name of the routine to execute.  On exit,
+;              the interpreter will begin execution of the routine.
+
+ctrl__subArgs  ROUT
+
+               ; --- A nasty macro ---
+               ;
+               ; Swap between the two states
+
+               MACRO
+               READARG
+               LDR     R0,sail_oldAnchor
+               LDR     R0,[R0]
+               MOV     R14,R10
+               SUB     R10,R3,#1
+               ADD     R10,R10,R0
+               LDR     R0,sail_currAnchor
+               LDR     R0,[R0]
+               SUB     R3,R14,R0
+               LDR     R14,sail_line
+               STR     R4,sail_line
+               MOV     R4,R14
+               MOV     R9,#-1
+               BL      getToken
+               MEND
+
+               MACRO
+               READDEF
+               LDR     R0,sail_currAnchor
+               LDR     R0,[R0]
+               MOV     R14,R10
+               SUB     R10,R3,#1
+               ADD     R10,R10,R0
+               LDR     R0,sail_oldAnchor
+               LDR     R0,[R0]
+               SUB     R3,R14,R0
+               LDR     R14,sail_line
+               STR     R4,sail_line
+               MOV     R4,R14
+               MOV     R9,#-1
+               BL      getToken
+               MEND
+
+               ; --- Now get on with it ---
+               ;
+               ; We're calling express_read during the first part of this,
+               ; so we don't have the luxury of a stack...
+
+               MOV     R5,R14                  ;Remember the return address
+
+               ; --- First, get the PROC/FN name ---
+
+               ADR     R2,sail_misc            ;Point to a nice buffer
+               SUBS    R14,R9,#'_'             ;Is it a valid characer?
+               SUBNE   R14,R9,#'A'
+               CMP     R14,#26
+               SUBCS   R14,R9,#'a'
+               CMPCS   R14,#26
+               SUBCS   R14,R9,#'0'
+               CMPCS   R14,#10
+               MOVCS   R0,#err_badCall         ;No -- get error then
+               BCS     error_report            ;And report it
+               STRB    R9,[R2],#1              ;And store in the buffer
+
+00             BL      getToken                ;Get the next character
+               SUBS    R14,R9,#'_'             ;Is it a valid characer?
+               SUBNE   R14,R9,#'A'
+               CMP     R14,#26
+               SUBCS   R14,R9,#'a'
+               CMPCS   R14,#26
+               SUBCS   R14,R9,#'0'
+               CMPCS   R14,#10
+               STRCCB  R9,[R2],#1              ;Yes -- store in the buffer
+               BCC     %b00                    ;...and keep on looping
+
+               MOV     R14,#0
+               STRB    R14,[R2],#1
+
+               ; --- Now find the PROC/FN ---
+
+               ADR     R1,sail_misc            ;Point to the name
+               BL      tree_find               ;Try to find the thing
+               MOVCC   R0,#err_noProc          ;Not there -- complain
+               BCC     error_report
+               LDMIB   R0,{R3,R4}              ;Load out address/line
+               ADD     R3,R3,#1                ;Skip past the proc
+
+               ; --- First, see if we have an open banana ---
+
+               SUBS    R1,R9,#'('              ;Do we have actual arguments?
+               BLEQ    getToken                ;Yes -- gobble the bracket
+               MOVNE   R1,#1                   ;No -- remember this then
+               READDEF                         ;Swap to the def
+               SUBS    R2,R9,#'('              ;Do we have formal args?
+               BLEQ    getToken                ;Yes -- gobble the bracket
+               MOVNE   R2,#1                   ;No -- remember this then
+               CMP     R1,R2                   ;Are both the same?
+               MOVNE   R0,#err_badArgs         ;No -- get an error
+               BNE     error_report            ;So report it then
+               CMP     R1,#0                   ;Any arguments?
+               BNE     %90ctrl__subArgs        ;No -- just tidy up then
+
+               MOV     R2,#0                   ;No arguments read yet
+
+               ; --- Stage 1: Read actual and formal arguments ---
+               ;
+               ; Here we will build 3 records on the val stack for each
+               ; argument:
+               ;
+               ;   If argument is RETURN, lvalue of actual arg, else 0
+               ;   rvalue of actual arg (read to avoid aliassing problems)
+               ;   lvalue of formal arg
+
+10ctrl__subArgs        CMP     R9,#tok_return          ;Is this a RETURN token?
+               BLEQ    getToken                ;If so, gobble it
+               READARG                         ;Swap back to the call
+               BNE     %f00                    ;No -- skip to read rvalue
+
+               ; --- Read lvalue for actual arg ---
+
+               MOV     R0,#1                   ;Read the lvalue here
+               BL      express_read            ;Read that please
+               STMFD   R13!,{R2,R3}            ;Save some registers
+               BL      express_pop             ;Pop the lvalue
+               BL      ctrl_load               ;Load the rvalue out
+               BL      express_push            ;Push the lvalue back
+               MOV     R0,R2                   ;Get the rvalue now
+               MOV     R1,R3                   ;And its type, please
+               BL      express_push            ;Push that too
+               LDMFD   R13!,{R2,R3}            ;Restore my registers
+               B       %f01                    ;Now skip to handling formal
+
+               ; --- Read rvalue for actual arg ---
+
+00             MOV     R1,#-1                  ;Mark a strange lvalue type
+               BL      express_push            ;Push that on
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Do that then
+
+               ; --- Now swap and read the formal argument ---
+
+01             ADD     R2,R2,#1                ;Bump argument counter
+               CMP     R9,#')'                 ;Is this a close bracket?
+               CMPNE   R9,#','                 ;Or maybe a comma?
+               MOVNE   R0,#err_badCall         ;No -- that's an error
+               BNE     error_report            ;So complain about it
+               MOV     R1,R9                   ;Look after this token
+               BL      getToken                ;Gobble the token
+
+               READDEF                         ;Swap back to the DEF
+               MOV     R0,#1                   ;Read an lvalue now
+               BL      express_read            ;Read the expression
+
+               CMP     R9,#')'                 ;Is this a close bracket?
+               CMPNE   R9,#','                 ;Or maybe a comma?
+               MOVNE   R0,#err_expBracket      ;No -- error (odd BASIC one)
+               BNE     error_report            ;So complain about it
+
+               CMP     R1,R9                   ;Do these match?
+               MOVNE   R0,#err_badArgs         ;No -- someone can't count
+               BNE     error_report            ;So report that
+               CMP     R9,#','                 ;Is there more to come?
+               BL      getToken                ;Get the next token
+               BEQ     %10ctrl__subArgs        ;Yes -- read the rest then
+
+               ; --- Stage 2: Bind arguments, and queue value/returns ---
+               ;
+               ; Here, we build the LOCAL frames for the arguments, and
+               ; store the actual arguments into the formal ones.  We also
+               ; remember which ones are value/return so we can sort them
+               ; out later.  Fortunately we've now done all the messing
+               ; about with express_read that we need to, so we can stack
+               ; registers and seriously get down to business...
+
+               STMFD   R13!,{R0-R10}           ;Save loads of registers
+               MOV     R10,R2                  ;Look after argument count
+               MOV     R9,#0                   ;Counter of valret args
+
+               ; --- First, build the LOCAL frame for formal arg ---
+
+00             MOV     R0,#cFrame__local       ;Create a local frame
+               BL      ctrl__pushFrame         ;Push that on the stack
+               MOV     R4,R0                   ;Look after the address
+               BL      express_pop             ;Pop a formal arg lvalue
+               BL      ctrl_load               ;Load the current value
+               STMIA   R4,{R0-R3}              ;Save all that lot away
+
+               ; --- Now read the rvalue and lvalue of actual arg ---
+
+               MOV     R4,R0                   ;Look after this lvalue
+               MOV     R5,R1                   ;Copy it away somewhere
+               BL      express_popTwo          ;Pop the lvalue and rvalue
+               CMP     R1,#-1                  ;Do we have an actual lvalue?
+               STMNEFD R13!,{R0,R1,R4,R5}      ;Yes -- stack that lot away
+               ADDNE   R9,R9,#1                ;And increment the counter
+               MOV     R0,R4                   ;Put formal lvalue in R0,R1
+               ORR     R1,R5,#(1<<31)          ;Don't remove strs from strc
+               BL      ctrl_store              ;And bind the argument
+
+               SUBS    R10,R10,#1              ;Decrement arg counter
+               BGT     %b00                    ;And loop till all done
+
+               ; --- Stage 3: Finally deal with value/return args ---
+               ;
+               ; We have to create the value/return frames now.  This is
+               ; complicated by the need to prevent LOCAL from over-
+               ; zealously restoring values.  We transform any LOCAL frames
+               ; which might do this into deadlocal ones, which won't.
+
+               CMP     R9,#0                   ;Do I need to do any of this?
+               BEQ     %85ctrl__subArgs        ;No -- go away then
+               LDR     R8,sail_execStkPtr      ;Find ctrl stack pointer
+               LDR     R7,sail_execStack       ;And find the anchor
+
+               ; --- Check for matching LOCAL frame ---
+
+05             LDR     R0,[R13,#0]             ;Load the lvalue to match
+               LDR     R14,[R7,#0]             ;Load the stack anchor
+               ADD     R14,R14,R8              ;And find the stack top
+00             LDR     R1,[R14,#-4]            ;Load the frame type
+               CMP     R1,#cFrame__local       ;Is this a local frame?
+               CMPNE   R1,#cFrame__dead        ;Or one we nobbled earlier?
+               BNE     %f00                    ;No -- not there then
+
+               LDR     R1,[R14,#-20]!          ;Load the lvalue from here
+               CMP     R1,R0                   ;Do these match?
+               BNE     %b00                    ;No -- keep looking then
+               MOV     R0,#cFrame__dead        ;Nobble this frame
+               STR     R0,[R14,#16]            ;Change the type to a dummy
+
+               ; --- Now create a value/return frame ---
+
+00             MOV     R0,#cFrame__return      ;Get the frame type
+               BL      ctrl__pushFrame         ;Push this frame
+               LDMFD   R13!,{R1-R4}            ;Load the lvalues out
+               STMIA   R0,{R1-R4}              ;Save that information away
+               SUBS    R9,R9,#1                ;One less of them to do
+               BGT     %b05                    ;If any more to do, do them
+
+               ; --- We're done here -- return to caller ---
+
+85             LDMFD   R13!,{R0-R10}           ;Restore registers
+90             MOVS    PC,R5                   ;And return (slurrrp)
+
+               LTORG
+
+; --- ctrl__unwind ---
+;
+; On entry:    R0 == type of frame to find (PROC or FN)
+;
+; On exit:     CS and R1 == address of frame found, else
+;              CC and R1 corrupted
+;              R0 corrupted
+;
+; Use:         Pops frames off the stack, until it finds a frame which
+;              matches the type specified. Looping constructs are ignored,
+;              and locals, deadlocals and return locals are all dealt with.
+;              It will stop at any other routine frame, and return CC.
+
+ctrl__unwind   ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack registers
+               MOV     R4,R0                   ;Look after the routine type
+               MOV     R5,#0                   ;Number of return-frames now
+00             BL      ctrl__popFrame          ;Pop the frame off the stack
+               CMP     R0,#cFrame__routine     ;Is it a routine frame?
+               BLT     %b00                    ;Nope -- keep on looking then
+
+               ; --- Now pop off routine frames ---
+
+               CMP     R0,R4                   ;Have we found it?
+               BEQ     %90ctrl__unwind         ;Yes -- return success
+
+               CMP     R0,#cFrame__local       ;Is this a local frame?
+               BNE     %10ctrl__unwind         ;No -- jump ahead
+
+               ; --- Deal with local frames ---
+
+               LDMIA   R1,{R0-R3}              ;Load lvalue/rvalue
+               ORR     R1,R1,#(1<<31)          ;Don't remove strings
+               BL      ctrl_store              ;Put it back to how it was
+               B       %b00                    ;And go round for more
+
+               ; --- Check for dead frame ---
+
+10             CMP     R0,#cFrame__dead        ;Is this frame dead?
+               BEQ     %b00                    ;Yes -- ignore it then
+
+15             CMP     R0,#cFrame__return      ;A return frame?
+               BNE     %95ctrl__unwind         ;Nope -- return CC then
+
+               ; --- We have a return frame ---
+
+               MOV     R6,R1                   ;Look after frame address
+               ADD     R1,R1,#8                ;Point to formal lvalue
+               LDMIA   R1,{R0,R1}              ;Load that out
+               BL      ctrl_load               ;Get its value
+               LDMIA   R6,{R0,R1}              ;Load destination lvalue
+               STMFD   R13!,{R0-R3}            ;Store on the R13 stack
+               ADD     R5,R5,#1                ;Increment number so far
+               B       %b00                    ;Yes -- ignore it then
+
+               ; --- We found what we were looking for ---
+               ;
+               ; Resolve all the value return types ---
+
+90             MOV     R6,R1                   ;Look after frame address
+               CMP     R5,#0                   ;And value returns on stack?
+00             LDMNEFD R13!,{R0-R3}            ;Load lvalue/rvalue
+               BLNE    ctrl_store              ;Store the value away
+               SUBNES  R5,R5,#1                ;Decrement the counter
+               BNE     %b00                    ;And do this for all
+
+               MOV     R1,R6                   ;Put address in R1
+               LDMFD   R13!,{R2-R6,R14}        ;Load registers
+               ORRS    PC,R14,#C_flag          ;Return success then
+
+               ; --- We didn't find it :-( ---
+
+95             LDMFD   R13!,{R2-R6,R14}        ;Load registers
+               BICS    PC,R14,#C_flag          ;Return failure
+
+               LTORG
+
+;----- String manipulation --------------------------------------------------
+
+; --- ctrl__alterStr ---
+;
+; On entry:    R2 == rvalue of string to change
+;              R3 == index to copy into
+;              R4 == number of chars to copy
+;              R5 = rvalue of string to copy from
+;
+; On exit:     --
+
+ctrl__alterStr         ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R0,R5                   ;Remeber rvalue of string 2
+               LDR     R14,sail_stracc         ;Get the stracc address
+               LDR     R14,[R14]
+               ADD     R2,R14,R2,LSR #8        ;Point to the string
+               ADD     R2,R2,R3                ;Point into the string
+               ADD     R5,R14,R5,LSR #8        ;Point to second string
+
+               CMP     R4,#0                   ;Anything to copy?
+00             LDRGTB  R14,[R5],#1             ;Load a byte
+               STRGTB  R14,[R2],#1             ;Store it again
+               SUBS    R4,R4,#1                ;Reduce the counter
+               BGT     %b00                    ;And keep on going
+
+               MOV     R1,#vType_string        ;R0 is a string
+               BL      stracc_free             ;We don't need it now
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+; --- ctrl_leftS ---
+
+               EXPORT  ctrl_leftS
+ctrl_leftS     ROUT
+
+               ; --- First, read the string variable ---
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the lvalue
+               BL      ctrl_load               ;Load the string into stracc
+               CMP     R3,#vType_string        ;Make sure we have a string
+               BNE     ctrl__notAString        ;And report the error
+               AND     R6,R2,#&FF              ;Get the length too
+               STMFD   R13!,{R0,R1}            ;Remember the lvalue
+
+               ; --- We need a comma now ---
+
+               CMP     R9,#','                 ;We need a comma now
+               MOVNE   R0,#err_expComma        ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Read the number of characters ---
+
+               MOV     R1,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- barf then
+               CMP     R0,R6                   ;Reading too many?
+               MOVLE   R4,R0                   ;Put the number in R4
+               MOVGT   R4,R6                   ;Put it in range
+               MOV     R3,#0                   ;The index is 0
+
+               ; --- Look for ')=' now ---
+
+               CMP     R9,#')'                 ;We need a ')' now
+               MOVNE   R0,#err_expBracket      ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+               CMP     R9,#'='                 ;We need a '=' now
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Now we need a replacement string ---
+
+               MOV     R0,#0                   ;Read another rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_string        ;Is it a string?
+               BNE     ctrl__notAString        ;And report the error
+               MOV     R5,R0                   ;Put the rvalue in R5
+               AND     R6,R0,#&FF              ;Get the length of that one
+               CMP     R4,R6                   ;Only copy enough
+               MOVGT   R4,R6                   ;To save embarrassment
+
+               BL      ctrl__alterStr          ;Do the string transform
+               MOV     R3,#vType_string        ;It is a string
+               LDMFD   R13!,{R0,R1}            ;Get the lvalue back
+               BL      ctrl_store              ;Store back the new string
+
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+; --- ctrl_midS ---
+
+               EXPORT  ctrl_midS
+ctrl_midS      ROUT
+
+               ; --- First, read the string variable ---
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the lvalue
+               BL      ctrl_load               ;Load the string into stracc
+               CMP     R3,#vType_string        ;Make sure we have a string
+               BNE     ctrl__notAString        ;And report the error
+               AND     R6,R2,#&FF              ;Get the length too
+               STMFD   R13!,{R0,R1}            ;Remember the lvalue
+
+               ; --- We need a comma now ---
+
+               CMP     R9,#','                 ;We need a comma now
+               MOVNE   R0,#err_expComma        ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Read the index ---
+
+               MOV     R1,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- barf then
+               SUBS    R3,R0,#1                ;Put it in R4
+               MOVLE   R3,#0                   ;Put it in range
+               CMP     R3,R6                   ;Is the index too high?
+               MOVGT   R3,R6                   ;Put it in range
+               SUB     R4,R6,R3                ;Get max to read
+
+               ; --- We may have a comma now ---
+
+               CMP     R9,#','                 ;We need a comma now
+               BNE     %10ctrl_midS            ;And jump ahead
+
+               ; --- Read the number of characters ---
+
+               BL      getToken                ;Skip past the comma
+               MOV     R1,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- barf then
+               CMP     R0,R4                   ;Is the index too high?
+               MOVLE   R4,R0                   ;Put the number in R4
+               CMP     R4,#0                   ;Not below 0 either
+               MOVLT   R4,#0
+
+               ; --- Look for ')=' now ---
+
+10ctrl_midS    CMP     R9,#')'                 ;We need a ')' now
+               MOVNE   R0,#err_expBracket      ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+               CMP     R9,#'='                 ;We need a '=' now
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Now we need a replacement string ---
+
+               MOV     R0,#0                   ;Read another rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_string        ;Is it a string?
+               BNE     ctrl__notAString        ;And report the error
+               MOV     R5,R0                   ;Put the rvalue in R5
+               AND     R6,R0,#&FF              ;Get the length of that one
+               CMP     R4,R6                   ;Only copy enough
+               MOVGT   R4,R6                   ;To save embarrassment
+
+               BL      ctrl__alterStr          ;Do the string transform
+               MOV     R3,#vType_string        ;It is a string
+               LDMFD   R13!,{R0,R1}            ;Get the lvalue back
+               BL      ctrl_store              ;Store back the new string
+
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+; --- ctrl_rightS ---
+
+               EXPORT  ctrl_rightS
+ctrl_rightS    ROUT
+
+               ; --- First, read the string variable ---
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the lvalue
+               BL      ctrl_load               ;Load the string into stracc
+               CMP     R3,#vType_string        ;Make sure we have a string
+               BNE     ctrl__notAString        ;And report the error
+               AND     R6,R2,#&FF              ;Get the length too
+               STMFD   R13!,{R0,R1}            ;Remember the lvalue
+
+               ; --- We need a comma now ---
+
+               CMP     R9,#','                 ;We need a comma now
+               MOVNE   R0,#err_expComma        ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Read the number of characters ---
+
+               MOV     R1,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BNE     ctrl__notAnInt          ;No -- barf then
+               CMP     R0,R6                   ;Reading too many?
+               MOVLE   R4,R0                   ;Put the number in R4
+               MOVGT   R4,R6                   ;Put it in range
+               SUBS    R3,R6,R4                ;Work out the index
+
+               ; --- Look for ')=' now ---
+
+               CMP     R9,#')'                 ;We need a ')' now
+               MOVNE   R0,#err_expBracket      ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+               CMP     R9,#'='                 ;We need a '=' now
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the comma
+
+               ; --- Now we need a replacement string ---
+
+               MOV     R0,#0                   ;Read another rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the value
+               CMP     R1,#vType_string        ;Is it a string?
+               BNE     ctrl__notAString        ;And report the error
+               MOV     R5,R0                   ;Put the rvalue in R5
+               AND     R0,R0,#&FF              ;Get the length of that one
+               CMP     R4,R0                   ;Only copy enough
+               MOVGT   R4,R0                   ;To save embarrassment
+               SUBGT   R3,R6,R4
+
+               BL      ctrl__alterStr          ;Do the string transform
+               MOV     R3,#vType_string        ;It is a string
+               LDMFD   R13!,{R0,R1}            ;Get the lvalue back
+               BL      ctrl_store              ;Store back the new string
+
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+;----- Arrays ---------------------------------------------------------------
+
+; --- ctrl_dim ---
+
+               EXPORT  ctrl_dim
+ctrl_dim       ROUT
+
+               ; --- Stash current position ---
+
+               LDR     R6,sail_line            ;Find the current line
+               STMFD   R13!,{R6-R10}           ;Save current position info
+
+               ; --- Now try reading an identifier ---
+
+               ADR     R1,sail_misc            ;Point to a buffer
+               MOV     R2,#vType_dimInt        ;Currently it's an int array
+
+               SUBS    R14,R9,#'_'             ;Allow strange ident chars
+               SUBNE   R14,R9,#'A'             ;Check for uppercase letters
+               CMP     R14,#26                 ;In range?
+               SUBCS   R14,R9,#'a'             ;Check for lowercase letters
+               CMPCS   R14,#26                 ;In range?
+               MOVCS   R0,#err_badDim          ;No -- get an error
+               BCS     error_report            ;And kill the program
+
+00             STRB    R9,[R1],#1              ;Store the character away
+               BL      getToken                ;Get another token
+               SUBS    R14,R9,#'_'             ;Allow strange ident chars
+               SUBNE   R14,R9,#'A'             ;Check for uppercase letters
+               CMP     R14,#26                 ;In range?
+               SUBCS   R14,R9,#'a'             ;Check for lowercase letters
+               CMPCS   R14,#26                 ;In range?
+               SUBCS   R14,R9,#'0'             ;Check for digits too now
+               CMPCS   R14,#10                 ;In range?
+               BCC     %b00                    ;We're OK here -- loop
+
+               ; --- Found something which stopped us ---
+
+               CMP     R9,#'$'                 ;Is it a dollar sign?
+               MOVEQ   R2,#vType_dimStr        ;It's a string array now
+               CMPNE   R9,#'%'                 ;Or a percentage?
+               STREQB  R9,[R1],#1              ;Yes -- store it then
+               CMPNE   R9,#' '                 ;Just check for a space
+               BLEQ    getToken                ;Valid terminator -- get tok
+
+               ; --- Now see if this is an array ---
+
+               CMP     R9,#'('                 ;Defining an array here?
+               BNE     %50ctrl_dim             ;No -- allocate a block then
+               ADD     R13,R13,#20             ;Lose positioning info
+               MOV     R14,#0                  ;Terminate the identifier
+               STRB    R14,[R1],#1             ;Store zero on the end
+               BL      getToken                ;Get the next token
+
+               ; --- Ensure that the name isn't already used ---
+
+               MOV     R0,R2                   ;Get the array type
+               ADR     R1,sail_misc            ;Point to the name
+               BL      tree_find               ;Is it there already?
+               MOVCS   R0,#err_reDim           ;Yes -- moan then
+               BCS     error_report            ;And kill things off
+
+               ; --- Stuff the string on stracc ---
+
+               BL      stracc_ensure           ;Make enough space for it
+               ADR     R3,sail_misc            ;Point to the misc buffer
+00             LDRB    R14,[R3],#1             ;Load the byte out
+               STRB    R14,[R0],#1             ;Store in the buffer
+               ADD     R1,R1,#1                ;And increment the length
+               CMP     R14,#0                  ;Finished yet?
+               BNE     %b00                    ;No -- then loop round
+               MOV     R0,R1                   ;Get the rvalue I made
+               BL      stracc_added            ;I've added this string
+               MOV     R5,R1                   ;Look after this value
+
+               ; --- Now read the subscripts ---
+               ;
+               ; We use the stack to keep track of them all.  This is
+               ; fairly crufty, but I don't care.
+
+               MOV     R3,#0                   ;No subscripts so far
+               MOV     R4,#1                   ;Number of items we need
+00             MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Evaluate an expression
+               BL      express_pop             ;Pop the rvalue
+               CMP     R1,#vType_integer       ;Ensure it's an integer
+               MOVNE   R0,#err_numNeeded       ;No -- moan then
+               BNE     error_report            ;And stop the program
+               ADD     R0,R0,#1                ;BASIC subscripts are odd
+               STMFD   R13!,{R0}               ;Stash the subscript
+               ADD     R3,R3,#1                ;Increment the counter
+               MUL     R4,R0,R4                ;Update the size we nee
+               CMP     R9,#','                 ;Is this a comma?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     %b00                    ;And read another subscript
+               CMP     R9,#')'                 ;Well, this must be next
+               MOVNE   R0,#err_dimKet          ;No -- well, get an error
+               BNE     error_report            ;And die horridly
+               BL      getToken                ;Get another token
+
+               ; --- We now have the subscripts on the stack ---
+
+               LDR     R14,sail_stracc         ;Find the stracc anchor
+               LDR     R14,[R14]               ;Bop WimpExtension for fun
+               ADD     R1,R14,R5,LSR #8        ;Find the name base
+               MOV     R0,R2                   ;Get the variable type
+               MOV     R2,R13                  ;Point to subscripts
+               BL      var_create              ;Create the array
+               MOV     R0,R5                   ;Get the rvalue again
+               BL      stracc_free             ;And release the memory
+               ADD     R13,R13,R3,LSL #2       ;Restore the stack pointer
+               B       %80ctrl_dim             ;And possibly go round again
+
+               ; --- Allocate a block of memory ---
+
+50ctrl_dim     LDMFD   R13!,{R6-R10}           ;Restore positioning info
+               STR     R6,sail_line            ;Restore the line number
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read that then
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;And read that too
+               BL      express_pop             ;Get the block size
+               CMP     R1,#vType_integer       ;Ensure it's an integer
+               MOVNE   R0,#err_numNeeded       ;No -- get the error then
+               BNE     error_report            ;And moan at the user
+               ADD     R3,R0,#8                ;Add a link word, 1 byte and
+               BIC     R3,R3,#3                ;...word align too
+               MOV     R0,#6                   ;Claim some memory
+               SWI     XOS_Module              ;From the RMA (bletch)
+               MOVVS   R0,#err_noMem           ;If it failed assume no mem
+               BVS     error_report            ;So deal appropriately
+               LDR     R14,sail_rmaList                ;Load RMA list head
+               STR     R2,sail_rmaList         ;Store this block in there
+               STR     R14,[R2],#4             ;Stuff the old link away
+               BL      express_pop             ;Pop the lvalue
+               MOV     R3,#vType_integer       ;Pointer is an integer
+               BL      ctrl_store              ;Store it away
+
+               ; --- Do more DIMs if wee need to ---
+
+80ctrl_dim     CMP     R9,#','                 ;Is there a comma now?
+               BLEQ    getToken                ;Yes -- get the next token
+               BEQ     ctrl_dim                ;Yes -- do another dim then
+
+               B       interp_next             ;Do another instruction
+
+               LTORG
+
+;----- Other useful routines ------------------------------------------------
+
+; --- ctrl_copyString ---
+;
+; On entry:    R0 == buffer to copy string to
+;              R1 == point to the string
+;              R2 == length of string to copy
+;
+; On exit:     --
+;
+; Use:         Copies the string into the buffer.
+
+               EXPORT  ctrl_copyString
+ctrl_copyString ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack registers
+               CMP     R2,#0                   ;Is this a short string?
+00             LDRGTB  R14,[R1],#1             ;Load a character
+               STRGTB  R14,[R0],#1             ;And then store it
+               SUBS    R2,R2,#1                ;Reduce the count
+               BGT     %b00                    ;And keep on goin'
+               MOV     R14,#0                  ;Get a terminator
+               STRB    R14,[R0],#1             ;Store the byte and return
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- ctrl__notAnInt ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Moans because something isn't an integer.
+
+ctrl__notAnInt ROUT
+
+               MOV     R0,#err_numNeeded
+               B       error_report
+
+               LTORG
+
+; --- ctrl__notAString ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Moans because something isn't a string.
+
+ctrl__notAString ROUT
+
+               MOV     R0,#err_strNeeded
+               B       error_report
+
+               LTORG
+
+; --- ctrl__findFrame ---
+;
+; On entry:    R0 == frame type
+;
+; On exit:     R0 == frame type we stopped at
+;              R1 == pointer to base of frame
+;              CS if frame type matched, else CC
+;
+; Use:         Finds a frame with the given type.  It pops frames from the
+;              exec stack until it finds either a frame which matches the
+;              type in R0 or a routine frame.  The frame which stopped the
+;              loop is *not* popped.
+
+ctrl__findFrame        ROUT
+
+               ORR     R14,R14,#C_flag         ;Assume a match -- be happy
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,R0                   ;Look after the frame type
+10             BL      ctrl__peekFrame         ;Look at the top frame
+               CMP     R0,R2                   ;Is this a match?
+               LDMEQFD R13!,{R2,PC}^           ;Yes -- unstack and return
+               CMP     R0,#cFrame__routine     ;Is this a routine frame?
+               BLCC    ctrl__popFrame          ;No -- remove it then
+               BCC     %10ctrl__findFrame      ;And keep on going
+               LDMFD   R13!,{R2,R14}           ;Unstack registers
+               BICS    PC,R14,#C_flag          ;And return with C clear
+
+               LTORG
+
+; --- ctrl_store ---
+;
+; On entry:    R0,R1 == lvalue to store in
+;              R2,R3 == rvalue to write
+;
+;              If bit 31 of R1 is set, then for strings only, the old
+;              string is NOT removed from the stracc. This is
+;              so that variables can be restored after a procedure.
+;
+; On exit:     --
+;
+; Use:         Stores an rvalue into an lvalue.
+
+               EXPORT  ctrl_store
+ctrl_store     ROUT
+
+               ; --- First, see what we're storing in ---
+
+               STMFD   R13!,{R14}              ;Save a register
+               BIC     R14,R1,#(1<<31)         ;Clear the weird bit
+               SUB     R14,R14,#vType_lvInt    ;Get the lvalue index thing
+               CMP     R14,#vType_lvStrArr-vType_lvInt+1
+               ADDCC   PC,PC,R14,LSL #2        ;It's OK, dispatch then
+               B       %00ctrl_store           ;Righty ho, on we go
+
+               B       ctrl__strInt            ;Store in an integer var
+               B       ctrl__strStr            ;Store in a string var
+               B       ctrl__strWord           ;Store in a memory word
+               B       ctrl__strByte           ;Store in a memory byte
+               B       ctrl__strBytes          ;Store in a memory string
+               B       ctrl__strIntArr         ;Store in a whole int array
+               B       ctrl__strStrArr         ;Store in a whole str array
+
+00ctrl_store   MOV     R0,#err_erk             ;This should never happen...
+               B       error_report            ;Since we always get lvalues
+
+               ; --- Store in an integer variable ---
+
+ctrl__strInt   CMP     R3,#vType_integer       ;Make sure we're storing int
+               LDREQ   R14,sail_varTree                ;Find the tree base
+               LDREQ   R14,[R14]               ;Why is WimpExt so odd?
+               STREQ   R2,[R14,R0]             ;Store the value in node
+               LDMEQFD R13!,{PC}^              ;And return to caller
+               B       ctrl__notAnInt
+
+               ; --- Store in a memory word somewhere ---
+
+ctrl__strWord  CMP     R3,#vType_integer       ;Make sure we're storing int
+               STREQ   R2,[R0,#0]              ;Save the word away
+               LDMEQFD R13!,{PC}^              ;And return to caller
+               B       ctrl__notAnInt
+
+               ; --- Store in a byte somewhere ---
+
+ctrl__strByte  CMP     R3,#vType_integer       ;Make sure we're storing int
+               STREQB  R2,[R0,#0]              ;Save the byte away
+               LDMEQFD R13!,{PC}^              ;And return to caller
+               B       ctrl__notAnInt
+
+               ; --- Store in a string variable ---
+
+ctrl__strStr   CMP     R3,#vType_string        ;Make sure we've got a string
+               BNE     ctrl__notAString        ;No -- complain then
+
+               ; --- Now do some messing about ---
+
+               STMFD   R13!,{R0-R5}            ;Store some registers
+               MOV     R5,R1                   ;Look after our flag bit
+
+               LDR     R4,sail_varTree         ;Find the tree base
+               LDR     R4,[R4]                 ;Who designed this heap?
+               ADD     R4,R4,R0                ;Work out the node address
+               LDR     R0,[R4,#0]              ;Load the old string offset
+               BL      strBucket_free          ;Don't want it any more
+
+               AND     R0,R2,#&FF              ;Get the string's length
+               BL      strBucket_alloc         ;Get a new string entry
+               STR     R1,[R4,#0]              ;Tuck that away nicely
+
+               LDR     R4,sail_stracc          ;Find string accumulator
+               LDR     R4,[R4]                 ;It must be one of those days
+               ADD     R4,R4,R2,LSR #8         ;Work out string address
+               ANDS    R3,R2,#&FF              ;Get the length
+00             LDRNEB  R14,[R4],#1             ;Load a string byte
+               STRNEB  R14,[R0],#1             ;Save it in the bucket
+               SUBNES  R3,R3,#1                ;Decrement the length count
+               BNE     %b00                    ;And loop back again
+
+               TST     R5,#(1<<31)             ;Do we remove from bucket?
+               MOV     R0,R2                   ;Get the offset
+               BLEQ    stracc_free             ;Free it nicely
+
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               LTORG
+
+               ; --- Store a string in memory ---
+
+ctrl__strBytes CMP     R3,#vType_string        ;Make sure we've got a string
+               BNE     ctrl__notAString        ;No -- complain then
+
+               STMFD   R13!,{R0-R4}            ;Store some registers
+               LDR     R4,sail_stracc          ;Find string accumulator
+               LDR     R4,[R4]                 ;It must be one of those days
+               ADD     R4,R4,R2,LSR #8         ;Work out string address
+               ANDS    R3,R2,#&FF              ;Get the length
+00             LDRNEB  R14,[R4],#1             ;Load a string byte
+               STRNEB  R14,[R0],#1             ;Save it in the bucket
+               SUBNES  R3,R3,#1                ;Decrement the length count
+               BNE     %b00                    ;And loop back again
+               MOV     R14,#13                 ;Get the terminator
+               STRB    R14,[R0],#1             ;And store that too
+
+               TST     R1,#(1<<31)             ;Do we remove from bucket?
+               MOV     R0,R2                   ;Put offset in R1
+               BLEQ    stracc_free             ;Free it nicely
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+ctrl__strIntArr
+ctrl__strStrArr
+
+               MOV     R0,#err_arrayBad        ;Point to the error message
+               B       error_report            ;And report the message
+
+; --- ctrl_load ---
+;
+; On entry:    R0,R1 == lvalue to read
+;
+; On exit:     R2,R3 == rvalue read from lvalue
+;
+; Use:         Loads the current value of the given lvalue.
+
+               EXPORT  ctrl_load
+ctrl_load      ROUT
+
+               ; --- First, see what we're storing in ---
+
+               SUB     R2,R1,#vType_lvInt      ;Get the lvalue index thing
+               CMP     R2,#vType_lvStrArr-vType_lvInt+1
+               ADDCC   PC,PC,R2,LSL #2         ;It's OK, dispatch then
+               B       %00ctrl_load            ;Righty ho, on we go
+
+               B       ctrl__ldInt             ;Store in an integer var
+               B       ctrl__ldStr             ;Store in a string var
+               B       ctrl__ldWord            ;Store in a memory word
+               B       ctrl__ldByte            ;Store in a memory byte
+               B       ctrl__ldBytes           ;Store in a memory string
+               B       ctrl__ldIntArr          ;Store in a whole int array
+               B       ctrl__ldStrArr          ;Store in a whole str array
+
+00ctrl_load    MOV     R0,#err_erk             ;This should never happen...
+               B       error_report            ;Since we always get lvalues
+
+               ; --- Load an integer variable ---
+
+ctrl__ldInt    MOV     R3,#vType_integer       ;We're loading an integer
+               LDR     R2,sail_varTree         ;Find the tree base
+               LDR     R2,[R2]                 ;Why is WimpExt so odd?
+               LDR     R2,[R2,R0]              ;Load the value out
+               MOVS    PC,R14                  ;Return to caller
+
+               ; --- Load from a memory word somewhere ---
+
+ctrl__ldWord   MOV     R3,#vType_integer       ;We're loading an integer
+               LDR     R2,[R0,#0]              ;Load the word
+               MOVS    PC,R14                  ;And return to caller
+
+               ; --- Load from a byte somewhere ---
+
+ctrl__ldByte   MOV     R3,#vType_integer       ;We're loading an integer
+               LDRB    R2,[R0,#0]              ;Load the byte
+               MOVS    PC,R14                  ;And return to caller
+
+               ; --- Load a string into stracc ---
+
+ctrl__ldStr    STMFD   R13!,{R0,R1,R4,R14}     ;Save some registers
+
+               LDR     R14,sail_varTree                ;Find the variable tree
+               LDR     R14,[R14]               ;Irate?  Me?
+               ADD     R3,R14,R0               ;Find the actual node
+               BL      stracc_ensure           ;Make sure there's enough
+
+               LDR     R3,[R3,#0]              ;Find the bucket entry
+               CMP     R3,#0                   ;Is there a string here
+               MOVEQ   R2,R1                   ;Yes -- return 0 length
+               BEQ     %f10                    ;...and branch ahead
+               LDR     R14,sail_bucket         ;Find the bucket anchor
+               LDR     R14,[R14]               ;I hate this!  I hate it!
+               ADD     R3,R14,R3               ;Find the actual string
+
+               LDRB    R4,[R3,#-1]             ;Load the string length
+               ORR     R2,R4,R1                ;Build the rvalue ready
+
+00             LDRB    R14,[R3],#1             ;Load a byte from string
+               STRB    R14,[R0],#1             ;And store byte in stracc
+               SUBS    R4,R4,#1                ;Decrement the length
+               BNE     %b00
+
+10             MOV     R3,#vType_string        ;This is a string
+               MOV     R0,R2                   ;Damn -- we need it in R0,R1
+               BL      stracc_added            ;Tell stracc about string
+               LDMFD   R13!,{R0,R1,R4,PC}^     ;And return to caller
+
+               ; --- Load a string from memory ---
+
+ctrl__ldBytes  STMFD   R13!,{R0,R1,R4,R14}     ;Save some registers
+
+               MOV     R3,R0                   ;Remember string pointer
+               BL      stracc_ensure           ;Make sure there's enough
+
+               MOV     R4,#0                   ;Make the length 0
+00             LDRB    R14,[R3],#1             ;Load a byte from string
+               CMP     R14,#13                 ;Is it the terminator
+               BEQ     %f10                    ;Yes -- jump ahead
+               STRB    R14,[R0],#1             ;And store byte in stracc
+               ADD     R4,R4,#1                ;Decrement the length
+               CMP     R4,#255                 ;Are we at the limit
+               BLT     %b00                    ;No -- go round for more
+
+10             MOV     R3,#vType_string        ;This is a string
+               ORR     R2,R1,R4                ;Get the rvalue
+               MOV     R0,R2                   ;Damn -- we need it in R0,R1
+               BL      stracc_added            ;Tell stracc about string
+               LDMFD   R13!,{R0,R1,R4,PC}^     ;And return to caller
+
+               LTORG
+
+ctrl__ldIntArr
+ctrl__ldStrArr
+               MOV     R0,#err_arrayBad        ;Get the error number
+               B       error_report            ;And report the error
+
+; --- ctrl_compare ---
+;
+; On entry:    R0,R1 == thing to compare
+;              R2,R3 == thing to compare the other thing with
+;
+; On exit:     The flags indicate the result of the comparison
+;
+; Use:         Compares two things.  Note that R3 contains the dominant
+;              type. If it is comparing strings, the string in R0,R1
+;              will be removed from stracc.
+
+               EXPORT  ctrl_compare
+ctrl_compare   ROUT
+
+               CMP     R3,#vType_integer       ;Is it an integer?
+               BNE     %10ctrl_compare         ;No -- jump ahead
+
+               ; --- We are comparing integers ---
+
+               CMP     R1,#vType_integer       ;Make sure we have an int
+               BNE     ctrl__notAnInt          ;No -- barf then
+               CMP     R0,R2                   ;Do the comparison
+               MOV     PC,R14                  ;And return to caller
+
+               ; --- Try to compare strings ---
+
+10ctrl_compare CMP     R3,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_arrayBad        ;No -- get the error number
+               BNE     error_report            ;...and report the error
+               CMP     R1,#vType_string        ;Make sure other is string
+               MOVNE   R0,#err_strNeeded       ;Nope -- complain
+               BNE     error_report
+
+               STMFD   R13!,{R0-R5,R14}        ;Stack some registers
+               AND     R1,R0,#&FF              ;Get length of first string
+               AND     R3,R2,#&FF              ;And of the second one
+               CMP     R3,R1                   ;Find the lowest
+               EORLT   R1,R1,R3                ;And put lowest in R1
+               EORLT   R3,R1,R3
+               EORLT   R1,R3,R1
+               MOVS    R5,R1                   ;How long is it?
+               BEQ     %50ctrl_compare         ;0 length -- jump ahead
+
+               LDR     R4,sail_stracc          ;Find string accumulator
+               LDR     R4,[R4]                 ;It must be one of those days
+               ADD     R2,R4,R2,LSR #8         ;of both strings
+               ADD     R0,R4,R0,LSR #8         ;Work out string address
+00             LDRB    R14,[R0],#1             ;Load a string byte
+               LDRB    R4,[R2],#1              ;from both strings
+               CMP     R14,R4                  ;Are they the same?
+               BNE     %19ctrl_compare         ;Nope -- return failure
+               SUBS    R5,R5,#1                ;Decrement the length count
+               BNE     %b00                    ;And loop back again
+               CMP     R1,R3                   ;Compare lengths then
+
+19ctrl_compare LDR     R0,[R13,#0]             ;Load an rvalue
+               BL      stracc_free             ;Free it then
+               LDMFD   R13!,{R0-R5,PC}         ;Load back registers
+
+50ctrl_compare CMP     R1,R3                   ;Make another comaprison
+               B       %19ctrl_compare         ;And return
+
+               LTORG
+
+;----- Stack frames ---------------------------------------------------------
+
+; --- Frame types ---
+
+               ^       0
+
+cFrame__loop   #       0
+
+cFrame__for    #       1
+cFrame__while  #       1
+cFrame__repeat #       1
+
+cFrame__routine        #       0
+
+cFrame__gosub  #       1
+cFrame__local  #       1
+cFrame__return #       1
+cFrame__proc   #       1
+cFrame__fn     #       1
+cFrame__dead   #       1
+
+; --- Frame formats ---
+
+               ; --- FOR ---
+
+               ^       0
+cFor__lval     #       8
+cFor__end      #       4
+cFor__step     #       4
+cFor__resume   #       8
+cFor__size     #       0
+
+               ; --- PROC ---
+
+               ^       0
+cProc__resume  #       8
+cProc__anchor  #       4
+cProc__stracc  #       4
+cProc__size    #       0
+
+               ; --- FN ---
+
+               ^       0
+cFn__resume    #       8
+cFn__flags     #       4
+cFn__anchor    #       4
+cFn__stracc    #       4
+cFn__stack     #       32
+cFn__size      #       0
+
+               ; --- REPEAT ---
+
+               ^       0
+cRepeat__resume        #       8
+cRepeat__size  #       0
+
+               ; --- WHILE ---
+
+               ^       0
+cWhile__resume #       8
+cWhile__size   #       0
+
+               ; --- GOSUB ---
+
+               ^       0
+cGosub__resume #       8
+cGosub__size   #       0
+
+               ; --- LOCAL ---
+
+               ^       0
+cLocal__lval   #       8
+cLocal__rval   #       8
+cLocal__size   #       0
+
+               ; --- RETURN ---
+
+               ^       0
+cReturn__lvalA #       8
+cReturn__lvalF #       8
+cReturn__size  #       0
+
+               ; --- DEAD ---
+
+               ^       0
+cDead__lval    #       8
+cDead__rval    #       8
+cDead__size    #       0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/driver b/StraySrc/Libraries/Sapphire/sail/s/driver
new file mode 100644 (file)
index 0000000..de07e05
--- /dev/null
@@ -0,0 +1,262 @@
+;
+; driver.s
+;
+; Test driver for Termite script language
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  |Image$$RW$$Limit|
+               IMPORT  |!!!TermScript$$Header$$Base|
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Driver$$Code|,CODE,READONLY
+               ENTRY
+
+main           ROUT
+
+               SWI     OS_GetEnv
+               MOV     R13,R1
+
+               SUB     R3,R1,#2048
+               LDR     R12,=|Image$$RW$$Limit|
+               ADD     R1,R12,#512
+               SUB     R3,R3,R1
+               MOV     R0,#0
+               SWI     OS_Heap
+               STR     R1,[R12,#0]
+
+               ; --- load the file ---
+
+               SWI     OS_GetEnv
+thingy         LDRB    R14,[R0],#1
+               CMP     R14,#32
+               BNE     thingy
+               BL      loadFile
+               STR     R0,[R12,#4]
+
+               ADR     R11,upcalls
+               LDR     R10,=|!!!TermScript$$Header$$Base|
+
+               ; --- Initialise ---
+
+               ADD     R2,R12,#4
+               MOV     R3,R1
+               MOV     R14,PC
+               ADD     PC,R10,#8
+               MOV     R9,R0
+
+               ; --- The main loop ---
+
+testloop       MOV     R0,R9
+               CMN     R0,#0
+               MOV     R14,PC
+               ADD     PC,R10,#12
+               BVS     error
+               CMP     R0,#0
+               BEQ     testloop
+
+               CMP     R0,#2
+               ADRLT   R0,end
+               ADREQ   R0,chain
+               ADRGT   R0,finish
+               SWI     OS_Write0
+
+done           MOV     R0,R9
+               MOV     R14,PC
+               ADD     PC,R10,#24
+
+               SWI     OS_WriteS
+               DCB     "+++ Finished!!!",10,13,0
+               SWI     OS_Exit
+
+error          SWI     OS_WriteS
+               DCB     "+++ Error: `",0
+               ADD     R0,R0,#4
+               SWI     OS_Write0
+               SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               B       done
+
+end            DCB     "+++ End",13,10,0
+chain          DCB     "+++ Chain",13,10,0
+finish         DCB     "+++ Finnish",13,10,0
+
+               LTORG
+
+loadFile       ROUT
+
+               STMFD   R13!,{R0-R5,R14}
+               MOV     R1,R0
+               MOV     R0,#17
+               SWI     OS_File
+               MOV     R3,R4
+               STR     R4,[R13,#4]
+               LDR     R1,[R12,#0]
+               MOV     R0,#2
+               SWI     OS_Heap
+               MOV     R3,#0
+               LDR     R1,[R13,#0]
+               STR     R2,[R13,#0]
+               MOV     R0,#16
+               SWI     OS_File
+               LDMFD   R13!,{R0-R5,PC}^
+
+upcalls                B       makeBeep
+               B       sendRemote
+               B       reportMessage
+               B       printMessage
+               B       sendLocal
+               B       logFileAdd
+               B       clearScreen
+               B       download
+               B       upload
+               B       checkCarrier
+               MOVS    PC,R14
+               B       readRemote
+               B       readLocal
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+               MOVS    PC,R14
+
+makeBeep       SWI     OS_WriteS
+               DCB     "+++ Beep!!!",7,10,13,0
+               MOVS    PC,R14
+
+sendRemote     STMFD   R13!,{R0-R3}
+               SWI     OS_WriteS
+               DCB     "+++ Sending out `",0
+dosod          CMP     R3,#0
+               BEQ     sodret
+sodloop                LDRB    R0,[R2],#1
+               CMP     R0,#127
+               CMPNE   R0,#31
+               SWIGT   OS_WriteC
+               BGT     sodendl
+               SWI     OS_WriteI+'['
+               AND     R1,R0,#15
+               MOV     R0,R0,LSR #4
+               CMP     R0,#10
+               ADDCC   R0,R0,#'0'
+               ADDCS   R0,R0,#'A'-10
+               SWI     OS_WriteC
+               CMP     R1,#10
+               ADDCC   R0,R1,#'0'
+               ADDCS   R0,R1,#'A'-10
+               SWI     OS_WriteC
+               SWI     OS_WriteI+']'
+sodendl                SUBS    R3,R3,#1
+               BGT     sodloop
+sodret         SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               LDMFD   R13!,{R0-R3}
+               MOVS    PC,R14
+
+reportMessage  STMFD   R13!,{R0,R14}
+               SWI     OS_WriteS
+               DCB     "+++ Reporting: `",0
+               SWI     OS_Write0
+               SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               LDMFD   R13!,{R0,PC}^
+
+printMessage   STMFD   R13!,{R0,R14}
+               SWI     OS_WriteS
+               DCB     "+++ Printing: `",0
+               SWI     OS_Write0
+               SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               LDMFD   R13!,{R0,PC}^
+
+sendLocal      STMFD   R13!,{R0-R3}
+               SWI     OS_WriteS
+               DCB     "+++ Sending in: `",0
+               B       dosod
+
+logFileAdd     STMFD   R13!,{R0,R14}
+               SWI     OS_WriteS
+               DCB     "+++ Adding to log: `",0
+               SWI     OS_Write0
+               SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               LDMFD   R13!,{R0,PC}^
+
+clearScreen    SWI     OS_WriteS
+               DCB     "+++ Clear screen",13,10,0
+               MOVS    PC,R14
+
+download       STMFD   R13!,{R0}
+               SWI     OS_WriteS
+               DCB     "+++ Download, protocol == `",0
+               MOV     R0,R2
+               SWI     OS_Write0
+               SWI     OS_WriteS
+               DCB     "', filename == `",0
+               CMP     R3,#0
+               ADREQ   R0,defname
+               MOVNE   R0,R3
+               SWI     OS_Write0
+               SWI     OS_WriteI+'''
+               SWI     OS_NewLine
+               LDMFD   R13!,{R0}
+               MOVS    PC,R14
+
+defname                DCB     "<default>",0
+
+upload         STMFD   R13!,{R0,R3,R14}
+               SWI     OS_WriteS
+               DCB     "+++ Upload, protocol == `",0
+               MOV     R0,R2
+               SWI     OS_Write0
+               SWI     OS_WriteS
+               DCB     "', files:",13,10,0
+uploop         LDRB    R0,[R3],#1
+               CMP     R0,#0
+               LDMEQFD R13!,{R0,R3,PC}^
+               SWI     OS_WriteS
+               DCB     "+++   ",0
+upotherloop    SWI     OS_WriteC
+               LDRB    R0,[R3],#1
+               CMP     R0,#0
+               BNE     upotherloop
+               SWI     OS_NewLine
+               B       uploop
+
+checkCarrier   SWI     OS_WriteS
+               DCB     "+++ Carrier detect? [yn] ",0
+               SWI     OS_ReadC
+               ORR     R0,R0,#&20
+               CMP     R0,#'n'
+               MOVNE   R0,#'y'
+               SWI     OS_WriteC
+               SWI     OS_NewLine
+               SUBS    R0,R0,#'n'
+               MOVNE   R0,#1
+               MOVS    PC,R14
+
+readLocal      SWI     OS_ReadC
+               MOVS    PC,R14
+
+readRemote     SWI     OS_ReadC
+               MOVS    PC,R14
+
+;----- Workspace ------------------------------------------------------------
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/env b/StraySrc/Libraries/Sapphire/sail/s/env
new file mode 100644 (file)
index 0000000..3aa5fd5
--- /dev/null
@@ -0,0 +1,127 @@
+;
+; env.s
+;
+; Environment handling for SAIL
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:subAlloc
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- sail_createEnv ---
+;
+; On entry:    R0 == parent environment handle or 0
+;              R1 == address of CALL table
+;
+; On exit:     R0 == environment handle
+;              May return an error
+;
+; Use:         Creates an environment.
+;
+;              The CALL tabe format is as follows:
+;
+;              string          prefix
+;              align
+;              word            size of data for this prefix
+;              align
+;              string          name of call
+;              word            address to call
+;              ...
+;              word            0
+
+               EXPORT  sail_createEnv
+
+sail_createEnv ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stach registers
+
+               MOV     R2,R0                   ;Look after handle
+               MOV     R0,#sEnv__size          ;Get the size
+               BL      sub_alloc               ;Allocate it then
+               BVS     %90                     ;Jump ahead with glum
+
+               STR     R2,[R0,#sEnv__parent]   ;Store the parent handle
+               STR     R1,[R0,#sEnv__table]    ;Store call table address
+               MOV     R14,#0                  ;I like this value
+               STR     R14,[R0,#sEnv__next]    ;No next block yet
+90             LDMFD   R13!,{R1,R2,R14}        ;Load back registers
+               ORRVSS  PC,R14,#V_flag          ;Return with error
+               BICVCS  PC,R14,#V_flag          ;Return without error
+
+               LTORG
+
+; --- sail_addCalls ---
+;
+; On entry:    R0 == environment handle
+;              R1 == address of new call table
+;
+; On exit:     May return an error
+;
+; Use:         Adds an extra CALL table to an environment.  Useful
+;              for extension DLLs.
+
+               EXPORT  sail_addCalls
+sail_addCalls  ROUT
+
+               ASSERT  sEnv__next=sCall__next
+               ASSERT  sEnv__table=sCall__table
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack register
+               MOV     R3,R1                   ;Look after the call table
+               ADD     R2,R0,#sEnv__next       ;Point to the next entry
+00             LDR     R14,[R2,#sCall__next]   ;Load the next pointer
+               CMP     R14,#0                  ;Is there one?
+               MOVNE   R2,R14                  ;No -- point to next one
+               BNE     %b00                    ;...and do this lots
+
+               MOV     R0,#sEnv__callSize      ;Get the size to allocate
+               BL      sub_alloc               ;Allocate it then
+               BVS     %95                     ;Report possible error
+
+               STR     R0,[R2,#sCall__next]    ;Store this as next pointer
+               STR     R3,[R0,#sCall__table]   ;Store the table pointer
+               MOV     R14,#0                  ;A NULL word
+               STR     R14,[R0,#sCall__next]   ;No next pointer yet
+
+               LDMFD   R13!,{R0-R3,R14}        ;Load back register
+               BICS    PC,R14,#V_flag          ;Return without error
+
+90             LDMFD   R13!,{R0-R3,R14}        ;Load back register
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+; --- Environment block ---
+
+               ^       0
+sEnv__start    #       0
+sEnv__next     #       4                       ;Pointer to next call table
+sEnv__table    #       4                       ;Pointer to the call table
+sEnv__parent   #       4                       ;Parent environment
+sEnv__size     #       0                       ;Size of the structure
+
+; --- The call block ---
+
+               ^       0
+sCall__start   #       0
+sCall__next    #       4
+sCall__table   #       4
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/error b/StraySrc/Libraries/Sapphire/sail/s/error
new file mode 100644 (file)
index 0000000..931e423
--- /dev/null
@@ -0,0 +1,127 @@
+;
+; error.s
+;
+; Generation and handling of errors
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.termScript
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- error_report ---
+;
+; On entry:    R0 == error number
+;
+; On exit:     doesn't -- reports error to Termite
+;
+; Use:         Reports an error, attaching the error number etc. and
+;              terminating the script.
+
+               EXPORT  error_report
+error_report   ROUT
+
+               ADR     R1,sail_misc            ;Point to the misc buffer
+               STR     R0,[R1],#4              ;Save the error number away
+
+               ; --- Find the error string ---
+
+               ADR     R14,errTable            ;Point to error table
+               LDR     R0,[R14,R0,LSL #2]      ;Find the error offset
+               ADD     R0,R14,R0               ;And convert that to address
+
+               ; --- Now build the actual string ---
+
+10error_report LDRB    R14,[R0],#1             ;Load byte from error text
+               CMP     R14,#0                  ;Is this the end yet?
+               STRNEB  R14,[R1],#1             ;No -- store the byte
+               BNE     %10error_report         ;And keep looping until done
+
+               ; -- Stick `at line' on the end ---
+
+               ADR     R0,error__atLine        ;Point to literal string
+20error_report LDRB    R14,[R0],#1             ;Load byte from text
+               CMP     R14,#0                  ;Is this the end yet?
+               STRNEB  R14,[R1],#1             ;No -- store the byte
+               BNE     %20error_report         ;And keep looping until done
+
+               ; --- Now attach the line number ---
+
+               LDR     R0,sail_line            ;Get the line number
+               MOV     R2,#256                 ;Assume a big buffer
+               SWI     OS_ConvertInteger4      ;Attach that to the end
+
+               ; --- Finally throw the error at Termite ---
+
+               ADR     R0,sail_misc            ;Point to error base
+               B       sail_error              ;And return the error
+
+error__atLine  DCB     " at line ",0
+               ALIGN
+
+               GET     sh.errTable
+
+               LTORG
+
+; --- error_reportReal ---
+;
+; On entry:    R0 == error block
+;
+; On exit:     doesn't -- reports error to Termite
+;
+; Use:         Reports an error, attaching the error number etc. and
+;              terminating the script.
+
+               EXPORT  error_reportReal
+error_reportReal ROUT
+
+               ADR     R1,sail_misc            ;Point to the misc buffer
+               LDR     R14,[R0],#4             ;Load the error number
+               STR     R14,[R1],#4             ;Save the error number away
+
+               ; --- Now build the actual string ---
+
+10             LDRB    R14,[R0],#1             ;Load byte from error text
+               CMP     R14,#0                  ;Is this the end yet?
+               STRNEB  R14,[R1],#1             ;No -- store the byte
+               BNE     %10error_reportReal     ;And keep looping until done
+
+               ; -- Stick `at line' on the end ---
+
+               ADRL    R0,error__atLine        ;Point to literal string
+20             LDRB    R14,[R0],#1             ;Load byte from text
+               CMP     R14,#0                  ;Is this the end yet?
+               STRNEB  R14,[R1],#1             ;No -- store the byte
+               BNE     %20error_reportReal     ;And keep looping until done
+
+               ; --- Now attach the line number ---
+
+               LDR     R0,sail_line            ;Get the line number
+               MOV     R2,#256                 ;Assume a big buffer
+               SWI     OS_ConvertInteger4      ;Attach that to the end
+
+               ; --- Finally throw the error at Termite ---
+
+               ADR     R0,sail_misc            ;Point to error base
+               B       sail_error              ;And return the error
+
+               GET     sh.errTable
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/express b/StraySrc/Libraries/Sapphire/sail/s/express
new file mode 100644 (file)
index 0000000..231e5e2
--- /dev/null
@@ -0,0 +1,2461 @@
+;
+; express.s
+;
+; Evaluation of BASIC expressions
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.ctrl
+               GET     sh.divide
+               GET     sh.errNum
+               GET     sh.error
+               GET     sh.getToken
+               GET     sh.stracc
+               GET     sh.termite
+               GET     sh.termScript
+               GET     sh.tokenise
+               GET     sh.tokens
+               GET     sh.upcalls
+               GET     sh.mem
+               GET     sh.var
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         GETOP   $r,$prec,$branch,$cc
+               ALIGN
+$label
+               MOV$cc  $r,#($prec)<<24
+               ORR$cc  $r,$r,#($branch-exp__bTable)>>2
+               MEND
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+;----- Stack handling -------------------------------------------------------
+
+; --- exp__pushOp ---
+;
+; On entry:    R0 == operator thing to push
+;
+; On exit:     R0-R4 corrupted
+;
+; Use:         Pushes an operator onto the stack.
+
+exp__pushOp    ROUT
+
+               STMFD   R13!,{R14}
+               MOV     R3,R0                   ;Look after thing to push
+               ADR     R1,sail_opStack         ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               ADD     R4,R1,#4                ;New used size
+               CMP     R4,R2                   ;Do we need more stack?
+               BGT     %10exp__pushOp          ;Yes -- jump ahead
+00exp__pushOp  STR     R4,sail_opStkPtr                ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R0,R0,R4                ;Address to put next thing on
+               STR     R3,[R0,#-4]             ;Store the new operator
+               LDMFD   R13!,{PC}^
+
+10exp__pushOp  ADD     R1,R4,#255              ;Align to next size thing
+               BIC     R1,R1,#255              ;Finish the align
+               BL      mem_realloc             ;Yes -- get more space then
+               STR     R1,sail_opStkSize       ;Store new size maybe
+               B       %00exp__pushOp          ;Branch back agin
+
+               LTORG
+
+; --- exp__popOp ---
+;
+; On entry:    --
+;
+; On exit:     R0 == value popped off
+;              R1-R4 corrupted
+;
+; Use:         Pops an operator from the stack.
+
+exp__popOp     ROUT
+
+               STMFD   R13!,{R14}
+               ADR     R1,sail_opStack         ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               SUB     R4,R1,#4                ;The new size
+               ADD     R1,R4,#255              ;Align up again
+               BIC     R1,R1,#255              ;Aligned down
+               ADD     R1,R1,#256              ;At least this much
+               CMP     R1,R2                   ;Has this size changed?
+               BLLT    mem_realloc             ;Yes -- reduce memory reqs.
+               STRLT   R1,sail_opStkSize       ;Store new size maybe
+               STR     R4,sail_opStkPtr                ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               LDR     R0,[R0,R4]              ;Load the value off the stack
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- exp__pushVal ---
+;
+; On entry:    R0 == operator thing to push
+;              R1 == type of thing to push
+;
+; On exit:     R0-R5 corrupted
+;
+; Use:         Pushes an value onto the stack.
+
+exp__pushVal   ROUT
+
+               STMFD   R13!,{R5,R14}
+               MOV     R3,R0                   ;Look after thing to push
+               MOV     R4,R1
+               ADR     R1,sail_calcStack       ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               ADD     R5,R1,#8                ;New used size
+               CMP     R5,R2
+               BGT     %10exp__pushVal
+00exp__pushVal STR     R5,sail_calcStkPtr      ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R0,R0,R5                ;Address to put next thing on
+               STMDB   R0,{R3,R4}              ;Store the thing
+               LDMFD   R13!,{R5,PC}^
+
+10exp__pushVal ADD     R1,R5,#255              ;Align to next size thing
+               BIC     R1,R1,#255              ;Finish the align
+               BL      mem_realloc             ;Yes -- get more space then
+               STR     R1,sail_calcStkSize     ;Store new size maybe
+               B       %00exp__pushVal
+
+               LTORG
+
+; --- exp__popVal ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1 == value popped off
+;              R2-R4 corrupted
+;
+; Use:         Pops a value from the stack.
+
+exp__popVal    ROUT
+
+               STMFD   R13!,{R14}
+               ADR     R1,sail_calcStack       ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               SUB     R4,R1,#8                ;The new size
+               ADD     R1,R4,#255              ;Align up again
+               BIC     R1,R1,#255              ;Aligned down
+               ADD     R1,R1,#256              ;At least this much please
+               CMP     R1,R2                   ;Has this size changed?
+               BLLT    mem_realloc             ;Yes -- reduce memory reqs.
+               STRLT   R1,sail_calcStkSize     ;Store new size maybe
+               STR     R4,sail_calcStkPtr      ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R0,R0,R4                ;Point into the stack
+               LDMIA   R0,{R0,R1}              ;Load values from the stack
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- exp__popTwoVals ---
+;
+; On entry:    --
+;
+; On exit:     R0-R3 == values popped off
+;              R4 corrupted
+;
+; Use:         Pops two values from the stack.
+
+exp__popTwoVals        ROUT
+
+               STMFD   R13!,{R14}
+               ADR     R1,sail_calcStack       ;Point to some stack data
+               LDMIA   R1,{R0-R2}              ;Load it out
+
+               SUB     R4,R1,#16               ;The new size
+               ADD     R1,R4,#255              ;Align up again
+               BIC     R1,R1,#255              ;Aligned down
+               ADD     R1,R1,#256              ;At least his much
+               CMP     R1,R2                   ;Has this size changed?
+               BLLT    mem_realloc             ;Yes -- reduce memory reqs.
+               STRLT   R1,sail_calcStkSize     ;Store new size maybe
+               STR     R4,sail_calcStkPtr      ;Store back new size
+               LDR     R0,[R0]                 ;Point to the stack
+               ADD     R0,R0,R4                ;Point into the stack
+               LDMIA   R0,{R0-R3}              ;Load values from the stack
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- express_pop ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1 == value popped off
+;
+; Use:         Pops a value from the stack.
+
+               EXPORT  express_pop
+express_pop    ROUT
+
+               STMFD   R13!,{R2-R4,R14}        ;Stack registers
+               BL      exp__popVal             ;Get the value
+               LDMFD   R13!,{R2-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- express_popTwo ---
+;
+; On entry:    --
+;
+; On exit:     R0-R3 == two values popped from the stack
+;
+; Use:         Pops two values from the stack.
+
+               EXPORT  express_popTwo
+express_popTwo ROUT
+
+               STMFD   R13!,{R4,R14}           ;Stack registers
+               BL      exp__popTwoVals         ;Pop the values
+               LDMFD   R13!,{R4,PC}^           ;And return to caller
+
+               LTORG
+
+; --- express_push ---
+;
+; On entry:    R0,R1 == l/rvalue to push
+;
+; On exit:     --
+;
+; Use:         Pushes a value onto the expression stack.
+
+               EXPORT  express_push
+express_push   ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               BL      exp__pushVal            ;Do the pushing
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Space-saving type checking routines ----------------------------------
+
+; --- exp__chkTwoInts ---
+;
+; On entry:    R1,R3 == types of variable
+;
+; On exit:     --
+;
+; Use:         Ensures that R1 and R3 are both of type integer, and
+;              complains otherwise.
+
+exp__chkTwoInts        ROUT
+
+               CMP     R3,#vType_integer       ;Is second an integer?
+               MOVNE   R1,R3                   ;No -- fiddle the first then
+
+               ; Drop through here (yuk)
+
+; --- exp__chkInt ---
+;
+; On entry:    R1 == type of a variable
+;
+; On exit:     --
+;
+; Use:         Ensures that R1 is of type integer, and complains otherwise.
+
+exp__chkInt    ROUT
+
+               CMP     R1,#vType_integer       ;Is it an integer
+               MOVEQS  PC,R14                  ;Yes -- all OK -- return
+               MOV     R0,#err_numNeeded       ;No -- get the error
+               B       error_report            ;And complain at the user
+
+               LTORG
+
+; --- exp__popInt ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1 == value popped from the stack
+;              R2-R4 corrupted
+;
+; Use:         Pops a value from the stack and ensures that it is an
+;              integer.
+
+exp__popInt    STMFD   R13!,{R14}              ;Save the link for a bit
+               BL      exp__popVal             ;Pop a value from stack
+               LDMFD   R13!,{R14}              ;Restore link register
+               B       exp__chkInt             ;And check the value
+
+               LTORG
+
+; --- exp__popTwoInts ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1,R2,R3 == two integers popped from the calc stack
+;              R4 corrupted
+;
+; Use:         Pops two values from the stack and ensures that they are
+;              integers.
+
+exp__popTwoInts        ROUT
+
+               STMFD   R13!,{R14}              ;Save the link for a bit
+               BL      exp__popTwoVals         ;Pop two values from stack
+               LDMFD   R13!,{R14}              ;Restore link register
+               B       exp__chkTwoInts         ;And check the values
+
+               LTORG
+
+; --- exp__chkTwoStrs ---
+;
+; On entry:    R1,R3 == types of variable
+;
+; On exit:     --
+;
+; Use:         Ensures that R1 and R3 are both of type string, and
+;              complains otherwise.
+
+exp__chkTwoStrs        ROUT
+
+               CMP     R3,#vType_string        ;Is second an integer?
+               MOVNE   R1,R3                   ;No -- fiddle the first then
+
+               ; Drop through here (yuk)
+
+; --- exp__chkStr ---
+;
+; On entry:    R1 == type of a variable
+;
+; On exit:     --
+;
+; Use:         Ensures that R1 is of type string, and complains otherwise.
+
+exp__chkStr    ROUT
+
+               CMP     R1,#vType_string        ;Is it an integer
+               MOVEQS  PC,R14                  ;Yes -- all OK -- return
+               MOV     R0,#err_strNeeded       ;No -- get the error
+               B       error_report            ;And complain at the user
+
+               LTORG
+
+; --- exp__popStr ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1 == value popped from the stack
+;              R2-R4 corrupted
+;
+; Use:         Pops a value from the stack and ensures that it is an
+;              integer.
+
+exp__popStr    STMFD   R13!,{R14}              ;Save the link for a bit
+               BL      exp__popVal             ;Pop a value from stack
+               LDMFD   R13!,{R14}              ;Restore link register
+               B       exp__chkStr             ;And check the value
+
+               LTORG
+
+; --- exp__popTwoStrs ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1,R2,R3 == two integers popped from the calc stack
+;              R4 corrupted
+;
+; Use:         Pops two values from the stack and ensures that they are
+;              integers.
+
+exp__popTwoStrs        ROUT
+
+               STMFD   R13!,{R14}              ;Save the link for a bit
+               BL      exp__popTwoVals         ;Pop two values from stack
+               LDMFD   R13!,{R14}              ;Restore link register
+               B       exp__chkTwoStrs         ;And check the values
+
+               LTORG
+
+;----- Expression evaluation routines ---------------------------------------
+
+; --- express_fnCont ---
+;
+; On entry:    Involved
+;
+; On exit:     Similarly involved.
+;
+; Use:         We continue here after executing a function.
+
+               EXPORT  express_fnCont
+
+; --- express_read ---
+;
+; On entry:    R0 == 1 to read an lvalue, 2 to read ident, 0 otherwise
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0,R1 == value of expression
+;              R7, R8, R9 == lookahead token
+;              R0, R1 == result of expression
+;              R10 == moved on to first char after expression
+;
+; Use:         Reads an expression for the current position in the
+;              tokenised file.
+
+               EXPORT  express_read
+express_read   ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Stack registers
+               MOV     R6,#0                   ;Current flags word
+               CMP     R0,#1                   ;Reading an lvalue?
+               ORREQ   R6,R6,#eFlag__lval      ;Yes -- set the flag then
+               CMP     R0,#2                   ;Reading an ident?
+               ORREQ   R6,R6,#eFlag__parseLval ;Yes -- parse as lval then
+
+               GETOP   R0,255,exp__bExpEnd     ;Push a sentinel operand
+               BL      exp__pushOp             ;To separate this expression
+
+exp__mainLoop
+express_fnCont
+10express_read TST     R6,#eFlag__done         ;Have we finished this?
+               BNE     %70express_read         ;Yes -- jump ahead
+               TST     R6,#eFlag__op           ;Are we reading an op?
+               BNE     %50express_read         ;Yes -- jump ahead
+
+               ; --- Read an operand then ---
+
+               SUBS    R4,R9,#'_'              ;Is it an underscore?
+               SUBNE   R4,R9,#'A'              ;Or a capital letter?
+               CMP     R4,#26
+               SUBCS   R4,R9,#'a'              ;Or a lowercase letter?
+               CMPCS   R4,#26
+               BCC     exp__readIdent          ;Read an identifier
+
+               CMP     R9,#'!'                 ;Is it an indirection op?
+               CMPNE   R9,#'?'
+               CMPNE   R9,#'$'
+               BEQ     exp__indir              ;Yes -- jump ahead
+
+               TST     R6,#eFlag__lval         ;Are we reading an lvalue?
+               MOVNE   R0,#err_syntax          ;Yes -- get the error number
+               BNE     error_report            ;...and report the error
+
+               CMP     R9,#'"'                 ;Is it a quote?
+               BEQ     exp__string             ;Yes -- read string then
+
+               CMP     R9,#'('                 ;Is it a bracket?
+               BEQ     exp__par                ;Yes -- jump ahead
+
+               CMP     R9,#tok_fn              ;Is it a function call?
+               BEQ     exp__userFn             ;Yes -- handle that then
+
+               CMP     R9,#tok_rnd             ;Is this the RND fn?
+               BLEQ    getToken                ;Yes -- gobble that
+               BEQ     exp__doRnd              ;And deal with it then
+
+               CMP     R9,#'+'                 ;Is it a unary '+'?
+               BLEQ    getToken                ;...get another token
+               BEQ     %10express_read         ;...keep going around again
+               CMP     R9,#'-'                 ;Is it a unary '-'?
+               BEQ     exp__uMinus             ;Yes -- jump ahead then
+
+               CMP     R7,#tClass_pseud        ;Is this a pseudovariable?
+               BEQ     exp__pseud              ;Yes -- deal with it
+
+               CMP     R7,#tClass_fn           ;Is it a function then?
+               BEQ     exp__fn                 ;Yes -- deal with that
+
+               CMP     R7,#tClass_streamOp     ;Also check for stream ops
+               BEQ     exp__streamOp           ;Just for luck
+
+               CMP     R7,#tClass_multArg      ;Multiple parameter thing?
+               BEQ     exp__multArg            ;Yes -- deal with it then
+
+               CMP     R9,#'&'                 ;Start a hex number?
+               BEQ     exp__readHex            ;Yes -- jump ahead
+               CMP     R9,#'%'                 ;Start of a binary number?
+               BEQ     exp__readBin            ;Yes -- jump ahead
+               SUB     R14,R9,#'0'             ;Set up for a range check
+               CMP     R14,#10                 ;Is it a number?
+               BCC     exp__readDec            ;Read a decimal number
+
+               MOV     R0,#err_unknown         ;Get all-encompassing error
+               B       error_report            ;And report the error
+
+               LTORG
+
+               ; --- Handle a string ---
+
+exp__string    BL      stracc_ensure           ;Ensure stracc is big enough
+               MOV     R2,#0                   ;The initial length
+00             BL      getToken                ;Read the next token
+               CMP     R9,#&0a                 ;Is this a line end?
+               CMPNE   R9,#&ff                 ;Or an end of file?
+               MOVEQ   R0,#err_expQuote        ;Yes -- get error number
+               BEQ     error_report            ;And report it
+               CMP     R9,#'"'                 ;Is it a quote?
+               BEQ     %f05                    ;Yes -- branch ahead
+03             STRB    R9,[R0],#1              ;No -- store the byte
+               ADDS    R2,R2,#1<<24            ;...increment the length
+               BCC     %b00                    ;Keep looping for more
+               MOVCS   R0,#err_strTooLong      ;Get error message
+               BCS     error_report            ;and report it nicely
+
+05             BL      getToken                ;Get another token
+               CMP     R9,#'"'                 ;Is this a quote too?
+               BEQ     %b03                    ;Yes -- jump back upwards
+
+               ORR     R0,R1,R2,LSR #24        ;Get the rvalue word
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               BL      exp__pushVal            ;Push the value
+               ORR     R6,R6,#eFlag__op        ;Read an operator now
+               B       %10express_read         ;And jump with glee
+
+               ; --- Handle a function call ---
+
+exp__userFn    ORR     R6,R6,#eFlag__op        ;Expect operand next
+               BL      getToken                ;Gobble the token
+               B       ctrl_fn                 ;And handle it elsewhere
+
+               ; --- Handle an open bracket ---
+
+exp__par       GETOP   R0,253,exp__bPar        ;Do a bracket like thing
+               BL      exp__pushOp             ;Push that onto the stack
+               ADD     R6,R6,#1<<8             ;Bump the paren count
+               BL      getToken                ;Get another token
+               B       %10express_read         ;And read the first operand
+
+               ; --- Handle a unary minus ---
+
+exp__uMinus    GETOP   R0,1,exp__bUMinus       ;Do a unary minus
+               BL      exp__pushOp             ;Push that onto the stack
+               BL      getToken                ;Get another token
+               B       %10express_read         ;And read the first operand
+
+               ; --- Handle a pseudovariable ---
+
+exp__pseud     MOV     R0,R8                   ;Look after token index
+               BL      getToken                ;Move on to next token
+               ORR     R6,R6,#eFlag__op        ;Now expecting an operator
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,PC,R0,LSL #2         ;Dispatch on token index
+               B       %10express_read         ;And return to the top
+
+               B       exp__doFalse            ;Return 0
+               B       exp__doTime             ;Get the current time
+               B       exp__doTimeS            ;Read time as a string (ouch)
+               B       exp__doTrue             ;Return -1
+
+               ; --- Handle unary functions ---
+
+exp__fn                MOV     R0,#(exp__fns-exp__bTable)>>2
+               ADD     R0,R0,R8                ;Add on the token index
+               ORR     R0,R0,#1<<24            ;Use normal unary precedence
+               CMP     R9,#tok_strS            ;Is this STR$?
+               BLNE    exp__pushOp             ;Put that on the stack
+               BLNE    getToken                ;Get the next token
+               BNE     %10express_read         ;And go back up top
+
+               BL      getToken                ;Get another token
+               CMP     R9,#'~'                 ;Hex conversion?
+               ORREQ   R0,R0,#1<<16            ;Set a useful flag
+               BLEQ    getToken                ;And get another token
+               BL      exp__pushOp             ;Put that on the stack
+               B       %10express_read         ;And go back up top
+
+               ; --- Handle stream operations with irritating #s ---
+
+exp__streamOp  MOV     R1,R8                   ;Look after token index
+               BL      getToken                ;Get the next token
+               CMP     R9,#'#'                 ;Is next char a hash?
+               MOVNE   R0,#err_expHash         ;No -- complain then
+               BNE     error_report            ;And report an error
+               BL      getToken                ;Get the next token
+               MOV     R0,#(exp__streamOps-exp__bTable)>>2
+               ADD     R0,R0,R1                ;Add on the token index
+               ORR     R0,R0,#1<<24            ;Use normal unary precedence
+               BL      exp__pushOp             ;Put that on the stack
+               B       %10express_read         ;And go back up top
+
+               ; --- Deal with multiple parameter commands ---
+
+exp__multArg   MOV     R0,#(exp__multArgs-exp__bTable)>>2
+               ADD     R0,R0,R8                ;Add on the token index
+               ORR     R0,R0,#1<<24            ;Use normal unary precedence
+               BL      exp__pushOp             ;Put that on the stack
+               BL      getToken                ;Get the next token
+
+               GETOP   R0,254,exp__bMultArg    ;Get the operator value
+               TST     R6,#eFlag__commaOk      ;Are we allowing commas?
+               ORRNE   R0,R0,#1<<16            ;Yes -- set the flag then
+               BL      exp__pushOp             ;Put that on there
+               ORR     R6,R6,#eFlag__commaOk   ;Allow commas for a while
+               ADD     R6,R6,#1<<8             ;Increment the paren count
+
+               B       %10express_read         ;And go back up top
+
+               ; --- Deal with an indirection operator ---
+
+exp__indir     MOV     R0,#0                   ;Prepare a zero base
+               TST     R6,#eFlag__lval         ;Are we reading an lvalue?
+               MOVEQ   R1,#vType_integer       ;No -- call it an integer
+               MOVNE   R1,#vType_lvInt         ;Yes -- call it an int lval
+               BICNE   R6,R6,#eFlag__lval      ;Clear lvalue flag too
+               ORRNE   R6,R6,#eFlag__parseLval ;But carry on parsing one!
+               BL      exp__pushVal            ;Push that on the calc stack
+               CMP     R9,#'$'                 ;Is this a dollar?
+               MOVLT   R0,#(exp__bPling-exp__bTable)>>2
+               MOVEQ   R0,#(exp__bDollar-exp__bTable)>>2
+               MOVGT   R0,#(exp__bQuery-exp__bTable)>>2
+               ORR     R0,R0,#1<<24            ;Make it precedence 1
+               BL      exp__pushOp             ;Stick that on the op stack
+               BL      getToken                ;Get another token
+               B       %10express_read         ;And read the operand
+
+               ; --- Read a hexadecimal number ---
+
+exp__readHex   MOV     R0,#0                   ;Initial value is zero
+               BL      getToken                ;Get a first token
+               SUB     R14,R9,#'A'             ;Is this a letter
+               CMP     R14,#6                  ;If so, make sure it's OK
+               ADDCC   R14,R14,#10             ;And move on to 10-15
+               SUBCS   R14,R9,#'0'             ;Otherwise check for digit
+               CMPCS   R14,#10                 ;Make sure that's in range
+               MOVCS   R0,#err_badHex          ;If not, make an error
+               BCS     error_report            ;And stop doing this
+
+00express_read ADD     R0,R14,R0,LSL #4        ;Accumulate a result
+               BL      getToken                ;Get another token
+               SUB     R14,R9,#'A'             ;Is this a letter
+               CMP     R14,#6                  ;If so, make sure it's OK
+               ADDCC   R14,R14,#10             ;And move on to 10-15
+               SUBCS   R14,R9,#'0'             ;Otherwise check for digit
+               CMPCS   R14,#10                 ;Make sure that's in range
+               BCC     %b00express_read        ;If it was OK, go round more
+
+               MOV     R1,#vType_integer       ;Call it an integer
+               BL      exp__pushVal            ;Stick that on the val stack
+               TST     R6,#eFlag__parseLval    ;Parsing an lvalue?
+               ORRNE   R6,R6,#eFlag__done      ;Yes -- we're finished
+               ORR     R6,R6,#eFlag__op        ;Now look for binary operator
+               B       %10express_read         ;And read the operator
+
+               ; --- Read a binary number ---
+
+exp__readBin   MOV     R0,#0                   ;Initial value is zero
+               BL      getToken                ;Get a first token
+               SUB     R14,R9,#'0'             ;Otherwise check for digit
+               CMP     R14,#1                  ;Make sure that's in range
+               MOVHI   R0,#err_badHex          ;If not, make an error
+               BHI     error_report            ;And stop doing this
+
+00express_read ADC     R0,R0,R0                ;Accumulate a result
+               BL      getToken                ;Get another token
+               SUB     R14,R9,#'0'             ;Otherwise check for digit
+               CMP     R14,#1                  ;Make sure that's in range
+               BLS     %b00express_read        ;If it was OK, go round more
+
+               MOV     R1,#vType_integer       ;Call it an integer
+               BL      exp__pushVal            ;Stick that on the val stack
+               TST     R6,#eFlag__parseLval    ;Parsing an lvalue?
+               ORRNE   R6,R6,#eFlag__done      ;Yes -- we're finished
+               ORR     R6,R6,#eFlag__op        ;Now look for binary operator
+               B       %10express_read         ;And read the operator
+
+               ; --- Read a decimal number ---
+
+exp__readDec   MOV     R0,#0                   ;Initial value is zero
+
+00express_read ADD     R0,R0,R0,LSL #2         ;Multiply accumulator by 5
+               ADD     R0,R14,R0,LSL #1        ;Accumulate the result
+
+               BL      getToken                ;Get another token
+               SUB     R14,R9,#'0'             ;Otherwise check for digit
+               CMP     R14,#10                 ;Make sure that's in range
+               BCC     %b00express_read        ;If it was OK, go round more
+
+               MOV     R1,#vType_integer       ;Call it an integer
+               BL      exp__pushVal            ;Stick that on the val stack
+               TST     R6,#eFlag__parseLval    ;Parsing an lvalue?
+               ORRNE   R6,R6,#eFlag__done      ;Yes -- we're finished
+               ORR     R6,R6,#eFlag__op        ;Now look for binary operator
+               B       %10express_read         ;And read the operator
+
+               ; --- Read an identifier ---
+
+exp__readIdent ADR     R1,sail_misc            ;Point to a nice block
+               MOV     R2,#vType_integer       ;The current variable type
+
+00express_read SUBS    R4,R9,#'_'              ;Is it an underscore?
+               SUBNE   R4,R9,#'0'              ;Or a number?
+               CMP     R4,#10
+               SUBCS   R4,R9,#'A'              ;Or a capital letter?
+               CMPCS   R4,#26
+               SUBCS   R4,R9,#'a'              ;Or a lowercase letter?
+               CMPCS   R4,#26
+               STRCCB  R9,[R1],#1              ;Yes -- store it away
+               BLCC    getToken                ;Read the next byte
+               MOVCS   R0,#err_unknown         ;Don't know this -- error!
+               BCS     error_report            ;So give a bogus error msg
+
+               CMP     R9,#'$'                 ;Is it a dollar sign?
+               MOVEQ   R2,#vType_string        ;It's a string now
+               CMPNE   R9,#'%'                 ;Or a percentage?
+               STREQB  R9,[R1],#1              ;Yes -- store it then
+               CMPNE   R9,#' '                 ;Just check for a space
+
+               BNE     %b00express_read        ;Go round for more
+
+               MOV     R14,#0                  ;The terminator
+               STRB    R14,[R1],#0             ;Store that in the var name
+               BL      getToken                ;Read the next token ready
+
+               ; --- Check for arrays ---
+
+               CMP     R9,#'('                 ;Is this an array?
+               BNE     %f05                    ;No -- skip on then
+               BL      getToken                ;Get another token
+               ADD     R2,R2,#vType_dimInt-vType_integer
+               MOV     R0,R2                   ;Put that in R2
+               ADR     R1,sail_misc            ;Point to variable name
+               BL      var_find                ;Find the variable
+               LDR     R14,sail_varTree                ;Find var tree anchor
+               LDR     R14,[R14,#0]            ;Grrr...
+               SUB     R3,R0,R14               ;Convert this to an offset
+               TST     R6,#eFlag__lval         ;Reading an lvalue?
+               ADDNE   R2,R2,#vType_lvIntArr-vType_dimInt
+
+               CMP     R9,#')'                 ;Is it a whole array?
+               BEQ     %f00                    ;Yes -- deal with that
+
+               ; --- Set up for subscripting the array ---
+
+               STMFD   R13!,{R2}               ;Save some registers
+               MOV     R0,R3                   ;Get the array's offset
+               BL      exp__pushOp             ;Stuff that on op stack (!)
+               LDMFD   R13!,{R0}               ;And get its type
+               BL      exp__pushOp             ;Stuff that on op stack too
+
+               GETOP   R0,254,exp__bSubscript  ;Get the operator value
+               TST     R6,#eFlag__commaOk      ;Are we allowing commas?
+               ORRNE   R0,R0,#1<<16            ;Yes -- set the flag then
+               TST     R6,#eFlag__lval         ;Are we reading an value?
+               ORRNE   R0,R0,#1<<17            ;Yes -- set that flag
+               BL      exp__pushOp             ;Put that on there
+               ORR     R6,R6,#eFlag__commaOk   ;Allow commas for a while
+               BIC     R6,R6,#eFlag__lval      ;Don't read as lvalues
+               ADD     R6,R6,#1<<8             ;Increment the paren count
+               B       %10express_read         ;Now read the subscripts
+
+               ; --- Just store the array lvalue ---
+
+00             BL      getToken                ;Skip over the bracket
+               MOV     R1,R2                   ;Get the type
+               MOV     R0,R3                   ;And the tree offset
+               BL      exp__pushVal            ;Stash it on the stack
+               ORR     R6,R6,#eFlag__op        ;Expect an operator
+               B       %10express_read         ;And go read that
+
+               ; --- Handle strings and things ---
+
+05             TST     R6,#eFlag__lval         ;Are we reading an lvalue?
+               BNE     %f20express_read        ;Yes -- jump ahead
+
+               TST     R6,#eFlag__parseLval    ;Parsing an lvalue?
+               ORRNE   R6,R6,#eFlag__done      ;Yes -- we're finished
+
+               ADR     R1,sail_misc            ;Point to variable name
+               MOV     R0,R2                   ;Get the variable type too
+               BL      var_find                ;Try to find the variable
+
+               ; --- Do wildly different things with strings ---
+
+               CMP     R2,#vType_string        ;Is this a string
+               BNE     %f00                    ;No -- jump ahead then
+               LDR     R14,sail_varTree                ;Load base of variable tree
+               LDR     R14,[R14]
+               SUB     R0,R0,R14               ;Get the offset of node
+               ADD     R0,R0,#4                ;Point to the actual word
+               MOV     R1,#vType_lvString      ;The variable type
+               BL      ctrl_load               ;Load the string into stracc
+               MOV     R0,R2                   ;Put rvalue into R0,R1
+               MOV     R1,R3
+               BL      exp__pushVal            ;Stack that nicely
+               ORR     R6,R6,#eFlag__op        ;Expect an operator
+               B       %10express_read         ;And keep on looking
+
+00express_read MOV     R1,R2                   ;Get the operand type
+               LDR     R0,[R0,#4]              ;Load the integer value
+               BL      exp__pushVal            ;Stack that nicely
+
+               ; --- Now try to cope with indirection ---
+
+               CMP     R9,#'!'                 ;Is this an indirection op?
+               CMPNE   R9,#'?'                 ;Or maybe a different one
+               ORRNE   R6,R6,#eFlag__op        ;No -- expect an operator
+               BNE     %10express_read         ;And go for that then
+
+               CMP     R9,#'?'                 ;Is this a '?' ?
+               MOVEQ   R0,#(exp__bQuery-exp__bTable)>>2
+               MOVNE   R0,#(exp__bPling-exp__bTable)>>2
+               ORR     R0,R0,#1<<24            ;Use unary op precedence
+               BL      exp__pushOp             ;Stick that on the stack
+               BL      getToken                ;Get another token
+               B       %10express_read         ;Return, still expecting val
+
+               ; --- We are reading an lvalue ---
+               ;
+               ; We only need to create the variable if there is not an
+               ; indirection operator following.
+
+20express_read CMP     R9,#'!'                 ;Is this an indirection op?
+               CMPNE   R9,#'?'                 ;Or maybe a different one
+               ORRNE   R6,R6,#eFlag__done      ;Yes -- we're finished
+               BIC     R6,R6,#eFlag__lval      ;Clear lvalue flag too
+               ORR     R6,R6,#eFlag__parseLval ;Parse an lvalue-ish now
+
+               ADR     R1,sail_misc            ;Point to variable name
+               MOV     R0,R2                   ;Get the variable type too
+               BLNE    var_create              ;Create the variable maybe
+               BLEQ    var_find                ;Or maybe we just find it
+
+               ADR     R14,exp__indirTran      ;Point to the translation
+               LDRB    R1,[R14,R2]             ;Get the new type
+               LDRNE   R14,sail_varTree                ;Get the tree address
+               LDRNE   R14,[R14]               ;Wimp_Extension is shitty
+               SUBNE   R0,R0,R14               ;Find the offset
+               ADDNE   R0,R0,#4                ;Point to the actual value
+               LDREQ   R0,[R0,#4]              ;If indirect op, load value
+               BL      exp__pushVal            ;Push on the new value
+
+               CMP     R9,#'?'                 ;Is this a '?' ?
+               MOVEQ   R0,#(exp__bQuery-exp__bTable)>>2
+               MOVNE   R0,#(exp__bPling-exp__bTable)>>2
+               CMPNE   R9,#'!'                 ;Or a '!' ?
+               ORREQ   R0,R0,#1<<24            ;Use unary op precedence
+               BLEQ    exp__pushOp             ;Stick that on the stack
+               BLEQ    getToken                ;Get a token if we need to
+
+               B       %10express_read         ;Return, still expecting val
+
+               ; --- Try reading an operator ---
+
+50express_read CMP     R9,#')'                 ;Is this a close bracket?
+               BEQ     exp__en                 ;Yes -- deal with that then
+
+               CMP     R9,#','                 ;Is it a comma?
+               BEQ     exp__comma              ;Yes -- deal with that
+
+               ADRL    R5,exp__opTable         ;Point to the op table
+               LDR     R0,[R5,R7,LSL #3]!      ;Load the precedence
+               CMP     R0,#0                   ;Is this reasonable?
+               ORREQ   R6,R6,#eFlag__done      ;No -- stop then
+               BEQ     %10express_read         ;Let things tidy up nicely
+
+               BL      exp__eval               ;Evaluate things on the stack
+               LDR     R5,[R5,#4]              ;Load the branch table offset
+               ORR     R0,R5,R0,LSL #24        ;Build the op stack entry
+               ADD     R0,R0,R8                ;Add on the op index
+               BL      exp__pushOp             ;Stick that on the stack
+               BL      getToken                ;Get another token
+               BIC     R6,R6,#eFlag__op        ;Expect another operand
+               B       %10express_read         ;And go round again
+
+               ; --- Handle a closing bracket ---
+
+exp__en                SUBS    R6,R6,#1<<8             ;Decrement paren counter
+               ORRLT   R6,R6,#eFlag__done      ;If no parens, then stop
+               BLT     %10express_read         ;It was someone else's `)'
+               BL      getToken                ;Get another token
+               MOV     R0,#252                 ;Stop at the dummy `(' op
+               BL      exp__eval               ;Force evaluation of that lot
+               BL      exp__popOp              ;Pop the dummy operator
+
+               ; --- Check for comma-separated pseudo-ops ---
+
+               MOV     R14,R0,LSR #24          ;Get the op precedence
+               CMP     R14,#254                ;Is it a cs-pseudo-op?
+               BNE     %10express_read         ;No -- keep going then
+
+               ; --- Reset the flags from the operator ---
+
+               BIC     R6,R6,#eFlag__lval+eFlag__commaOk
+               TST     R0,#1<<16               ;Is the comma-ok flag set?
+               ORRNE   R6,R6,#eFlag__commaOk   ;Yes -- then set it in R6
+               TST     R0,#1<<17               ;Is the lvalue flag set?
+               ORRNE   R6,R6,#eFlag__done+eFlag__lval
+
+               ; --- Now do the required processing ---
+
+               MOV     R5,R0,LSR #8            ;Get the number of arguments
+               ADD     R5,R5,#1                ;One less comman than subs
+               AND     R5,R5,#&FF              ;Clear the other bits
+               AND     R0,R0,#&FF              ;Also find jump entry
+               ADRL    R14,exp__bTable         ;Find the op table
+               ADD     PC,R14,R0,LSL #2        ;And dispatch
+
+               ; --- Handle a comma ---
+
+exp__comma     TST     R6,#eFlag__commaOk      ;Expecting a comma here?
+               ORREQ   R6,R6,#eFlag__done      ;No -- must be someone else's
+               BEQ     %10express_read         ;So let them handle it
+               BL      getToken                ;Gobble the comma char
+               MOV     R0,#253                 ;Evaluate up to pseudoop
+               BL      exp__eval               ;Do lots of evaluating
+               BL      exp__popOp              ;Pop the pseudoop
+               ADD     R0,R0,#1<<8             ;Bump the argument count
+               BL      exp__pushOp             ;Put the pseudoop back again
+               BIC     R6,R6,#eFlag__op        ;Read another operand
+               B       %10express_read         ;Now continue doing things
+
+               ; --- We have finished reading the expression ---
+
+70express_read MOV     R0,#254                 ;Choose a suitable prec.
+               BL      exp__eval               ;Do rest of evaluations
+               BL      exp__popOp              ;Pop of the expression
+
+               ; --- See if this was an evaluated string ---
+
+               AND     R14,R0,#&FF             ;Get the branch table offset
+               CMP     R14,#(exp__bEvalOp-exp__bTable)>>2
+               BEQ     exp__endEval            ;Yes -- continue doing that
+
+               LDMFD   R13!,{R0-R6,PC}^        ;Load some registers
+
+exp__indirTran DCB     vType_lvInt
+               DCB     vType_lvString
+               DCB     vType_lvIntArr
+               DCB     vType_lvStrArr
+
+               LTORG
+
+; --- exp__eval ---
+;
+; On entry:    R0 == precedence to look for
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R1-R4 corrupted
+;
+; Use:         Performs things
+
+exp__eval      ROUT
+
+               STMFD   R13!,{R0,R14}           ;Stack some registers
+00exp__eval    BL      exp__popOp              ;Pop an operator
+               LDR     R1,[R13,#0]             ;Load back thing
+               CMP     R1,R0,LSR #24           ;Compare the prec things
+               BLT     %10exp__eval            ;It's GE so jump ahead
+               MOV     R2,R0                   ;Put op thing in R2
+               AND     R0,R0,#&FF              ;Get the branch offset
+               ADR     R1,exp__bTable          ;Point to the table
+               ADD     PC,R1,R0,LSL #2         ;Branch to the do it routine
+exp__evalRet   BL      exp__pushVal            ;Push the returned value
+               B       %00exp__eval            ;And keep on going
+
+10exp__eval    BL      exp__pushOp             ;Push it back on again
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+; --- exp__doMultArg ---
+;
+; On entry:    R5 == number of subscripts provided
+;              R6 == flags
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == upcall block pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Subscripts an array of things to find just one of them.
+
+exp__doMultArg ROUT
+
+               BL      exp__popOp              ;Pop off the function
+               AND     R0,R0,#&FF              ;Get the branch offset
+               ADR     R1,exp__bTable          ;Point to the table
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R1,R0,LSL #2         ;Branch to the do it routine
+               BL      exp__pushVal            ;Push the returned value
+               B       exp__mainLoop           ;Go back to main loop
+
+               LTORG
+
+               ; --- A nice precedance table ----
+
+exp__opTable   DCD     0,0
+               DCD     25,(exp__andOps-exp__bTable)>>2
+               DCD     0,0
+               DCD     0,0
+               DCD     0,0
+               DCD     0,0
+               DCD     0,0
+               DCD     10,(exp__multOps-exp__bTable)>>2
+               DCD     30,(exp__orOps-exp__bTable)>>2
+               DCD     0,0
+               DCD     0,0
+               DCD     0,0
+               DCD     20,(exp__relOps-exp__bTable)>>2
+               DCD     15,(exp__addOps-exp__bTable)>>2
+               DCD     0,0
+               DCD     5,(exp__powOps-exp__bTable)>>2
+
+               ; --- The main dispatch table ---
+
+exp__bTable
+
+exp__andOps    B       exp__doAnd
+
+exp__multOps   B       exp__doDiv
+               B       exp__doMod
+               B       exp__doDiv
+               B       exp__doMult
+
+exp__orOps     B       exp__doXor
+               B       exp__doOr
+
+exp__relOps    B       exp__doEqual
+               B       exp__doLess
+               B       exp__doLessEq
+               B       exp__doNotEq
+               B       exp__doMore
+               B       exp__doMoreEq
+               B       exp__doLSL
+               B       exp__doASR
+               B       exp__doLSR
+
+exp__addOps    B       exp__doAdd
+               B       exp__doSub
+
+exp__fns       B       exp__doAbs
+               B       exp__doAsc
+               B       exp__doChrS
+               B       exp__doEval
+               B       exp__doLen
+               B       exp__doNot
+               B       exp__doOpenin
+               B       exp__doOpenout
+               B       exp__doOpenup
+               B       exp__doSgn
+               B       exp__doStrS
+               B       exp__doVal
+
+exp__streamOps B       exp__doBget
+               B       exp__doEof
+               B       exp__doExt
+               B       exp__doGetS
+               B       exp__doPtr
+
+exp__multArgs  B       exp__doInstr
+               B       exp__doLeftS
+               B       exp__doMidS
+               B       exp__doRightS
+               B       exp__doStringS
+
+exp__powOps    B       exp__doPow
+
+exp__bUMinus   B       exp__doUMinus
+exp__bPar      B       exp__doParen
+exp__bExpEnd   B       exp__doEndEval
+exp__bEvalOp   B       exp__doEndEval
+exp__bPling    B       exp__doPling
+exp__bQuery    B       exp__doQuery
+exp__bDollar   B       exp__doDollar
+
+exp__bSubscript        B       exp__doSubscript
+
+exp__bMultArg  B       exp__doMultArg
+
+; --- exp__doAdd ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Adds two things.
+
+exp__doAdd     ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               CMP     R1,#vType_integer       ;Is this an integer?
+               BNE     %10exp__doAdd           ;No -- onwards ho
+
+               CMP     R3,#vType_integer       ;Is this a integer too?
+               MOVNE   R0,#err_numNeeded       ;No -- get error number
+               BNE     error_report            ;...and report the error
+               ADD     R0,R0,R2                ;Add the numbers together
+               B       exp__evalRet            ;Jump back into eval loop
+
+               ; --- Concatenate strings ---
+
+10exp__doAdd   CMP     R1,#vType_string        ;This is a string I hope
+               MOVNE   R0,#err_arrayBad        ;Arrays are bad
+               BNE     error_report            ;So says my mum
+               CMP     R3,#vType_string        ;Is this a string too?
+               MOVNE   R0,#err_strNeeded       ;No -- get error number
+               BNE     error_report            ;...and report the error
+
+               MOV     R14,R2,LSL #24          ;Get the second string len
+               CMN     R14,R0,LSL #24          ;Is the string short enough?
+               ADDCC   R0,R0,R14,LSR #24       ;Add on second length
+               BCC     exp__evalRet            ;Finished -- return
+
+               MOV     R0,#err_strTooLong      ;String is too long
+               B       error_report
+
+               LTORG
+
+; --- exp__doSub ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Subtracts one thing from another thing.
+
+exp__doSub     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               SUB     R0,R0,R2                ;Subtract the things
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doMult ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Multiplies two things together.
+
+exp__doMult    ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MUL     R0,R2,R0                ;Multiply the things
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doDiv ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Divides one thing by another thing.
+
+exp__doDiv     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MOV     R1,R2                   ;Get the other thing to do
+               BL      divide                  ;Divide the things
+               MOV     R1,#vType_integer       ;Set the return type
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doMod ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Gives the remainder when one thing is divided by another
+;              thing.
+
+exp__doMod     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MOV     R1,R2                   ;Get the dividend ready
+               BL      divide                  ;Divide the things
+               MOV     R0,R1                   ;Get the remainder
+               MOV     R1,#vType_integer       ;Get the type of the thing
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doPow ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Raises one thing to the power of another thing.
+
+exp__doPow     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+
+               ; --- Check for some special cases ---
+
+               CMP     R0,#1                   ;Raising 1 ^ anything...
+               CMPNE   R2,#0                   ;And raising anything ^ 0...
+               MOVEQ   R0,#1                   ;Gives you 1
+               BEQ     exp__evalRet            ;And return to eval loop
+
+               CMP     R2,#0                   ;Is the exponent negative?
+               MOVLT   R0,#0                   ;Yes -- result is fractional
+               BLT     exp__evalRet            ;And return to eval loop
+
+               ; --- Now we use a cunning loop to make this quick ---
+               ;
+               ; Basically, we note that x^2y == (x^2)^y
+
+               MOV     R3,R0                   ;Look after the x value
+               MOV     R0,#1                   ;An initial multiplier
+
+10exp__doPow   MOVS    R2,R2,LSR #1            ;Get bottom bit
+               MULCS   R0,R3,R0                ;If set, do multiply
+               MUL     R14,R3,R3               ;Square thing to raise
+               MOV     R3,R14                  ;Can't do in one instr :-(
+               BNE     %10exp__doPow           ;If not finished, continue
+
+               B       exp__evalRet            ;Go back to eval loop
+
+               LTORG
+
+; --- exp__doAnd ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         ANDs two things.
+
+exp__doAnd     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               AND     R0,R0,R2                ;Do the AND op
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doOr ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         ORs two things.
+
+exp__doOr      ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               ORR     R0,R0,R2                ;Do the OR op
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doXor ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         XORs two things.
+
+exp__doXor     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               EOR     R0,R0,R2                ;Do the XOR op
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doPling ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Reads a word from a memory address.
+
+exp__doPling   ROUT
+
+               BL      exp__popTwoVals         ;Get next two values
+               CMP     R1,#vType_lvInt         ;We can cope with lvalues
+               BEQ     %50exp__doPling         ;If this is the case, be odd
+               BL      exp__chkTwoInts         ;Make sure we have integers
+               LDR     R0,[R0,R2]              ;Load the word
+               B       exp__evalRet            ;Jump back into eval loop
+
+50exp__doPling CMP     R3,#vType_integer       ;Make sure other val is int
+               MOVNE   R0,#err_numNeeded       ;If not, moan at the user
+               BNE     error_report            ;That's that done then
+               ADD     R0,R0,R2                ;Calculate the address
+               MOV     R1,#vType_lvWord        ;This is a word lvalue
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doQuery ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Reads a byte from a memory address.
+
+exp__doQuery   ROUT
+
+               BL      exp__popTwoVals         ;Get next two values
+               CMP     R1,#vType_lvInt         ;We can cope with lvalues
+               BEQ     %50exp__doQuery         ;If this is the case, be odd
+               BL      exp__chkTwoInts         ;Make sure we have integers
+               LDRB    R0,[R0,R2]              ;Load the byte
+               B       exp__evalRet            ;Jump back into eval loop
+
+50exp__doQuery CMP     R3,#vType_integer       ;Make sure other val is int
+               MOVNE   R0,#err_numNeeded       ;If not, moan at the user
+               BNE     error_report            ;That's that done then
+               ADD     R0,R0,R2                ;Calculate the address
+               MOV     R1,#vType_lvByte        ;This is a byte lvalue
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doDollar ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Reads a word from a memory address.
+
+exp__doDollar  ROUT
+
+               BL      exp__popTwoVals         ;Get next two values
+               CMP     R1,#vType_lvInt         ;We can cope with lvalues
+               BEQ     %50exp__doDollar        ;If this is the case, be odd
+               BL      exp__chkTwoInts         ;Make sure we have integers
+
+               ADD     R2,R0,R2                ;Point to the string
+               BL      stracc_ensure           ;Make sure there is room
+               MOV     R3,#0                   ;Number so far
+00             LDRB    R14,[R2],#1             ;Load a byte
+               CMP     R14,#13                 ;Is this the terminator?
+               BEQ     %10exp__doDollar        ;Yes -- jump ahead
+               STRB    R14,[R0],#1             ;No -- save it away
+               ADD     R3,R3,#1                ;Increment the length
+               CMP     R3,#255                 ;Are we at the maximum?
+               BLT     %b00                    ;No -- branch back then
+
+10             ORR     R0,R1,R3                ;Set up the lvalue
+               MOV     R1,#vType_string        ;This is a string
+               B       exp__evalRet            ;Jump back into eval loop
+
+               ; --- The lvalue form ---
+
+50exp__doDollar        CMP     R3,#vType_integer       ;Make sure other val is int
+               MOVNE   R0,#err_numNeeded       ;If not, moan at the user
+               BNE     error_report            ;That's that done then
+               ADD     R0,R0,R2                ;Calculate the address
+               MOV     R1,#vType_lvBytes       ;This is a bytes lvalue
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- RND ---
+
+exp__doRnd     ROUT
+
+               CMP     R9,#'('                 ;Do we have a bracket here?
+               MOVNE   R0,#-1                  ;No -- range here then
+               BLNE    exp__rng                ;And generate random number
+               ORRNE   R6,R6,#eFlag__op        ;Read operator next
+               BNE     exp__mainLoop           ;And go back up top
+               BL      getToken                ;Gobble the bracket
+
+               ; --- Start scanning for an RND multi-op ---
+
+               GETOP   R0,1,exp__rndArg        ;Get the operator value
+               BL      exp__pushOp             ;Put that on the stack
+
+               GETOP   R0,254,exp__bMultArg    ;Get the operator value
+               TST     R6,#eFlag__commaOk      ;Are we allowing commas?
+               ORRNE   R0,R0,#1<<16            ;Yes -- set the flag then
+               BL      exp__pushOp             ;Put that on there
+               BIC     R6,R6,#eFlag__commaOk   ;Disallow commas for a while
+               ADD     R6,R6,#1<<8             ;Increment the paren count
+               B       exp__mainLoop           ;And go back up top
+
+               LTORG
+
+; --- RND(arg) ---
+
+exp__rndArg    ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               BL      exp__popInt             ;Pop off the argument
+               CMP     R0,#0                   ;Is the value negative?
+               BLT     %50exp__rndArg          ;Yes -- deal with that
+               CMPNE   R0,#1                   ;Is it one then?
+               BEQ     %60exp__rndArg          ;Yes -- be odd then
+               BL      exp__rng                ;And generate random number
+               BL      exp__popVal             ;Pop the value off
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               ; --- Store a seed ---
+
+50exp__rndArg  STR     R0,sail_rndSeed         ;Store the new seed
+               MOV     R14,#0                  ;Clear the top bit
+               STR     R14,sail_rndSeed+4      ;Store that too
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               ; --- Request for FP random number ---
+
+60exp__rndArg  STMFD   R13!,{R5}               ;Save another register
+               MOV     R0,#0                   ;Return zero here
+               MOV     R1,#vType_integer       ;Say this is an integer
+               LDMFD   R13!,{R5,PC}^           ;And return
+
+               LTORG
+
+; --- exp__rng ---
+;
+; On entry:    R0 == maximum value for random number
+;
+; On exit:     --
+;
+; Use:         Stacks a random number between 1 and R0.
+
+exp__rng       ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save lots of registers
+               MOV     R3,R0                   ;Look after this
+               ADR     R14,sail_rndSeed                ;Find the random seed
+               LDMIA   R14,{R0,R1}             ;Load that out
+               TST     R1,R1,LSR #1            ;Top bit into carry
+               MOVS    R2,R0,RRX               ;33-bit rotate right
+               ADC     R1,R1,R1                ;Carry into LSB of Rb
+               EOR     R2,R2,R0,LSL #12        ;(Involved!)
+               EOR     R0,R2,R2,LSR #20        ;(Similarly involved!)
+               STMIA   R14,{R0,R1}             ;Store new seed back
+               MOV     R1,R3                   ;Get maximum value again
+               BL      div_unsigned            ;Do the division we need
+               ADD     R0,R1,#1                ;Fit it into range
+               MOV     R1,#vType_integer       ;This is an integer
+               BL      exp__pushVal            ;Push it onto the stack
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               LTORG
+
+; --- Relational operators (and shifts) ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Does comparing.  Or shifting.  Depending.
+
+exp__doLess    ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVLT   R0,#-1                  ;It's less -- that's true
+               MOVGE   R0,#0                   ;It's more or equal, -- false
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doMore    ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVGT   R0,#-1                  ;It's more -- that's true
+               MOVLE   R0,#0                   ;It's less or equal, -- false
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doLessEq  ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVLE   R0,#-1                  ;It's less or equal -- true
+               MOVGT   R0,#0                   ;It's more -- that's false
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doMoreEq  ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVGE   R0,#-1                  ;It's more or equal -- true
+               MOVLT   R0,#0                   ;It's less -- that's false
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doEqual   ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVEQ   R0,#-1                  ;If equal, return TRUE
+               MOVNE   R0,#0                   ;Otherwise return FALSE
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doNotEq   ROUT
+
+               BL      exp__popTwoVals         ;Get two values
+               BL      ctrl_compare            ;Compare them
+               MOVNE   R0,#-1                  ;If nonzero, return TRUE
+               MOVEQ   R0,#0                   ;Otherwise return FALSE
+               MOV     R1,#vType_integer       ;We are returning an integer
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doLSL     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MOV     R0,R0,LSL R2            ;Do the shift
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doLSR     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MOV     R0,R0,LSR R2            ;Do the shift
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+exp__doASR     ROUT
+
+               BL      exp__popTwoInts         ;Get two integers
+               MOV     R0,R0,ASR R2            ;Do the shift
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doUMinus ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Negates a thing.
+
+exp__doUMinus  ROUT
+
+               BL      exp__popInt             ;Pop a val
+               RSB     R0,R0,#0                ;Negate the thing
+               B       exp__evalRet            ;Jump back into eval loop
+
+               LTORG
+
+; --- exp__doSubscript ---
+;
+; On entry:    R5 == number of subscripts provided
+;              R6 == flags
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == upcall block pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Subscripts an array of things to find just one of them.
+
+exp__doSubscript ROUT
+
+               BL      exp__popOp              ;Read the array's type
+               STMFD   R13!,{R0}               ;Save that away
+               BL      exp__popOp              ;Now find the offset too
+               LDMFD   R13!,{R2}               ;Restore the type word
+               LDR     R14,sail_varTree                ;Find the variable tree
+               LDR     R14,[R14,#0]            ;Grrr...
+               ADD     R3,R0,R14               ;Find the actual array
+
+               ; --- Do some preliminary checking ---
+
+               LDR     R14,[R3,#4]             ;Find number of subscripts
+               CMP     R14,R5                  ;Do they match up?
+               MOVNE   R0,#err_numSubs         ;No -- get an error
+               BNE     error_report            ;And report it
+
+               ; --- Now actually find the element ---
+
+               STMFD   R13!,{R2,R7-R10}        ;Save some more registers
+               ADD     R10,R3,#12              ;Point to subscripts
+               ADD     R10,R10,R5,LSL #2       ;Find topmost subscript
+               MOV     R9,R10                  ;Do this again
+               MOV     R8,#0                   ;Current element is 0
+               MOV     R7,R5                   ;Get the number of subscripts
+
+00             BL      exp__popInt             ;Read the next integer
+               LDR     R14,[R9,#-4]!           ;And load subscript size
+               CMP     R0,R14                  ;How does this compare?
+               MOVCS   R0,#err_subRange        ;Out of range -- get error
+               BCS     error_report            ;And report it
+               MLA     R8,R14,R8,R0            ;Accumulate subscript
+               SUBS    R7,R7,#1                ;Decrement my counter
+               BGT     %b00                    ;If more to go, keep on
+
+               ; --- Finally get an rvalue or lvalue as required ---
+
+               ADD     R0,R10,R8,LSL #2        ;Find the lvalue
+               LDMFD   R13!,{R1,R7-R10}        ;Restore system registers
+               LDR     R14,sail_varTree                ;Find the variable tree
+               LDR     R14,[R14,#0]            ;Grrr...
+               SUB     R0,R0,R14               ;Yes -- turn into offset
+               TST     R6,#eFlag__lval         ;Reading an lvalue?
+               SUBNE   R1,R1,#vType_lvIntArr-vType_lvInt
+               SUBEQ   R1,R1,#vType_dimInt-vType_lvInt
+               BLEQ    ctrl_load               ;No -- load rvalue then
+               MOVEQ   R0,R2                   ;And shift results around
+               MOVEQ   R1,R3                   ;Because of strangeness
+               BL      exp__pushVal            ;Push the result
+               B       exp__mainLoop           ;Go back to main loop
+
+               LTORG
+
+; --- exp__doParen ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Complains.
+
+exp__doParen   ROUT
+
+               MOV     R0,#err_expBracket      ;Get the error message
+               B       error_report            ;And complain bitterly
+
+               LTORG
+
+; --- exp__doEndEval ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0-R3 corrupted
+;
+; Use:         Complains.
+
+exp__doEndEval ROUT
+
+               MOV     R0,#err_erk             ;Get the error message
+               B       error_report            ;And complain bitterly
+
+               LTORG
+
+; --- exp__getString ---
+;
+; On entry:    R0 == buffer for string
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0 == length of string
+;
+; Use:         Reads a string argument, and copies it into sail_misc.
+
+exp__getString ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Stack some register
+               MOV     R5,R0                   ;Look after address
+               BL      exp__popStr             ;Get a string
+               LDR     R1,sail_stracc          ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+               MOV     R3,R0                   ;Look after the rvalue
+               MOV     R0,R5                   ;Point to a buffer
+               BL      termite_copyString      ;Copy the string over
+               MOV     R0,R3                   ;Put the rvalue back
+               BL      stracc_free             ;Won't need it any more
+               MOV     R0,R2                   ;Put the length in R0
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to caller
+
+               LTORG
+
+;----- Pseudovariables ------------------------------------------------------
+
+; --- TIME ---
+
+exp__doTime    STMFD   R13!,{R14}
+               SWI     OS_ReadMonotonicTime
+               LDR     R1,sail_timeOff
+               SUB     R0,R0,R1
+               MOV     R1,#vType_integer
+               BL      exp__pushVal
+               LDMFD   R13!,{PC}^
+
+; --- TIME$ ---
+
+exp__doTimeS   STMFD   R13!,{R14}              ;Save some registers
+
+               ; --- First, read the system clock ---
+
+               SUB     R13,R13,#8              ;Get a nice block
+               MOV     R0,#14                  ;Read the system clock
+               MOV     R1,R13                  ;Point to the block
+               MOV     R14,#3                  ;Get the reason code
+               STRB    R14,[R1,#0]             ;Store in block
+               SWI     OS_Word                 ;Read the time then
+
+               ; -- Now put it into stracc ---
+
+               BL      stracc_ensure           ;Make sure we have room
+               MOV     R4,R1                   ;Remember the index
+               MOV     R1,R0                   ;Put the address in R1
+               MOV     R0,R13                  ;Point to time block
+               MOV     R2,#255                 ;Size of the buffer
+               ADR     R3,exp__timeFormat      ;Point to the format
+               SWI     OS_ConvertDateAndTime   ;Convert the date and time
+               ORR     R0,R4,#24               ;Set up the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               ADD     R13,R13,#8              ;Reclaim my stack
+               BL      exp__pushVal            ;Push on my value
+               LDMFD   R13!,{PC}^              ;Return the caller
+
+exp__timeFormat        DCB     "%W3,%DY %M3 %CE%YR.%24:%MI:%SE",0
+
+; --- FALSE ---
+
+exp__doFalse   MOV     R0,#0
+               MOV     R1,#vType_integer
+               B       exp__pushVal
+
+; --- TRUE ---
+
+exp__doTrue    MOV     R0,#-1
+               MOV     R1,#vType_integer
+               B       exp__pushVal
+
+;----- Functions ------------------------------------------------------------
+
+; --- EVAL ---
+
+exp__doEval    ROUT
+
+               ; --- Hack the stack ---
+               ;
+               ; We're called from exp__eval, which has stacked R0 and R14.
+               ; We pop these off the stack, and stuff them onto the op
+               ; stack instead.  Yukmeister.
+
+               LDMFD   R13!,{R0}               ;Get R0 off the stack
+               BL      exp__pushOp             ;Push that onto op stack
+               LDMFD   R13!,{R0}               ;And R14 off too
+               BL      exp__pushOp             ;Push that onto op stack
+               MOV     R0,R5                   ;We need to corrupt R5
+               BL      exp__pushOp             ;Push that onto op stack
+
+               ; --- Tokenise the string to evaluate ---
+
+               BL      stracc_ensure           ;Make space for tokenised
+               STMFD   R13!,{R0,R1}            ;Save the address away
+               BL      exp__popStr             ;Pop the string
+               LDR     R14,sail_stracc         ;Load stracc anchor address
+               LDR     R14,[R14,#0]            ;Grrr....
+               MOV     R5,R0                   ;Remember this for a while
+               AND     R1,R0,#&FF              ;Get the string length
+               ADD     R0,R14,R0,LSR #8        ;Work out string address
+               LDMFD   R13!,{R2}               ;Load the address out
+               MOV     R3,#0                   ;Just tokenise the expression
+               BL      tokenise                ;Go and do that then
+               LDMFD   R13!,{R0}               ;Load the stracc rvalue
+               ADD     R0,R0,#&FF              ;Say it's very long
+               BL      stracc_added            ;And record that
+
+               ; --- Now save state on the op stack ---
+
+               STMFD   R13!,{R2}               ;Save the address again
+               MOV     R0,R5                   ;Save the stracc offset
+               BL      exp__pushOp             ;Stack that
+               MOV     R0,R6                   ;Save the eval flags
+               BL      exp__pushOp             ;Stack that
+               LDR     R0,sail_oldAnchor       ;Load the old anchor
+               BL      exp__pushOp             ;Push that away too
+               LDR     R0,sail_currAnchor      ;Load current file anchor
+               STR     R0,sail_oldAnchor       ;This is now the old one
+               LDR     R0,[R0,#0]              ;Load the actual pointer
+               SUB     R0,R10,R0               ;Find the file offset
+               BL      exp__pushOp             ;Push that away too
+               LDR     R14,sail_stracc         ;Input is now in stracc
+               STR     R14,sail_currAnchor     ;This is the new anchor
+               LDMFD   R13!,{R10}              ;Load the new address
+               GETOP   R0,255,exp__bEvalOp     ;Create a pseudoop
+               BL      exp__pushOp             ;Stuff that on the stack
+               MOV     R6,#0                   ;Just read an expression
+               MOV     R9,#-1                  ;Make getToken happy
+               BL      getToken                ;Prime the first token
+               B       exp__mainLoop           ;And resume the main loop
+
+               LTORG
+
+; --- exp__endEval ---
+
+exp__endEval   ROUT
+
+               BL      exp__popOp              ;Pop the file offset
+               MOV     R10,R0                  ;Look after this
+               LDR     R14,sail_oldAnchor      ;Load the previous anchor
+               STR     R14,sail_currAnchor     ;This is now the current one
+               LDR     R14,[R14,#0]            ;Bodge for wimpextension
+               ADD     R10,R14,R10             ;Relocate the output pointer
+               BL      exp__popOp              ;And the anchor pointer
+               STR     R0,sail_oldAnchor       ;Remember this now
+               SUB     R10,R10,#1              ;Quick hack now
+               MOV     R9,#-1                  ;Make getToken happy
+               BL      getToken                ;Prime lookahead token
+               BL      exp__popOp              ;Pop the express_read flags
+               MOV     R6,R0                   ;Re-instate them
+               BL      exp__popOp              ;Get the stracc offset
+               BL      stracc_free             ;Free *both* the strings
+               BL      exp__popOp              ;Get preserved R5 value
+               MOV     R5,R0                   ;Put that back nicely
+               BL      exp__popOp              ;Get stacked R14 value
+               STMFD   R13!,{R0}               ;Push that back on the stack
+               BL      exp__popOp              ;Get stacked R0 value
+               STMFD   R13!,{R0}               ;Push that back on the stack
+               BL      exp__popVal             ;Pop the result (odd)
+               B       exp__evalRet            ;Now leap back into routine
+
+               LTORG
+
+; --- VAL ---
+
+exp__doVal     ROUT
+
+               ADR     R0,sail_misc            ;Point to a buffer
+               BL      exp__getString          ;Get a string
+               ADR     R1,sail_misc            ;Point to the string
+
+               ; --- Scan the string ---
+               ;
+               ; We skip spaces, and stop at the first non space.
+               ; If that happens to be a minus sign, we remember that.
+
+00             LDRB    R14,[R1],#1             ;Read the character
+               CMP     R14,#0                  ;Are we at the end?
+               MOVEQ   R0,#0                   ;Yes -- get the rvalue
+               BEQ     %20exp__doVal           ;And jump ahead a bit
+               CMP     R14,#32                 ;Is this a space
+               BEQ     %b00                    ;Yes -- go round for more
+               CMP     R14,#'-'                ;Is it a minus sign?
+               SUBNE   R1,R1,#1                ;No -- backtrack then
+               MOV     R0,#10                  ;Read as base 10 by default
+               SWI     XOS_ReadUnsigned        ;Read the value
+               RSBEQ   R0,R2,#0                ;Negate if we should
+               MOVNE   R0,R2                   ;Otherwise don't bother
+               MOVVS   R0,#0                   ;Return 0 on an error
+20             MOV     R1,#vType_integer       ;This is an integer
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+;----- Arithmetic routine ---------------------------------------------------
+
+; --- ABS ---
+
+exp__doAbs     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               CMP     R0,#0                   ;Is the argument <0?
+               RSBLT   R0,R0,#0                ;Yes -- negate it then
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+; --- NOT ---
+
+exp__doNot     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MVN     R0,R0                   ;Invert the operand
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+; --- SGN ---
+
+exp__doSgn     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               CMP     R0,#0                   ;Compare argument with 0
+               MOVGT   R0,#1                   ;If bigger return 1
+               MOVLT   R0,#-1                  ;If smaller, return -1
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+;----- String associated routines -------------------------------------------
+
+; --- ASC ---
+
+exp__doAsc     ROUT
+
+               BL      exp__popStr             ;Get a string
+               BL      stracc_free             ;Won't need it any more
+               MOV     R1,#vType_integer       ;We will return an int
+               TST     R0,#&FF                 ;Is this a NULL string?
+               MOVEQ   R0,#-1                  ;Yes -- return -1 then
+               BEQ     exp__evalRet
+
+               LDR     R14,sail_stracc         ;Loacte stracc
+               LDR     R14,[R14]
+               ADD     R14,R14,R0,LSR #8       ;Point to the string
+               LDRB    R0,[R14,#0]             ;Load a byte
+               B       exp__evalRet            ;Return this to caller
+
+; --- CHR$ ---
+
+exp__doChrS    ROUT
+
+               BL      exp__popInt             ;Pop an integer
+               MOV     R2,R0                   ;Look after the value
+               BL      stracc_ensure           ;Make sure there's space
+               MOVS    R14,R2,LSR #8           ;Check the value's OK
+               STREQB  R2,[R0,#0]              ;If so, store it
+               ORREQ   R1,R1,#1                ;And set length one
+               MOV     R0,R1                   ;Get the rvalue
+               MOV     R1,#vType_string        ;Say it's a string
+               BL      stracc_added            ;Say I've added it
+               B       exp__evalRet            ;And return to eval loop
+
+
+; --- LEN ---
+
+exp__doLen     ROUT
+
+               BL      exp__popStr             ;Get a string
+               BL      stracc_free             ;Won't need it any more
+               AND     R0,R0,#&FF              ;Get the length
+               MOV     R1,#vType_integer       ;This is an integer
+               B       exp__evalRet            ;Return to eval loop
+
+; --- STR$ ---
+
+exp__doStrS    ROUT
+
+               TST     R2,#(1<<16)             ;Is this a hex conversion?
+               BL      exp__popInt             ;Pop an integer
+               MOV     R3,R0                   ;Put it in R3
+               BL      stracc_ensure           ;Make sure we have room
+               MOV     R4,R1                   ;Look after the offset
+               BNE     %10exp__doStrS          ;If hex -- jump ahead
+
+
+               MOV     R1,R0                   ;Write result to here
+               MOV     R2,#255                 ;Buffer is big
+               MOVS    R0,R3                   ;Put the number in here
+               RSBLT   R0,R0,#0                ;If -ve, mak positive
+               MOVLT   R14,#'-'                ;...get a minus ready
+               STRLTB  R14,[R1],#1             ;Store in the buffer
+               SWI     OS_ConvertInteger4      ;Convert to a string
+               SUB     R14,R1,R0               ;Get the string length
+               ADDLT   R14,R14,#1              ;There may be a minus
+               ORR     R0,R4,R14               ;Get the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about it
+               B       exp__evalRet            ;Return to eval loop
+
+               ; --- We need to output as hex ---
+
+10exp__doStrS  ADR     R1,sail_misc            ;Point to a nice buffer
+00             AND     R2,R3,#&F               ;Get teh remainder
+               MOV     R3,R3,LSR #4            ;Divide number by 16
+               ADD     R14,R2,#'0'             ;Turn into a digit
+               CMP     R14,#'9'+1              ;Is it too big for this?
+               ADDCS   R14,R14,#'A'-'9'-1      ;Yes -- turn into a letter
+               STRB    R14,[R1],#1             ;Save the next byte
+               CMP     R3,#0                   ;Have we finished now?
+               BNE     %b00                    ;Yes -- jump back then
+
+               ; --- Copy the digits over ---
+               ;
+               ; The characters are now in the buffer in reverse order
+
+               ADR     R2,sail_misc            ;Point to the buffer
+               SUBS    R2,R1,R2                ;Get the number of chars
+               ORR     R4,R4,R2                ;Put that in the index
+00             LDRGTB  R14,[R1,#-1]!           ;Load out  byte
+               STRGTB  R14,[R0],#1             ;Store that in the buffer
+               SUBS    R2,R2,#1                ;Reduce the number count
+               BGT     %b00                    ;And keep on doing this
+
+               MOV     R0,R4                   ;Get the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about it
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+;----- File operations ------------------------------------------------------
+
+; --- OPENOUT ---
+
+exp__doOpenout ADR     R0,sail_misc            ;Point to a buffer
+               BL      exp__getString          ;Get the string argument
+
+               MOV     R0,#&81                 ;The flags to open with
+               ADR     R1,sail_misc            ;Point to the name
+               SWI     XOS_Find                ;Try to open the file
+               BVS     error_reportReal        ;Return possible error
+               BL      exp__opened             ;Remember we opened the file
+
+               MOV     R1,#vType_integer       ;We will return an int
+               B       exp__evalRet            ;Return this to caller
+
+               LTORG
+
+; --- OPENUP ---
+
+exp__doOpenup  ADR     R0,sail_misc            ;Point to a buffer
+               BL      exp__getString          ;Get the string argument
+
+               MOV     R0,#&C7                 ;The flags to open with
+               ADR     R1,sail_misc            ;Point to the name
+               SWI     XOS_Find                ;Try to open the file
+               BVS     error_reportReal        ;Return possible error
+               BL      exp__opened             ;Remember we opened the file
+
+               MOV     R1,#vType_integer       ;We will return an int
+               B       exp__evalRet            ;Return this to caller
+
+               LTORG
+
+; --- OPENIN ---
+
+exp__doOpenin  ADR     R0,sail_misc            ;Point to a buffer
+               BL      exp__getString          ;Get the string argument
+
+               MOV     R0,#&47                 ;The flags to open with
+               ADR     R1,sail_misc            ;Point to the name
+               SWI     XOS_Find                ;Try to open the file
+               BVS     error_reportReal        ;Return possible error
+               BL      exp__opened             ;Remember we opened the file
+
+               MOV     R1,#vType_integer       ;We will return an int
+               B       exp__evalRet            ;Return this to caller
+
+               LTORG
+
+; --- exp__opened ---
+;
+; On entry:    R0 == file handle
+;
+; On exit:     --
+;
+; Use:         Remembers that a file has been opened.  (Bit bashing code
+;              courtesy of the RISC OS 3.5 Keyboard Drivers, duplicated
+;              without permission.)
+
+exp__opened    ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADR     R1,sail_files           ;Find file bit-array
+               MOV     R14,R0,LSR #5           ;Get word index
+               LDR     R14,[R1,R14,LSL #2]!    ;Load the word I want
+               MOV     R2,#(1<<31)             ;Set the top bit here
+               ORR     R14,R14,R2,ROR R0       ;Set the correct bit
+               STR     R14,[R1,#0]             ;Save the word back again
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Stream operations ----------------------------------------------------
+
+; --- BGET ---
+
+exp__doBget    ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MOV     R1,R0                   ;Put it in R1
+               SWI     XOS_BGet                ;Get a byte from the file
+               BVS     error_reportReal
+               MOV     R1,#vType_integer       ;It's an integer Jim
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+; --- EOF ---
+
+exp__doEof     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MOV     R1,R0                   ;Put it in R1
+               MOV     R0,#5                   ;Read EOF status
+               SWI     XOS_Args                ;Read it then
+               BVS     error_reportReal
+               MOVS    R0,R2                   ;Put result in R0
+               MOVNE   R0,#-1                  ;Make it -1 if TRUE
+               MOV     R1,#vType_integer       ;It's an integer Jim
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+; --- EXT ---
+
+exp__doExt     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MOV     R1,R0                   ;Put it in R1
+               MOV     R0,#2                   ;Read EOF status
+               SWI     XOS_Args                ;Read it then
+               BVS     error_reportReal
+               MOV     R0,R2                   ;Put result in R0
+               MOV     R1,#vType_integer       ;It's an integer Jim
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+; --- GET$ ---
+
+exp__doGetS    ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MOV     R4,R0                   ;Put it in R4
+               BL      stracc_ensure           ;Ensure there is enough space
+               MOV     R2,R0                   ;Remember the address
+               MOV     R3,R1                   ;And the offset
+               MOV     R1,R4                   ;Put file handle in R1
+               MOV     R4,#0                   ;The length so far
+00             SWI     XOS_BGet                ;Geta byte
+               BVS     error_reportReal        ;Report possible error
+               BCS     %10exp__doGetS          ;Undefined -- dropout
+               CMP     R0,#10                  ;Have we reached the end?
+               CMPNE   R0,#13
+               CMPNE   R0,#0
+               BEQ     %10exp__doGetS          ;Yes -- drop out
+               STRB    R0,[R2],#1              ;No -- store the byte
+               ADD     R4,R4,#1                ;And increment the count
+               CMP     R4,#255                 ;Have we read the maximum?
+               BLT     %b00                    ;No -- keep getting them
+
+10exp__doGetS  ORR     R0,R3,R4                ;Get the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               B       exp__evalRet            ;Return to eval loop
+
+; --- PTR ---
+
+exp__doPtr     ROUT
+
+               BL      exp__popInt             ;Get an integer
+               MOV     R1,R0                   ;Put it in R1
+               MOV     R0,#0                   ;Read EOF status
+               SWI     XOS_Args                ;Read it then
+               BVS     error_reportReal
+               MOV     R0,R2                   ;Put result in R0
+               MOV     R1,#vType_integer       ;It's an integer Jim
+               B       exp__evalRet            ;Return to eval loop
+
+               LTORG
+
+;---- Multiple argument things ----------------------------------------------
+
+; --- exp__midString ---
+;
+; On entry:    R1 == index into string
+;              R2 == number of chars needed
+;              String is in sail_misc
+;
+; On exit:     R0, R1 == value to push
+;
+; Use:         Performs a string extraction on the string
+
+exp__midString ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link
+               ADR     R0,sail_misc            ;Point to the string
+               ADD     R3,R0,R1                ;Copy from here
+               MOV     R4,R2                   ;Remember the length
+               BL      stracc_ensure           ;Make sure we have room
+               CMP     R2,#0                   ;Anything to copy?
+00             LDRGTB  R14,[R3],#1             ;Load a byte
+               STRGTB  R14,[R0],#1             ;Store it
+               SUBS    R2,R2,#1                ;Decrement the count
+               BGT     %b00                    ;Go round for more
+               ORR     R0,R1,R4                ;Get the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- LEFT$ ---
+
+exp__doLeftS   ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack registers
+               CMP     R5,#2                   ;Two of them?
+               MOVNE   R0,#err_leftSArgs       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               BL      exp__popInt             ;Get the number of chars
+               MOV     R2,R0                   ;Put that in R2
+               MOV     R1,#0                   ;From the beginning
+               ADR     R0,sail_misc            ;Point to a buffer
+               BL      exp__getString          ;Get then string
+               CMP     R2,R0                   ;Are we getting too many?
+               MOVCS   R2,R0                   ;Yes -- get this many
+               BL      exp__midString          ;Do the mid$
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- MID$ ---
+
+exp__doMidS    ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack registers
+               CMP     R5,#2                   ;Two of them?
+               CMPNE   R5,#3                   ;Or maybe 3?
+               MOVNE   R0,#err_midSArgs        ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               CMP     R5,#2                   ;Just two args?
+               BEQ     %10exp__doMidS          ;Yes -- jump ahead
+
+               BL      exp__popTwoInts         ;Get the number of chars
+               SUBS    R1,R0,#1                ;Put index in R1
+               MOVLT   R1,#0                   ;Put it in range
+               ADR     R0,sail_misc            ;Point to a buffer
+               BL      exp__getString          ;Get then string
+               CMP     R1,R0                   ;Is the index in range?
+               MOVGT   R1,R0                   ;No -- put it in range
+               SUB     R14,R0,R1               ;Get number of chars left
+               CMP     R2,R14                  ;Are we getting too many?
+               MOVCS   R2,R14                  ;Yes -- get this many
+               BL      exp__midString          ;Do the mid$
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               ; --- Deal with 2 arg variation ---
+
+10exp__doMidS  BL      exp__popInt             ;Get the index
+               SUB     R1,R0,#1                ;Put it in R1
+               ADR     R0,sail_misc            ;Point to a buffer
+               BL      exp__getString          ;Get the string
+               CMP     R1,R0                   ;Are we in range?
+               MOVCS   R1,R0                   ;No -- we are now
+               SUB     R2,R0,R1                ;Get the number to get
+               BL      exp__midString          ;Do the mid$
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- RIGHT$ ---
+
+exp__doRightS  ROUT
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack registers
+               CMP     R5,#2                   ;Two of them?
+               MOVNE   R0,#err_rightSArgs      ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               BL      exp__popInt             ;Get the number
+               MOV     R2,R0                   ;Put it in R2
+               ADR     R0,sail_misc            ;Point to the buffer
+               BL      exp__getString          ;Get the string
+               SUBS    R1,R0,R2                ;Work out the index
+               MOVLT   R1,#0                   ;If getting too many, reduce
+               MOVLT   R2,R0
+               BL      exp__midString          ;Do the mid$
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- STRING$ ---
+
+exp__doStringS ROUT
+
+               ; --- Make sure we have the right number of arguments ---
+
+               STMFD   R13!,{R2-R6,R14}        ;Stack registers
+               CMP     R5,#2                   ;Two of them?
+               MOVNE   R0,#err_stringSArgs     ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ADR     R0,sail_misc            ;Point to a buffer
+               BL      exp__getString          ;Copy the string into buffer
+               MOV     R5,R0                   ;Put length in R2
+               BL      exp__popInt             ;Pop an integer
+               MOV     R3,R0                   ;Put number in R3
+               MUL     R6,R5,R0                ;Get the overall length
+               CMP     R6,#255                 ;Is it too big?
+               MOVGT   R0,#err_strTooLong      ;Yes -- get error number
+               BGT     error_report            ;And report it happily
+
+               ; --- Now copy the string ---
+
+               CMP     R5,#0                   ;Is this a 0 length string?
+               MOVEQ   R0,#0                   ;Yes -- get rvalue
+               BEQ     %10exp__doStringS       ;And jump ahead
+
+               BL      stracc_ensure           ;Make sure we have room
+               MOV     R4,R1                   ;Look after the offset
+               MOV     R2,R5                   ;Keep copy of length
+
+00             ADR     R1,sail_misc            ;Point to the string
+05             LDRB    R14,[R1],#1             ;Load a byte
+               STRB    R14,[R0],#1             ;Store it
+               SUBS    R2,R2,#1                ;Decrement the string length
+               BGT     %b05                    ;And go round for more
+               MOV     R2,R5                   ;Get the length back
+               SUBS    R3,R3,#1                ;Decrment other counter
+               BGT     %b00                    ;And go round for more
+
+               ORR     R0,R4,R6                ;Get the rvalue
+10             MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about it
+               LDMFD   R13!,{R2-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- INSTR ---
+
+exp__doInstr   ROUT
+
+               STMFD   R13!,{R5,R14}           ;Stack registers
+               CMP     R5,#2                   ;Two of them?
+               CMPNE   R5,#3                   ;Or maybe 3?
+               MOVNE   R0,#err_instrSArgs      ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               CMP     R5,#3                   ;Are there 3 args?
+               BLEQ    exp__popInt             ;Yes -- get it then
+               SUBEQ   R5,R0,#1                ;And reduce by 1
+               MOVNE   R5,#0                   ;Otherwise use 0
+
+               BL      exp__popTwoStrs         ;Get two strings
+               STMFD   R13!,{R0,R6-R9}         ;Stack nice stracc position
+               LDR     R14,sail_stracc         ;Get the stracc anchor
+               LDR     R14,[R14]
+               AND     R1,R0,#&FF              ;Get a string length
+               ADD     R0,R14,R0,LSR #8        ;Point at the strings
+               AND     R3,R2,#&FF              ;Do this for...
+               ADD     R2,R14,R2,LSR #8        ;...both of them
+
+               SUB     R1,R1,R5                ;Get len of remaining string
+05             CMP     R1,R3                   ;Enough string for a match?
+               BLT     %90exp__doInstr         ;No match -- jump onwards
+               ADD     R6,R0,R5                ;Look after values
+               MOV     R7,R2
+               MOV     R9,R3                   ;Remember the length too
+00             SUBS    R9,R9,#1                ;Reduce length count
+               BLT     %95exp__doInstr         ;We have a match :-)
+               LDRB    R8,[R6],#1              ;Load a byte
+               LDRB    R14,[R7],#1             ;From both strings
+               CMP     R8,R14                  ;Do the bytes match?
+               BEQ     %b00                    ;Yes -- keep on comparing
+               ADD     R5,R5,#1                ;Increment the position
+               SUB     R1,R1,#1                ;Reduce length
+               B       %b05                    ;And keep on going
+
+               ; --- We return failure ---
+
+90             LDMFD   R13!,{R0,R6-R9}         ;Load back registers
+               BL      stracc_free             ;Free my strings
+               MOV     R0,#0                   ;No match
+               MOV     R1,#vType_integer       ;Return a string please
+               LDMFD   R13!,{R5,PC}^           ;Return to caller
+
+               ; --- Return success then ---
+
+95             LDMFD   R13!,{R0,R6-R9}         ;Load back registers
+               BL      stracc_free             ;Free my strings
+               ADD     R0,R5,#1                ;No match
+               MOV     R1,#vType_integer       ;Return a string please
+               LDMFD   R13!,{R5,PC}^           ;Return to caller
+
+               LTORG
+
+;----- Flags and things -----------------------------------------------------
+
+eFlag__commaOk EQU     (1<<0)                  ;We can cope with commas here
+eFlag__op      EQU     (1<<1)                  ;We are reading an operator
+eFlag__done    EQU     (1<<2)                  ;Finished reading expression
+eFlag__lval    EQU     (1<<3)                  ;Reading an lvalue
+eFlag__parseLval EQU   (1<<4)                  ;We are parsing an lvalue
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/getToken b/StraySrc/Libraries/Sapphire/sail/s/getToken
new file mode 100644 (file)
index 0000000..724b33d
--- /dev/null
@@ -0,0 +1,67 @@
+;
+; getToken.s
+;
+; The getting of the next token from the input file
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- getToken ---
+;
+; On entry:    R9 == previous token, or -1
+;              R10 == pointer into the tokenised buffer
+;              R12 == anchor block pointer
+;
+; On exit:     R7 == token class of token read
+;              R8 == index of token in token class
+;              R9 == new lookahead token
+;              R10 == moved on to the first character after the rvalue
+;
+; Use:         Tries to read an token from the current input line
+
+               EXPORT  getToken
+getToken       ROUT
+
+10getToken     CMP     R9,#10                  ;Is it a newline?
+               BEQ     %20getToken             ;A newline -- bump line count
+               LDRB    R9,[R10],#1             ;Load a byte
+               CMP     R9,#31                  ;Is it an implicit newline?
+               BEQ     %20getToken             ;Yes -- bump line counter
+
+15getToken     ADR     R8,tokClasses           ;Point to class table
+               LDR     R8,[R8,R9,LSL #1]
+               AND     R7,R8,#&FF
+               AND     R8,R8,#&FF00
+               MOV     R8,R8,LSR #8
+               MOVS    PC,R14                  ;Return to caller
+
+20getToken     LDR     R7,sail_line            ;Yes -- get current line
+               ADD     R7,R7,#1                ;Increment line num
+               STR     R7,sail_line            ;And save new line number
+               LDRB    R9,[R10],#1             ;Load a byte
+               CMP     R9,#31                  ;Should we ignore this char?
+               BEQ     %20getToken             ;Yes -- look for the next
+               B       %15getToken
+
+               GET     sh.tokClasses
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/interp b/StraySrc/Libraries/Sapphire/sail/s/interp
new file mode 100644 (file)
index 0000000..3a57d5c
--- /dev/null
@@ -0,0 +1,259 @@
+;
+; interp.s
+;
+; Main entry point for the interpreter
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.ctrl
+               GET     sh.errNum
+               GET     sh.error
+               GET     sh.express
+               GET     sh.getToken
+               GET     sh.sail
+               GET     sh.tokens
+               GET     sh.upcalls
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- interp_start ---
+;
+; On entry:    R12 == pointer to our anchor block
+;
+; On exit:     R7-R9 == next token
+;
+; Use:         Prepares for execution, and even does some too.
+
+               EXPORT  interp_start
+interp_start   ROUT
+
+               LDR     R10,sail_tokAnchor      ;Load the anchor
+
+               MOV     R14,#1                  ;The current line number
+               STR     R14,sail_line           ;Store it
+               MOV     R9,#-1                  ;Prepare for the first line
+               BL      getToken                ;Get the first token ready
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               STR     R0,sail_timeSoFar       ;Remember this time
+               B       interp_exec             ;Do some execution
+
+               LTORG
+
+; --- interp_resume ---
+;
+; On entry:    R12 == script anchor
+;
+; On exit:     --
+;
+; Use:         Resumes the script from where it left off.
+
+               EXPORT  interp_resume
+
+; --- interp_exec ---
+;
+; On entry:    R7-R9 == token to deal with
+;              R11 == offset in file to execute from
+;              R12 == pointer to the anchor block
+;
+; On exit:     R0 == type code (eg. 0 == we are still executing
+;              R7-R9 == next token to deal with
+;
+; Use:         Executes some of the file.
+
+               EXPORT  interp_exec
+interp_exec    ROUT
+
+               LDR     R1,sail_preempt         ;Load the pre-emption time
+               CMP     R1,#-1                  ;Do we need to return?
+               BEQ     %10interp_exec          ;No -- jump onwards then
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               LDR     R14,sail_timeSoFar      ;Load the time we started
+               SUB     R0,R0,R14               ;Thie we have been executing
+               CMP     R0,R1                   ;Time up yet?
+               BCC     %10interp_exec          ;No -- keep on going then
+
+               ; --- Return control for a little while then ---
+
+00interp_exec  B       sail_wait               ;Yes -- wait some then
+interp_resume  SWI     OS_ReadMonotonicTime    ;Read the current time
+               STR     R0,sail_timeSoFar       ;Remember this time
+
+10interp_exec  CMP     R7,#tClass_instr        ;Is this an instruction?
+               BNE     %50interp_exec          ;No -- could be other things
+
+               ; --- We have an instruction ---
+
+               MOV     R0,R8                   ;Look after index
+               BL      getToken                ;Get the next tokem
+               ADD     PC,PC,R0,LSL #2         ;Branch to the correct code
+               DCB     "Jive"
+
+               ; --- The main dispatch table ---
+
+               B       ctrl_bput
+               B       ctrl_case
+               B       ctrl_close
+               B       ctrl_call               ;CALL
+               B       ctrl_data
+               B       ctrl_def
+               B       ctrl_dim
+               B       ctrl_end
+               B       ctrl_endproc
+               B       ctrl_endwhile
+               B       interp_next             ;ENDIF
+               B       interp_next             ;ENDCASE
+               B       ctrl_else
+               B       interp_notImpl          ;B      ctrl_error
+               B       ctrl_for
+               B       ctrl_goto
+               B       ctrl_gosub
+               B       ctrl_if
+               B       ctrl_let
+               B       ctrl_local
+               B       ctrl_next
+               B       ctrl_oscli              ;OSCLI
+               B       ctrl_otherwise
+               B       ctrl_proc
+               B       ctrl_return
+               B       ctrl_repeat
+               B       ctrl_read
+               B       ctrl_restore
+               B       ctrl_swap
+               B       ctrl_sys
+               B       ctrl_until
+               B       ctrl_while
+               B       ctrl_when
+
+               ; --- Handle pseudo varaible and the like ---
+
+50interp_exec  SUBS    R4,R9,#'_'              ;Is it an underscore?
+               SUBNES  R4,R9,#'!'
+               SUBNES  R4,R9,#'?'
+               SUBNES  R4,R9,#'$'
+               SUBNE   R4,R9,#'A'              ;Or a capital letter?
+               CMP     R4,#26
+               SUBCS   R4,R9,#'a'              ;Or a lowercase letter?
+               CMPCS   R4,#26
+               BCC     ctrl_let                ;If so, assume assignment
+
+               CMP     R9,#tok_time            ;Is this a TIME pseudovar?
+               BLEQ    getToken                ;Yes -- done with this token
+               BEQ     ctrl_timeEq             ;Yes -- assign that then
+
+               CMP     R7,#tClass_streamOp     ;Is it a streamOp?
+               BNE     %60interp_exec          ;No -- jump ahead
+
+               MOV     R0,R9                   ;Remember the tokoen
+               BL      getToken                ;Get another token
+               CMP     R9,#'#'                 ;Do we have a hash next?
+               MOVNE   R0,#err_expHash         ;No -- complain then
+               BNE     error_report            ;And report an error
+               BL      getToken                ;Get the next token
+               CMP     R0,#tok_ptr             ;Setting of pointer?
+               BEQ     ctrl_ptr                ;Yes -- do that then
+               CMP     R0,#tok_ext             ;Setting of extent?
+               BEQ     ctrl_ext                ;Yes -- do that
+               BNE     interp_next             ;Probably emtpy statement
+
+60interp_exec  CMP     R7,#tClass_multArg      ;A multiple argument thing?
+               BNE     %70interp_exec          ;No -- jump ahead
+
+               ; --- Deal with a multiple argument command ---
+
+               CMP     R9,#tok_leftS           ;Is it LEFT$?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     ctrl_leftS              ;Yes -- deal with it
+               CMP     R9,#tok_midS            ;Is it MID$?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     ctrl_midS               ;Yes -- deal with it
+               CMP     R9,#tok_rightS          ;Is it RIGHT$?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     ctrl_rightS             ;Yes -- deal with it
+               BNE     interp_next             ;Probably emtpy statement
+
+70interp_exec  CMP     R9,#'='                 ;Is it a return-from-fn?
+               BLEQ    getToken                ;Yes -- gobble it then
+               BEQ     ctrl_equals             ;Yes -- return then
+
+               CMP     R9,#'*'                 ;Is this a star command?
+               BNE     interp_next             ;Probably emtpy statement
+
+               ; --- We have a star command ---
+               ;
+               ; We copy the command into a buffer, until we reach
+               ; a terminating character.
+
+               ADR     R0,sail_misc            ;Point to the destination
+00             BL      getToken                ;Get a token
+               CMP     R9,#10                  ;Is this the end of the line?
+               CMPNE   R9,#&FF                 ;Or the end of the file
+               STRNEB  R9,[R0],#1              ;No -- store the byte
+               BNE     %b00                    ;And keep on going
+
+               ; --- We have the string in the buffer ---
+
+               MOV     R14,#0                  ;We had better terminate it
+               STRB    R14,[R0],#1             ;By store a NULL char
+               ADR     R0,sail_misc            ;Point to the command
+               SWI     OS_CLI                  ;Perform the command
+
+               B       interp_next             ;Just keep on goin' then
+
+               LTORG
+
+; --- interp_notImpl ---
+
+               EXPORT  interp_notImpl
+interp_notImpl MOV     R0,#err_lazy
+
+               B       error_report
+
+; --- interp_next ---
+;
+; On entry:    R7-R9 == token to deal with
+;              R11 == offset in file to execute from
+;              R12 == pointer to the anchor block
+;
+; On exit:     R0 == type code (eg. 0 == we are still executing)
+;              R7-R9 == next token to deal with
+;
+; Use:         Checks the next instruction and acts approriately.
+
+               EXPORT  interp_next
+interp_next    ROUT
+
+               CMP     R9,#10                  ;Is this newline?
+               LDR     R14,sail_flags          ;Load the flags word
+               ORREQ   R14,R14,#tscFlag_nl     ;Newline just arrived
+               BICNE   R14,R14,#tscFlag_nl     ;Or maybe not
+               STR     R14,sail_flags          ;Store the new flags back
+               CMPNE   R9,#':'                 ;Is this a ':'?
+               BLEQ    getToken                ;Either -- get a token
+               BEQ     interp_exec             ;...and keep on looping
+
+               CMP     R9,#tok_else            ;Is this an ELSE?
+               BLEQ    getToken                ;Yes -- read a token
+               BEQ     ctrl_else               ;...and branch to else ctrl
+               SUBS    R0,R9,#&FF              ;Is this the end?
+               BEQ     sail_return             ;Yes -- just end then
+               MOV     R0,#err_syntax          ;This is a synatx error
+               B       error_report            ;So report it
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/mem b/StraySrc/Libraries/Sapphire/sail/s/mem
new file mode 100644 (file)
index 0000000..b37abef
--- /dev/null
@@ -0,0 +1,97 @@
+;
+; mem.s
+;
+; Generic memory allocation for TermScript
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.errNum
+               GET     sh.error
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- mem_alloc ---
+;
+; On entry:    R0 == size of block to allocate
+;
+; On exit:     R0 == pointer to anchor for that block
+;              May return an error
+;
+; Use:         Tries to allocate a block of memory, and returns a pointer
+;              to the anchor for that block. All very unusual really,
+;              but we blame Wimp_Extension which allocates anchors for
+;              you in an utterley horrible way.
+
+
+               EXPORT  mem_alloc
+mem_alloc      ROUT
+
+               ; --- For now, we will use the RMA ---
+
+               STMFD   R13!,{R1-R3,R14}
+               ADD     R3,R0,#4
+               MOV     R0,#6
+               SWI     XOS_Module
+               BVS     %99mem_alloc
+               ADD     R3,R2,#4
+               STR     R3,[R2,#0]
+               MOV     R0,R2
+               LDMFD   R13!,{R1-R3,PC}^
+
+99mem_alloc    MOV     R0,#err_noMem
+               B       error_report
+
+               LTORG
+
+; --- mem_free ---
+;
+; On entry:    R0 == anchor of the block to free
+;
+; On exit:     --
+;
+; Use:         Frees the block.
+
+               EXPORT  mem_free
+mem_free       ROUT
+
+               STMFD   R13!,{R0-R2,R14}
+               LDR     R2,[R0,#0]
+               SUB     R2,R2,#4
+               MOV     R0,#7
+               SWI     OS_Module
+               LDMFD   R13!,{R0-R2,PC}^
+
+               LTORG
+
+; --- mem_realloc ---
+;
+; On entry:    R0 == pointer to block anchor
+;              R1 == new size requested
+;
+; On exit:     May return an error
+;
+; Use:         Resizes a block
+
+               EXPORT  mem_realloc
+mem_realloc    ROUT
+
+               MOV     R0,#err_realloc
+               B       error_report
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/sail b/StraySrc/Libraries/Sapphire/sail/s/sail
new file mode 100644 (file)
index 0000000..459909e
--- /dev/null
@@ -0,0 +1,342 @@
+;
+; sail.s
+;
+; Main SAIL API
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- sail_initScript ---
+;
+; On entry:    R0 == flex block handle of file
+;              R1 == environment handle to attach script to
+;              R2 == flex anchor of global variable pool
+;              R3 == how often to pre-empt the script (-1 == don't)
+;
+; On exit:     R0 == script handle
+;              May return an error
+;
+; Use:         Tokenises the script, set up global labels etc.
+
+               EXPORT  sail_initScript
+sail_initScript        ROUT
+
+
+               STMFD   R13!,{R1-R4,R12,R14}    ;Save some registers
+
+                ; --- Find the size of the file ---
+
+                MOV    R4,R0                   ;Look after the anchor
+                BL     flex_size               ;Find the file size
+                MOV    R1,R0                   ;Look after this value
+
+               ; --- Allocate an anchor/stack block ---
+
+               MOV     R0,#sail_blkSize        ;Get the block's size
+               BL      alloc                   ;Try to allocate memory
+               BLCS    alloc_error             ;Allocate memory
+               BCS     %99                     ;If it failed, return error
+               MOV     R12,R0                  ;Point to block in R12
+
+               ; --- Fill in the rest of the block ---
+
+               LDMIB   R13,{R0-R2}             ;Load other inforamtion
+               STR     R0,sail_env             ;Store environment handle
+               STR     R1,sail_global          ;Store ptr to global anchor
+               STR     R2,sail_preempt         ;Store the pre-empt time
+
+               MOV     R1,#512                 ;Initial size of var stack
+               STR     R1,sail_varSize         ;Size of current stack
+               ADR     R0,sail_varTree         ;Point tothe anchor
+               BL      flex_alloc              ;Try to allocate it
+               BLCS    alloc_error             ;Get the error message
+               BCS     %99                     ;On error -- return
+               MOV     R14,#7*4                ;A nice NULL value
+               STR     R14,sail_varPtr         ;Nothing on the stack yet
+               LDR     R0,sail_varTree         ;Find block address
+
+               MOV     R14,#0                  ;Zero out the tree roots
+               MOV     R1,#7                   ;Seven type trees to clear
+10             STR     R14,[R0],#4             ;Clear another one
+               SUBS    R1,R1,#1                ;Decrement the counter
+               BGT     %10                     ;And keep on going
+
+               ADR     R0,sail_execStack       ;Point to the anchor
+               MOV     R1,#256                 ;Space for the execution st.
+               BL      flex_alloc              ;Try to allocate it
+               BVS     %98                     ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#256                 ;Total size
+               ADR     R3,sail_execStack       ;Point to the stack data
+               STMIB   R3,{R1,R2}              ;Store the information
+
+               ADR     R0,sail_opStack         ;Point to the anchor
+               MOV     R1,#256                 ;Space for the operators
+               BL      flex_alloc              ;Try to allocate it
+               BVS     %97                     ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#256                 ;Total size
+               ADR     R3,sail_opStack         ;Point to the stack data
+               STMIB   R3,{R1,R2}              ;Store the information
+
+               ADR     R0,sail_calcStack       ;Point to the anchor
+               MOV     R1,#256                 ;Space for the operands
+               BL      flex_alloc              ;Try to allocate it
+               BVS     %96                     ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#256                 ;Total size
+               ADR     R3,sail_calcStack       ;Point to the stack data
+               STMIB   R3,{R1,R2}              ;Store the information
+
+               ADR     R0,sail_stracc          ;POint tothe anchor
+               MOV     R1,#512                 ;Space for the operands
+               BL      flex_alloc              ;Try to allocate it
+               BVS     %95                     ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#512                 ;Total size
+               ADR     R3,sail_stracc          ;Point to the stack data
+               STMIB   R3,{R1,R2}              ;Store the information
+
+               BL      strBucket_init          ;Set up the string handling
+
+               MOV     R14,#tscFlag_nl         ;Start with this flags word
+               STR     R14,sail_flags          ;Store the new flags
+               MOV     R14,#0                  ;A NULL word
+               STR     R14,sail_rmaList        ;No DIMed blocks yet
+
+               ; --- Now tokenise the file ---
+
+               LDR     R2,[R13,#0]             ;Load the flex address
+               MOV     R0,R1                   ;Put it in R0
+               BL      flex_size               ;Get the file size
+               ADD     R1,R0,#8                ;Put the size in R1
+               ADR     R0,sail_tokAnchor       ;Point to the anchor
+               BL      flex_alloc              ;Allocate a block
+               BLCS    alloc_error             ;Get the error message
+               BCS     %94                     ;No -- return an error
+               ADR     R0,sail_tokAnchor       ;Point to the anchor again
+               STR     R0,sail_currAnchor      ;This is current anchor
+               STR     R0,sail_oldAnchor       ;This is the `previous' one
+
+               LDR     R0,[R2,#0]              ;POint to the text file
+               LDR     R2,sail_tokAnchor       ;Point to the output buffer
+               MOV     R3,#1                   ;Tokenise the whole file
+               BL      tokenise                ;Tokenise the file
+               BVS     %94                     ;Report possible error
+
+               ; --- Zero-init the file array ---
+
+               MOV     R14,#0                  ;Zero-init the array
+               MOV     R0,#8                   ;This many words to do
+               ADR     R1,sail_files           ;Point to the array
+00             STR     R14,[R1],#4             ;Store
+               SUBS    R0,R0,#1                ;Decrement the counter
+               BGT     %b00                    ;And loop
+
+               ; --- Finish setting up, and return ---
+
+               SWI     OS_ReadMonotonicTime    ;Read start time of program
+               STR     R0,sail_timeOff         ;This is initial time offset
+               MOV     R1,#0                   ;Clear top bit
+               ADR     R14,sail_rndSeed        ;Point to seed buffer
+               STMIA   R14,{R0,R1}             ;Save that away
+
+               MOV     R14,#0                  ;Current data offset
+               STR     R14,sail_dataPtr        ;Store that
+               MOV     R14,#1                  ;Current data line
+               STR     R14,sail_dataLine       ;Store that too
+               BL      ctrl_findDATA           ;Set up the pointer
+
+               MOV     R0,R12                  ;Return my block as handle
+               LDMFD   R13!,{R1-R4,R12,R14}    ;Unstack registers
+               BICS    PC,R14,#V_flag          ;And return without error
+
+               ; --- An error occured ---
+
+94             MOV     R4,R0
+               ADR     R0,sail_straccStack     ;Load the stack anchor
+               BL      flex_free               ;Free it
+               MOV     R0,R4
+95             MOV     R4,R0
+               ADR     R0,sail_calcStack       ;Load the stack anchor
+               BL      flex_free               ;Free it
+               MOV     R0,R4
+96             MOV     R4,R0
+               ADR     R0,sail_opStack         ;Load the stack anchor
+               BL      flex_free               ;Free it
+               MOV     R0,R4
+97             MOV     R4,R0
+               ADR     R0,sail_execStack       ;Load the stack anchor
+               BL      flex_free               ;Free it
+               MOV     R0,R4
+98             MOV     R4,R0
+               ADR     R0,sail_varTree         ;Load the stack anchor
+               BL      flex_free               ;Free it
+               MOV     R0,R4
+99             LDMFD   R13!,{R1-R4,R12,R14}    ;Unstack registers
+               ORRS    PC,R14,#V_flag          ;Return error to caller
+
+               LTORG
+
+; --- sail_killScript ---
+;
+; On entry:    R0 == handle of the script
+;
+; On exit:     --
+;
+; Use:         Removes all the information associates with a given
+;              script.
+
+               EXPORT  sail_killScript
+sail_killScript        ROUT
+
+               STMFD   R13!,{{R0-R2,R12,R14}   ;Save some register
+               MOV     R12,R0                  ;Put block in R12
+
+               ADR     R0,sail_rszBlocks       ;Find the resizing blocks
+               ADR     R1,sail_erszBlocks      ;Find the end of them
+00             BL      flex_free               ;Free this block
+               ADD     R0,R0,#12               ;Point to the next one
+               CMP     R0,R1                   ;Finished yet?
+               BCC     %b00                    ;No -- loop
+
+               ; --- Now free DIMed RMA blocks ---
+
+               MOV     R0,#7                   ;Free blocks
+               LDR     R2,sail_rmaList         ;Load the head of the list
+               CMP     R2,#0                   ;Is there one here?
+00             LDRNE   R3,[R2,#0]              ;Yes -- load the next link
+               SWINE   OS_Module               ;...free the block
+               MOVNE   R2,R3                   ;...put the next in R2
+               CMP     R2,#0                   ;Are there more to go?
+               BNE     %b00                    ;Yes -- do them then
+
+               ; --- Close any open files ---
+
+               MOV     R0,#0                   ;Close these files
+               MOV     R1,#0                   ;Start at file 1
+               ADR     R2,sail_files           ;Point to file array
+00             TST     R1,#&1F                 ;Start new word?
+               LDREQ   R3,[R2],#4              ;Yes -- load new one then
+               MOVS    R3,R3,LSL #1            ;Shift word up by one
+               SWICS   OS_Find                 ;If set, close the file
+               ADD     R1,R1,#1                ;Increment file handle
+               CMP     R1,#&100                ;Finished yet?
+               BCC     %b00                    ;No -- keep looping
+
+               ; --- Free the tokenised file ---
+
+               ADR     R0,sail_tokAnchor       ;Load anchor of tok'ed file
+               BL      flex_free               ;Free that block
+
+               ; --- Free the anchor block ---
+
+               MOV     R0,R12                  ;Point to the anchor blk
+               BL      free                    ;Free it nicely
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- sail_error ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     Doesn't, probably
+;
+; Use:         Returns an error to the caller.
+
+               EXPORT  sail_error
+sail_error     ROUT
+
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+; --- sail_goto ---
+;
+; On entry:    R0 == script handle
+;              R1 == pointer to lable name, or 0 for start
+;
+; On exit:     R1 == 0 if finished, else more to go
+;
+; Use:         Starts executing the script from the given label.
+
+               ; --- This routine is rather incomplete at the moment ---
+
+               EXPORT  sail_goto
+sail_goto      ROUT
+
+               STMFD   R13!,{R0,R2-R12,R14}    ;Stack registers
+               MOV     R12,R0                  ;Put anchor in R12
+               B       interp_start            ;Start execution
+
+               LTORG
+
+; --- sail_continue ---
+;
+; On entry:    R0 == handle of the script
+;
+; On exit:     --
+;
+; Use:         Executes the script from where it left off.
+
+               EXPORT  sail_continue
+sail_continue  ROUT
+
+               STMFD   R13!,{R0,R2-R12,R14}    ;Stack registers
+               MOV     R12,R0                  ;Put anchor in R12
+               B       interp_resume           ;Start execution
+
+               LTORG
+
+; --- sail_wait ---
+;
+; On entry:    --
+;
+; On exit:     R1 <> 0
+;
+; Use:         Returns to the caller indication that we have *not* yet
+;              finished.
+
+               EXPORT  sail_wait
+sail_wait      ROUT
+
+               MOV     R1,#1                   ;More to go
+               LDMFD   R13!,{R0,R2-R12,R14}    ;Load back registers
+               BICS    PC,R14,#V_flag          ;Return happily
+
+               LTORG
+
+; --- sail_return ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Returns to caller once the script has finished.
+
+               EXPORT  sail_return
+sail_return    ROUT
+
+               MOV     R1,#0                   ;No more to do
+               LDMFD   R13!,{R0,R2-R12,R14}    ;Load back registers
+               BICS    PC,R14,#V_flag          ;Return happily
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/strBucket b/StraySrc/Libraries/Sapphire/sail/s/strBucket
new file mode 100644 (file)
index 0000000..a42cd2e
--- /dev/null
@@ -0,0 +1,155 @@
+;
+; strBucket.s
+;
+; String bucket handling
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.mem
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- strBucket_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the string bucket.
+
+               EXPORT  strBucket_init
+strBucket_init ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Allocate the string bucket block ---
+
+               MOV     R0,#1024                ;Start off nice and big
+               BL      mem_alloc               ;Allocate the block
+               MOV     R1,#256                 ;Reserve space for the table
+               MOV     R2,#1024                ;Remember starting size
+               ADR     R14,sail_bucket         ;Find the workspace part
+               STMIA   R14,{R0-R2}             ;Save this information away
+
+               ; --- Now initialise the bucket table ---
+
+               LDR     R0,[R0]                 ;Load actual block address
+               MOV     R1,#64                  ;We have 64 buckets to handle
+               MOV     R14,#0                  ;Clear them all to zero
+00             STR     R14,[R0],#4             ;Save the initial value
+               SUBS    R1,R1,#1                ;Decrement the counter
+               BNE     %00strBucket_init       ;And loop
+
+               LDMFD   R13!,{R0-R2,PC}^        ;Now return to caller
+
+               LTORG
+
+; --- strBucket_alloc ---
+;
+; On entry:    R0 == size of string to allocate
+;
+; On exit:     R0 == pointer to area to use (length at [R0,#-1])
+;              R1 == offset to that (for storing)
+;
+; Use:         Allocates space for a string of the given size.
+
+               EXPORT  strBucket_alloc
+strBucket_alloc        ROUT
+
+               ; --- Quick optimisation ---
+
+               SUBS    R1,R0,#0                ;Is this a null string?
+               MOVEQS  PC,R14                  ;Yes -- return zero then
+
+               STMFD   R13!,{R2,R3,R14}        ;Save some registers
+               MOV     R2,R0                   ;Look after length
+
+               ; --- Find the actual block length ---
+
+               ADD     R3,R2,#4                ;Add 1 byte for len, and...
+               BIC     R3,R3,#3                ;...word align
+
+               LDR     R0,sail_bucket          ;Find the bucket anchor
+               LDR     R14,[R0]                ;WimpExt?  Bollocks more like
+               LDR     R1,[R14,R3]             ;Load the free list head
+               CMP     R1,#0                   ;Is this empty?
+               LDRNE   R0,[R14,R1]             ;Load the link from this blk
+               STRNE   R0,[R14,R3]             ;And stuff it in list head
+               ADDNE   R0,R14,R1               ;No -- work out address
+               BNE     %20strBucket_alloc      ;And skip ahead
+
+               ; --- Need to allocate more space ---
+
+               ADR     R14,sail_bktPtr         ;Find the free pointer
+               LDMIA   R14,{R1,R14}            ;Load free ptr and size
+               ADD     R1,R1,R3                ;Add on the space we need
+               STR     R1,sail_bktPtr          ;Store modified pointer
+               SUB     R3,R1,R3                ;Look after old offset
+               CMP     R1,R14                  ;Do we have enough?
+               BGT     %50strBucket_alloc      ;No -- get some more then
+10             MOV     R1,R3                   ;Find start of string space
+               LDR     R0,[R0]                 ;This is getting IRRITATING
+               ADD     R0,R0,R1                ;Get string block address
+
+               ; --- Set up the string ready for caller ---
+
+20             STRB    R2,[R0],#1              ;Save the length byte
+               ADD     R1,R1,#1                ;Bump the offset on
+               LDMFD   R13!,{R2,R3,PC}^        ;And return to caller
+
+               ; --- Extend the bucket area ---
+
+50             MOV     R14,#&FF                ;Build up 1023
+               ORR     R14,R14,#&300
+               ADD     R1,R1,R14               ;Add on chunking size
+               BIC     R1,R1,R14               ;And align nicely
+               BL      mem_realloc             ;Reallocate the area
+               STR     R1,sail_bktSize         ;And save the new size
+               B       %10strBucket_alloc      ;And leap back again
+
+               LTORG
+
+; --- strBucket_free ---
+;
+; On entry:    R0 == offset of string to free
+;
+; On exit:     --
+;
+; Use:         Frees the memory the string took up.
+
+               EXPORT  strBucket_free
+strBucket_free ROUT
+
+               CMP     R0,#0                   ;Is this a bogus offset
+               MOVEQS  PC,R14                  ;Yes -- ignore it then
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               LDR     R1,sail_bucket          ;Load the bucket anchor
+               LDR     R1,[R1]                 ;Spotted the pattern yet?
+               SUB     R0,R0,#1                ;Find the actual start offset
+               LDRB    R2,[R1,R0]              ;Load the length byte
+               ADD     R2,R2,#4                ;Add length byte and align
+               BIC     R2,R2,#3
+               LDR     R14,[R1,R2]             ;Load the list head
+               STR     R14,[R1,R0]             ;Save this in freed block
+               STR     R0,[R1,R2]              ;And make this the new head
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/stracc b/StraySrc/Libraries/Sapphire/sail/s/stracc
new file mode 100644 (file)
index 0000000..e80305f
--- /dev/null
@@ -0,0 +1,118 @@
+;
+; stracc.s
+;
+; String accululator management
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:flex
+
+               GET     sh.anchor
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScrip$$Code|,CODE,READONLY
+
+; --- stracc_ensure ---
+;
+; On entry:    --
+;
+; On exit:     R0 == address of string to use
+;              R1 == offset of string from stracc, in upper 24 bits
+;
+; Use:         Ensures tha there are at least 256 bytes available in stracc,
+;              and then returns a pointer to them.
+
+               EXPORT  stracc_ensure
+stracc_ensure  ROUT
+
+               STMFD   R13!,{R2-R4,R14}        ;Stack registers
+               ADR     R0,sail_stracc          ;Point to the data
+               LDMIB   R0,{R0,R2,R3}           ;Load out the data
+               SUB     R1,R3,R2                ;Look at how much is left
+               CMP     R1,#256                 ;Is there at least 256?
+               BLT     %f00                    ;No -- get some more
+05             ADD     R0,R0,R2                ;Point at memory to use
+               MOV     R1,R2,LSL #8            ;Return offset to use
+               LDMFD   R13!,{R2-R4,PC}^        ;Return to caller
+
+00             LDR     R4,sail_currAnchor      ;Load the current anchor
+               LDR     R14,[R4,#0]             ;This is an indirection!
+               SUB     R10,R10,R14             ;Convert R10 to offset
+               ADD     R3,R3,#512              ;Add on some room
+               MOV     R1,R3                   ;We need this in R1
+               ADR     R0,sail_straccStack     ;Point to the anchor
+               BL      mem_realloc             ;Reallocate the memory
+               STR     R3,sail_straccSize      ;And store the new size
+               LDR     R0,[R4,#0]              ;It's still an indirection
+               ADD     R10,R10,R0              ;Turn R10 into address
+               B       %b05                    ;And leap back again
+
+               LTORG
+
+; --- stracc_added ---
+;
+; On entry:    R0 == rvalue of string added
+;
+; On exit:     --
+;
+; Use:         Informs stracc that a new string has been added.
+
+               EXPORT  stracc_added
+stracc_added   ROUT
+
+               STMFD   R13!,{R14}              ;Save registers
+               AND     R14,R0,#&FF             ;Get the string length
+               ADD     R14,R14,R0,LSR #8       ;Add on the offset
+               STR     R14,sail_straccPtr      ;Store the new pointer
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- stracc_free ---
+;
+; On entry:    R0 == rvalue of string no longer needed
+;
+; On exit:     --
+;
+; Use:         Tells stracc that a string is no longer needed.
+
+               EXPORT  stracc_free
+stracc_free    ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack registers
+               AND     R14,R0,#&FF             ;Get the string length
+               MOV     R4,R0,LSR #8            ;Get the new offset
+               ADR     R14,sail_stracc         ;Point to the stracc data
+               LDMIA   R14,{R0,R2,R3}          ;Load out the data
+               STR     R4,sail_straccPtr       ;Store new offset
+               SUB     R14,R3,R4               ;Get free space size
+               SUBS    R14,R14,#512            ;Calc amount to take off
+               LDMLEFD R13!,{R0-R4,PC}^        ;And return to caller
+
+               SUB     R1,R3,R14               ;Work out new block size
+               LDR     R4,sail_currAnchor      ;Load the current anchor
+               LDR     R14,[R4,#0]             ;Indirection alert
+               SUB     R10,R10,R14             ;Convert R10 to offset
+               ADR     R0,sail_straccStack     ;Point to the anchor
+               BL      mem_realloc             ;Reallocate as appropriate
+               STR     R1,sail_straccSize      ;Store the new size
+               LDR     R14,[R4,#0]             ;Indirection
+               ADD     R10,R10,R14             ;Convert R10 to address
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/termScript b/StraySrc/Libraries/Sapphire/sail/s/termScript
new file mode 100644 (file)
index 0000000..809729d
--- /dev/null
@@ -0,0 +1,512 @@
+;
+; termScript.s
+;
+; Coroutine handling for Termite Script
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.ctrl
+               GET     sh.interp
+               GET     sh.mem
+               GET     sh.strBucket
+               GET     sh.termite
+               GET     sh.tree
+               GET     sh.tokenise
+               GET     sh.var
+
+;----- Code header ----------------------------------------------------------
+
+               AREA    |!!!TermScript$$Header|,CODE,READONLY
+
+               MOVS    PC,R14                  ;No initialisation reqd
+               MOVS    PC,R14                  ;No finalisation either
+               B       sail__create            ;Create a new script
+               B       sail__poll              ;Continue execution
+               B       termite_remoteInput     ;Some input's come for us
+               B       sail__stop              ;Stop executing now
+               MOVS    PC,R14                  ;Misc operation
+               B       sail_execEnd            ;End of an EXEC
+               B       sail_getLine            ;Get line number
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- sail__create ---
+;
+; On entry:    R2 == pointer to anchor for script file
+;              R3 == length of script file
+;              R4 == block with A% to H%
+;
+; On exit:     R0 == pointer to script handle (stack block)
+;
+; Use:         Sets up a new script session.
+
+sail__create   ROUT
+
+               STMFD   R13!,{R1-R4,R12,R14}    ;Save some registers
+
+               ; --- Allocate an anchor/stack block ---
+
+               MOV     R0,#6                   ;Allocate memory
+               MOV     R3,#sail_blkSize                ;Get the block's size
+               SWI     XOS_Module              ;Try to allocate the memory
+               BVS     %99sail__create         ;If it failed, return error
+               MOV     R12,R2                  ;Point to block in R12
+
+               ; --- Set up the coroutine ready to start ---
+
+               ADD     R4,R12,#sail_blkSize    ;Point to the very top
+               ADR     R3,sail__start          ;Install a `return address'
+               MOV     R1,R11                  ;Pass upcall block pointer
+               STMFD   R4!,{R3}                ;Save `R11', `R12' and `R14'
+               SUB     R4,R4,#40               ;Leave `R1'-`R10' blank
+               STR     R4,sail_R13             ;Save the initial stack ptr
+
+               ; --- Fill in the rest of the block ---
+
+               LDMIB   R13,{R0,R1}             ;Load the anchor and length
+               STMIB   R12,{R0,R1}             ;Save them in my block
+
+               MOV     R0,#512                 ;Initial size of var stack
+               STR     R0,sail_varSize         ;Size of current stack
+               BL      mem_alloc               ;Try to allocate it
+               BVS     %99sail__create         ;On error -- return
+               STR     R0,sail_varTree         ;Store this anchor pointer
+               MOV     R14,#7*4                ;A nice NULL value
+               STR     R14,sail_varPtr         ;Nothing on the stack yet
+               LDR     R0,[R0]                 ;Find block address
+
+               MOV     R14,#0                  ;Zero out the tree roots
+               MOV     R1,#7                   ;Seven type trees to clear
+10sail__create STR     R14,[R0],#4             ;Clear another one
+               SUBS    R1,R1,#1                ;Decrement the counter
+               BGT     %10sail__create         ;And keep on going
+
+               MOV     R0,#256                 ;Space for the execution st.
+               BL      mem_alloc               ;Try to allocate it
+               BVS     %98sail__create         ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#256                 ;Total size
+               ADR     R3,sail_execStack       ;Point to the stack data
+               STMIA   R3,{R0-R2}              ;Store the information
+
+               MOV     R0,#256                 ;Space for the operators
+               BL      mem_alloc               ;Try to allocate it
+               BVS     %98sail__create         ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#256                 ;Total size
+               ADR     R3,sail_opStack         ;Point to the stack data
+               STMIA   R3,{R0-R2}              ;Store the information
+
+               MOV     R0,#256                 ;Space for the operands
+               BL      mem_alloc               ;Try to allocate it
+               BVS     %98sail__create         ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#256                 ;Total size
+               ADR     R3,sail_calcStack       ;Point to the stack data
+               STMIA   R3,{R0-R2}              ;Store the information
+
+               MOV     R0,#512                 ;Space for the operands
+               BL      mem_alloc               ;Try to allocate it
+               BVS     %98sail__create         ;On error -- return
+               MOV     R1,#0                   ;Amount used so far
+               MOV     R2,#512                 ;Total size
+               ADR     R3,sail_stracc          ;Point to the stack data
+               STMIA   R3,{R0-R2}              ;Store the information
+
+               BL      strBucket_init          ;Set up the string handling
+
+               MOV     R14,#tscFlag_nl+tscFlag_echoLR+tscFlag_echoRL
+               STR     R14,sail_flags          ;Store the new flags
+               MOV     R14,#0                  ;A NULL word
+               STR     R14,sail_rmaList                ;No DIMed blocks yet
+               STR     R14,sail_wForState      ;State of WATCHFOR
+               STR     R14,sail_wForNumber     ;No strings being watched for
+               STR     R14,sail_spool          ;No SPOOL handle
+
+               ; --- Now tokenise the file ---
+
+               LDR     R0,sail_scSize          ;Load the script size
+               ADD     R0,R0,#8                ;Put the size in R0
+               BL      mem_alloc               ;Allocate a block
+               BVS     %98sail__create         ;No -- return an error
+               STR     R0,sail_tokAnchor       ;Store this anchor pointer
+               STR     R0,sail_currAnchor      ;This is current anchor
+               STR     R0,sail_oldAnchor       ;This is the `previous' one
+
+               LDR     R2,[R0,#0]              ;Get angry with WimpExt_Heap
+               ADR     R14,sail_anchor         ;Find untokenised script
+               LDMIA   R14,{R0,R1}             ;Load them out
+               LDR     R0,[R0,#0]              ;Grrrr...
+               MOV     R3,#1                   ;Tokenise the whole file
+               BL      tokenise                ;Tokenise the file
+
+       [ 1=0
+               STMFD   R13!,{R0-R5}
+               MOV     R0,#10
+               ADR     R1,name
+               LDR     r2,=&FFF
+               LDR     R4,sail_tokAnchor
+               LDR     R4,[R4]
+               LDR     R5,sail_scSize
+               ADD     R5,R4,R5
+               SWI     OS_File
+               LDMFD   R13!,{R0-R5}
+       ]
+
+               ; --- Zero-init the file array ---
+
+               MOV     R14,#0                  ;Zero-init the array
+               MOV     R0,#8                   ;This many words to do
+               ADR     R1,sail_files           ;Point to the array
+00             STR     R14,[R1],#4             ;Store
+               SUBS    R0,R0,#1                ;Decrement the counter
+               BGT     %b00                    ;And loop
+
+               ; --- Finsh setting up, and return ---
+
+               SWI     OS_ReadMonotonicTime    ;Read start time of program
+               STR     R0,sail_timeOff         ;This is initial time offset
+               MOV     R1,#0                   ;Clear top bit
+               ADR     R14,sail_rndSeed                ;Point to seed buffer
+               STMIA   R14,{R0,R1}             ;Save that away
+
+               STR     R1,sail_errorS          ;ERROR$=""
+
+               MOV     R0,#2                   ;We want a string this big
+               BL      strBucket_alloc         ;Get it then
+               MOV     R14,#13                 ;Get char 13
+               STRB    R14,[R0],#1             ;Put in the string
+               MOV     R14,#10                 ;Get char 10
+               STRB    R14,[R0],#1             ;Put in the string
+               STR     R1,sail_lnewline                ;Store the offset away
+
+               MOV     R0,#1                   ;We want a string this big
+               BL      strBucket_alloc         ;Get it then
+               MOV     R14,#13                 ;Get char 13
+               STRB    R14,[R0],#1             ;Put in the string
+               STR     R1,sail_rnewline                ;Store the offset away
+
+               MOV     R14,#0                  ;Current data offset
+               STR     R14,sail_dataPtr                ;Store that
+               MOV     R14,#1                  ;Current data line
+               STR     R14,sail_dataLine       ;Store that too
+               BL      ctrl_findDATA           ;Set up the pointer
+
+               ; --- Copy over the A%-H% values ---
+
+               ADR     R1,sail__varNames       ;Point to the names
+               MOV     R4,#8                   ;Number of vars to transfer
+               LDR     R2,[R13,#12]            ;Load te block ptr
+00             MOV     R0,#vType_integer       ;It's an integer
+               BL      var_create              ;Try to create it
+               LDR     R14,[R2],#4             ;Load the value to transfer
+               STR     R14,[R0,#4]             ;Store the value
+               ADD     R1,R1,#3                ;Point to the next name
+               SUBS    R4,R4,#1                ;Reduce the count
+               BGT     %00                     ;And keep on looking
+
+               MOV     R0,R12                  ;Return my block as handle
+               LDMFD   R13!,{R1-R4,R12,R14}    ;Unstack registers
+               BICS    PC,R14,#V_flag          ;And return without error
+
+               ; --- An error occured ---
+
+98sail__create MOV     R4,R0
+               LDR     R0,sail_varTree         ;Load the stack anchor
+               BL      mem_free                ;Free it
+               MOV     R0,R4
+99sail__create LDMFD   R13!,{R1-R4,R12,R14}    ;Unstack registers
+               ORRS    PC,R14,#V_flag          ;Return error to caller
+
+sail__varNames DCB     "A%",0,"B%",0,"C%",0,"D%",0
+               DCB     "E%",0,"F%",0,"G%",0,"H%",0
+
+               LTORG
+
+; --- sail__start ---
+;
+; On entry:    R11 == pointer to upcall block
+;              R12 == pointer to anchor block
+;
+; On exit:     via interpreter
+;
+; Use:         Starts the interpreter coroutine.
+
+sail__start    ROUT
+
+               BL      interp_start            ;Start the interpreter
+               MOV     R0,#0                   ;Terminate the script
+               B       sail_end                        ;By calling the closedown rtn
+
+               LTORG
+
+; --- sail__stop ---
+;
+; On entry:    R0 == pointer to script anchor
+;
+; On exit:     --
+;
+; Use:         Stops a script from going.
+
+sail__stop     ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers
+               MOV     R12,R0                  ;Put block in R12
+
+               ADR     R1,sail_rszBlocks       ;Find the resizing blocks
+               ADR     R2,sail_erszBlocks      ;Find the end of them
+10sail__stop   LDR     R0,[R1],#12             ;Load the anchor
+               BL      mem_free                ;Free this block
+               CMP     R1,R2                   ;Finished yet?
+               BCC     %10sail__stop           ;No -- loop
+
+               ; --- Now free DIMed RMA blocks ---
+
+               MOV     R0,#7                   ;Free blocks
+               LDR     R2,sail_rmaList         ;Load the head of the list
+               CMP     R2,#0                   ;Is there one here?
+00             LDRNE   R3,[R2,#0]              ;Yes -- load the next link
+               SWINE   OS_Module               ;...free the block
+               MOVNE   R2,R3                   ;...put the next in R2
+               CMP     R2,#0                   ;Are there more to go?
+               BNE     %b00                    ;Yes -- do them then
+
+               ; --- Close any open files ---
+
+               MOV     R0,#0                   ;Close these files
+               MOV     R1,#0                   ;Start at file 1
+               ADR     R2,sail_files           ;Point to file array
+00             TST     R1,#&1F                 ;Start new word?
+               LDREQ   R3,[R2],#4              ;Yes -- load new one then
+               MOVS    R3,R3,LSL #1            ;Shift word up by one
+               SWICS   OS_Find                 ;If set, close the file
+               ADD     R1,R1,#1                ;Increment file handle
+               CMP     R1,#&100                ;Finished yet?
+               BCC     %b00                    ;No -- keep looping
+
+               ; --- Close the SPOOL file ---
+
+               LDR     R1,sail_spool           ;Load the current handle
+               CMP     R1,#0                   ;Are we spooling?
+               MOVNE   R0,#0                   ;Yes -- close current file
+               SWINE   XOS_Find                ;So do that then
+
+               ; --- Free the tokenised file ---
+
+               LDR     R0,sail_tokAnchor       ;Load anchor of tok'ed file
+               BL      mem_free                ;Free that block
+
+               ; --- Free the anchor block ---
+
+               MOV     R2,R12                  ;Point to the anchor blk
+               MOV     R0,#7                   ;Free the anchor
+               SWI     XOS_Module              ;Do that then
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;And return to caller
+
+               LTORG
+
+; --- sail__poll ---
+;
+; On entry:    R0 == address of anchor block
+;
+; On exit:     R0 == event code
+;
+; Use:         Continues running the script for a while.
+
+sail__poll     ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               MOV     R12,R0                  ;Put anchor block ptr away
+               BL      sail__resume            ;Switch to other coroutine
+               LDMFD   R13!,{R12,R14}          ;Restore registers
+               ORRVSS  PC,R14,#V_flag          ;If error, return that
+               BICVCS  PC,R14,#V_flag          ;Else return no error
+
+               LTORG
+
+; --- sail__resume ---
+;
+; On entry:    R0 == event code to pass to interpreter
+;              R1,R2 == other arguments to pass
+;
+; On exit:     R0, R1 == return values (passed to sail_wait)
+;
+; Use:         Resumes the interpreter, giving it an event.
+
+sail__resume   ROUT
+
+               STMFD   R13!,{R3-R12,R14}       ;Save main corout context
+               LDR     R14,sail_R13            ;Load interpreter's R13
+               STR     R13,sail_R13            ;Save our R13 away for a bit
+               MOV     R13,R14                 ;Switch to interpreter
+               LDMFD   R13!,{R1-R10,R14}       ;Restore interp registers
+               LDR     R0,sail_currAnchor      ;Load the token anchor
+               LDR     R0,[R0]                 ;Thump thump thump
+               ADD     R10,R0,R10              ;Turn offset into address
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- sail_wait ---
+;
+; On entry:    --
+;
+; On exit:     R0, R1, R2 == event and arguments from Termite
+;
+; Use:         Waits for some multitasking and gets something from Termite.
+
+               EXPORT  sail_wait
+sail_wait      ROUT
+
+               LDR     R0,sail_currAnchor      ;Find tokenised file anchor
+               LDR     R0,[R0]                 ;Grrrrrrrr
+               SUB     R10,R10,R0              ;Turn this into an offset
+               STMFD   R13!,{R1-R10,R14}       ;Save interpreter's context
+               LDR     R14,sail_R13            ;Load main routine's R13
+               STR     R13,sail_R13            ;Save our R13 away for a bit
+               MOV     R13,R14                 ;Switch back to main routine
+               MOV     R0,#0                   ;Just continue for a while
+               LDMFD   R13!,{R3-R12,R14}       ;Restore Termite's regs
+               BICS    PC,R14,#V_flag          ;And return with no error
+
+               LTORG
+
+; --- sail_end ---
+;
+; On entry:    R0 == pointer to script to chain (bit 30 set for exec),
+;                    0 to just end, or -1 to CLOSE
+;
+; On exit:     Doesn't, hopefully (except for exec?)
+;
+; Use:         Ends the script, optionally starting up another one.
+
+               EXPORT  sail_end
+sail_end               ROUT
+
+               STMFD   R13!,{R1-R10,R14}       ;Save interpreter's context
+               LDR     R14,sail_currAnchor     ;Find tokenised file anchor
+               LDR     R14,[R14]               ;Grrrrrrrr
+               SUB     R10,R10,R14             ;Turn this into an offset
+               STR     R10,[R13,#36]           ;Store R10 value
+               LDR     R14,sail_R13            ;Load main routine's R13
+               STR     R13,sail_R13            ;Save our R13 away (useless)
+               MOV     R13,R14                 ;Switch back to main routine
+
+               MOV     R5,R0                   ;Look after the return type
+
+               ; --- Copy across A% to H% ---
+
+               ADR     R2,sail_misc            ;Point to a misc block
+               ADRL    R1,sail__varNames       ;Point to the names
+               MOV     R4,#8                   ;Number of vars to transfer
+00             MOV     R0,#vType_integer       ;It's an integer
+               BL      tree_find               ;Try to find it
+               MOVCC   R14,#0                  ;Not there -- use 0
+               LDRCS   R14,[R0,#4]             ;Otherwise load value
+               STR     R14,[R2],#4             ;Store the value
+               ADD     R1,R1,#3                ;Point tot he next name
+               SUBS    R4,R4,#1                ;Reduce the count
+               BGT     %00                     ;And keep on looking
+               ADR     R2,sail_misc            ;Point to the block again
+               MOV     R0,R5                   ;Put return type in R0
+               MOV     R1,R6                   ;And file name in R1
+
+               ; --- Now return appropriately ---
+
+               MOV     R1,R5                   ;Get the string in R1
+               CMP     R1,#0                   ;Is it >0?
+               BLE     %10sail_end             ;Nope -- jump ahead
+
+               TST     R1,#(1<<30)             ;Are we EXECing?
+               MOVEQ   R0,#2                   ;If chaining, return 2
+               MOVNE   R0,#3                   ;Otherwise return 3
+               BIC     R1,R1,#(1<<30)          ;Clear bit 30
+
+               B       %90sail_end             ;Just return now
+
+10sail_end     MOVEQ   R0,#1                   ;Else just end the script
+               MOVLT   R0,#4                   ;Or maybe finish, even
+90sail_end     LDMFD   R13!,{R3-R12,R14}       ;Restore Termite's regs
+               BICS    PC,R14,#V_flag          ;And return with no error
+
+               LTORG
+
+; --- sail_error ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     Doesn't, probably
+;
+; Use:         Returns an error to Termite.
+
+               EXPORT  sail_error
+sail_error     ROUT
+
+               STMFD   R13!,{R1-R10,R14}       ;Save interpreter's context
+               LDR     R14,sail_R13            ;Load main routine's R13
+               STR     R13,sail_R13            ;Save our R13 away (useless)
+               MOV     R13,R14                 ;Switch back to main routine
+               LDMFD   R13!,{R3-R12,R14}       ;Restore Termite's registers
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+; --- sail_execEnd ---
+;
+; On entry:    R0 == parent handle
+;              R4 == 8 word block of A%-H%
+;              R11 == upcall block
+;
+; On exit:     --
+;
+; Use:         Update the parents A%-H%
+
+sail_execEnd   ROUT
+
+               STMFD   R13!,{R0-R4,R12,R14}    ;Stack registers
+               MOV     R12,R0                  ;Put anchor in R12
+               ADRL    R1,sail__varNames       ;Point to the names
+               MOV     R2,#8                   ;Number of vars to transfer
+00             MOV     R0,#vType_integer       ;It's an integer
+               BL      var_find                ;Try to create it
+               LDR     R14,[R4],#4             ;Load the value to transfer
+               STR     R14,[R0,#4]             ;Store the value
+               ADD     R1,R1,#3                ;Point to the next name
+               SUBS    R2,R2,#1                ;Reduce the count
+               BGT     %00                     ;And keep on looking
+
+               LDMFD   R13!,{R0-R4,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- sail_getLine ---
+;
+; On entry:    R0 == handle
+;
+; On exit:     R0 == current line number
+;
+; Use:         Returns the current line number
+
+sail_getLine   ROUT
+
+               LDR     R0,[R0,#:INDEX:sail_line]
+               MOVS    PC,R14
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/termite b/StraySrc/Libraries/Sapphire/sail/s/termite
new file mode 100644 (file)
index 0000000..32e3a53
--- /dev/null
@@ -0,0 +1,1590 @@
+;
+; termite.s
+;
+; Implementation of Termite specific instructions
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.ctrl
+               GET     sh.errNum
+               GET     sh.error
+               GET     sh.express
+               GET     sh.getToken
+               GET     sh.interp
+               GET     sh.stracc
+               GET     sh.strBucket
+               GET     sh.termscript
+               GET     sh.tokens
+               GET     sh.upcalls
+               GET     sh.var
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- termite_beep ---
+
+               EXPORT  termite_beep
+termite_beep   ROUT
+
+               TCALL   termite_makeBeep        ;Make a beep
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_break ---
+
+               EXPORT  termite_break
+termite_break  ROUT
+
+               TCALL   termite_sendBreak       ;Send the break
+               BL      termite__error          ;Handle possible error
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_call ---
+
+               EXPORT  termite_call
+termite_call   ROUT
+
+               BL      ctrl_setUpRegs          ;Set up the regs then
+
+               CMP     R10,#vType_integer      ;Is this an integer?
+               MOVNE   R0,#err_numNeeded       ;No -- get error number
+               BNE     error_report            ;...and report the error
+
+               MOV     R14,PC                  ;Set up return address
+               MOV     PC,R9                   ;Execute the code
+
+               LDR     R9,=termite__retned     ;Point to some space
+               STMIA   R9!,{R0-R8}             ;Store returned registers
+               MOV     R14,PC,LSR #28          ;Get the flags
+               STMIA   R9,{R14}                ;Strore the flags too
+               LDMFD   R13!,{R7-R12}           ;Load back position info
+               LDMFD   R13!,{R0}               ;Load stracc offset
+               BL      stracc_free             ;Free any strings I had
+
+               ; --- We have now done the SWI instr ---
+
+               LDR     R0,=termite__retned     ;Point to the returned regs
+               BL      ctrl_resolveRegs        ;Do the other half now
+               B       interp_next             ;If flags -- return
+
+               LTORG
+
+; --- termite_chain ---
+
+               EXPORT  termite_chain
+termite_chain  ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,sail_stracc          ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               ADR     R0,sail_misc+8*4                ;Point to the misc buffer
+               BL      termite_copyString      ;Copy the string over
+               B       sail_end                        ;End the script, and chain
+
+               LTORG
+
+; --- termite_close ---
+
+               EXPORT  termite_close
+termite_close  ROUT
+
+               MOV     R0,#-1                  ;Close the session
+               B       sail_end                        ;Do that then
+
+               LTORG
+
+; --- termite_cls ---
+
+               EXPORT  termite_cls
+termite_cls    ROUT
+
+               TCALL   termite_clearScreen     ;Clear the screen
+               BL      termite__error          ;Handle possible error
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_download ---
+
+               EXPORT  termite_download
+termite_download ROUT
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               ; --- Null terminate this ---
+
+               MOV     R2,R0                   ;Look after the offset
+               MOV     R5,#0                   ;Useful, t' be sure
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Check for another string ---
+
+               CMP     R9,#','                 ;Do we have a comma?
+               MOVNE   R3,#0                   ;No -- use default then
+               BNE     %10termite_download     ;...and jump ahead
+
+               BL      getToken                ;Skip over the comma
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               ; --- Null terminate this ---
+
+               MOV     R3,R0                   ;Look after the offset
+               MOV     R5,#0                   ;Useful, t' be sure
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Do the download now ---
+
+10             LDR     R1,sail_stracc          ;Load stracc address
+               MOV     R4,R2                   ;Look after the offet
+               ADD     R2,R1,R2                ;Point to protocal name
+               CMP     R3,#0                   ;Do we have a filename?
+               ADDNE   R3,R1,R3                ;Yes -- point to it then
+               TCALL   termite_downLoad        ;Do the download
+               BL      termite__error          ;Handle possible error
+               MOV     R0,R4                   ;Get offset of protocol name
+               BL      stracc_free             ;Free it now
+               B       interp_next             ;Do another instruction
+
+               LTORG
+
+; --- termite_error ---
+
+               EXPORT  termite_error
+termite_error  ROUT
+
+               CMP     R9,#tok_on              ;Is this an option?
+               CMPNE   R9,#tok_off
+               BEQ     %50termite_error        ;Yes -- jump ahead
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,sail_stracc          ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,sail_misc            ;Point to the misc buffer
+               MOV     R14,#1                  ;A sillu error number
+               STR     R14,[R0],#4             ;Store that
+               BL      termite_copyString      ;Copy the string over
+               ADR     R0,sail_misc            ;Point to the misc buffer
+               B       sail_error              ;Return the error
+
+               ; --- There was an option ---
+
+50termite_error        LDR     R0,sail_flags           ;Load the flags word
+               CMP     R9,#tok_on              ;Turn on the errors?
+               ORREQ   R0,R0,#tscFlag_error    ;Yes -- set the bit then
+               BICEQ   R0,R0,#tscFlag_error    ;No -- clear it then
+               STR     R0,sail_flags           ;Store the flags back
+               BL      getToken                ;Skip over the token
+               B       interp_next             ;Do the next one
+
+               LTORG
+
+; --- termite_exec ---
+
+               EXPORT  termite_exec
+termite_exec   ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,sail_stracc          ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,sail_misc+8*4                ;Point to the misc buffer
+               BL      termite_copyString      ;Copy the string over
+               MOV     R0,R5                   ;Get the rvalue
+               BL      stracc_free             ;Free the string from stracc
+               ADR     R0,sail_misc+8*4                ;Point to the misc buffer
+               ORR     R0,R0,#(1<<30)          ;Make this into an exec
+               BL      sail_end                        ;Exec new script
+               B       interp_next             ;Continue happily
+
+               LTORG
+
+; --- termite_finish ---
+
+               EXPORT  termite_finish
+termite_finish ROUT
+
+               TCALL   termite_finishSession   ;Finish the session
+               B       interp_next             ;And go round for more
+
+               LTORG
+
+; --- termite_hangup ---
+
+               EXPORT  termite_hangup
+termite_hangup ROUT
+
+               TCALL   termite_dropCarrier     ;Hang up the modem
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_lclear ---
+
+               EXPORT  termite_lclear
+termite_lclear ROUT
+
+               TCALL   termite_clearLocal      ;Clear the buffer
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_lecho ---
+
+               EXPORT  termite_lecho
+termite_lecho  ROUT
+
+               CMP     R9,#tok_off             ;Is this an option thingy?
+               CMPNE   R9,#tok_local
+               CMPNE   R9,#tok_remote
+               CMPNE   R9,#tok_both
+               BEQ     %50termite_lecho        ;Yes -- deal seperately
+
+               ; --- Just echo the result to the screen then ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read the next expression
+               BL      express_pop             ;Get the value in R0,R1
+               CMP     R1,#vType_integer       ;Is this an integer?
+               BEQ     %10termite_lecho        ;Yes -- jump ahead
+               CMP     R1,#vType_string        ;Or a string?
+               MOVNE   R0,#err_arrayBad
+               BNE     error_report
+
+               ; --- Display a string ---
+
+               LDR     R2,sail_stracc          ;Get the stracc address
+               LDR     R2,[R2]
+               ADD     R2,R2,R0,LSR #8         ;Point to the string
+               AND     R3,R0,#&FF              ;Get the length
+               BL      termite__doSpool        ;Maybe spool this lot
+               TCALL   termite_sendLocal       ;Write out the message
+               BL      termite__error          ;Handle possible error
+               BL      stracc_free             ;Free the string from stracc
+               B       %20termite_lecho        ;Jump ahead
+
+               ; --- Display an integer on the screen ---
+
+10termite_lecho        ADR     R1,sail_misc            ;Point to a nice buffer
+               MOV     R2,#256                 ;The buffer is big
+               SWI     OS_ConvertInteger4      ;Convert the number to a str
+               SUB     R3,R1,R0                ;Get the length
+               MOV     R2,R0                   ;Point at the block
+               BL      termite__doSpool        ;Maybe spool this lot
+               TCALL   termite_sendLocal       ;Write out the message
+               BL      termite__error          ;Handle possible error
+
+               ; --- Maybe write out the return char ---
+
+20termite_lecho        CMP     R9,#';'                 ;Is there a semicolon now?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     interp_next             ;...read another instr
+
+               LDR     R2,sail_bucket          ;Get the bucket anchor
+               LDR     R2,[R2]
+               LDR     R0,sail_lnewline                ;Load the newline offset
+               CMP     R0,#0                   ;Is there one?
+               BEQ     interp_next             ;No -- stop here then
+               ADD     R2,R2,R0                ;Point to the string
+               LDRB    R3,[R2,#-1]             ;Load out the length
+               BL      termite__doSpool        ;Maybe spool this lot
+               TCALL   termite_sendLocal       ;Write out the terminator
+               BL      termite__error          ;Handle possible error
+               B       interp_next             ;And read another instruction
+
+               ; --- Handle the options ---
+
+50termite_lecho        LDR     R0,sail_flags           ;Load the flags word
+               BIC     R0,R0,#tscFlag_echoLR+tscFlag_echoLL
+               CMP     R9,#tok_local           ;Do we require local echoing?
+               CMPNE   R9,#tok_both
+               ORREQ   R0,R0,#tscFlag_echoLL   ;Yes -- set the flag
+               CMP     R9,#tok_remote          ;Do we require remote echos?
+               CMPNE   R9,#tok_both
+               ORREQ   R0,R0,#tscFlag_echoLR   ;Yes -- set the flag
+               STR     R0,sail_flags           ;Store back the flags word
+               BL      getToken                ;Get another token
+
+               B       interp_next             ;Keep on going then!
+
+               LTORG
+
+; -- termite_linput ---
+
+               EXPORT  termite_linput
+termite_linput ROUT
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it in
+
+               ; --- Now enter a string reading loop ---
+
+               BL      stracc_ensure           ;Make sure that there's room
+               MOV     R2,R0                   ;Look after address
+               MOV     R4,R0                   ;Twice
+               MOV     R5,#0                   ;The length so far
+               MOV     R3,#1                   ;Length of buffer to echo
+
+00
+               TCALL   termite_readLocal       ;Read a byte from the buffer
+               CMP     R0,#-1                  ;Was there one?
+               BLEQ    sail_wait               ;No -- wait for it then
+               LDREQ   R2,sail_stracc
+               LDREQ   R2,[R2]
+               ADDEQ   R2,R2,R1,LSR #8
+               ADDEQ   R2,R2,R5
+               BEQ     %b00
+               CMP     R0,#127                 ;Is this a delete?
+               CMPNE   R0,#8
+               BEQ     %f05                    ;Yes -- deal with that then
+               CMP     R0,#32                  ;Was it valid?
+               STRGEB  R0,[R2,#0]              ;Yes -- store the byte
+               BLGE    termite_doLEcho         ;Echo the buffer
+               ADDGE   R2,R2,#1                ;Increment the pointer
+               ADDGE   R5,R5,#1                ;Increment the length
+               CMP     R0,#13                  ;Are we finished?
+               CMPNE   R5,#256
+               BLT     %b00                    ;No -- get some more then
+               B       %f10                    ;Finished -- jump ahead
+
+               ; --- Do a delete operation ---
+
+05             CMP     R5,#0                   ;Is the buffer empty?
+               BLE     %b00                    ;Yes -- do nothing
+               MOV     R14,#8                  ;Get a backspace
+               STRB    R14,[R2,#0]             ;Store it...
+               STRB    R14,[R2,#2]             ;In two places
+               MOV     R14,#32                 ;And a space too
+               STRB    R14,[R2,#1]             ;Put that in the middle
+               MOV     R3,#3                   ;Send 3 characters
+               BLGE    termite_doLEcho         ;Echo the buffer
+               SUB     R2,R2,#1                ;Reduce the address
+               SUB     R5,R5,#1                ;And the number of chars
+               MOV     R3,#1                   ;Put R3 back to 1
+               B       %b00                    ;Join main loop again
+
+               ; --- We have finished reading the string ---
+
+10             ORR     R0,R1,R5                ;Get the rvalue
+               MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               MOV     R3,R1                   ;Move these up a little
+               MOV     R2,R0
+               BL      express_pop             ;Get my lvalue off
+               BL      ctrl_store              ;Store this away
+               B       interp_next             ;Do another command
+
+               LTORG
+
+; --- termite_lnewline ---
+
+               EXPORT  termite_lnewline
+termite_lnewline ROUT
+
+               CMP     R9,#'='                 ;Next char must be `='
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the equals sign
+
+               LDR     R0,sail_lnewline                ;Get existing offset
+               BL      strBucket_free          ;Free it
+               MOV     R0,#0                   ;Prepare to read rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop it off the stack
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_strNeeded       ;No -- get error number
+               BNE     error_report            ;And report the error
+               BL      termite__storeStr       ;Store in the bucket
+               STR     R0,sail_lnewline                ;Store the new offset
+               B       interp_next             ;And do the next instruction
+
+; --- termite_log ---
+
+               EXPORT  termite_log
+termite_log    ROUT
+
+               ; --- Load the first parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,sail_stracc          ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;Look after the rvalue
+               ADR     R0,sail_misc            ;Point to the misc buffer
+               BL      termite_copyString      ;Copy the string over
+               TCALL   termite_logFileAdd      ;Add the string to the log
+               BL      termite__error          ;Handle possible error
+               MOV     R0,R5                   ;Get the rvalue back
+               BL      stracc_free             ;Free it from stracc
+               B       interp_next             ;Return to main loop
+
+               LTORG
+
+; --- termite_newsession ---
+
+               EXPORT  termite_newsession
+termite_newsession ROUT
+
+               ; --- Read the base name ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_numNeeded       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ; --- NULL terminate it ---
+               ;
+               ; We rely on the fact that there can't be anything else
+               ; after this string.  It is also important that we remember
+               ; the stracc offset of this string, so that all the strings
+               ; can be removed from stracc in one go.
+
+               MOV     R3,R1                   ;Look after the offset
+               MOV     R5,#0                   ;Useful, t' be sure
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Read the sub-style name ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_numNeeded       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ; --- NULL terminate it ---
+
+               MOV     R6,R1                   ;Look after the offset
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ADD     R4,R1,#(1<<8)           ;The next string will go here
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Now we keep on adding strings to the list ---
+
+05             CMP     R9,#','                 ;Do we have a comma?
+               BNE     %50termite_newsession   ;No -- do the deed then
+               BL      getToken                ;Skip over the comma
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the string
+               CMP     R1,#vType_dimStr        ;Is this a string array?
+               BEQ     %10termite_newsession   ;Yes -- jump ahead
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_strNeeded       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ; --- We have a string then ---
+
+               CMP     R0,#0                   ;Does it have a length?
+               BEQ     %05termite_newsession   ;No -- find another one then
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+               B       %05termite_newsession   ;Find another string
+
+               ; --- We have a string array ---
+
+10             MOV     R3,R0                   ;Look after rvalue
+               MOV     R2,#0                   ;Start from the beginning
+15             MOV     R1,R3                   ;Put it in R1
+               BL      termite__enumArray      ;Get an element
+               BCC     %05termite_newsession   ;No more, get another string
+               ANDS    R14,R0,#&FF             ;Get the length
+               BEQ     %15termite_newsession   ;Zero -- get another one then
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+               B       %15termite_newsession   ;Find another element
+
+               ; --- All the strings are in stracc now ---
+               ;
+               ; First, we terminate the list
+
+50             BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Now, point to the strings ---
+
+               LDR     R5,sail_stracc          ;Load stracc anchor
+               LDR     R5,[R5]
+               ADD     R0,R5,R3,LSR #8         ;Point to the base name
+               ADD     R1,R5,R6,LSR #8         ;Point to the sub-style
+               ADD     R2,R5,R4,LSR #8         ;Point to strings
+
+               TCALL   termite_newSession      ;Open the session
+               BL      termite__error          ;Handle possible error
+
+               MOV     R0,R3                   ;Put the offset in R0
+               BL      stracc_free             ;Free all those strings!
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+; --- termite_oscli ---
+
+               EXPORT  termite_oscli
+termite_oscli  ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,sail_stracc          ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,sail_misc            ;Point to the misc buffer
+               BL      termite_copyString      ;Copy the string over
+               SWI     Wimp_StartTask          ;Do the command
+               MOV     R0,R5                   ;Get the rvalue back
+               BL      stracc_free             ;Free the string from stracc
+               B       interp_next             ;Continue happily
+
+               LTORG
+
+; --- termite_rclear ---
+
+               EXPORT  termite_rclear
+termite_rclear ROUT
+
+               TCALL   termite_clearRemote     ;Clear the buffer
+               B       interp_next             ;And go for more
+
+               LTORG
+
+; --- termite_recho ---
+
+               EXPORT  termite_recho
+termite_recho  ROUT
+
+               CMP     R9,#tok_off             ;Is this an option thingy?
+               CMPNE   R9,#tok_local
+               CMPNE   R9,#tok_remote
+               CMPNE   R9,#tok_both
+               BEQ     %50termite_recho        ;Yes -- deal seperately
+
+               ; --- Just echo the result to the screen then ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read the next expression
+               BL      express_pop             ;Get the value in R0,R1
+               CMP     R1,#vType_integer       ;Is this an integer?
+               BEQ     %10termite_recho        ;Yes -- jump ahead
+               CMP     R1,#vType_string        ;Or a string?
+               MOVNE   R0,#err_arrayBad
+               BNE     error_report
+
+               ; --- Display a string ---
+
+               LDR     R2,sail_stracc          ;Get the stracc address
+               LDR     R2,[R2]
+               ADD     R2,R2,R0,LSR #8         ;Point to the string
+               AND     R3,R0,#&FF              ;Get the length
+               TCALL   termite_sendRemote      ;Write out the message
+               BL      termite__error          ;Handle possible error
+               BL      stracc_free             ;Free the string from stracc
+               B       %20termite_recho        ;Maybe write out return char
+
+               ; --- Display an integer on the screen ---
+
+10termite_recho        ADR     R1,sail_misc            ;Point to a nice buffer
+               MOV     R2,#256                 ;The buffer is big
+               SWI     OS_ConvertInteger4      ;Convert the number to a str
+               SUB     R3,R1,R0                ;Get the length
+               MOV     R2,R0                   ;Point at the block
+               TCALL   termite_sendRemote      ;Write out the message
+               BL      termite__error          ;Handle possible error
+
+               ; --- Maybe write out the return char ---
+
+20termite_recho        CMP     R9,#';'                 ;Is there a semicolon now?
+               BLEQ    getToken                ;Yes -- get a token
+               BEQ     interp_next             ;...read another instr
+
+               LDR     R2,sail_bucket          ;Get the bucket anchor
+               LDR     R2,[R2]
+               LDR     R0,sail_rnewline                ;Load the newline offset
+               CMP     R0,#0                   ;Is there one?
+               BEQ     interp_next             ;No -- stop here then
+               ADD     R2,R2,R0                ;Point to the string
+               LDRB    R3,[R2,#-1]             ;Load out the length
+               TCALL   termite_sendRemote      ;Write out the terminator
+               BL      termite__error          ;Handle possible error
+               B       interp_next             ;And read another instruction
+
+               ; --- Handle the options ---
+
+50termite_recho        LDR     R0,sail_flags           ;Load the flags word
+               BIC     R0,R0,#tscFlag_echoRR+tscFlag_echoRL
+               CMP     R9,#tok_local           ;Do we require local echoing?
+               CMPNE   R9,#tok_both
+               ORREQ   R0,R0,#tscFlag_echoRL   ;Yes -- set the flag
+               CMP     R9,#tok_remote          ;Do we require remote echos?
+               CMPNE   R9,#tok_both
+               ORREQ   R0,R0,#tscFlag_echoRR   ;Yes -- set the flag
+               STR     R0,sail_flags           ;Store back the flags word
+               BL      getToken                ;Get another token
+
+               B       interp_next             ;Keep on going then!
+
+               LTORG
+
+; --- termite_report ---
+
+               EXPORT  termite_report
+termite_report ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_string        ;Is this a string?
+               MOVNE   R0,#err_strNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               LDR     R1,sail_stracc          ;Get the stracc address
+               LDR     R1,[R1]
+               ADD     R1,R1,R0,LSR #8         ;Point to the string
+               AND     R2,R0,#&FF              ;Get the length
+
+               MOV     R5,R0                   ;look after the rvalue
+               ADR     R0,sail_misc            ;Point to the misc buffer
+               BL      termite_copyString      ;Copy the string over
+               TCALL   termite_printMessage    ;Report the message
+               MOV     R0,R5                   ;Get the rvalue back
+               BL      stracc_free             ;Free the string from stracc
+               B       interp_next             ;Continue happily
+
+               LTORG
+
+; --- termite_rinput ---
+
+               EXPORT  termite_rinput
+termite_rinput ROUT
+
+               MOV     R0,#1                   ;Read an lvalue
+               BL      express_read            ;Read it in
+
+               ; --- Now enter a string reading loop ---
+
+               BL      stracc_ensure           ;Make sure that there's room
+               MOV     R2,R0                   ;Look after address
+               MOV     R4,R0                   ;Twice
+               MOV     R5,#0                   ;The length so far
+               MOV     R3,#1                   ;Length of buffer to echo
+
+00
+               TCALL   termite_checkCarrier    ;Get current carrier state
+               CMP     R0,#0                   ;Is there one?
+               MOVEQ   R0,#0                   ;No, return ""
+               BEQ     %90termite_rinput       ;And jump ahead
+
+               TCALL   termite_readRemote      ;Read a byte from the buffer
+               CMP     R0,#-1                  ;Was there one?
+               BLEQ    sail_wait               ;No -- wait for it then
+               LDREQ   R2,sail_stracc
+               LDREQ   R2,[R2]
+               ADDEQ   R2,R2,R1,LSR #8
+               ADDEQ   R2,R2,R5
+               BEQ     %b00
+               CMP     R0,#127                 ;Is this a delete?
+               CMPNE   R0,#8
+               BEQ     %f05                    ;Yes -- deal with that then
+               CMP     R0,#32                  ;Was it valid?
+               STRGEB  R0,[R2,#0]              ;Yes -- store the byte
+               BLGE    termite_doREcho         ;Echo the buffer
+               ADDGE   R2,R2,#1                ;Increment the pointer
+               ADDGE   R5,R5,#1                ;Increment the length
+               CMP     R0,#13                  ;Are we finished?
+               CMPNE   R5,#256
+               BLT     %b00                    ;No -- get some more then
+               B       %f10                    ;Finished -- jump ahead
+
+               ; --- Do a delete operation ---
+
+05             CMP     R5,#0                   ;Is the buffer empty?
+               BLE     %b00                    ;Yes -- do nothing
+               MOV     R14,#8                  ;Get a backspace
+               STRB    R14,[R2,#0]             ;Store it...
+               STRB    R14,[R2,#2]             ;In two places
+               MOV     R14,#32                 ;And a space too
+               STRB    R14,[R2,#1]             ;Put that in the middle
+               MOV     R3,#3                   ;Send 3 characters
+               BLGE    termite_doREcho         ;Echo the buffer
+               SUB     R2,R2,#1                ;Reduce the address
+               SUB     R5,R5,#1                ;And the number of chars
+               MOV     R3,#1                   ;Put R3 back to 1
+               B       %b00                    ;Join main loop again
+
+               ; --- We have finished reading the string ---
+
+10             ORR     R0,R1,R5                ;Get the rvalue
+90             MOV     R1,#vType_string        ;This is a string
+               BL      stracc_added            ;Tell stracc about this
+               MOV     R3,R1                   ;Move these up a little
+               MOV     R2,R0
+               BL      express_pop             ;Get my lvalue off
+               BL      ctrl_store              ;Store this away
+               B       interp_next             ;Do another command
+
+               LTORG
+
+; --- termite_rnewline ---
+
+               EXPORT  termite_rnewline
+termite_rnewline ROUT
+
+               CMP     R9,#'='                 ;Next char must be `='
+               MOVNE   R0,#err_expEq           ;If it isn't, moan
+               BNE     error_report
+               BL      getToken                ;Skip past the equals sign
+
+               LDR     R0,sail_rnewline                ;Get existing offset
+               BL      strBucket_free          ;Free it
+               MOV     R0,#0                   ;Prepare to read rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop it off the stack
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_strNeeded       ;No -- get error number
+               BNE     error_report            ;And report the error
+               BL      termite__storeStr       ;Store inthe bucket
+               STR     R0,sail_rnewline                ;Store the new offset
+               B       interp_next             ;And do the next instruction
+
+; --- termite_spool ---
+
+               EXPORT  termite_spool
+termite_spool  ROUT
+
+               CMP     R9,#10                  ;Is this a newline?
+               CMPNE   R9,#':'                 ;Or a colon
+               CMPNE   R9,#&FF                 ;Or the end of the file?
+               CMPNE   R9,#tok_else            ;Or an else
+               BEQ     %50                     ;Yes -- turn off spooling
+
+               ; --- Turn on spooling ---
+               ;
+               ; Ooh, spooling, I really dig you.
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read the expression
+               BL      express_pop             ;Pop the result
+               CMP     R1,#vType_string        ;Do we have a string?
+               MOVNE   R0,#err_strNeeded       ;No -- moan at thick user
+               BNE     error_report            ;Do that then
+
+               ; --- Copy the string to the misc buffer ---
+
+               LDR     R1,sail_stracc          ;Find the stracc buffer
+               LDR     R1,[R1,#0]              ;Load the pointer out
+               MOV     R2,R0                   ;Look after the rvalue
+               ADD     R0,R1,R0,LSR #8         ;Find the string base
+               AND     R1,R2,#&FF              ;And get the length
+               ADR     R3,sail_misc            ;Point to destination buffer
+00             LDRB    R14,[R0],#1             ;Load byte from string
+               STRB    R14,[R3],#1             ;Store in destination
+               SUBS    R1,R1,#1                ;Decrement the counter
+               BGT     %b00                    ;And carry on going
+               MOV     R14,#0                  ;Terminate the string
+               STRB    R14,[R3],#1             ;Stick that on the end
+
+               MOV     R0,R2                   ;Find the string rvalue
+               BL      stracc_free             ;Remove it from stracc
+
+               ; --- Make sure we're not spooling right now ---
+
+               LDR     R1,sail_spool           ;Load the current handle
+               CMP     R1,#0                   ;Are we spooling?
+               MOVNE   R0,#0                   ;Yes -- close current file
+               SWINE   XOS_Find                ;So do that then
+
+               ; --- Now open the file ---
+
+               MOV     R0,#&8F                 ;Give me lots of errors
+               ADR     R1,sail_misc            ;Point to the buffer
+               SWI     XOS_Find                ;Find a file handle for it
+               BVS     error_reportReal        ;If failed, report the error
+               STR     R0,sail_spool           ;Save the file handle
+               B       interp_next             ;Now do another instruction
+
+               ; --- Close the current file ---
+
+50termite_spool        LDR     R1,sail_spool           ;Load the current handle
+               CMP     R1,#0                   ;Are we spooling?
+               MOVNE   R0,#0                   ;Yes -- close current file
+               SWINE   XOS_Find                ;So do that then
+               BVS     error_reportReal
+               MOV     R14,#0                  ;Get a zero value
+               STR     R14,sail_spool          ;Clear the file handle
+               B       interp_next             ;Now do another instruction
+
+               LTORG
+
+; --- termite_syscall ---
+
+               EXPORT  termite_syscall
+termite_syscall        ROUT
+
+               BL      ctrl_setUpRegs          ;Set up the regs then
+
+               CMP     R10,#vType_string       ;Is this a string?
+               LDREQ   R14,sail_stracc         ;Yes -- load the stracc addr#
+               LDREQ   R14,[R14]               ;Grrrr...
+               ADDEQ   R9,R14,R9,LSR #8        ;Point to the string
+               MOVEQ   R14,PC                  ;Yes -- set up return address
+               ADDEQ   PC,R11,#termite_sysNumString
+               BVS     error_reportReal        ;Report possible error
+               CMPNE   R10,#vType_integer      ;Is this an integer?
+               MOVNE   R0,#err_arrayBad        ;No -- get error number
+               BNE     error_report            ;...and report the error
+
+               TCALL   termite_sysCall         ;Call the call then!
+
+               ADR     R10,termite__retned     ;Point to some space
+               STMIA   R10!,{R0-R8}            ;Store returned registers
+               MOV     R14,PC,LSR #28          ;Get the flags
+               STMIA   R10!,{R14}              ;Strore the flags too
+
+               ; --- Convert the string if needed ---
+
+               LDMFD   R13!,{R7-R12}           ;Load back position info
+               LDMFD   R13!,{R0}               ;Load stracc offset
+               BL      stracc_free             ;Free any strings I had
+
+               ; --- We have now done the SYSCALL instr ---
+
+               ADR     R0,termite__retned      ;Point to the returned regs
+               BL      ctrl_resolveRegs        ;Do the other half now
+               B       interp_next             ;No error -- happy
+
+termite__retned        DCD     0,0,0,0,0,0,0,0,0,0,0   ;For SYSCALL, CALL
+
+               LTORG
+
+; --- termite_upload ---
+
+               EXPORT  termite_upload
+termite_upload ROUT
+
+               ; --- Read the protocol name ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Get the rvalue
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_numNeeded       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ; --- NULL terminate it ---
+               ;
+               ; We rely on the fact that there can't be anything else
+               ; after this string.  It is also important that we remember
+               ; the stracc offset of this string, so that all the strings
+               ; can be removed from stracc in one go.
+
+
+               MOV     R3,R1                   ;Look after the offset
+               MOV     R5,#0                   ;Useful, t' be sure
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ADD     R4,R1,#(1<<8)           ;The next string will go here
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Now we keep on adding strings to the list ---
+
+05             CMP     R9,#','                 ;Do we have a comma?
+               BNE     %50termite_upload       ;No -- do the deed then
+               BL      getToken                ;Skip over the comma
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off the string
+               CMP     R1,#vType_dimStr        ;Is this a string array?
+               BEQ     %10termite_upload       ;Yes -- jump ahead
+               CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_strNeeded       ;No -- get the error number
+               BNE     error_report            ;And report the error
+
+               ; --- We have a string then ---
+
+               CMP     R0,#0                   ;Does it have a length?
+               BEQ     %05termite_upload       ;No -- find another one then
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+               B       %05termite_upload       ;Find another string
+
+               ; --- We have a string array ---
+
+10             MOV     R3,R0                   ;Look after rvalue
+               MOV     R2,#0                   ;Start from the beginning
+15             MOV     R1,R3                   ;Put it in R1
+               BL      termite__enumArray      ;Get an element
+               BCC     %05termite_upload       ;No more, get another string
+               ANDS    R14,R0,#&FF             ;Get the length
+               BEQ     %15termite_upload       ;Zero -- get another one then
+               BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+               B       %15termite_upload       ;Find another element
+
+               ; --- All the strings are in stracc now ---
+               ;
+               ; First, we terminate the list
+
+50             BL      stracc_ensure           ;Ensure we have space
+               STRB    R5,[R0,#0]              ;Terminate the string
+               ORR     R0,R1,#1                ;Get the rvalue
+               BL      stracc_added            ;Tell stracc about terminator
+
+               ; --- Now, point to the strings ---
+
+               LDR     R1,sail_stracc          ;Load stracc anchor
+               LDR     R1,[R1]
+               MOV     R5,R3                   ;Look after offset
+               ADD     R2,R1,R3,LSR #8         ;Point to the protocol name
+               ADD     R3,R1,R4,LSR #8         ;Point to files to upload
+
+               TCALL   termite_upLoad          ;Upload the files
+               BL      termite__error          ;Handle possible error
+
+               MOV     R0,R5                   ;Put the offset in R0
+               BL      stracc_free             ;Free all those strings!
+               B       interp_next             ;Do the next instruction
+
+               LTORG
+
+; --- termite_wait ---
+
+               EXPORT  termite_wait
+termite_wait   ROUT
+
+               ; --- Read a parameter ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;And get it off the stack
+               CMP     R1,#vType_integer       ;Is this an integer
+               MOVNE   R0,#err_numNeeded       ;Nope -- get error number
+               BNE     error_report            ;...and report the error
+
+               MOV     R1,R0                   ;Remember this time
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               ADD     R1,R1,R0                ;Return after this time
+
+               ; --- Now enter a waiting loop ---
+
+00             SWI     OS_ReadMonotonicTime    ;Read the current time
+               CMP     R0,R1                   ;Have we finished waiting?
+               BLCC    sail_wait               ;No -- wait some more
+               BCC     %b00                    ;...and keep on looping
+
+               B       interp_next             ;Go round for next command
+
+               LTORG
+
+; --- termite_watchfor ---
+
+               EXPORT  termite_watchfor
+termite_watchfor ROUT
+
+               ; --- See if we are ending the WATCHFOR ---
+
+               CMP     R9,#tok_end             ;Are we ending it?
+               BEQ     %70termite_watchfor     ;Yes -- jump ahead
+
+               ; --- First, we must set up strings ---
+               ;
+               ; We actually store the strings in the strBucket.
+               ; In the string list, we have a word for the pointer into
+               ; the string list, and a byte for the match position so far.
+
+               MOV     R5,#0                   ;Number so far
+               ADR     R3,sail_wForStrings     ;Point to the block
+               MOV     R4,#0                   ;For the match position
+               STR     R5,sail_wForState       ;Reset the state to 0
+
+10             CMP     R5,#32                  ;Are we at the maximum?
+               MOVGE   R0,#err_WFTooMany       ;Yes -- get error number
+               BEQ     error_report            ;And report the error
+
+               ; --- Now read the strings one at a time ---
+
+               MOV     R0,#0                   ;Read an rvalue
+               BL      express_read            ;Read it then
+               BL      express_pop             ;Pop off this value
+               CMP     R1,#vType_dimStr        ;Is this a string array?
+               BNE     %19termite_watchfor     ;No -- jump ahead
+
+               ; --- We have a string array ---
+
+               MOV     R1,R0                   ;Put the array in R1
+               MOV     R2,#0                   ;Start from the beginning
+00             BL      termite__enumArray      ;Get the next string
+               BCC     %15termite_watchfor     ;No more -- jump ahead
+               BL      termite__storeStr       ;Store the string
+               CMP     R9,#&7e                 ;Are we case insensitive?
+               ORREQ   R0,R0,#(1<<31)          ;Yes -- set the flag
+               STMIA   R3!,{R0,R4}             ;Store information
+               ADD     R5,R5,#1                ;Increment the counter
+               B       %b00                    ;And keep doing this
+
+               ; --- The array has finished ---
+
+15             CMP     R9,#&7e                 ;Should we skip a token?
+               BLEQ    getToken                ;Yes - do that then
+               B       %25termite_watchfor     ;Jump ahead a little
+
+               ; --- See if it's a string then ---
+
+19             CMP     R1,#vType_string        ;Is it a string?
+               MOVNE   R0,#err_strNeeded       ;No -- get the error
+               BNE     error_report            ;And then report it
+
+               ; --- We have a string in stracc ---
+
+               CMP     R9,#&7e                 ;Case insensitive? (#'~')
+               BLEQ    getToken                ;Yes -- skip over it
+20             BL      termite__storeStr       ;Put it in the bucket
+               ORREQ   R0,R0,#(1<<31)          ;Set the top bit for insens
+               STMIA   R3!,{R0,R4}             ;Store inforamtion
+               ADD     R5,R5,#1                ;Increment the counter
+
+               ; --- Do any more we have ---
+
+25             CMP     R9,#','                 ;Do we have a comma
+               BLEQ    getToken                ;Yes -- skip over it
+               BEQ     %10termite_watchfor     ;...and then go round
+               STR     R5,sail_wForNumber      ;Store the number of strings
+
+               ; --- Now we must check the ring buffer ---
+               ;
+               ; We keep taking bytes off until either a match is achieved,
+               ; we have read 255 chars or there are no more in the
+               ; buffer.  In any case we then on the buffer.
+               ; If we have 255 chars we simply start all over again.
+
+               ADR     R2,sail_misc            ;Point to the buffer
+               MOV     R3,#0                   ;Number read so far
+00
+               TCALL   termite_readRemote      ;Get a byte
+               CMP     R0,#-1                  ;Was there a byte?
+               BEQ     %50termite_watchfor     ;No -- jump ahead
+               ADD     R3,R3,#1                ;Increment the count
+               STRB    R0,[R2],#1              ;Store it in the buffer
+               BL      termite__checkWF        ;Does this make a match?
+               BCS     %50termite_watchfor     ;Yes -- jump ahead
+               CMP     R3,#255                 ;Have we had 255 bytes now?
+               BNE     %b00                    ;No -- keep on going then
+
+               ; --- Send on the buffer ---
+
+               ADR     R2,sail_misc            ;Point to the buffer
+               BL      termite_doREcho         ;Echo it appropriately
+               MOV     R3,#0                   ;Reset the count to 0
+               B       %b00                    ;And start all over again
+
+               ; --- We have stopped reading bytes ---
+               ;
+               ; Either we ran out of bytes, or we got a match,
+               ; for either case we do the same thing
+
+50             ADR     R2,sail_misc            ;Point to the buffer
+               BL      termite_doREcho         ;Echo it appropriately
+               B       interp_next             ;Do the next instruction
+
+               ; --- We are ending the watchfor ---
+
+70             BL      getToken                ;Gobble up the END
+               BL      termite__endWF          ;End the WATCHFOR
+               B       interp_next             ;Do the next command
+
+               LTORG
+
+; --- termite__endWF ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Ends a WATCHFOR condition.
+
+termite__endWF ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some regsiters
+               ADR     R1,sail_wForStrings     ;Point to the string list
+               LDR     R2,sail_wForNumber      ;Get the number of strings
+               CMP     R2,#0                   ;Are there any?
+               BEQ     %f05                    ;No -- jump ahead then
+               MOV     R3,R2,LSL #3            ;Multiply by 8
+               ADD     R1,R1,R3                ;Point just past the last one
+00             LDR     R0,[R1,#-8]!            ;Load out an offset
+               BIC     R0,R0,#(1<<31)          ;Clear the flag
+               BL      strBucket_free          ;Remove the string
+               SUBS    R2,R2,#1                ;Reduce the count
+               BGT     %b00                    ;And free the rest
+
+05             STR     R2,sail_wForNumber      ;Make that clear
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- termite__checkWF ---
+;
+; On entry:    R0 == byte to check
+;
+; On exit:     CS if that byte caused a match,
+;              CC otherwise
+;
+; Use:         Tests all the strings in the WATCHFOR list, to see if
+;              the character caused a match.  If it did, then WATCH
+;              is set.
+
+termite__checkWF ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Stack registers
+               LDR     R1,sail_bucket          ;Load the bucket anchor
+               LDR     R1,[R1,#0]              ;Point to it
+               ADR     R2,sail_wForStrings     ;Point to the strings
+               LDR     R3,sail_wForNumber      ;Load the number of strings
+
+               ; --- Get the information on the string ---
+
+00             LDR     R7,[R2],#4              ;Load the offset
+               CMP     R7,#0                   ;Is this one blank?
+               ADDEQ   R2,R2,#4                ;Yes -- skip over position
+               BEQ     %10termite__checkWF     ;Zero length -- ignore
+               BICS    R4,R7,#(1<<31)          ;Clear the 'insens' bit
+               LDR     R5,[R2],#4              ;Load position so far
+               ADD     R4,R1,R4                ;Point to the string
+               LDRB    R6,[R4,#-1]             ;Load the string length
+               ADD     R4,R4,R5                ;Point to the character
+
+               ; --- Now do the comparison ---
+
+02             LDRB    R14,[R4,#0]             ;Load the next byte
+               MOV     R9,R0                   ;Put byte to comapre in R8
+               TST     R7,#(1<<31)             ;Case insensitive?
+               ORRNE   R9,R9,#32               ;Yes -- make lower case
+               ORRNE   R14,R14,#32             ;Both of them
+               CMP     R9,R14                  ;Are they the same?
+               BEQ     %05termite__checkWF     ;Yes -- jump ahead
+               CMP     R5,#0                   ;Was that the first char?
+               SUB     R4,R4,R5                ;Point to the string start
+               MOV     R5,#0                   ;Put it back to 0
+               BNE     %02termite__checkWF     ;No --  test first char
+               STR     R5,[R2,#-4]             ;...store that back
+               B       %10termite__checkWF     ;...jump ahead
+
+               ; --- The characters matched ---
+
+05             ADD     R5,R5,#1                ;Increment position
+               CMP     R5,R6                   ;Has the string been done?
+               BEQ     %20termite__checkWF     ;Yes -- we jump ahead then
+               STR     R5,[R2,#-4]             ;Store the new position
+
+               ; --- Move onto the next string ---
+
+10             SUBS    R3,R3,#1                ;Decrement the string count
+               BGT     %00termite__checkWF     ;And keep on looking
+               LDMFD   R13!,{R0-R9,R14}        ;Load back registers
+               BICS    PC,R14,#C_flag          ;And return to caller
+
+               ; --- We found a matching string ---
+
+20             LDR     R14,sail_wForNumber     ;Get teh number of strings
+               SUB     R14,R14,R3              ;Get index-1
+               ADD     R14,R14,#1              ;Get the index
+               STR     R14,sail_wForState      ;Store as the state
+               BL      termite__endWF          ;End the current watchfor
+               LDMFD   R13!,{R0-R9,R14}        ;Load back registers
+               ORRS    PC,R14,#C_flag          ;And return to caller
+
+               LTORG
+
+; --- termite_remoteInput ---
+;
+; On entry:    R0 == handle of script
+;              R2 == buffer containing bytes read
+;              R3 == number of bytes in buffer
+;              R11 == upcall block
+;
+; On exit:     R2 == new buffer containing bytes to put into ring buffer
+;              R3 == number of bytes in this buffer
+;
+; Use:         If we are not doing a watchfor, then this call will return
+;              immediately, resulting in all the buffer being sent
+;              to the ring buffer.
+;              If we are in a watchfor, then all data received, up until
+;              a match, is echoed immediatley, and not sent to the buffer.
+
+               EXPORT  termite_remoteInput
+termite_remoteInput ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               LDR     R14,[R0,#:INDEX:sail_wForNumber]
+               CMP     R14,#0                  ;Are we in a WATCHFOR?
+               LDMEQFD R13!,{PC}^              ;No -- return AQAP then
+
+               STMFD   R13!,{R0,R4,R5,R12}     ;Stack some more registers
+               MOV     R12,R0                  ;Put workspace in R12
+               MOV     R4,R2                   ;Look after buffer address
+               MOV     R5,R3                   ;Remember number of bytes
+
+               ; --- Scan the buffer ---
+
+00             LDRB    R0,[R4],#1              ;Load a byte
+               SUB     R5,R5,#1                ;Reduce the count
+               BL      termite__checkWF        ;Does this cause a match
+               BCS     %10termite_remoteInput  ;We have a match
+               CMP     R5,#0                   ;Have we finished?
+               BGT     %b00                    ;More to go -- loop
+
+               ; -- Send this buffer then ---
+
+               BL      termite_doREcho         ;Send the buffer
+               MOV     R3,#0                   ;Put nothing in the buffer
+               B       %90termite_remoteInput  ;And return to caller
+
+               ; --- We got a match ---
+
+10             SUB     R3,R3,R5                ;Get number to send
+               BL      termite_doREcho         ;Send the buffer
+               MOV     R3,R5                   ;Get bytes left
+               MOV     R2,R4                   ;Point to rest of buffer
+
+90             LDMFD   R13!,{R0,R4,R5,R12,PC}^ ;Return to caller
+
+               LTORG
+
+;----- Utility routines -----------------------------------------------------
+
+; --- termite_copyString ---
+;
+; On entry:    R0 == buffer to copy string to
+;              R1 == point to the string
+;              R2 == length of string to copy
+;
+; On exit:     --
+;
+; Use:         Copies the string into the buffer.
+
+               EXPORT  termite_copyString
+termite_copyString ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack registers
+               CMP     R2,#0                   ;Is this a short string?
+00             LDRGTB  R14,[R1],#1             ;Load a character
+               STRGTB  R14,[R0],#1             ;And then store it
+               SUBS    R2,R2,#1                ;Reduce the count
+               BGT     %b00                    ;And keep on goin'
+               MOV     R14,#0                  ;Get a terminator
+               STRB    R14,[R0],#1             ;Store the byte and return
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- termite_doLEcho ---
+;
+; On entry:    R2 == pointer to the buffer
+;              R3 == number of bytes to send
+;
+; On exit:     --
+;
+; Use:         Echos the buffer to local and remote according to the
+;              current flags, assuming the buffer came from the local input
+
+               EXPORT  termite_doLEcho
+termite_doLEcho        ROUT
+
+               STMFD   R13!,{R0,R3,R14}        ;Stack some registers
+               LDR     R0,sail_flags           ;Load the flags word
+               TST     R0,#tscFlag_echoLR      ;Should we echo to remote?
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               ADDNE   PC,R11,#termite_sendRemote ;...and send the bytes
+               TST     R0,#tscFlag_echoLL      ;Should we echo to local?
+               BLNE    termite__doSpool        ;Yes -- check for spooling
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               ADDNE   PC,R11,#termite_sendLocal ;...and send the bytes
+               LDMFD   R13!,{R0,R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- termite_doREcho ---
+;
+; On entry:    R2 == pointer to the buffer
+;              R3 == number of bytes to send
+;
+; On exit:     --
+;
+; Use:         Echos the buffer to local and remote according to the
+;              current flags, assuming the buffer came from remote input
+
+               EXPORT  termite_doREcho
+termite_doREcho        ROUT
+
+               STMFD   R13!,{R0,R3,R14}        ;Stack some registers
+               LDR     R0,sail_flags           ;Load the flags word
+               TST     R0,#tscFlag_echoRR      ;Should we echo to remote?
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               ADDNE   PC,R11,#termite_sendRemote ;...and send the bytes
+               TST     R0,#tscFlag_echoRL      ;Should we echo to local?
+               BLNE    termite__doSpool        ;Yes -- check for spooling
+               MOVNE   R14,PC                  ;Yes -- set up return address
+               ADDNE   PC,R11,#termite_sendLocal ;...and send the bytes
+               LDMFD   R13!,{R0,R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- termite__doSpool ---
+;
+; On entry:    R2 == pointer to data to spool
+;              R3 == size of the data
+;
+; On exit:     --
+;
+; Use:         Maybe writes the data to the current spool file.
+
+termite__doSpool ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               LDR     R1,sail_spool           ;Load the spool handle
+               CMP     R1,#0                   ;Is spooling enabled?
+               MOVNE   R0,#2                   ;Yes -- write to the file
+               SWINE   XOS_GBPB                ;Do the write
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+; --- termite__storeStr ---
+;
+; On entry:    R0 == rvalue of string
+;
+; On exit:     R0 == offset into bucket of string
+;
+; Use:         Puts the string in stracc, into the string bucket.
+
+termite__storeStr ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack some registers
+               MOV     R2,R0                   ;Put the string in R2
+               MOV     R4,R0                   ;And in R4
+               ANDS    R0,R2,#&FF              ;Get the length
+               MOVEQ   R0,#0                   ;Zero length, get a zero
+               BEQ     %90termite__storeStr    ;And return to caller
+               BL      strBucket_alloc         ;Allocate the bucket
+               LDR     R3,sail_stracc          ;Load the bucket anchor
+               LDR     R3,[R3]                 ;This is getting annoying
+               ADD     R3,R3,R2,LSR #8         ;Point to the string
+               AND     R2,R2,#&FF              ;Get the length
+00             LDRB    R14,[R3],#1             ;Load a character
+               STRB    R14,[R0],#1             ;Copy it over
+               SUBS    R2,R2,#1                ;Reduce the counter
+               BGT     %b00                    ;Keep on looping
+               MOV     R0,R4                   ;Put the rvalue in R0
+               BL      stracc_free             ;Remove it from stracc
+               MOV     R0,R1                   ;Return offset in R0
+
+90             LDMFD   R13!,{R1-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- termite__enumArray ---
+;
+; On entry:    R1 == offset of array definition
+;              R2 == item to read next
+;
+; On exit:     CS if item found, and
+;                R0 == rvalue of item
+;                R2 == updated
+;              CC otherwise
+;
+; Use:         Goes through an string array, returning each item.
+
+termite__enumArray ROUT
+
+               STMFD   R13!,{R1,R3,R4,R14}     ;Stack registers
+               LDR     R3,sail_varTree         ;Point at the tree
+               LDR     R3,[R3]
+               ADD     R0,R3,R1                ;Point at the array
+               MOV     R4,R2                   ;Remember the count
+               LDR     R14,[R0,#8]             ;Load number of items
+               CMP     R2,R14                  ;Have we finished?
+               BEQ     %95termite__enumArray   ;Yes -- return then
+
+               LDR     R14,[R0,#4]             ;Load number of subscripts
+               ADD     R0,R0,#12               ;Point to them
+               ADD     R0,R0,R14,LSL #2        ;Point past them
+               ADD     R0,R0,R2,LSL #2         ;Point at the item
+               SUB     R0,R0,R3                ;Make that an offset
+               MOV     R1,#vType_lvString      ;The item is a string
+               BL      ctrl_load               ;Load it out
+               MOV     R0,R2                   ;Put the rvalue in R0
+               ADD     R2,R4,#1                ;Increment the item pos
+
+               LDMFD   R13!,{R1,R3,R4,R14}     ;Load back registers
+               ORRS    PC,R14,#C_flag          ;And return success
+
+95             LDMFD   R13!,{R1,R3,R4,R14}     ;Load back registers
+               BICS    PC,R14,#C_flag          ;And return failure
+
+               LTORG
+
+; --- termite__error ---
+;
+; On entry:    V flag and R0 determine error condition
+;
+; On exit:     --
+;
+; Use:         This call will generate an error, if ERROR ON has been
+;              done, or set the ERROR$ variable otherwise.
+
+termite__error ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save regiters
+               LDR     R1,sail_flags           ;Load the fags word
+               BVS     %50termite__error       ;Jump ahead if there's an err
+
+               ; --- There was no error ---
+
+               TST     R1,#tscFlag_error       ;Do we generate errors?
+               BNE     %90termite__error       ;Yes -- just return then
+
+               ; --- Put a NULL string into ERROR$ ---
+
+               LDR     R0,sail_errorS          ;Get the exesting offset
+               BL      strBucket_free          ;Free it
+               MOV     R0,#0                   ;Get a 0 length string
+               STR     R0,sail_errorS          ;Save that away
+               B       %90termite__error       ;Return to caller
+
+               ; --- There was an error ---
+
+50             TST     R1,#tscFlag_error       ;Do we generate errors?
+               BNE     error_reportReal        ;Yes -- report the error then
+
+               ; --- Copy the string into ERROR$ ---
+
+               ADD     R2,R0,#4                ;Put string pointer in R2
+               LDR     R0,sail_errorS          ;Get the exesting offset
+               BL      strBucket_free          ;Free it
+               MOV     R1,R2                   ;Point to the string
+               MOV     R0,#0                   ;Current sting length
+00             LDRB    R14,[R1],#1             ;Load a byte
+               CMP     R14,#0                  ;Is it a NULL one?
+               ADDNE   R0,R0,#1                ;No -- increment the length
+               BNE     %b00                    ;And keep on going
+
+               ; --- Now copy over the string ---
+
+               BL      strBucket_alloc         ;We need this much room
+               STR     R1,sail_errorS          ;Store this offset away
+00             LDRB    R14,[R2],#1             ;Load a byte from string
+               CMP     R14,#0                  ;Is this the end?
+               STRNE   R14,[R0],#1             ;No -- store in ERROR$
+               BNE     %b00                    ;And keep doing this
+
+               ; --- Return to caller ---
+
+90             LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/tokenise b/StraySrc/Libraries/Sapphire/sail/s/tokenise
new file mode 100644 (file)
index 0000000..b6051c2
--- /dev/null
@@ -0,0 +1,563 @@
+;
+; tokenise.s
+;
+; Tokenise a Termite script
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.tokens
+               GET     sh.var
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- tokenise ---
+;
+; On entry:    R0 == pointer to source buffer
+;              R1 == size of source text
+;              R2 == pointer to destination buffer
+;              R3 == flags:
+;                      bit 0 == start reading a statement
+;              R11 == pointer to Termite upcall block
+;              R12 == pointer to script anchor
+;
+; On exit:     May return an error
+;
+; Use:         Tokenises a Termite script into an output buffer.
+
+               EXPORT  tokenise
+tokenise       ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Save some registers
+               MOV     R10,R2                  ;Point to output buffer
+               MOV     R7,R0                   ;Point to input buffer
+               ADD     R8,R7,R1                ;Point to input buffer limit
+               ADR     R9,sail_misc            ;Point to temporary buffer
+               ANDS    R14,R3,#1               ;Awaiting a statement?
+               MOVNE   R6,#tState__stmt        ;Yes -- select that state
+               MOVEQ   R6,#tState__dunno       ;No -- normal scanning state
+               MOVNE   R14,#1                  ;We start on line 1
+               STR     R14,[R13,#-8]!          ;Save this initial value
+
+               ; --- Ok, start lexing ---
+
+               MOV     R3,#0                   ;No flags set yet
+00tokenise     CMP     R7,R8                   ;Finished yet?
+               BHI     %10tokenise             ;Yes -- stop then
+               LDRB    R0,[R7],#1              ;No -- load the next byte
+               MOVEQ   R0,#-1                  ;Yes -- get an EOF character
+
+               MOV     R14,PC
+               ADD     PC,PC,R6,LSL #2         ;And leap off into oblivion
+               B       %00tokenise
+
+               B       tok__stmt
+               B       tok__dunno
+               B       tok__string
+               B       tok__dblQte
+               B       tok__star
+               B       tok__decimal
+               B       tok__hex
+               B       tok__ident
+               B       tok__keyWord
+               B       tok__label
+               B       tok__expLab
+               B       tok__lineCmt
+               B       tok__blkCmt
+               B       tok__cmtStar
+
+               ; --- Tidy up if we've finished ---
+
+10tokenise     MOV     R14,#255                ;Mark the end of the script
+               STRB    R14,[R10],#1            ;Save that on the end
+               ADD     R13,R13,#8              ;Restore the stack pointer
+               LDMFD   R13!,{R0-R10,R14}       ;And return to caller
+               BICS    PC,R14,#V_flag
+
+               LTORG
+
+; --- tok__error ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     --
+;
+; Use:         Reports an error during tokenising.
+
+tok__error     ROUT
+
+               ADD     R13,R13,#12             ;Restore the stack pointer
+               LDMFD   R13!,{R1-R10,R14}       ;Restore registers too
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- tok__incLineNo ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Increments the current line number.
+
+tok__incLineNo ROUT
+
+               LDR     R1,[R13,#0]             ;Yes -- load line number
+               CMP     R1,#0                   ;Are we scanning a file?
+               ADDNE   R1,R1,#1                ;Increment it
+               STRNE   R1,[R13,#0]             ;And store it back
+               MOVS    PC,R14
+
+               LTORG
+
+; --- tok__stmt ---
+
+tok__stmt      ROUT
+
+               CMP     R0,#'*'                 ;Is this a *command?
+               STREQB  R0,[R10],#1             ;Yes -- store the * character
+               MOVEQ   R6,#tState__star        ;And read a star command
+               MOVEQS  PC,R14                  ;And return to caller
+
+               CMP     R0,#'.'                 ;Is this a label
+               ORREQ   R3,R3,#tFlag__readDot   ;We've just read a dot
+               MOVEQ   R6,#tState__label       ;Read a label, please
+               MOVEQ   R4,#0                   ;No character read yet
+               MOVEQS  PC,R14                  ;And return to caller
+
+               ; Drop through to dunno
+
+; --- tok__dunno ---
+
+tok__dunno     ROUT
+
+               ; --- Ignore whitespace ---
+               ;
+               ; Other states will have dealt with this as necessary already
+               ; so we don't need to bother.
+
+               MOV     R2,R14                  ;Preserve the link
+               CMP     R0,#10                  ;Is it a newline
+               STREQB  R0,[R10],#1             ;Yes -- store it in buffer
+               BLEQ    tok__incLineNo          ;Increment the line number
+               MOVEQ   R6,#tState__stmt        ;And start a new statement
+               CMPNE   R0,#' '                 ;Is it a space
+               CMPNE   R0,#9                   ;Or a tab?
+               MOVEQS  PC,R2                   ;Yes -- don't do anything
+               MOV     R14,R2                  ;Put the link back
+
+               ; --- Now find an appropriate state ---
+
+               CMP     R0,#'/'                 ;Is this a slash?
+               STREQ   R6,[R13,#4]             ;Yes -- save old state away
+
+               SUBS    R1,R0,#'+'              ;Check for strange chars
+               SUBNES  R1,R0,#'-'              ;Check for strange chars
+               SUBNES  R1,R0,#'*'              ;Check for strange chars
+               SUBNES  R1,R0,#'/'              ;Check for strange chars
+               SUBNES  R1,R0,#'<'              ;Check for strange chars
+               SUBNES  R1,R0,#'>'              ;Check for strange chars
+               SUBNE   R1,R0,#'A'              ;Otherwise check uppercase
+               CMP     R1,#26                  ;Is it in the right range?
+               SUBCC   R7,R7,#1                ;Yes -- backtrack one char
+               MOVCC   R6,#tState__keyWord     ;And read a keyword
+               MOVCC   R5,#0                   ;Entry in state table
+               MOVCC   R4,#0                   ;No characters read yet
+               MOVCC   R2,#0                   ;No token discovered yet
+               MOVCCS  PC,R14                  ;And return to caller
+
+               MOV     R6,#tState__dunno       ;Read char, so not new stmt
+
+               CMP     R0,#'"'                 ;Is it a string?
+               STREQB  R0,[R10],#1             ;Yes -- store opening quote
+               MOVEQ   R6,#tState__string      ;And read a string literal
+               MOVEQS  PC,R14                  ;And return to caller
+
+               SUB     R1,R0,#'0'              ;Check if it's a digit
+               CMP     R1,#10                  ;Is it in the right range?
+               STRCCB  R0,[R10],#1             ;Yes -- store digit
+               MOVCC   R6,#tState__decimal     ;And read a decimal number
+               MOVCCS  PC,R14                  ;And return to caller
+
+               CMP     R0,#'&'                 ;Also check for hex numbers
+               STREQB  R0,[R10],#1             ;Yes -- store the ampersand
+               MOVEQ   R6,#tState__hex         ;And read a hex number
+               MOVEQS  PC,R14                  ;And return to caller
+
+               SUBS    R1,R0,#'_'              ;Is this an underscore?
+               SUBNE   R1,R0,#'a'              ;Check if it's a lowercase
+               CMP     R1,#26                  ;Is it in the right range?
+               STRCCB  R0,[R10],#1             ;Yes -- store the character
+               MOVCC   R6,#tState__ident       ;And read an identifier
+               MOVCCS  PC,R14                  ;And return to caller
+
+               CMP     R0,#':'                 ;Is this a colon?
+               STREQB  R0,[R10],#1             ;Yes -- store the character
+               MOVEQ   R6,#tState__stmt        ;And start a new statement
+               MOVEQS  PC,R14                  ;And return to caller
+
+               STRB    R0,[R10],#1
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- tok__star ---
+
+tok__star      ROUT
+
+               MOV     R2,R14                  ;Preserve the link
+               STRB    R0,[R10],#1             ;Save the character
+               CMP     R0,#10                  ;Is this a newline?
+               MOVEQ   R6,#tState__stmt        ;Start a new statement
+               BLEQ    tok__incLineNo          ;Increment the line number
+               MOVS    PC,R2                   ;And return to caller
+
+               LTORG
+
+; --- tok__string ---
+
+tok__string    ROUT
+
+               STRB    R0,[R10],#1             ;Save the character
+               CMP     R0,#'"'                 ;Is it another quote?
+               MOVEQ   R6,#tState__dblQte      ;Yes -- change state
+               MOVEQS  PC,R14                  ;And return
+               MOV     R2,R14                  ;Preserve the link
+               CMP     R0,#10                  ;Is it newline?
+               MOVEQ   R6,#tState__stmt        ;Yes -- change state
+               BLEQ    tok__incLineNo          ;...increment line number
+               MOVS    PC,R2                   ;And return
+
+               LTORG
+
+; --- tok__dblQte ---
+
+tok__dblQte    ROUT
+
+               CMP     R0,#'"'                 ;Is this a 2nd quote?
+               MOVEQ   R6,#tState__string      ;Yes -- go back to string
+               STREQB  R0,[R10],#1             ;..and store it away
+               SUBNE   R7,R7,#1                ;Otherwise backtrack
+               MOVNE   R6,#tState__dunno       ;..and enter dunno state
+               MOVS    PC,R14
+
+               LTORG
+
+; --- tok__decimal ---
+
+tok__decimal   ROUT
+
+               SUB     R1,R0,#'0'              ;Set up for range check
+               CMP     R1,#10                  ;Are we in range?
+               STRCCB  R0,[R10],#1             ;Yes -- store the number
+               MOVCCS  PC,R14                  ;And return
+
+               ; --- A bit of bodgery now ---
+               ;
+               ; This hackery introduces a space between two numbers, which
+               ; would otherwise severely upset something like
+               ;
+               ;    DIM a%!24 64
+
+tok__numHack   CMP     R0,#&20                 ;Is this a space?
+               BNE     %f00                    ;No -- just stop normally
+               LDRB    R1,[R7,#0]              ;Get the next byte
+               SUB     R1,R1,#'0'              ;Is it a digit?
+               CMP     R1,#10                  ;Quick check
+               STRCCB  R0,[R10],#1             ;Yes -- store the space
+00             SUB     R7,R7,#1                ;Backtrack a little
+               MOV     R6,#tState__dunno       ;...and change state
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- tok__hex ---
+
+tok__hex       ROUT
+
+               SUB     R1,R0,#'a'              ;Set up for range check
+               CMP     R1,#6                   ;Are we in range?
+               SUBCC   R0,R0,#'a'-'A'          ;Force to uppercase
+               SUBCS   R1,R0,#'0'
+               CMPCS   R1,#10
+               SUBCS   R1,R0,#'A'
+               CMPCS   R1,#6
+               STRCCB  R0,[R10],#1             ;Yes -- store the number
+               MOVCCS  PC,R14                  ;And return
+
+               ; --- Hack as above ---
+
+               B       tok__numHack            ;Use hacking code above
+
+               LTORG
+
+; --- tok__ident ---
+
+tok__ident     ROUT
+
+               CMP     R0,#'$'                 ;Is it a dollar sign?
+               CMPNE   R0,#'%'                 ;Or a percentage?
+               STREQB  R0,[R10],#1             ;Yes -- store it then
+               MOVEQ   R6,#tState__dunno       ;Change state
+               MOVEQS  PC,R14                  ;And return to caller
+
+               SUBS    R1,R0,#'_'              ;Is it an underscore?
+               SUBNE   R1,R0,#'0'              ;Or a number?
+               CMP     R1,#10
+               SUBCS   R1,R0,#'A'              ;Or a capital letter?
+               CMPCS   R1,#26
+               SUBCS   R1,R0,#'a'              ;Or a lowercase letter?
+               CMPCS   R1,#26
+               MOVCS   R1,#' '                 ;If not valid, append space
+               MOVCC   R1,R0                   ;Otherwise write character
+               STRB    R1,[R10],#1             ;Store a character
+               SUBCS   R7,R7,#1                ;No -- backtrack a little
+               MOVCS   R6,#tState__dunno       ;...and change state
+               MOVS    PC,R14                  ;Return to caller
+
+; --- tok__label ---
+
+tok__label     ROUT
+
+               SUBS    R1,R0,#'_'              ;Is it an underscore?
+               SUBNE   R1,R0,#'0'              ;Or a number?
+               CMP     R1,#10
+               SUBCS   R1,R0,#'A'              ;Or a capital letter?
+               CMPCS   R1,#26
+               SUBCS   R1,R0,#'a'              ;Or a lowercase letter?
+               CMPCS   R1,#26
+               BCS     %05tok__label           ;No -- do other things then
+
+               TST     R3,#tFlag__readDot + tFlag__readDEF
+               STREQB  R0,[R10],#1             ;No -- store the number
+               STRNEB  R0,[R9],#1              ;Otherwise store in scratch
+               MOVS    PC,R14                  ;...and return
+
+               ; --- Are we defining this label? ---
+
+05tok__label   TST     R3,#tFlag__readDot + tFlag__readDEF
+               SUBEQ   R7,R7,#1                ;No -- backtrack a little
+               MOVEQ   R6,#tState__dunno       ;...change state
+               MOVEQS  PC,R14                  ;...and return
+
+               ; --- Create the variable then ---
+
+               STMFD   R13!,{R3,R14}           ;Preserve R3 and link
+               MOV     R14,#0                  ;Terminate scratch buffer
+               STRB    R14,[R9],#1             ;To make things nice
+               TST     R3,#tFlag__readDot      ;Have we just read a dot?
+               MOVNE   R0,#vType_label         ;Yes -- create a label
+               BNE     %10tok__label           ;...and jump ahead
+               TST     R3,#tFlag__readFN       ;Is this a DEFFN?
+               MOVNE   R0,#vType_fn            ;Yes -- define one of these
+               MOVEQ   R0,#vType_proc          ;No -- define a DEFPROC then
+10tok__label   ADR     R9,sail_misc            ;Point to scratch start
+               MOV     R1,R9                   ;Point to label name
+               MOV     R2,R10                  ;Get the file address
+               LDR     R3,[R13,#8]             ;Load the line number
+               CMP     R3,#0                   ;Are we scanning the file?
+               BLNE    var_create              ;Create the variable
+               LDMVSFD R13!,{R3,R14}           ;If it failed, unstack...
+               BVS     tok__error              ;...and die horridly
+
+               SUB     R7,R7,#1                ;No -- backtrack a little
+               MOV     R6,#tState__dunno       ;...change state
+               LDMFD   R13!,{R3,R14}           ;Restore flags word
+               BIC     R3,R3,#tFlag__readDot + tFlag__readDEF
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- tok__expLab ---
+
+               ROUT
+
+tok__expLab    CMP     R0,#' '                 ;Is it a space?
+               CMPNE   R0,#9                   ;Or a TAB char?
+               SUBNE   R7,R7,#1                ;No -- backtrack a little
+               MOVNE   R6,#tState__label       ;...we are reading a label
+               MOVS    PC,R14                  ;Return
+
+               LTORG
+
+; --- tok__lineCmt ---
+
+tok__lineCmt   ROUT
+
+               MOV     R2,R14                  ;Preserve the link
+               CMP     R0,#10                  ;Is this a newline?
+               STREQB  R0,[R10],#1             ;Save the newline character
+               MOVEQ   R6,#tState__stmt        ;Start a new statement
+               BLEQ    tok__incLineNo          ;Increment the line number
+               MOVS    PC,R2                   ;And return to caller
+
+               LTORG
+
+; --- tok__blkCmt ---
+
+tok__blkCmt    ROUT
+
+               MOV     R2,R14                  ;Preserve the link
+               CMP     R0,#10                  ;Is this a newline?
+               MOVEQ   R0,#31                  ;Yes -- insert a weird char
+               STREQB  R0,[R10],#1             ;Put it in the buffer
+               BLEQ    tok__incLineNo          ;Increment the line number
+               MOVEQS  PC,R2                   ;And return
+               CMP     R0,#'*'                 ;Is it a star?
+               MOVEQ   R6,#tState__cmtStar     ;Yes -- change mode then
+               MOVS    PC,R2                   ;Return to caller
+
+               LTORG
+
+; --- tok__cmtStar ---
+
+tok__cmtStar   ROUT
+
+               MOV     R2,R14                  ;Preserve the link
+               CMP     R0,#10                  ;Is this a newline?
+               MOVEQ   R1,#31                  ;Yes -- insert a weird char
+               STREQB  R1,[R10],#1             ;Put it in the buffer
+               BLEQ    tok__incLineNo          ;Increment the line number
+               CMP     R0,#'/'                 ;Is the comment over now?
+               LDREQ   R6,[R13,#4]             ;Yes -- load previous state
+               CMPNE   R0,#'*'                 ;Is it still a star?
+               MOVNE   R6,#tState__blkCmt      ;No -- change state back
+               MOVS    PC,R2                   ;And return to caller
+
+               LTORG
+
+; --- tok__keyWord ---
+
+tok__keyWord   ROUT
+
+               STMFD   R13!,{R14}
+               ADR     R1,tokTable             ;Point to the toaken table
+               ADD     R1,R1,R5,LSR #16        ;Point into the table
+               CMP     R0,#'.'                 ;Is this a dot?
+               BEQ     %18tok__keyWord         ;Yes -- jump ahead then
+               ADD     R4,R4,#1                ;Increment char count
+10tok__keyWord LDR     R14,[R1],#4             ;Load LSB
+               CMP     R14,#0                  ;Is this the end?
+               BEQ     %15tok__keyWord         ;Yes -- jump ahead
+               CMP     R0,R14,LSR #24          ;Is this a match?
+               BNE     %10tok__keyWord         ;No -- keep looking
+
+               BIC     R14,R14,#&FF000000      ;Clear char to match byte
+               MOVS    R0,R14,LSR #16          ;Get the token byte
+               MOVNE   R2,R0                   ;This is a token
+               MOVNE   R4,#0                   ;So clear backtrack count
+               MOVS    R5,R14,LSL #16          ;Shift it up a bit
+               LDMNEFD R13!,{PC}^              ;And return to caller
+
+               ; --- Come to the end of the line ---
+
+15tok__keyWord SUB     R7,R7,R4                ;Do the backtracking
+               CMP     R2,#0                   ;Did we find a token?
+               MOVEQ   R6,#tState__ident       ;No -- read an identifier
+               LDMEQFD R13!,{PC}^              ;Bad luck then
+
+               ; --- We have found a match ---
+
+11tok__keyWord LDMFD   R13!,{R14}              ;Restore return address
+               MOV     R5,R2                   ;Get the matched token
+
+               ; --- Skip over REMS ---
+
+               CMP     R5,#tok_rem             ;Check for REM statements
+               CMPNE   R5,#tok_DD              ;Or a // comment
+               MOVEQ   R6,#tState__lineCmt     ;Introduces line comments
+               MOVEQS  PC,R14                  ;Return if it was one
+
+               CMP     R5,#tok_DT              ;Is it a /* comment?
+               MOVEQ   R6,#tState__blkCmt      ;Yes -- it's a block comment
+               MOVEQS  PC,R14                  ;And return to caller
+
+               ; --- Set up various flags and things ---
+
+17tok__keyWord STRB    R5,[R10],#1             ;Store in the block
+
+               BIC     R3,R3,#tFlag__readFN+tFlag__readPROC
+               CMP     R5,#tok_proc            ;Is this a PROC?
+               ORREQ   R3,R3,#tFlag__readPROC  ;Yes -- remember this
+               CMP     R5,#tok_fn              ;Or a FN?
+               ORREQ   R3,R3,#tFlag__readFN    ;Yes -- remember this
+               TST     R3,#tFlag__readPROC+tFlag__readFN
+               MOVNE   R6,#tState__label       ;If either -- change state
+               MOVNES  PC,R14                  ;...and return
+
+               BIC     R3,R3,#tFlag__readDEF   ;No -- clear DEF flag
+               CMP     R5,#tok_def             ;Was it a DEF then?
+               ORREQ   R3,R3,#tFlag__readDEF   ;Yes -- set the def flag
+
+               ; --- Are we expecting a label next? ---
+
+               CMP     R5,#tok_goto            ;Is there a label next?
+               CMPNE   R5,#tok_gosub
+               CMPNE   R5,#tok_restore
+               MOVEQ   R6,#tState__expLab      ;Yes -- change state
+               MOVEQ   R4,#0                   ;...No characters read yet
+               BIC     R3,R3,#tFlag__readDot   ;We are not expecting a dot
+               MOVEQS  PC,R14                  ;...and return
+
+               ; --- Return to caller ---
+
+               MOV     R6,#tState__dunno       ;Change state back again
+               MOVS    PC,R14                  ;And return to caller
+
+               ; --- User has abbreviated key word ---
+
+18tok__keyWord ADR     R0,tokTable             ;Point to the table
+19tok__keyWord LDR     R5,[R1,#0]              ;Load the next index
+               MOVS    R4,R5,LSL #16           ;Shift it up a bit
+               ADDNE   R1,R0,R4,LSR #16        ;If more to go -- point
+               BNE     %19tok__keyWord         ;...and keep on looping
+               BIC     R2,R5,#&FF000000        ;Clear the match char
+               MOV     R2,R2,LSR #16           ;And get the final token
+               B       %11tok__keyWord         ;Deal with the key word
+
+               GET     sh.tokTable
+
+               LTORG
+
+               ; --- States for the tokeniser ---
+
+               ^       0
+tState__stmt   #       1                       ;Start of a new statement
+tState__dunno  #       1                       ;Not sure what to expect
+tState__string #       1                       ;Tokenising a string
+tState__dblQte #       1                       ;Checking for double quotes
+tState__star   #       1                       ;Processing a *command
+tState__decimal        #       1                       ;Reading a decimal/bin number
+tState__hex    #       1                       ;Reading a hex number
+tState__ident  #       1                       ;Processing an identifier
+tState__keyWord        #       1                       ;Checking for keywords
+tState__label  #       1                       ;Reading a label
+tState__expLab #       1                       ;Waiting for a label
+tState__lineCmt        #       1                       ;Skipping a line comment
+tState__blkCmt #       1                       ;Skipping a block comment
+tState__cmtStar        #       1                       ;Found star in block comment
+
+               ; --- Flags ---
+
+tFlag__readDot EQU     (1<<0)                  ;Creating a label
+tFlag__readDEF EQU     (1<<1)                  ;We're doing a def
+tFlag__readFN  EQU     (1<<5)                  ;Just read a FN
+tFlag__readPROC        EQU     (1<<6)                  ;Just read a PROC
+
+;----- Workspace ------------------------------------------------------------
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/tree b/StraySrc/Libraries/Sapphire/sail/s/tree
new file mode 100644 (file)
index 0000000..1035d3e
--- /dev/null
@@ -0,0 +1,215 @@
+;
+; tree.s
+;
+; Another attempt at symbol table management
+;
+; © 1995 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.mem
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- tree_add ---
+;
+; On entry:    R0 == type number
+;              R1 == address of name
+;              R2 == size of user data
+;
+; On exit:     R0 == address of user data in new node
+;              CS if node already exists, else CC
+;              May return an error
+;
+; Use:         Adds a node into a symbol table tree.
+
+               EXPORT  tree_add
+tree_add       ROUT
+
+               BIC     R14,R14,#V_flag         ;Assume no errors for now
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+
+               ; --- Find a suitable place for the node ---
+
+               LDR     R5,sail_varTree         ;Load base address of tree
+               LDR     R5,[R5]                 ;Because it's an anchor addr
+               ADD     R3,R5,R0,LSL #2         ;Find the appropriate root
+
+               ; --- Keep on until we find a leaf ---
+
+10tree_add     LDR     R4,[R3,#0]              ;Load this offset
+               CMP     R4,#0                   ;Was this a leaf item?
+               BEQ     %20tree_add             ;Yes -- then we found the end
+               ADD     R4,R5,R4                ;Convert this to an address
+               LDR     R0,[R4,#tNode_name]     ;Find this node's name offset
+               ADD     R0,R5,R0                ;Convert this to an address
+               BL      str_cmp                 ;Compare the strings
+               ADDLT   R3,R4,#tNode_right      ;Less -- go right
+               ADDGT   R3,R4,#tNode_left       ;More -- go left
+               BNE     %10tree_add             ;If not a match, continue
+               ADD     R0,R4,#tNode_user       ;Point to node's user data
+               LDMFD   R13!,{R1-R5,R14}        ;Restore caller's registers
+               ORRS    PC,R14,#C_flag          ;And tell him it was there
+
+               ; --- Insert a new node ---
+
+20tree_add     SUB     R3,R3,R5                ;Convert to an offset
+               MOV     R4,R1                   ;Look after the name address
+21tree_add     LDRB    R14,[R1],#1             ;Load a byte from the name
+               CMP     R14,#32                 ;Is this the end yet?
+               BCS     %21tree_add             ;No -- keep on going
+               SUB     R1,R1,R4                ;Work out the string length
+               ADD     R1,R1,#3+8              ;Now word align this size
+               BIC     R1,R1,#3                ;Tum te tum te tum
+               ADD     R2,R2,R1                ;Work out how much I need
+
+               ; --- Extend the block ---
+
+               ADR     R14,sail_varPtr         ;Find the block sizes
+               LDMIA   R14,{R0,R1}             ;Load used and total length
+               ADD     R0,R0,R2                ;How much do I actually need?
+               STR     R0,sail_varPtr          ;Save the updated value
+               SUB     R2,R0,R2                ;And get the original offset
+               ADD     R0,R0,#255              ;Align this to chunk size
+               BIC     R0,R0,#255              ;Pom pom pe pom pom...
+               CMP     R0,R1                   ;Do we have enough?
+               BLS     %30tree_add             ;Yes -- that's OK then
+
+               ; --- Allocate some more memory ---
+
+               MOV     R1,R0                   ;Get the new size I want
+               LDR     R0,sail_varTree         ;Find the block's anchor
+               BL      mem_realloc             ;Make the block bigger
+               BVS     %90tree_add             ;If it failed, give up
+               STR     R1,sail_varSize         ;Save the new size away
+
+               ; --- Now we're ready to go ---
+
+30tree_add     MOV     R1,R2                   ;Look after this offset
+               LDR     R5,sail_varTree         ;Find the tree base
+               LDR     R5,[R5]                 ;Irritating WimpExtension
+               ADD     R2,R5,R2                ;Turn offset into address
+35tree_add     LDRB    R14,[R4],#1             ;Load a byte of the name
+               CMP     R14,#32                 ;Is this the end yet?
+               MOVCC   R14,#0                  ;Yes -- store final 0
+               STRB    R14,[R2],#1             ;Store this byte away
+               BCS     %35tree_add             ;And keep on going
+               ADD     R2,R2,#3                ;Word align output ptr
+               BIC     R2,R2,#3                ;Yawn-o-matic on a stick
+
+               SUB     R14,R2,R5               ;Work out the current offset
+               STR     R14,[R5,R3]             ;Link this node into the tree
+               MOV     R3,R1                   ;Find the string offset
+               MOV     R0,#0                   ;Zero the left hand offset
+               MOV     R1,#0                   ;And the right hand one
+               STMIA   R2,{R0,R1,R3}           ;Fill in this node
+               ADD     R0,R2,#tNode_user       ;Find the user data
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack caller's registers
+               BICS    PC,R14,#C_flag          ;Say it wasn't there before
+
+               ; --- Something went badly wrong ---
+
+90tree_add     LDMFD   R13!,{R1-R5,R14}        ;Unstack caller's registers
+               ORRS    PC,R14,#V_flag          ;Return the error
+
+               LTORG
+
+; --- tree_find ---
+;
+; On entry:    R0 == type number
+;              R1 == pointer to the name
+;
+; On exit:     CS if the variable was found, and
+;                R0 == pointer to the variable block
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Tries to find a node with the given type and name in
+;              the symbol tree.
+
+               EXPORT  tree_find
+tree_find      ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+
+               ; --- Find a suitable place for the node ---
+
+               LDR     R5,sail_varTree         ;Load base address of tree
+               LDR     R5,[R5]                 ;Because it's an anchor addr
+               ADD     R3,R5,R0,LSL #2         ;Find the appropriate root
+
+               ; --- Keep on until we find a leaf ---
+
+10tree_find    LDR     R4,[R3,#0]              ;Load this offset
+               CMP     R4,#0                   ;Was this a leaf item?
+               BEQ     %20tree_find            ;Yes -- then we found the end
+               ADD     R4,R5,R4                ;Convert this to an address
+               LDR     R0,[R4,#tNode_name]     ;Find this node's name offset
+               ADD     R0,R5,R0                ;Convert this to an address
+               BL      str_cmp                 ;Compare the strings
+               ADDLT   R3,R4,#tNode_right      ;Less -- go right
+               ADDGT   R3,R4,#tNode_left       ;More -- go left
+               BNE     %10tree_find            ;If not a match, continue
+
+               ADD     R0,R4,#tNode_user       ;Point to node's user data
+               LDMFD   R13!,{R1-R5,R14}        ;Restore caller's registers
+               ORRS    PC,R14,#C_flag          ;And tell him it was there
+
+               ; --- Something went badly wrong ---
+
+20tree_find    LDMFD   R13!,{R1-R5,R14}        ;Unstack caller's registers
+               BICS    PC,R14,#C_flag          ;Return `not found'
+
+               LTORG
+
+; --- str_cmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         Case-sensitively compares two strings.  You can use the
+;              normal ARM condition codes after the compare, so you can
+;              treat this fairly much like a normal CMP.
+
+               EXPORT  str_cmp
+str_cmp                ROUT
+
+               STMFD   R13!,{R0,R1,R3,R4,R14}
+00str_cmp      LDRB    R3,[R0],#1              ;Get a character from A
+               LDRB    R4,[R1],#1              ;And one from B
+               CMP     R3,#&20                 ;Is that the end of A?
+               MOVLT   R3,#0                   ;Yes -- pretend it's null
+               CMP     R4,#&20                 ;Is that the end of B?
+               MOVLT   R4,#0                   ;Yes -- pretend it's null
+               CMP     R3,R4                   ;How do they match up?
+               LDMNEFD R13!,{R0,R1,R3,R4,PC}   ;If NE, return condition
+               CMP     R3,#0                   ;Is this the end?
+               BNE     %00str_cmp              ;No -- loop again
+               LDMFD   R13!,{R0,R1,R3,R4,PC}   ;Return to caller
+
+               LTORG
+
+               ; --- Tree node format ---
+
+               ^       0
+tNode_left     #       4                       ;Left branch offset
+tNode_right    #       4                       ;Right branch offset
+tNode_user     #       0                       ;Start of user data area
+tNode_name     #       4                       ;Offset of name in table
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/value b/StraySrc/Libraries/Sapphire/sail/s/value
new file mode 100644 (file)
index 0000000..d090855
--- /dev/null
@@ -0,0 +1,294 @@
+;
+; value.s
+;
+; Table drive expression evaluator for TermScript
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Termscript$$Code|,CODE,READONLY
+
+; --- val_readExp ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R7, R8, R9 == lookahead token
+;              R0, R1 == result of expression
+;              R10 == moved on to first char after expression
+;
+; Use:         Reads an expression for the current point in the tokenised
+;              file, and returns it's result. The implementation is
+;              table driven and should be very fast.
+
+               EXPORT  val_readExp
+val_readExp    ROUT
+
+10val_readExp  BL      val__operand
+               BLCS    val__operator
+               BCS     val_readExp
+
+               ; --- Now work out the result ---
+
+               BL      val__copyRest           ;Copy rest of tokens over
+
+
+               LTORG
+
+; --- val__operand ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0 corrupted
+;              R7, R8, R9 == lookahead token
+;              R10 modified appropriately
+;              CS if operand found,
+;              CC otherwise
+;
+; Use:         Reads an operand from the input, and does appropriate
+;              stack like things with it.
+
+val__operand   ROUT
+
+               STMFD   R13!,{R14}              ;Stack registers
+00val__operand CMP     R9,#'&'                 ;Start a hex number?
+               BEQ     %10val__operand         ;Yes -- jump ahead
+               CMP     R9,#'%'                 ;Start of a binary number?
+               BEQ     %20val__operand         ;Yes -- jump ahead
+               CMP     R9,#'!'                 ;An indirection operand?
+               CMPNE   R9,#'?'
+               CMPNE   R9,#'$'
+               BEQ     %40val__operand         ;Yes -- jump ahead
+               CMP     R9,#'+'                 ;Unary operator then?
+               CMPNE   R9,#'-'
+               BEQ     %50val__operand         ;Yes -- jump ahead
+               CMPNE   R9,#'('                 ;A nice bracket?
+               BEQ     %60val__operand         ;Yes -- jump ahead
+               SUB     R14,R9,#'0'             ;Set up for a range check
+               CMP     R14,#10                 ;Is it a digit?
+               MOVCC   R0,#0                   ;Yes -- set up accumulator
+               BCC     %30val__operand         ;Yes -- deal with that
+               B       %70val__operand         ;Assume it's an identifier
+
+               ; --- Read a hex number ---
+
+10val__operand BL      getToken                ;Get another token
+               MOV     R0,#0                   ;The number so far
+               SUB     R14,R9,#'A'             ;Check if it's a letter
+               CMP     R14,#6                  ;But only A-F
+               ADDCC   R14,R14,#10             ;If so, add 10 on
+               SUBCS   R14,R9,#'0'             ;Otherwise check for digit
+               CMPCS   R14,#10                 ;Make sure it's OK
+               BCC     %12val__operand         ;And jump head
+               MOV     R0,#err_badHex          ;Point to error message
+               B       error_report            ;And return the error
+
+11val__operand SUB     R14,R9,#'A'             ;Check if it's a letter
+               CMP     R14,#6                  ;But only A-F
+               ADDCC   R14,R14,#10             ;If so, add 10 on
+               SUBCS   R14,R9,#'0'             ;Otherwise check for digit
+               CMPCS   R14,#10                 ;Make sure it's OK
+               BCS     %35val__readSimple      ;No -- that's it then
+
+12val__operand ADD     R0,R14,R0,LSL #4        ;Multiply by 16 and add digit
+               BL      getToken                ;Load a character
+               B       %11val__readSimple      ;Keep on reading more
+
+               ; --- Read a binary number ---
+
+20val__operand BL      getToken                ;Get another token
+               MOV     R0,#0                   ;The number so far
+               SUB     R14,R9,#'0'             ;Set up for a range check
+               CMP     R14,#1                  ;Is it a digit
+               BLS     %22val__readSimple      ;Yes -- jump ahead
+               MOV     R0,#err_badBinary       ;Point to error message
+               B       error_report            ;And return the error
+
+21val__operand SUB     R14,R9,#'0'             ;Set up for a range check
+               CMP     R14,#1                  ;Is it a digit
+               BHI     %35val__readSimple      ;Nope -- jump ahead then
+
+22val__operand ADC     R0,R0,R0                ;Multiply by 2
+               BL      getToken                ;Load a character
+               B       %21val__readSimple      ;Keep on reading more
+
+               ; --- Read a decimal number ---
+
+30val__operand SUB     R14,R9,#'0'             ;Set up for a range check
+               CMP     R14,#10                 ;Is it a digit
+               BCS     %35val__readSimple      ;Nope -- jump ahead then
+
+32val__operand ADD     R0,R0,R0,LSL #2         ;Multiply by 5
+               ADD     R0,R14,R0,LSL #1        ;And then by 2 (* 10)
+               BL      getToken                ;Load the next token
+               B       %30val__readSimple      ;Keep on reading more
+
+               ; --- Finished reading a number ---
+
+35val__operand BL      val__stackNumber        ;Put a number on the stack
+               B       %90val__operand         ;Jump ahead
+
+               ; --- Read an indirection operator ---
+
+40val__operand MOV     R0,#0                   ;Get the offset ready
+               BL      val__stackNumber        ;Put it on the stack
+               BL      val__stackToken         ;And put operator on too
+               BL      getToken                ;Get the next token
+               B       %00val__operand         ;Need another operand
+
+               ; --- Deal with unary signs ---
+
+50val__operand CMP     R9,#'-'                 ;Is is a unary minus
+               BLEQ    val__stackToken         ;Yes -- put it on the stack
+               BL      getToken                ;Get another token
+               B       %00val__operand         ;Need another operand
+
+               ; --- We have just read a '(' ---
+
+60val__operand BL      val__stackToken         ;Stackit immediately
+               BL      getToken                ;Get another token
+               B       %00val__operand         ;Need another operand
+
+               ; --- Assume it's an identifier then ---
+
+70val__operand ADR     R1,sail_misc            ;Point to a nice block
+               MOV     R0,#vType_integer       ;The current variable type
+
+75val__operand SUBS    R14,R9,#'_'             ;Is it an underscore?
+               SUBNE   R14,R9,#'0'             ;Or a number?
+               CMP     R14,#10
+               SUBCS   R14,R9,#'A'             ;Or a capital letter?
+               CMPCS   R14,#26
+               SUBCS   R14,R9,#'a'             ;Or a lowercase letter?
+               CMPCS   R14,#26
+               STRCCB  R9,[R1],#1              ;Yes -- store it away
+               BLCC    getToken                ;Read the next byte
+               BCS     %95val_readLvalue       ;Ouch -- not an identifier
+
+               CMP     R9,#'$'                 ;Is it a dollar sign?
+               MOVEQ   R0,#vType_string        ;It's a string now
+               CMPNE   R9,#'%'                 ;Or a percentage?
+               STREQB  R9,[R2],#1              ;Yes -- store it then
+               CMPNE   R9,#' '                 ;Just check for a space
+
+               BNE     %75val_readLvalue       ;Go round for more
+
+               MOV     R14,#0                  ;The terminator
+               STRB    R14,[R1],#0             ;Store that in the var name
+               BL      getToken                ;Read the next token ready
+
+               ; --- The identifier name is in the buffer ---
+
+               ADR     R1,sail_misc            ;Point to the name
+               BL      var_find                ;Try to find the variable
+               MOVCC   R0,#err_unknown         ;Not there, get the error
+               BCC     error_report            ;And report a possible error
+
+               LDR     R1,[R0,#0]              ;Load out the variable type
+               LDR     R0,[R0,#4]              ;Load out the value
+               CMP     R1,#vType_integer       ;Is it an integer?
+               BLEQ    val__stackInteger       ;Yes -- stack it
+               BLNE    val__stackString        ;No -- it's a string then
+
+90val__operand LDMFD   R13!,{R14}              ;Load back registers
+               ORRS    PC,R14,#C_flag          ;We found an operand
+
+95val__operand LDMFD   R13!,{R14}              ;Load back registers
+               BICS    PC,R14,#C_flag          ;No operand was found
+
+               LTORG
+
+; --- val__operator ---
+;
+; On entry:    R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R7, R8, R9 == lookahead token
+;              R10 modified appropriately
+;              CS if operator found,
+;              CC otherwise
+;
+; Use:         Reads an operator from the input, and does appropriate
+;              stack like things with it.
+
+               ROUT
+
+val__operator  STMFD   R13!,{R14}              ;Stack registers
+00val__operator        CMP     R9,#')'                 ;Is it a close bracket?
+               BEQ     %10val__operator        ;Yes -- jump ahead
+               ; --- Make sure we recognise it ---
+
+               CMP     R9,#'!'                 ;An indirection operator?
+               CMPNE   R9,#'?'
+               CMPNE   R7,#tClass__andOp
+               CMPNE   R7,#tClass__orOp
+               CMPNE   R7,#tClass__addOp
+               CMPNE   R7,#tClass__multOp
+               CMPNE   R7,#tClass__relOp
+               BNE     %95val__operator        ;Nope -- just return
+               BL      val__stackToken         ;Stack this token
+               BL      getToken                ;Get another one
+               B       %90val__operator        ;And return success
+
+               ; --- We have read a ')' ---
+
+               BL      val__stackToken         ;Stack this token
+               BL      getToken                ;Get another one
+               B       %00val__operator        ;We expect another operator
+
+90val__operator        LDMFD   R13!,{R14}              ;Load back registers
+               ORRS    PC,R14,#C_flag          ;We found an operand
+
+95val__operator        LDMFD   R13!,{R14}              ;Load back registers
+               BICS    PC,R14,#C_flag          ;No operand was found
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+val__precTable DCD     val__andOp-val__precTable
+               DCD     0
+               DCD     0
+               DCD     0
+               DCD     val__multOp-val__precTable
+               DCD     val__orOp-val__precTable
+               DCD     0
+               DCD     val__relOp-val__precTable
+               DCD     val__addOp-val__precTable
+               DCD     0
+
+               ; --- The precedence tables ---
+               ;
+               ; Each byte indicates whether or not the given type of
+               ; toke has a higher or lower precedence than another type.
+               ; The order of the bytes is:
+               ;
+               ; and,-,-,-,mult,or,-,-,rel,add,-
+
+val__andOp     DCB      0, 0, 0, 0,-1, 1, 0, 0,-1,-1, 0
+val__multOp    DCB      1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0
+val__orOp      DCB     -1, 0, 0, 0,-1, 0, 0, 0,-1,-1, 0
+val__relOp     DCB      1, 0, 0, 0,-1, 1, 0, 0, 0,-1, 0
+val__addOp     DCB      1, 0, 0, 0,-1, 1, 0, 0, 1, 0, 0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/s/var b/StraySrc/Libraries/Sapphire/sail/s/var
new file mode 100644 (file)
index 0000000..edf69f2
--- /dev/null
@@ -0,0 +1,189 @@
+;
+; var.s
+;
+; Variable handling
+;
+; © 1995 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.anchor
+               GET     sh.errNum
+               GET     sh.error
+               GET     sh.tree
+
+;----- Other definitions ----------------------------------------------------
+
+var__chunkSize EQU     256                     ;Chunck size of var stack
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |TermScript$$Code|,CODE,READONLY
+
+; --- var_create ---
+;
+; On entry:    R0 == type of variable
+;              R1 == pointer to variable name
+;              R12 == pointer to the anchor block
+;              Other registers depend on the type
+;              vType_label, vType_proc, vType_fn:
+;                R2 == file offset of label of DEF
+;                R3 == line number of label or DEF
+;              vType_dimInt, vType_dimStr:
+;                R2 == pointer to subscript block (in *reverse* order)
+;                R3 == number of subscripts
+;                R4 == number of items to create
+;
+; On exit:     R0 == pointer to the variable
+;
+; Use:         Tries to find the variable given, and return a pointer
+;              to it if it is found. Otherwise it will try to create the
+;              variable and return a pointer to the new one.
+
+               EXPORT  var_create
+var_create     ROUT
+
+               ADD     PC,PC,R0,LSL #2         ;Branch to correct dispatcher
+               DCB     "TMA!"                  ;A little padding
+
+               B       var__normal
+               B       var__normal
+               B       var__dim
+               B       var__dim
+               B       var__label
+               B       var__label
+               B       var__label
+
+               LTORG
+
+; --- var_find ---
+;
+; On entry:    R0 == type of the variable
+;              R1 == name of the variable
+;
+; On exit:     CS if the variable was found, and
+;                R0 == pointer to the variable block
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Tries to find the given variable in the current tree.
+
+               EXPORT  var_find
+var_find       ROUT
+
+               STMFD   R13!,{R2,R14}           ;Save some registers
+               MOV     R2,R0                   ;Look after the type
+               BL      tree_find               ;Find the variable
+               LDMCSFD R13!,{R2,PC}^           ;If found, return now
+               CMP     R2,#vType_dimInt        ;Is it an integer array?
+               CMPNE   R2,#vType_dimStr        ;Or a string array?
+               MOVEQ   R0,#err_ukArray         ;Yes -- find `unknown array'
+               MOVNE   R0,#err_unknown         ;No -- use `unknown var'
+               B       error_report            ;And report it to the world
+
+               LTORG
+
+;----- Variable creation routines -------------------------------------------
+;
+; On entry:    R0 == variable type
+;              R1 == address of variable name
+
+; --- var__normal ---
+
+var__normal    ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack registers
+
+               ; --- Allocate space for the variable ---
+
+               MOV     R2,#8                   ;Variable requires 16 bytes
+               BL      tree_add                ;Add it to the symbol table
+               BVS     var__error              ;Return possible error
+
+               MOV     R14,#0                  ;Initialise the value
+               STRCC   R14,[R0,#4]             ;Set this up nicely
+               LDMFD   R13!,{R1-R4,PC}^        ;And return to caller
+
+; --- var__dim ---
+
+var__dim       ROUT
+
+               STMFD   R13!,{R1-R6,R14}        ;Stack registers
+               ADD     R5,R2,R3,LSL #2         ;Look after subscript block
+               MOV     R2,#12                  ;Room for name + num of subs
+               ADD     R2,R2,R3,LSL #2         ;Add room for sizes
+               ADD     R2,R2,R4,LSL #2         ;And subscripts themselves
+               BL      tree_add                ;Try to allocate space
+               BVS     var__error              ;Barf on error
+               STR     R3,[R0,#4]              ;Store number of subscripts
+               STR     R4,[R0,#8]              ;Store total number of items
+               ADD     R6,R0,#12               ;Point to the first size
+
+               ; --- Set up the subscript sizes ---
+
+00             LDR     R14,[R5,#-4]!           ;Load the subscript size
+               STR     R14,[R6],#4             ;Store that in the block
+               SUBS    R3,R3,#1                ;Reduce subscript count
+               BGT     %b00                    ;Keep filling in block
+
+               ; --- Initialise all the entries ---
+
+               MOV     R14,#0                  ;Initialiser
+00             STR     R14,[R6],#4             ;Set entry to 0
+               SUBS    R4,R4,#1                ;Reduce the item count
+               BGT     %b00                    ;Keep on initialising
+
+               LDMFD   R13!,{R1-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- var__label ---
+
+var__label     ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack registers
+               LDR     R14,sail_tokAnchor      ;Find anchor of t'ised file
+               LDR     R14,[R14]               ;I hate WimpExt_Heap
+               SUB     R4,R2,R14               ;Make the address an offset
+
+               ; --- Allocate space for the variable ---
+
+               MOV     R2,#12                  ;Variable requires 16 bytes
+               BL      tree_add                ;Add it to the symbol table
+               BVS     var__error              ;Return possible error
+
+               ; --- Fill in the block ---
+
+               MOV     R2,R4                   ;Get the file offset
+               STMIB   R0,{R2,R3}              ;Store the informtion
+               LDMFD   R13!,{R1-R4,PC}^        ;Unstack registers
+
+var__error     MOV     R0,#err_noMem           ;Get the error number
+               B       error_report            ;And report the error
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ; --- Variable types ---
+
+               ^       0
+vType_integer  #       1                       ;Integer
+vType_string   #       1                       ;String
+vType_dimInt   #       1                       ;DIM of integers
+vType_dimStr   #       1                       ;DIM of strings
+vType_label    #       1                       ;Label
+vType_proc     #       1                       ;Procedure name
+vType_fn       #       1                       ;Function name
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/anchor b/StraySrc/Libraries/Sapphire/sail/sh/anchor
new file mode 100644 (file)
index 0000000..e8b0f5a
--- /dev/null
@@ -0,0 +1,80 @@
+;
+; anchor.sh
+;
+; Layout of anchor blocks
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:anchor__dfn
+               GBLL    anchor__dfn
+
+               ; --- Anchor block contents ---
+
+               ^       0,R12
+
+sail_R13       #       4                       ;Saved R13 (stack pointer)
+sail_tokAnchor #       4                       ;Ptr to tokenised file anchor
+sail_currAnchor        #       4                       ;Current anchor for input
+sail_oldAnchor #       4                       ;Previous anchor for input
+sail_flags     #       4                       ;A nice flags word
+sail_timeOff   #       4                       ;OS_ReadMonotonicTime-TIME
+sail_line      #       4                       ;Current line number
+sail_timeSoFar #       4                       ;Time execution started
+sail_rndSeed   #       8                       ;Random number seed
+sail_rmaList   #       4                       ;List of blocks from RMA
+sail_env       #       4                       ;Handle of environment
+sail_global    #       4                       ;Ptr to global vars anchor
+sail_preempt   #       4                       ;Time allowed before return
+sail_files     #       32                      ;Files-open flags
+
+               ; --- DATA information ---
+
+sail_dataPtr   #       4                       ;Current DATA pointer
+sail_dataLine  #       4                       ;Current data line
+
+               ; --- Resizing blocks ---
+
+sail_rszBlocks #       0
+
+sail_varTree   #       4                       ;The variable stack anchor
+sail_varPtr    #       4                       ;Where to create the next var
+sail_varSize   #       4                       ;Current size if the stack
+
+sail_execStack #       4                       ;Anchor of execution stack
+sail_execStkPtr        #       4                       ;Pointer into stack
+sail_execStkSize #     4                       ;Size of the stack
+
+sail_opStack   #       4                       ;Anchor of execution stack
+sail_opStkPtr  #       4                       ;Pointer into stack
+sail_opStkSize #       4                       ;Size of the stack
+
+sail_calcStack #       4                       ;Anchor of execution stack
+sail_calcStkPtr        #       4                       ;Pointer into stack
+sail_calcStkSize #     4                       ;Size of the stack
+
+sail_stracc    #       4                       ;Anchor of execution stack
+sail_straccPtr #       4                       ;Pointer into stack
+sail_straccSize        #       4                       ;Size of the stack
+
+sail_bucket    #       4                       ;String bucket anchor
+sail_bktPtr    #       4                       ;Free pointer for bucket
+sail_bktSize   #       4                       ;Current size of bucket block
+
+sail_erszBlocks        #       0
+
+sail_misc      #       256                     ;A big buffer for things
+
+sail_blkSize   EQU     2048                    ;Enough space for a stack
+
+               [       {VAR}-sail_R13+1024>tsc_blkSize
+               !       1,"sail_blkSize is too small"
+               ]
+
+tscFlag_nl     EQU     (1<<0)                  ;We have just read a newline
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/ctrl b/StraySrc/Libraries/Sapphire/sail/sh/ctrl
new file mode 100644 (file)
index 0000000..6479065
--- /dev/null
@@ -0,0 +1,289 @@
+;
+; ctrl.sh
+;
+; Control flow handling
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  ctrl_let
+;  ctrl_timeEq
+;  ctrl_for
+;  ctrl_next
+;  ctrl_repeat
+;  ctrl_until
+;  ctrl_while
+;  ctrl_endwhile
+;  ctrl_gosub
+;  ctrl_return
+;  ctrl_if
+;  ctrl_else
+;  ctrl_goto
+;  ctrl_case
+;  ctrl_when
+;  ctrl_otherwise
+;  ctrl_end
+;  ctrl_swap
+;  ctrl_ptr
+;  ctrl_ext
+;  ctrl_close
+;  ctrl_bput
+;  ctrl_findDATA
+;  ctrl_read
+;  ctrl_restore
+;  ctrl_sys
+;  ctrl_setUpRegs
+;  ctrl_resolveRegs
+;  ctrl_fn
+;  ctrl_equals
+;  ctrl_proc
+;  ctrl_endproc
+;  ctrl_data
+;  ctrl_def
+;  ctrl_local
+;  ctrl_leftS
+;  ctrl_midS
+;  ctrl_rightS
+;  ctrl_dim
+;  ctrl_store
+;  ctrl_load
+;  ctrl_compare
+
+               [       :LNOT::DEF:ctrl__dfn
+               GBLL    ctrl__dfn
+
+; --- ctrl_let ---
+
+               IMPORT  ctrl_let
+
+; --- ctrl_timeEq ---
+
+               IMPORT  ctrl_timeEq
+
+; --- ctrl_for ---
+
+               IMPORT  ctrl_for
+
+; --- ctrl_next ---
+
+               IMPORT  ctrl_next
+
+; --- ctrl_repeat ---
+
+               IMPORT  ctrl_repeat
+
+; --- ctrl_until ---
+
+               IMPORT  ctrl_until
+
+; --- ctrl_while ---
+
+               IMPORT  ctrl_while
+
+; --- ctrl_endwhile ---
+
+               IMPORT  ctrl_endwhile
+
+; --- ctrl_gosub ---
+
+               IMPORT  ctrl_gosub
+
+; --- ctrl_return ---
+
+               IMPORT  ctrl_return
+
+; --- ctrl_if ---
+
+               IMPORT  ctrl_if
+
+; --- ctrl_else ---
+
+               IMPORT  ctrl_else
+
+; --- ctrl_goto ---
+
+               IMPORT  ctrl_goto
+
+; --- ctrl_case ---
+
+               IMPORT  ctrl_case
+
+; --- ctrl_when ---
+
+               IMPORT  ctrl_when
+
+; --- ctrl_otherwise ---
+
+               IMPORT  ctrl_otherwise
+
+; --- ctrl_end ---
+
+               IMPORT  ctrl_end
+
+; --- ctrl_swap ---
+
+               IMPORT  ctrl_swap
+
+; --- ctrl_ptr ---
+
+               IMPORT  ctrl_ptr
+
+; --- ctrl_ext ---
+
+               IMPORT  ctrl_ext
+
+; --- ctrl_close ---
+
+               IMPORT  ctrl_close
+
+; --- ctrl_bput ---
+
+               IMPORT  ctrl_bput
+
+; --- ctrl__findDATA ---
+;
+; On entry:    All the normal things
+;
+; On exit:     R0 == *address* in file of next DATA
+;
+; Use:         Sets the internal data pointer to the first DATA statement
+;              fromthe current position.
+
+               IMPORT  ctrl_findDATA
+
+; --- ctrl_read ---
+
+               IMPORT  ctrl_read
+
+; --- ctrl_restore ---
+
+               IMPORT  ctrl_restore
+
+; --- ctrl_sys ---
+
+               IMPORT  ctrl_sys
+
+; --- ctrl_setUpRegs ---
+;
+; On entry:    R7-R10 == position info
+;
+; On exit:     R0-R8 set up for sys call
+;              R9,R10 == rvalue of first parameter
+;              On the stack:
+;                new position info, R7-R12
+;                place to stracc free
+;
+; Use:         Sets up all the registers as required by a SYS or SYSCALL
+;              command.
+
+               IMPORT  ctrl_setUpRegs
+
+; --- ctrl_resolveRegs ---
+;
+; On entry:    R0 == pointer to register block
+;
+; On exit:     CS if flags were required, CC otherwise
+;
+; Use:         Resolves the registers returned from a SYS or SYSCALL
+;              into the appropriate variables.  The code assumes that
+;              we have possibly just read a TO command, and goes on
+;              from there.
+
+               IMPORT  ctrl_resolveRegs
+
+; --- FN ---
+;
+; OK, maybe it shouldn't be here.  I don't really care.
+;
+; Hack warning:        This is a hack.  We unwind express_read's stack and stuff
+;              them away somewhere completely different.
+
+               IMPORT  ctrl_fn
+
+; --- = ---
+
+               IMPORT  ctrl_equals
+
+; --- PROC ---
+
+               IMPORT  ctrl_proc
+
+; --- ENDPROC ---
+
+               IMPORT  ctrl_endproc
+
+; --- DATA ---
+
+               IMPORT  ctrl_data
+
+; --- DEF  ---
+
+               IMPORT  ctrl_def
+
+; --- LOCAL ---
+
+               IMPORT  ctrl_local
+
+; --- ctrl_leftS ---
+
+               IMPORT  ctrl_leftS
+
+; --- ctrl_midS ---
+
+               IMPORT  ctrl_midS
+
+; --- ctrl_rightS ---
+
+               IMPORT  ctrl_rightS
+
+; --- ctrl_dim ---
+
+               IMPORT  ctrl_dim
+
+; --- ctrl_store ---
+;
+; On entry:    R0,R1 == lvalue to store in
+;              R2,R3 == rvalue to write
+;
+;              If bit 31 of R1 is set, then for strings only, the old
+;              string is NOT removed from the stracc. This is
+;              so that variables can be restored after a procedure.
+;
+; On exit:     --
+;
+; Use:         Stores an rvalue into an lvalue.
+
+               IMPORT  ctrl_store
+
+; --- ctrl_load ---
+;
+; On entry:    R0,R1 == lvalue to read
+;
+; On exit:     R2,R3 == rvalue read from lvalue
+;
+; Use:         Loads the current value of the given lvalue.
+
+               IMPORT  ctrl_load
+
+; --- ctrl_compare ---
+;
+; On entry:    R0,R1 == thing to compare
+;              R2,R3 == thing to compare the other thing with
+;
+; On exit:     The flags indicate the result of the comparison
+;
+; Use:         Compares two things.  Note that R3 contains the dominant
+;              type. If it is comparing strings, the string in R0,R1
+;              will be removed from stracc.
+
+               IMPORT  ctrl_compare
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/divide b/StraySrc/Libraries/Sapphire/sail/sh/divide
new file mode 100644 (file)
index 0000000..dfbb4b9
--- /dev/null
@@ -0,0 +1,57 @@
+;
+; divide.sh
+;
+; Various routines of a division-related nature (MDW/TMA)
+;
+; © 1994 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  divide
+;  div_unsigned
+
+               [       :LNOT::DEF:divide__dfn
+               GBLL    divide__dfn
+
+; --- divide ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         A standard divide routine.  Fairly speedy, hopefully.
+;              The results are always such that
+;
+;                      |quotient| <= |(divisor/dividend)|,
+;
+;                      |remainder| < |divisor|
+;
+;              and
+;
+;                      quotient * divisor + remainder == dividend
+
+               IMPORT  divide
+
+; --- div_unsigned ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         As for divide, except that it considers its operands to be
+;              unsigned.
+
+               IMPORT  div_unsigned
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/errNum b/StraySrc/Libraries/Sapphire/sail/sh/errNum
new file mode 100644 (file)
index 0000000..e3e3bdf
--- /dev/null
@@ -0,0 +1,78 @@
+;
+; errNum.sh
+;
+; Define error numbers (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:errNum__dfn
+               GBLL    errNum__dfn
+
+               ^       0
+err_numNeeded  #       1
+err_strNeeded  #       1
+err_arrayBad   #       1
+err_expBracket #       1
+err_expHash    #       1
+err_expQuote   #       1
+err_expEq      #       1
+err_expComma   #       1
+err_badHex     #       1
+err_badBinary  #       1
+err_unknown    #       1
+err_divZero    #       1
+err_noMem      #       1
+err_syntax     #       1
+err_mistake    #       1
+err_strTooLong #       1
+err_eqInFor    #       1
+err_badForVar  #       1
+err_expTo      #       1
+err_zStep      #       1
+err_noFor      #       1
+err_noRepeat   #       1
+err_expEndwhile        #       1
+err_noWhile    #       1
+err_expEndif   #       1
+err_expOf      #       1
+err_afterCase  #       1
+err_expEndcase #       1
+err_expLabel   #       1
+err_noLabel    #       1
+err_badDim     #       1
+err_dimKet     #       1
+err_reDim      #       1
+err_numSubs    #       1
+err_subRange   #       1
+err_ukArray    #       1
+err_rgetInWatch        #       1
+err_rgetSInWatch       #       1
+err_lgetInWatch        #       1
+err_lgetSInWatch       #       1
+err_rinkeyInWatch      #       1
+err_rinkeySInWatch     #       1
+err_linkeyInWatch      #       1
+err_linkeySInWatch     #       1
+err_stringSArgs        #       1
+err_leftSArgs  #       1
+err_rightSArgs #       1
+err_midSArgs   #       1
+err_instrSArgs #       1
+err_badArgs    #       1
+err_noProc     #       1
+err_badCall    #       1
+err_notInSub   #       1
+err_notInProc  #       1
+err_notInFn    #       1
+err_WFTooMany  #       1
+err_sysTooManyI        #       1
+err_sysTooManyO        #       1
+err_outOfDATA  #       1
+err_realloc    #       1
+err_lazy       #       1
+err_erk                #       1
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/errTable b/StraySrc/Libraries/Sapphire/sail/sh/errTable
new file mode 100644 (file)
index 0000000..11c7649
--- /dev/null
@@ -0,0 +1,141 @@
+;
+; errTable.sh
+;
+; Define error messages table (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:errTable__dfn
+               GBLL    errTable__dfn
+
+errTable
+               DCD     err__msg0-errTable
+               DCD     err__msg1-errTable
+               DCD     err__msg2-errTable
+               DCD     err__msg3-errTable
+               DCD     err__msg4-errTable
+               DCD     err__msg5-errTable
+               DCD     err__msg6-errTable
+               DCD     err__msg7-errTable
+               DCD     err__msg8-errTable
+               DCD     err__msg9-errTable
+               DCD     err__msg10-errTable
+               DCD     err__msg11-errTable
+               DCD     err__msg12-errTable
+               DCD     err__msg13-errTable
+               DCD     err__msg14-errTable
+               DCD     err__msg15-errTable
+               DCD     err__msg16-errTable
+               DCD     err__msg17-errTable
+               DCD     err__msg18-errTable
+               DCD     err__msg19-errTable
+               DCD     err__msg20-errTable
+               DCD     err__msg21-errTable
+               DCD     err__msg22-errTable
+               DCD     err__msg23-errTable
+               DCD     err__msg24-errTable
+               DCD     err__msg25-errTable
+               DCD     err__msg26-errTable
+               DCD     err__msg27-errTable
+               DCD     err__msg28-errTable
+               DCD     err__msg29-errTable
+               DCD     err__msg30-errTable
+               DCD     err__msg31-errTable
+               DCD     err__msg32-errTable
+               DCD     err__msg33-errTable
+               DCD     err__msg34-errTable
+               DCD     err__msg35-errTable
+               DCD     err__msg36-errTable
+               DCD     err__msg37-errTable
+               DCD     err__msg38-errTable
+               DCD     err__msg39-errTable
+               DCD     err__msg40-errTable
+               DCD     err__msg41-errTable
+               DCD     err__msg42-errTable
+               DCD     err__msg43-errTable
+               DCD     err__msg44-errTable
+               DCD     err__msg45-errTable
+               DCD     err__msg46-errTable
+               DCD     err__msg47-errTable
+               DCD     err__msg48-errTable
+               DCD     err__msg49-errTable
+               DCD     err__msg50-errTable
+               DCD     err__msg51-errTable
+               DCD     err__msg52-errTable
+               DCD     err__msg53-errTable
+               DCD     err__msg54-errTable
+               DCD     err__msg55-errTable
+               DCD     err__msg56-errTable
+               DCD     err__msg57-errTable
+               DCD     err__msg58-errTable
+               DCD     err__msg59-errTable
+               DCD     err__msg60-errTable
+               DCD     err__msg61-errTable
+
+err__msg0      DCB     "Type mismatch: Number needed",0
+err__msg1      DCB     "Type mismatch: String needed",0
+err__msg2      DCB     "Whole array reference is invalid in this context",0
+err__msg3      DCB     "Missing )",0
+err__msg4      DCB     "Missing #",0
+err__msg5      DCB     "Missing """,0
+err__msg6      DCB     "Missing =",0
+err__msg7      DCB     "Missing ,",0
+err__msg8      DCB     "Bad hex",0
+err__msg9      DCB     "Bad binary",0
+err__msg10     DCB     "Unknown or missing variable",0
+err__msg11     DCB     "Division by zero",0
+err__msg12     DCB     "Out of memory",0
+err__msg13     DCB     "Syntax error",0
+err__msg14     DCB     "Mistake",0
+err__msg15     DCB     "String too long",0
+err__msg16     DCB     "Missing = in FOR",0
+err__msg17     DCB     "Bad FOR control variable",0
+err__msg18     DCB     "Missing TO",0
+err__msg19     DCB     "The step cannot be zero",0
+err__msg20     DCB     "Not in a FOR loop",0
+err__msg21     DCB     "Not in a REPEAT loop",0
+err__msg22     DCB     "Missing ENDWHILE",0
+err__msg23     DCB     "Not in a WHILE loop",0
+err__msg24     DCB     "Missing ENDIF",0
+err__msg25     DCB     "Missing OF",0
+err__msg26     DCB     "CASE..OF statement must be the last thing on a line",0
+err__msg27     DCB     "Missing ENDCASE",0
+err__msg28     DCB     "Missing label",0
+err__msg29     DCB     "Unknown label",0
+err__msg30     DCB     "Bad DIM statement",0
+err__msg31     DCB     "No end of dimension list )",0
+err__msg32     DCB     "Arrays cannot be redimensioned",0
+err__msg33     DCB     "Incorrect number of subscripts",0
+err__msg34     DCB     "Subscript out of range",0
+err__msg35     DCB     "Unknown array",0
+err__msg36     DCB     "Can't use RGET while in a WATCHFOR state",0
+err__msg37     DCB     "Can't use RGET$ while in a WATCHFOR state",0
+err__msg38     DCB     "Can't use LGET while in a WATCHFOR state",0
+err__msg39     DCB     "Can't use LGET$ while in a WATCHFOR state",0
+err__msg40     DCB     "Can't use RINKEY while in a WATCHFOR state",0
+err__msg41     DCB     "Can't use RINKEY$ while in a WATCHFOR state",0
+err__msg42     DCB     "Can't use LINKEY while in a WATCHFOR state",0
+err__msg43     DCB     "Can't use LINKEY$ while in a WATCHFOR state",0
+err__msg44     DCB     "Wrong number of arguments passed to STRING$",0
+err__msg45     DCB     "Wrong number of arguments passed to LEFT$",0
+err__msg46     DCB     "Wrong number of arguments passed to RIGHT$",0
+err__msg47     DCB     "Wrong number of arguments passed to MID$",0
+err__msg48     DCB     "Wrong number of arguments passed to INSTR",0
+err__msg49     DCB     "Arguments of function/procedure incorrect",0
+err__msg50     DCB     "No such function/procedure",0
+err__msg51     DCB     "Bad call of function/procedure",0
+err__msg52     DCB     "Not in a subroutine",0
+err__msg53     DCB     "Not in a procedure",0
+err__msg54     DCB     "Not in a function",0
+err__msg55     DCB     "Too many strings passed to WATCHFOR",0
+err__msg56     DCB     "Too many input parameters to SYS/SYSCALL",0
+err__msg57     DCB     "Too many output parameters to SYS/SYSCALL",0
+err__msg58     DCB     "Out of DATA",0
+err__msg59     DCB     "mem_realloc not implemented",0
+err__msg60     DCB     "Not yet implemented",0
+err__msg61     DCB     "The script interpreter has gone wrong",0
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/error b/StraySrc/Libraries/Sapphire/sail/sh/error
new file mode 100644 (file)
index 0000000..5c451ca
--- /dev/null
@@ -0,0 +1,45 @@
+;
+; error.sh
+;
+; Generation and handling of errors
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  error_report
+;  error_reportReal
+
+               [       :LNOT::DEF:error__dfn
+               GBLL    error__dfn
+
+; --- error_report ---
+;
+; On entry:    R0 == error number
+;
+; On exit:     doesn't -- reports error to Termite
+;
+; Use:         Reports an error, attaching the error number etc. and
+;              terminating the script.
+
+               IMPORT  error_report
+
+; --- error_reportReal ---
+;
+; On entry:    R0 == error block
+;
+; On exit:     doesn't -- reports error to Termite
+;
+; Use:         Reports an error, attaching the error number etc. and
+;              terminating the script.
+
+               IMPORT  error_reportReal
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/express b/StraySrc/Libraries/Sapphire/sail/sh/express
new file mode 100644 (file)
index 0000000..c08ea21
--- /dev/null
@@ -0,0 +1,84 @@
+;
+; express.sh
+;
+; Evaluation of BASIC expressions
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  express_pop
+;  express_popTwo
+;  express_push
+;  express_fnCont
+;  express_read
+
+               [       :LNOT::DEF:express__dfn
+               GBLL    express__dfn
+
+; --- express_pop ---
+;
+; On entry:    --
+;
+; On exit:     R0,R1 == value popped off
+;
+; Use:         Pops a value from the stack.
+
+               IMPORT  express_pop
+
+; --- express_popTwo ---
+;
+; On entry:    --
+;
+; On exit:     R0-R3 == two values popped from the stack
+;
+; Use:         Pops two values from the stack.
+
+               IMPORT  express_popTwo
+
+; --- express_push ---
+;
+; On entry:    R0,R1 == l/rvalue to push
+;
+; On exit:     --
+;
+; Use:         Pushes a value onto the expression stack.
+
+               IMPORT  express_push
+
+; --- express_fnCont ---
+;
+; On entry:    Involved
+;
+; On exit:     Similarly involved.
+;
+; Use:         We continue here after executing a function.
+
+               IMPORT  express_fnCont
+
+; --- express_read ---
+;
+; On entry:    R0 == 1 to read an lvalue, 2 to read ident, 0 otherwise
+;              R7, R8, R9 == lookahead token
+;              R10 == pointer into tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor pointer
+;
+; On exit:     R0,R1 == value of expression
+;              R7, R8, R9 == lookahead token
+;              R0, R1 == result of expression
+;              R10 == moved on to first char after expression
+;
+; Use:         Reads an expression for the current position in the
+;              tokenised file.
+
+               IMPORT  express_read
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/getToken b/StraySrc/Libraries/Sapphire/sail/sh/getToken
new file mode 100644 (file)
index 0000000..8ed647a
--- /dev/null
@@ -0,0 +1,39 @@
+;
+; getToken.sh
+;
+; The getting of the next token from the input file
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  getToken
+
+               [       :LNOT::DEF:getToken__dfn
+               GBLL    getToken__dfn
+
+; --- getToken ---
+;
+; On entry:    R8 == lookahead token
+;              R9 == current line number
+;              R10 == evaluation stack pointer
+;              R11 == pointer into the tokenised buffer
+;              R12 == anchor block pointer
+;
+; On exit:     R8 == new lookahead token
+;              R11 == moved on to the first character after the rvalue
+;              CC if the EOF char has not been reached,
+;              CS otherwise
+;
+; Use:         Tries to read an token from the current input line
+
+               IMPORT  getToken
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/interp b/StraySrc/Libraries/Sapphire/sail/sh/interp
new file mode 100644 (file)
index 0000000..e805d48
--- /dev/null
@@ -0,0 +1,65 @@
+;
+; interp.sh
+;
+; Main entry point for the interpreter
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  interp_start
+;  interp_exec
+;  interp_notImpl
+;  interp_next
+
+               [       :LNOT::DEF:interp__dfn
+               GBLL    interp__dfn
+
+; --- interp_start ---
+;
+; On entry:    R12 == pointer to our anchor block
+;
+; On exit:     R7-R9 == next token
+;
+; Use:         Prepares for execution, and even does some too.
+
+               IMPORT  interp_start
+
+; --- interp_exec ---
+;
+; On entry:    R7-R9 == token to deal with
+;              R11 == offset in file to execute from
+;              R12 == pointer to the anchor block
+;
+; On exit:     R0 == type code (eg. 0 == we are still executing
+;              R7-R9 == next token to deal with
+;
+; Use:         Executes some of the file.
+
+               IMPORT  interp_exec
+
+; --- interp_notImpl ---
+
+               IMPORT  interp_notImpl
+
+; --- interp_next ---
+;
+; On entry:    R7-R9 == token to deal with
+;              R11 == offset in file to execute from
+;              R12 == pointer to the anchor block
+;
+; On exit:     R0 == type code (eg. 0 == we are still executing
+;              R7-R9 == next token to deal with
+;
+; Use:         Checks the next instruction and acts approriately.
+
+               IMPORT  interp_next
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/mem b/StraySrc/Libraries/Sapphire/sail/sh/mem
new file mode 100644 (file)
index 0000000..8afab9c
--- /dev/null
@@ -0,0 +1,60 @@
+;
+; mem.sh
+;
+; Generic memory allocation for TermScript
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  mem_alloc
+;  mem_free
+;  mem_realloc
+
+               [       :LNOT::DEF:mem__dfn
+               GBLL    mem__dfn
+
+; --- mem_alloc ---
+;
+; On entry:    R0 == size of block to allocate
+;
+; On exit:     R0 == pointer to anchor for that block
+;              May return an error
+;
+; Use:         Tries to allocate a block of memory, and returns a pointer
+;              to the anchor for that block. All very unusual really,
+;              but we blame Wimp_Extension which allocates anchors for
+;              you in an utterley horrible way.
+
+
+               IMPORT  mem_alloc
+
+; --- mem_free ---
+;
+; On entry:    R0 == anchor of the block to free
+;
+; On exit:     --
+;
+; Use:         Frees the block.
+
+               IMPORT  mem_free
+
+; --- mem_realloc ---
+;
+; On entry:    R0 == pointer to block anchor
+;              R1 == new size requested
+;
+; On exit:     May return an error
+;
+; Use:         Resizes a block
+
+               IMPORT  mem_realloc
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/strBucket b/StraySrc/Libraries/Sapphire/sail/sh/strBucket
new file mode 100644 (file)
index 0000000..f78fcff
--- /dev/null
@@ -0,0 +1,55 @@
+;
+; strBucket.sh
+;
+; String bucket handling
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  strBucket_init
+;  strBucket_alloc
+;  strBucket_free
+
+               [       :LNOT::DEF:strBucket__dfn
+               GBLL    strBucket__dfn
+
+; --- strBucket_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the string bucket.
+
+               IMPORT  strBucket_init
+
+; --- strBucket_alloc ---
+;
+; On entry:    R0 == size of string to allocate
+;
+; On exit:     R0 == pointer to area to use (length at [R0,#-1])
+;              R1 == offset to that (for storing)
+;
+; Use:         Allocates space for a string of the given size.
+
+               IMPORT  strBucket_alloc
+
+; --- strBucket_free ---
+;
+; On entry:    R0 == offset of string to free
+;
+; On exit:     --
+;
+; Use:         Frees the memory the string took up.
+
+               IMPORT  strBucket_free
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/stracc b/StraySrc/Libraries/Sapphire/sail/sh/stracc
new file mode 100644 (file)
index 0000000..c2efadd
--- /dev/null
@@ -0,0 +1,56 @@
+;
+; stracc.sh
+;
+; String accululator management
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  stracc_ensure
+;  stracc_added
+;  stracc_free
+
+               [       :LNOT::DEF:stracc__dfn
+               GBLL    stracc__dfn
+
+; --- stracc_ensure ---
+;
+; On entry:    --
+;
+; On exit:     R0 == address of string to use
+;              R1 == offset of string from stracc, in upper 24 bits
+;
+; Use:         Ensures tha there are at least 256 bytes available in stracc,
+;              and then returns a pointer to them.
+
+               IMPORT  stracc_ensure
+
+; --- stracc_added ---
+;
+; On entry:    R0 == rvalue of string added
+;
+; On exit:     --
+;
+; Use:         Informs stracc that a new string has been added.
+
+               IMPORT  stracc_added
+
+; --- stracc_free ---
+;
+; On entry:    R0 == rvalue of string no longer needed
+;
+; On exit:     --
+;
+; Use:         Tells stracc that a string is no longer needed.
+
+               IMPORT  stracc_free
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/termScript b/StraySrc/Libraries/Sapphire/sail/sh/termScript
new file mode 100644 (file)
index 0000000..7308db7
--- /dev/null
@@ -0,0 +1,68 @@
+;
+; termScript.sh
+;
+; Coroutine handling for Termite Script
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  sail_wait
+;  sail_end
+;  sail_error
+
+               [       :LNOT::DEF:termScript__dfn
+               GBLL    termScript__dfn
+
+; --- sail_wait ---
+;
+; On entry:    --
+;
+; On exit:     R0, R1, R2 == event and arguments from Termite
+;
+; Use:         Waits for some multitasking and gets something from Termite.
+
+               IMPORT  sail_wait
+
+; --- sail_end ---
+;
+; On entry:    R0 == pointer to script to chain, 0 to just end, or -1 for
+;                    FINISH
+;
+; On exit:     Doesn't, hopefully
+;
+; Use:         Ends the script, optionally starting up another one.
+
+               IMPORT  sail_end
+
+; --- sail_error ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     Doesn't, probably
+;
+; Use:         Returns an error to Termite.
+
+               IMPORT  sail_error
+
+               ; --- Event codes returned by sail_wait ---
+
+               ^       0
+
+tscEvent_poll  #       1                       ;Nothing interesting happened
+
+tscEvent_serial        #       1                       ;Serial input received
+                                               ;R1 == address of block
+                                               ;R2 == size of block
+
+tscEvent_key   #       1                       ;User pressed a key
+                                               ;R1 == key number (from WIMP)
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/termite b/StraySrc/Libraries/Sapphire/sail/sh/termite
new file mode 100644 (file)
index 0000000..4779ffc
--- /dev/null
@@ -0,0 +1,219 @@
+;
+; termite.sh
+;
+; Implementation of Termite specific instructions
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  termite_beep
+;  termite_break
+;  termite_call
+;  termite_chain
+;  termite_close
+;  termite_cls
+;  termite_download
+;  termite_error
+;  termite_exec
+;  termite_finish
+;  termite_hangup
+;  termite_lclear
+;  termite_lecho
+;  termite_linput
+;  termite_lnewline
+;  termite_log
+;  termite_newsession
+;  termite_oscli
+;  termite_rclear
+;  termite_recho
+;  termite_report
+;  termite_rinput
+;  termite_rnewline
+;  termite_spool
+;  termite_syscall
+;  termite_upload
+;  termite_wait
+;  termite_watchfor
+;  termite_remoteInput
+;  termite_copyString
+;  termite_doLEcho
+;  termite_doREcho
+
+               [       :LNOT::DEF:termite__dfn
+               GBLL    termite__dfn
+
+; --- termite_beep ---
+
+               IMPORT  termite_beep
+
+; --- termite_break ---
+
+               IMPORT  termite_break
+
+; --- termite_call ---
+
+               IMPORT  termite_call
+
+; --- termite_chain ---
+
+               IMPORT  termite_chain
+
+; --- termite_close ---
+
+               IMPORT  termite_close
+
+; --- termite_cls ---
+
+               IMPORT  termite_cls
+
+; --- termite_download ---
+
+               IMPORT  termite_download
+
+; --- termite_error ---
+
+               IMPORT  termite_error
+
+; --- termite_exec ---
+
+               IMPORT  termite_exec
+
+; --- termite_finish ---
+
+               IMPORT  termite_finish
+
+; --- termite_hangup ---
+
+               IMPORT  termite_hangup
+
+; --- termite_lclear ---
+
+               IMPORT  termite_lclear
+
+; --- termite_lecho ---
+
+               IMPORT  termite_lecho
+
+; -- termite_linput ---
+
+               IMPORT  termite_linput
+
+; --- termite_lnewline ---
+
+               IMPORT  termite_lnewline
+
+; --- termite_log ---
+
+               IMPORT  termite_log
+
+; --- termite_newsession ---
+
+               IMPORT  termite_newsession
+
+; --- termite_oscli ---
+
+               IMPORT  termite_oscli
+
+; --- termite_rclear ---
+
+               IMPORT  termite_rclear
+
+; --- termite_recho ---
+
+               IMPORT  termite_recho
+
+; --- termite_report ---
+
+               IMPORT  termite_report
+
+; --- termite_rinput ---
+
+               IMPORT  termite_rinput
+
+; --- termite_rnewline ---
+
+               IMPORT  termite_rnewline
+
+; --- termite_spool ---
+
+               IMPORT  termite_spool
+
+; --- termite_syscall ---
+
+               IMPORT  termite_syscall
+
+; --- termite_upload ---
+
+               IMPORT  termite_upload
+
+; --- termite_wait ---
+
+               IMPORT  termite_wait
+
+; --- termite_watchfor ---
+
+               IMPORT  termite_watchfor
+
+; --- termite_remoteInput ---
+;
+; On entry:    R0 == handle of script
+;              R2 == buffer containing bytes read
+;              R3 == number of bytes in buffer
+;              R11 == upcall block
+;
+; On exit:     R2 == new buffer containing bytes to put into ring buffer
+;              R3 == number of bytes in this buffer
+;
+; Use:         If we are not doing a watchfor, then this call will return
+;              immediately, resulting in all the buffer being sent
+;              to the ring buffer.
+;              If we are in a watchfor, then all data received, up until
+;              a match, is echoed immediatley, and not sent to the buffer.
+
+               IMPORT  termite_remoteInput
+
+; --- termite_copyString ---
+;
+; On entry:    R0 == buffer to copy string to
+;              R1 == point to the string
+;              R2 == length of string to copy
+;
+; On exit:     --
+;
+; Use:         Copies the string into the buffer.
+
+               IMPORT  termite_copyString
+
+; --- termite_doLEcho ---
+;
+; On entry:    R2 == pointer to the buffer
+;              R3 == number of bytes to send
+;
+; On exit:     --
+;
+; Use:         Echos the buffer to local and remote according to the
+;              current flags, assuming the buffer came from the local input
+
+               IMPORT  termite_doLEcho
+
+; --- termite_doREcho ---
+;
+; On entry:    R2 == pointer to the buffer
+;              R3 == number of bytes to send
+;
+; On exit:     --
+;
+; Use:         Echos the buffer to local and remote according to the
+;              current flags, assuming the buffer came from remote input
+
+               IMPORT  termite_doREcho
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/tokClasses b/StraySrc/Libraries/Sapphire/sail/sh/tokClasses
new file mode 100644 (file)
index 0000000..815ce14
--- /dev/null
@@ -0,0 +1,272 @@
+;
+; tokClasses.sh
+;
+; Token class and index tables (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:tokClasses__dfn
+               GBLL    tokClasses__dfn
+
+tokClasses
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     7,3
+               DCB     13,0
+               DCB     0,0
+               DCB     13,1
+               DCB     0,0
+               DCB     7,2
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     12,1
+               DCB     12,0
+               DCB     12,4
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     15,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     1,0
+               DCB     2,0
+               DCB     2,1
+               DCB     3,0
+               DCB     4,0
+               DCB     5,0
+               DCB     3,1
+               DCB     3,2
+               DCB     6,0
+               DCB     3,3
+               DCB     3,4
+               DCB     2,2
+               DCB     3,5
+               DCB     3,6
+               DCB     3,7
+               DCB     3,8
+               DCB     3,9
+               DCB     7,0
+               DCB     3,10
+               DCB     3,11
+               DCB     3,12
+               DCB     3,13
+               DCB     3,14
+               DCB     3,15
+               DCB     3,16
+               DCB     3,17
+               DCB     2,3
+               DCB     3,18
+               DCB     6,1
+               DCB     4,1
+               DCB     8,0
+               DCB     3,19
+               DCB     4,2
+               DCB     3,20
+               DCB     6,2
+               DCB     3,21
+               DCB     6,3
+               DCB     9,0
+               DCB     3,22
+               DCB     4,3
+               DCB     3,23
+               DCB     3,24
+               DCB     3,25
+               DCB     10,0
+               DCB     3,26
+               DCB     3,27
+               DCB     10,1
+               DCB     2,4
+               DCB     3,28
+               DCB     2,5
+               DCB     2,6
+               DCB     3,29
+               DCB     6,4
+               DCB     6,5
+               DCB     3,30
+               DCB     6,6
+               DCB     3,31
+               DCB     10,2
+               DCB     7,1
+               DCB     3,32
+               DCB     3,33
+               DCB     2,7
+               DCB     11,0
+               DCB     5,1
+               DCB     11,1
+               DCB     8,1
+               DCB     2,8
+               DCB     2,9
+               DCB     2,10
+               DCB     3,34
+               DCB     3,35
+               DCB     4,4
+               DCB     3,36
+               DCB     3,37
+               DCB     3,38
+               DCB     3,39
+               DCB     3,40
+               DCB     3,41
+               DCB     11,2
+               DCB     5,2
+               DCB     3,42
+               DCB     3,43
+               DCB     10,3
+               DCB     2,11
+               DCB     2,12
+               DCB     3,44
+               DCB     9,1
+               DCB     6,7
+               DCB     6,8
+               DCB     6,9
+               DCB     11,3
+               DCB     2,13
+               DCB     3,45
+               DCB     2,14
+               DCB     10,4
+               DCB     3,46
+               DCB     3,47
+               DCB     3,48
+               DCB     11,4
+               DCB     6,10
+               DCB     6,11
+               DCB     11,5
+               DCB     6,12
+               DCB     3,49
+               DCB     3,50
+               DCB     2,15
+               DCB     3,51
+               DCB     6,13
+               DCB     3,52
+               DCB     3,53
+               DCB     3,54
+               DCB     12,2
+               DCB     12,3
+               DCB     12,5
+               DCB     12,6
+               DCB     12,7
+               DCB     12,8
+               DCB     11,6
+               DCB     11,7
+               DCB     14,0
+               DCB     14,1
+               DCB     14,2
+               DCB     14,3
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+               DCB     0,0
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/tokNames b/StraySrc/Libraries/Sapphire/sail/sh/tokNames
new file mode 100644 (file)
index 0000000..3f10d76
--- /dev/null
@@ -0,0 +1,262 @@
+;
+; tokNames.sh
+;
+; Number-to-name table for tokens (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:tokNames__dfn
+               GBLL    tokNames__dfn
+
+tokNames       DCD     tn__0
+               DCD     tn__1
+               DCD     tn__2
+               DCD     tn__3
+               DCD     tn__4
+               DCD     tn__5
+               DCD     tn__6
+               DCD     tn__7
+               DCD     tn__8
+               DCD     tn__9
+               DCD     tn__10
+               DCD     tn__11
+               DCD     tn__12
+               DCD     tn__13
+               DCD     tn__14
+               DCD     tn__15
+               DCD     tn__16
+               DCD     tn__17
+               DCD     tn__18
+               DCD     tn__19
+               DCD     tn__20
+               DCD     tn__21
+               DCD     tn__22
+               DCD     tn__23
+               DCD     tn__24
+               DCD     tn__25
+               DCD     tn__26
+               DCD     tn__27
+               DCD     tn__28
+               DCD     tn__29
+               DCD     tn__30
+               DCD     tn__31
+               DCD     tn__32
+               DCD     tn__33
+               DCD     tn__34
+               DCD     tn__35
+               DCD     tn__36
+               DCD     tn__37
+               DCD     tn__38
+               DCD     tn__39
+               DCD     tn__40
+               DCD     tn__41
+               DCD     tn__42
+               DCD     tn__43
+               DCD     tn__44
+               DCD     tn__45
+               DCD     tn__46
+               DCD     tn__47
+               DCD     tn__48
+               DCD     tn__49
+               DCD     tn__50
+               DCD     tn__51
+               DCD     tn__52
+               DCD     tn__53
+               DCD     tn__54
+               DCD     tn__55
+               DCD     tn__56
+               DCD     tn__57
+               DCD     tn__58
+               DCD     tn__59
+               DCD     tn__60
+               DCD     tn__61
+               DCD     tn__62
+               DCD     tn__63
+               DCD     tn__64
+               DCD     tn__65
+               DCD     tn__66
+               DCD     tn__67
+               DCD     tn__68
+               DCD     tn__69
+               DCD     tn__70
+               DCD     tn__71
+               DCD     tn__72
+               DCD     tn__73
+               DCD     tn__74
+               DCD     tn__75
+               DCD     tn__76
+               DCD     tn__77
+               DCD     tn__78
+               DCD     tn__79
+               DCD     tn__80
+               DCD     tn__81
+               DCD     tn__82
+               DCD     tn__83
+               DCD     tn__84
+               DCD     tn__85
+               DCD     tn__86
+               DCD     tn__87
+               DCD     tn__88
+               DCD     tn__89
+               DCD     tn__90
+               DCD     tn__91
+               DCD     tn__92
+               DCD     tn__93
+               DCD     tn__94
+               DCD     tn__95
+               DCD     tn__96
+               DCD     tn__97
+               DCD     tn__98
+               DCD     tn__99
+               DCD     tn__100
+               DCD     tn__101
+               DCD     tn__102
+               DCD     tn__103
+               DCD     tn__104
+               DCD     tn__105
+               DCD     tn__106
+               DCD     tn__107
+               DCD     tn__108
+               DCD     tn__109
+               DCD     tn__110
+               DCD     tn__111
+               DCD     tn__112
+               DCD     tn__113
+               DCD     tn__114
+               DCD     tn__115
+               DCD     tn__116
+               DCD     tn__117
+               DCD     tn__118
+               DCD     tn__119
+               DCD     tn__120
+               DCD     tn__121
+               DCD     tn__122
+
+tn__0          DCB     "AND",0
+tn__1          DCB     "ABS",0
+tn__2          DCB     "ASC",0
+tn__3          DCB     "BEEP",0
+tn__4          DCB     "BGET",0
+tn__5          DCB     "BOTH",0
+tn__6          DCB     "BPUT",0
+tn__7          DCB     "BREAK",0
+tn__8          DCB     "CARRIER",0
+tn__9          DCB     "CASE",0
+tn__10         DCB     "CHAIN",0
+tn__11         DCB     "CHR$",0
+tn__12         DCB     "CLOSE",0
+tn__13         DCB     "CLS",0
+tn__14         DCB     "CALL",0
+tn__15         DCB     "DATA",0
+tn__16         DCB     "DEF",0
+tn__17         DCB     "DIV",0
+tn__18         DCB     "DIM",0
+tn__19         DCB     "DOWNLOAD",0
+tn__20         DCB     "END",0
+tn__21         DCB     "ENDPROC",0
+tn__22         DCB     "ENDWHILE",0
+tn__23         DCB     "ENDIF",0
+tn__24         DCB     "ENDCASE",0
+tn__25         DCB     "ELSE",0
+tn__26         DCB     "EVAL",0
+tn__27         DCB     "ERROR",0
+tn__28         DCB     "ERROR$",0
+tn__29         DCB     "EOF",0
+tn__30         DCB     "EOR",0
+tn__31         DCB     "EXEC",0
+tn__32         DCB     "EXT",0
+tn__33         DCB     "FOR",0
+tn__34         DCB     "FALSE",0
+tn__35         DCB     "FINISH",0
+tn__36         DCB     "FINISHED",0
+tn__37         DCB     "FN",0
+tn__38         DCB     "GOTO",0
+tn__39         DCB     "GET$",0
+tn__40         DCB     "GOSUB",0
+tn__41         DCB     "HANGUP",0
+tn__42         DCB     "IF",0
+tn__43         DCB     "INSTR(",0
+tn__44         DCB     "LCLEAR",0
+tn__45         DCB     "LECHO",0
+tn__46         DCB     "LEFT$(",0
+tn__47         DCB     "LEN",0
+tn__48         DCB     "LET",0
+tn__49         DCB     "LINKEY",0
+tn__50         DCB     "LINKEY$",0
+tn__51         DCB     "LINPUT",0
+tn__52         DCB     "LGET",0
+tn__53         DCB     "LGET$",0
+tn__54         DCB     "LOCAL",0
+tn__55         DCB     "LNEWLINE$",0
+tn__56         DCB     "LOG",0
+tn__57         DCB     "MID$(",0
+tn__58         DCB     "MOD",0
+tn__59         DCB     "NEWSESSION",0
+tn__60         DCB     "NEXT",0
+tn__61         DCB     "NOT",0
+tn__62         DCB     "OF",0
+tn__63         DCB     "OFF",0
+tn__64         DCB     "ON",0
+tn__65         DCB     "OR",0
+tn__66         DCB     "OPENIN",0
+tn__67         DCB     "OPENOUT",0
+tn__68         DCB     "OPENUP",0
+tn__69         DCB     "OSCLI",0
+tn__70         DCB     "OTHERWISE",0
+tn__71         DCB     "PTR",0
+tn__72         DCB     "PROC",0
+tn__73         DCB     "RCLEAR",0
+tn__74         DCB     "RETURN",0
+tn__75         DCB     "REPEAT",0
+tn__76         DCB     "READ",0
+tn__77         DCB     "RECHO",0
+tn__78         DCB     "REM",0
+tn__79         DCB     "REMOTE",0
+tn__80         DCB     "REPORT",0
+tn__81         DCB     "RESTORE",0
+tn__82         DCB     "RIGHT$(",0
+tn__83         DCB     "RINKEY",0
+tn__84         DCB     "RINKEY$",0
+tn__85         DCB     "RINPUT",0
+tn__86         DCB     "RND",0
+tn__87         DCB     "RGET",0
+tn__88         DCB     "RGET$",0
+tn__89         DCB     "RNEWLINE$",0
+tn__90         DCB     "STEP",0
+tn__91         DCB     "SGN",0
+tn__92         DCB     "SPOOL",0
+tn__93         DCB     "STR$",0
+tn__94         DCB     "STRING$(",0
+tn__95         DCB     "SWAP",0
+tn__96         DCB     "SYS",0
+tn__97         DCB     "SYSCALL",0
+tn__98         DCB     "THEN",0
+tn__99         DCB     "TIME",0
+tn__100                DCB     "TIME$",0
+tn__101                DCB     "TO",0
+tn__102                DCB     "TRUE",0
+tn__103                DCB     "UNTIL",0
+tn__104                DCB     "UPLOAD",0
+tn__105                DCB     "VAL",0
+tn__106                DCB     "WAIT",0
+tn__107                DCB     "WATCH",0
+tn__108                DCB     "WATCHFOR",0
+tn__109                DCB     "WHILE",0
+tn__110                DCB     "WHEN",0
+tn__111                DCB     "<=",0
+tn__112                DCB     "<>",0
+tn__113                DCB     ">=",0
+tn__114                DCB     "<<",0
+tn__115                DCB     ">>",0
+tn__116                DCB     ">>>",0
+tn__117                DCB     "/*",0
+tn__118                DCB     "//",0
+tn__119                DCB     "+=",0
+tn__120                DCB     "-=",0
+tn__121                DCB     "*=",0
+tn__122                DCB     "/=",0
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/tokTable b/StraySrc/Libraries/Sapphire/sail/sh/tokTable
new file mode 100644 (file)
index 0000000..e574645
--- /dev/null
@@ -0,0 +1,943 @@
+;
+; tokTable.sh
+;
+; State table for lexical analysis (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:tokTable__dfn
+               GBLL    tokTable__dfn
+
+               MACRO
+$label         TOKTBL  $char,$next,$token
+$label
+               [       "$next"="0"
+               DCW     0
+               |
+               DCW     $next-kt0
+               ]
+               [       "$token"<>""
+               DCB     $token
+               |
+               DCB     0
+               ]
+               DCB     $char
+               MEND
+
+tokTable
+kt0            TOKTBL  'A',kt1
+               TOKTBL  'B',kt2
+               TOKTBL  'C',kt3
+               TOKTBL  'D',kt4
+               TOKTBL  'E',kt5
+               TOKTBL  'F',kt6
+               TOKTBL  'G',kt7
+               TOKTBL  'H',kt8
+               TOKTBL  'I',kt9
+               TOKTBL  'L',kt10
+               TOKTBL  'M',kt11
+               TOKTBL  'N',kt12
+               TOKTBL  'O',kt13
+               TOKTBL  'P',kt14
+               TOKTBL  'R',kt15
+               TOKTBL  'S',kt16
+               TOKTBL  'T',kt17
+               TOKTBL  'U',kt18
+               TOKTBL  'V',kt19
+               TOKTBL  'W',kt20
+               TOKTBL  '=',0,'='
+               TOKTBL  '<',kt21,'<'
+               TOKTBL  '>',kt22,'>'
+               TOKTBL  '/',kt23,'/'
+               TOKTBL  '+',kt24,'+'
+               TOKTBL  '-',kt25,'-'
+               TOKTBL  '*',kt26,'*'
+               TOKTBL  '^',0,'^'
+               TOKTBL  0,0
+
+kt26           TOKTBL  '=',0,tok_TE
+               TOKTBL  0,0
+
+kt25           TOKTBL  '=',0,tok_ME
+               TOKTBL  0,0
+
+kt24           TOKTBL  '=',0,tok_PE
+               TOKTBL  0,0
+
+kt23           TOKTBL  '*',0,tok_DT
+               TOKTBL  '/',0,tok_DD
+               TOKTBL  '=',0,tok_DE
+               TOKTBL  0,0
+
+kt22           TOKTBL  '=',0,tok_GE
+               TOKTBL  '>',kt27,tok_GG
+               TOKTBL  0,0
+
+kt27           TOKTBL  '>',0,tok_GGG
+               TOKTBL  0,0
+
+kt21           TOKTBL  '=',0,tok_LE
+               TOKTBL  '>',0,tok_LG
+               TOKTBL  '<',0,tok_LL
+               TOKTBL  0,0
+
+kt20           TOKTBL  'A',kt28
+               TOKTBL  'H',kt29
+               TOKTBL  0,0
+
+kt29           TOKTBL  'I',kt30
+               TOKTBL  'E',kt31
+               TOKTBL  0,0
+
+kt31           TOKTBL  'N',0,tok_when
+               TOKTBL  0,0
+
+kt30           TOKTBL  'L',kt32
+               TOKTBL  0,0
+
+kt32           TOKTBL  'E',0,tok_while
+               TOKTBL  0,0
+
+kt28           TOKTBL  'I',kt33
+               TOKTBL  'T',kt34
+               TOKTBL  0,0
+
+kt34           TOKTBL  'C',kt35
+               TOKTBL  0,0
+
+kt35           TOKTBL  'H',kt36,tok_watch
+               TOKTBL  0,0
+
+kt36           TOKTBL  'F',kt37
+               TOKTBL  0,0
+
+kt37           TOKTBL  'O',kt38
+               TOKTBL  0,0
+
+kt38           TOKTBL  'R',0,tok_watchfor
+               TOKTBL  0,0
+
+kt33           TOKTBL  'T',0,tok_wait
+               TOKTBL  0,0
+
+kt19           TOKTBL  'A',kt39
+               TOKTBL  0,0
+
+kt39           TOKTBL  'L',0,tok_val
+               TOKTBL  0,0
+
+kt18           TOKTBL  'N',kt40
+               TOKTBL  'P',kt41
+               TOKTBL  0,0
+
+kt41           TOKTBL  'L',kt42
+               TOKTBL  0,0
+
+kt42           TOKTBL  'O',kt43
+               TOKTBL  0,0
+
+kt43           TOKTBL  'A',kt44
+               TOKTBL  0,0
+
+kt44           TOKTBL  'D',0,tok_upload
+               TOKTBL  0,0
+
+kt40           TOKTBL  'T',kt45
+               TOKTBL  0,0
+
+kt45           TOKTBL  'I',kt46
+               TOKTBL  0,0
+
+kt46           TOKTBL  'L',0,tok_until
+               TOKTBL  0,0
+
+kt17           TOKTBL  'H',kt47
+               TOKTBL  'I',kt48
+               TOKTBL  'O',0,tok_to
+               TOKTBL  'R',kt49
+               TOKTBL  0,0
+
+kt49           TOKTBL  'U',kt50
+               TOKTBL  0,0
+
+kt50           TOKTBL  'E',0,tok_true
+               TOKTBL  0,0
+
+kt48           TOKTBL  'M',kt51
+               TOKTBL  0,0
+
+kt51           TOKTBL  'E',kt52,tok_time
+               TOKTBL  0,0
+
+kt52           TOKTBL  '$',0,tok_timeS
+               TOKTBL  0,0
+
+kt47           TOKTBL  'E',kt53
+               TOKTBL  0,0
+
+kt53           TOKTBL  'N',0,tok_then
+               TOKTBL  0,0
+
+kt16           TOKTBL  'T',kt54
+               TOKTBL  'G',kt55
+               TOKTBL  'P',kt56
+               TOKTBL  'W',kt57
+               TOKTBL  'Y',kt58
+               TOKTBL  0,0
+
+kt58           TOKTBL  'S',kt59,tok_sys
+               TOKTBL  0,0
+
+kt59           TOKTBL  'C',kt60
+               TOKTBL  0,0
+
+kt60           TOKTBL  'A',kt61
+               TOKTBL  0,0
+
+kt61           TOKTBL  'L',kt62
+               TOKTBL  0,0
+
+kt62           TOKTBL  'L',0,tok_syscall
+               TOKTBL  0,0
+
+kt57           TOKTBL  'A',kt63
+               TOKTBL  0,0
+
+kt63           TOKTBL  'P',0,tok_swap
+               TOKTBL  0,0
+
+kt56           TOKTBL  'O',kt64
+               TOKTBL  0,0
+
+kt64           TOKTBL  'O',kt65
+               TOKTBL  0,0
+
+kt65           TOKTBL  'L',0,tok_spool
+               TOKTBL  0,0
+
+kt55           TOKTBL  'N',0,tok_sgn
+               TOKTBL  0,0
+
+kt54           TOKTBL  'E',kt66
+               TOKTBL  'R',kt67
+               TOKTBL  0,0
+
+kt67           TOKTBL  '$',0,tok_strS
+               TOKTBL  'I',kt68
+               TOKTBL  0,0
+
+kt68           TOKTBL  'N',kt69
+               TOKTBL  0,0
+
+kt69           TOKTBL  'G',kt70
+               TOKTBL  0,0
+
+kt70           TOKTBL  '$',kt71
+               TOKTBL  0,0
+
+kt71           TOKTBL  '(',0,tok_stringS
+               TOKTBL  0,0
+
+kt66           TOKTBL  'P',0,tok_step
+               TOKTBL  0,0
+
+kt15           TOKTBL  'C',kt72
+               TOKTBL  'E',kt73
+               TOKTBL  'I',kt74
+               TOKTBL  'N',kt75
+               TOKTBL  'G',kt76
+               TOKTBL  0,0
+
+kt76           TOKTBL  'E',kt77
+               TOKTBL  0,0
+
+kt77           TOKTBL  'T',kt78,tok_rget
+               TOKTBL  0,0
+
+kt78           TOKTBL  '$',0,tok_rgetS
+               TOKTBL  0,0
+
+kt75           TOKTBL  'D',0,tok_rnd
+               TOKTBL  'E',kt79
+               TOKTBL  0,0
+
+kt79           TOKTBL  'W',kt80
+               TOKTBL  0,0
+
+kt80           TOKTBL  'L',kt81
+               TOKTBL  0,0
+
+kt81           TOKTBL  'I',kt82
+               TOKTBL  0,0
+
+kt82           TOKTBL  'N',kt83
+               TOKTBL  0,0
+
+kt83           TOKTBL  'E',kt84
+               TOKTBL  0,0
+
+kt84           TOKTBL  '$',0,tok_rnewlineS
+               TOKTBL  0,0
+
+kt74           TOKTBL  'G',kt85
+               TOKTBL  'N',kt86
+               TOKTBL  0,0
+
+kt86           TOKTBL  'K',kt87
+               TOKTBL  'P',kt88
+               TOKTBL  0,0
+
+kt88           TOKTBL  'U',kt89
+               TOKTBL  0,0
+
+kt89           TOKTBL  'T',0,tok_rinput
+               TOKTBL  0,0
+
+kt87           TOKTBL  'E',kt90
+               TOKTBL  0,0
+
+kt90           TOKTBL  'Y',kt91,tok_rinkey
+               TOKTBL  0,0
+
+kt91           TOKTBL  '$',0,tok_rinkeyS
+               TOKTBL  0,0
+
+kt85           TOKTBL  'H',kt92
+               TOKTBL  0,0
+
+kt92           TOKTBL  'T',kt93
+               TOKTBL  0,0
+
+kt93           TOKTBL  '$',kt94
+               TOKTBL  0,0
+
+kt94           TOKTBL  '(',0,tok_rightS
+               TOKTBL  0,0
+
+kt73           TOKTBL  'T',kt95
+               TOKTBL  'P',kt96
+               TOKTBL  'A',kt97
+               TOKTBL  'C',kt98
+               TOKTBL  'M',kt99,tok_rem
+               TOKTBL  'S',kt100
+               TOKTBL  0,0
+
+kt100          TOKTBL  'T',kt101
+               TOKTBL  0,0
+
+kt101          TOKTBL  'O',kt102
+               TOKTBL  0,0
+
+kt102          TOKTBL  'R',kt103
+               TOKTBL  0,0
+
+kt103          TOKTBL  'E',0,tok_restore
+               TOKTBL  0,0
+
+kt99           TOKTBL  'O',kt104
+               TOKTBL  0,0
+
+kt104          TOKTBL  'T',kt105
+               TOKTBL  0,0
+
+kt105          TOKTBL  'E',0,tok_remote
+               TOKTBL  0,0
+
+kt98           TOKTBL  'H',kt106
+               TOKTBL  0,0
+
+kt106          TOKTBL  'O',0,tok_recho
+               TOKTBL  0,0
+
+kt97           TOKTBL  'D',0,tok_read
+               TOKTBL  0,0
+
+kt96           TOKTBL  'E',kt107
+               TOKTBL  'O',kt108
+               TOKTBL  0,0
+
+kt108          TOKTBL  'R',kt109
+               TOKTBL  0,0
+
+kt109          TOKTBL  'T',0,tok_report
+               TOKTBL  0,0
+
+kt107          TOKTBL  'A',kt110
+               TOKTBL  0,0
+
+kt110          TOKTBL  'T',0,tok_repeat
+               TOKTBL  0,0
+
+kt95           TOKTBL  'U',kt111
+               TOKTBL  0,0
+
+kt111          TOKTBL  'R',kt112
+               TOKTBL  0,0
+
+kt112          TOKTBL  'N',0,tok_return
+               TOKTBL  0,0
+
+kt72           TOKTBL  'L',kt113
+               TOKTBL  0,0
+
+kt113          TOKTBL  'E',kt114
+               TOKTBL  0,0
+
+kt114          TOKTBL  'A',kt115
+               TOKTBL  0,0
+
+kt115          TOKTBL  'R',0,tok_rclear
+               TOKTBL  0,0
+
+kt14           TOKTBL  'T',kt116
+               TOKTBL  'R',kt117
+               TOKTBL  0,0
+
+kt117          TOKTBL  'O',kt118
+               TOKTBL  0,0
+
+kt118          TOKTBL  'C',0,tok_proc
+               TOKTBL  0,0
+
+kt116          TOKTBL  'R',0,tok_ptr
+               TOKTBL  0,0
+
+kt13           TOKTBL  'F',kt119,tok_of
+               TOKTBL  'N',0,tok_on
+               TOKTBL  'R',0,tok_or
+               TOKTBL  'P',kt120
+               TOKTBL  'S',kt121
+               TOKTBL  'T',kt122
+               TOKTBL  0,0
+
+kt122          TOKTBL  'H',kt123
+               TOKTBL  0,0
+
+kt123          TOKTBL  'E',kt124
+               TOKTBL  0,0
+
+kt124          TOKTBL  'R',kt125
+               TOKTBL  0,0
+
+kt125          TOKTBL  'W',kt126
+               TOKTBL  0,0
+
+kt126          TOKTBL  'I',kt127
+               TOKTBL  0,0
+
+kt127          TOKTBL  'S',kt128
+               TOKTBL  0,0
+
+kt128          TOKTBL  'E',0,tok_otherwise
+               TOKTBL  0,0
+
+kt121          TOKTBL  'C',kt129
+               TOKTBL  0,0
+
+kt129          TOKTBL  'L',kt130
+               TOKTBL  0,0
+
+kt130          TOKTBL  'I',0,tok_oscli
+               TOKTBL  0,0
+
+kt120          TOKTBL  'E',kt131
+               TOKTBL  0,0
+
+kt131          TOKTBL  'N',kt132
+               TOKTBL  0,0
+
+kt132          TOKTBL  'I',kt133
+               TOKTBL  'O',kt134
+               TOKTBL  'U',kt135
+               TOKTBL  0,0
+
+kt135          TOKTBL  'P',0,tok_openup
+               TOKTBL  0,0
+
+kt134          TOKTBL  'U',kt136
+               TOKTBL  0,0
+
+kt136          TOKTBL  'T',0,tok_openout
+               TOKTBL  0,0
+
+kt133          TOKTBL  'N',0,tok_openin
+               TOKTBL  0,0
+
+kt119          TOKTBL  'F',0,tok_off
+               TOKTBL  0,0
+
+kt12           TOKTBL  'E',kt137
+               TOKTBL  'O',kt138
+               TOKTBL  0,0
+
+kt138          TOKTBL  'T',0,tok_not
+               TOKTBL  0,0
+
+kt137          TOKTBL  'W',kt139
+               TOKTBL  'X',kt140
+               TOKTBL  0,0
+
+kt140          TOKTBL  'T',0,tok_next
+               TOKTBL  0,0
+
+kt139          TOKTBL  'S',kt141
+               TOKTBL  0,0
+
+kt141          TOKTBL  'E',kt142
+               TOKTBL  0,0
+
+kt142          TOKTBL  'S',kt143
+               TOKTBL  0,0
+
+kt143          TOKTBL  'S',kt144
+               TOKTBL  0,0
+
+kt144          TOKTBL  'I',kt145
+               TOKTBL  0,0
+
+kt145          TOKTBL  'O',kt146
+               TOKTBL  0,0
+
+kt146          TOKTBL  'N',0,tok_newsession
+               TOKTBL  0,0
+
+kt11           TOKTBL  'I',kt147
+               TOKTBL  'O',kt148
+               TOKTBL  0,0
+
+kt148          TOKTBL  'D',0,tok_mod
+               TOKTBL  0,0
+
+kt147          TOKTBL  'D',kt149
+               TOKTBL  0,0
+
+kt149          TOKTBL  '$',kt150
+               TOKTBL  0,0
+
+kt150          TOKTBL  '(',0,tok_midS
+               TOKTBL  0,0
+
+kt10           TOKTBL  'C',kt151
+               TOKTBL  'E',kt152
+               TOKTBL  'I',kt153
+               TOKTBL  'G',kt154
+               TOKTBL  'O',kt155
+               TOKTBL  'N',kt156
+               TOKTBL  0,0
+
+kt156          TOKTBL  'E',kt157
+               TOKTBL  0,0
+
+kt157          TOKTBL  'W',kt158
+               TOKTBL  0,0
+
+kt158          TOKTBL  'L',kt159
+               TOKTBL  0,0
+
+kt159          TOKTBL  'I',kt160
+               TOKTBL  0,0
+
+kt160          TOKTBL  'N',kt161
+               TOKTBL  0,0
+
+kt161          TOKTBL  'E',kt162
+               TOKTBL  0,0
+
+kt162          TOKTBL  '$',0,tok_lnewlineS
+               TOKTBL  0,0
+
+kt155          TOKTBL  'C',kt163
+               TOKTBL  'G',0,tok_log
+               TOKTBL  0,0
+
+kt163          TOKTBL  'A',kt164
+               TOKTBL  0,0
+
+kt164          TOKTBL  'L',0,tok_local
+               TOKTBL  0,0
+
+kt154          TOKTBL  'E',kt165
+               TOKTBL  0,0
+
+kt165          TOKTBL  'T',kt166,tok_lget
+               TOKTBL  0,0
+
+kt166          TOKTBL  '$',0,tok_lgetS
+               TOKTBL  0,0
+
+kt153          TOKTBL  'N',kt167
+               TOKTBL  0,0
+
+kt167          TOKTBL  'K',kt168
+               TOKTBL  'P',kt169
+               TOKTBL  0,0
+
+kt169          TOKTBL  'U',kt170
+               TOKTBL  0,0
+
+kt170          TOKTBL  'T',0,tok_linput
+               TOKTBL  0,0
+
+kt168          TOKTBL  'E',kt171
+               TOKTBL  0,0
+
+kt171          TOKTBL  'Y',kt172,tok_linkey
+               TOKTBL  0,0
+
+kt172          TOKTBL  '$',0,tok_linkeyS
+               TOKTBL  0,0
+
+kt152          TOKTBL  'C',kt173
+               TOKTBL  'F',kt174
+               TOKTBL  'N',0,tok_len
+               TOKTBL  'T',0,tok_let
+               TOKTBL  0,0
+
+kt174          TOKTBL  'T',kt175
+               TOKTBL  0,0
+
+kt175          TOKTBL  '$',kt176
+               TOKTBL  0,0
+
+kt176          TOKTBL  '(',0,tok_leftS
+               TOKTBL  0,0
+
+kt173          TOKTBL  'H',kt177
+               TOKTBL  0,0
+
+kt177          TOKTBL  'O',0,tok_lecho
+               TOKTBL  0,0
+
+kt151          TOKTBL  'L',kt178
+               TOKTBL  0,0
+
+kt178          TOKTBL  'E',kt179
+               TOKTBL  0,0
+
+kt179          TOKTBL  'A',kt180
+               TOKTBL  0,0
+
+kt180          TOKTBL  'R',0,tok_lclear
+               TOKTBL  0,0
+
+kt9            TOKTBL  'F',0,tok_if
+               TOKTBL  'N',kt181
+               TOKTBL  0,0
+
+kt181          TOKTBL  'S',kt182
+               TOKTBL  0,0
+
+kt182          TOKTBL  'T',kt183
+               TOKTBL  0,0
+
+kt183          TOKTBL  'R',kt184
+               TOKTBL  0,0
+
+kt184          TOKTBL  '(',0,tok_instr
+               TOKTBL  0,0
+
+kt8            TOKTBL  'A',kt185
+               TOKTBL  0,0
+
+kt185          TOKTBL  'N',kt186
+               TOKTBL  0,0
+
+kt186          TOKTBL  'G',kt187
+               TOKTBL  0,0
+
+kt187          TOKTBL  'U',kt188
+               TOKTBL  0,0
+
+kt188          TOKTBL  'P',0,tok_hangup
+               TOKTBL  0,0
+
+kt7            TOKTBL  'O',kt189
+               TOKTBL  'E',kt190
+               TOKTBL  0,0
+
+kt190          TOKTBL  'T',kt191
+               TOKTBL  0,0
+
+kt191          TOKTBL  '$',0,tok_getS
+               TOKTBL  0,0
+
+kt189          TOKTBL  'T',kt192
+               TOKTBL  'S',kt193
+               TOKTBL  0,0
+
+kt193          TOKTBL  'U',kt194
+               TOKTBL  0,0
+
+kt194          TOKTBL  'B',0,tok_gosub
+               TOKTBL  0,0
+
+kt192          TOKTBL  'O',0,tok_goto
+               TOKTBL  0,0
+
+kt6            TOKTBL  'O',kt195
+               TOKTBL  'A',kt196
+               TOKTBL  'I',kt197
+               TOKTBL  'N',0,tok_fn
+               TOKTBL  0,0
+
+kt197          TOKTBL  'N',kt198
+               TOKTBL  0,0
+
+kt198          TOKTBL  'I',kt199
+               TOKTBL  0,0
+
+kt199          TOKTBL  'S',kt200
+               TOKTBL  0,0
+
+kt200          TOKTBL  'H',kt201,tok_finish
+               TOKTBL  0,0
+
+kt201          TOKTBL  'E',kt202
+               TOKTBL  0,0
+
+kt202          TOKTBL  'D',0,tok_finished
+               TOKTBL  0,0
+
+kt196          TOKTBL  'L',kt203
+               TOKTBL  0,0
+
+kt203          TOKTBL  'S',kt204
+               TOKTBL  0,0
+
+kt204          TOKTBL  'E',0,tok_false
+               TOKTBL  0,0
+
+kt195          TOKTBL  'R',0,tok_for
+               TOKTBL  0,0
+
+kt5            TOKTBL  'N',kt205
+               TOKTBL  'L',kt206
+               TOKTBL  'V',kt207
+               TOKTBL  'R',kt208
+               TOKTBL  'O',kt209
+               TOKTBL  'X',kt210
+               TOKTBL  0,0
+
+kt210          TOKTBL  'E',kt211
+               TOKTBL  'T',0,tok_ext
+               TOKTBL  0,0
+
+kt211          TOKTBL  'C',0,tok_exec
+               TOKTBL  0,0
+
+kt209          TOKTBL  'F',0,tok_eof
+               TOKTBL  'R',0,tok_eor
+               TOKTBL  0,0
+
+kt208          TOKTBL  'R',kt212
+               TOKTBL  0,0
+
+kt212          TOKTBL  'O',kt213
+               TOKTBL  0,0
+
+kt213          TOKTBL  'R',kt214,tok_error
+               TOKTBL  0,0
+
+kt214          TOKTBL  '$',0,tok_errorS
+               TOKTBL  0,0
+
+kt207          TOKTBL  'A',kt215
+               TOKTBL  0,0
+
+kt215          TOKTBL  'L',0,tok_eval
+               TOKTBL  0,0
+
+kt206          TOKTBL  'S',kt216
+               TOKTBL  0,0
+
+kt216          TOKTBL  'E',0,tok_else
+               TOKTBL  0,0
+
+kt205          TOKTBL  'D',kt217,tok_end
+               TOKTBL  0,0
+
+kt217          TOKTBL  'P',kt218
+               TOKTBL  'W',kt219
+               TOKTBL  'I',kt220
+               TOKTBL  'C',kt221
+               TOKTBL  0,0
+
+kt221          TOKTBL  'A',kt222
+               TOKTBL  0,0
+
+kt222          TOKTBL  'S',kt223
+               TOKTBL  0,0
+
+kt223          TOKTBL  'E',0,tok_endcase
+               TOKTBL  0,0
+
+kt220          TOKTBL  'F',0,tok_endif
+               TOKTBL  0,0
+
+kt219          TOKTBL  'H',kt224
+               TOKTBL  0,0
+
+kt224          TOKTBL  'I',kt225
+               TOKTBL  0,0
+
+kt225          TOKTBL  'L',kt226
+               TOKTBL  0,0
+
+kt226          TOKTBL  'E',0,tok_endwhile
+               TOKTBL  0,0
+
+kt218          TOKTBL  'R',kt227
+               TOKTBL  0,0
+
+kt227          TOKTBL  'O',kt228
+               TOKTBL  0,0
+
+kt228          TOKTBL  'C',0,tok_endproc
+               TOKTBL  0,0
+
+kt4            TOKTBL  'A',kt229
+               TOKTBL  'E',kt230
+               TOKTBL  'I',kt231
+               TOKTBL  'O',kt232
+               TOKTBL  0,0
+
+kt232          TOKTBL  'W',kt233
+               TOKTBL  0,0
+
+kt233          TOKTBL  'N',kt234
+               TOKTBL  0,0
+
+kt234          TOKTBL  'L',kt235
+               TOKTBL  0,0
+
+kt235          TOKTBL  'O',kt236
+               TOKTBL  0,0
+
+kt236          TOKTBL  'A',kt237
+               TOKTBL  0,0
+
+kt237          TOKTBL  'D',0,tok_download
+               TOKTBL  0,0
+
+kt231          TOKTBL  'V',0,tok_div
+               TOKTBL  'M',0,tok_dim
+               TOKTBL  0,0
+
+kt230          TOKTBL  'F',0,tok_def
+               TOKTBL  0,0
+
+kt229          TOKTBL  'T',kt238
+               TOKTBL  0,0
+
+kt238          TOKTBL  'A',0,tok_data
+               TOKTBL  0,0
+
+kt3            TOKTBL  'A',kt239
+               TOKTBL  'H',kt240
+               TOKTBL  'L',kt241
+               TOKTBL  0,0
+
+kt241          TOKTBL  'O',kt242
+               TOKTBL  'S',0,tok_cls
+               TOKTBL  0,0
+
+kt242          TOKTBL  'S',kt243
+               TOKTBL  0,0
+
+kt243          TOKTBL  'E',0,tok_close
+               TOKTBL  0,0
+
+kt240          TOKTBL  'A',kt244
+               TOKTBL  'R',kt245
+               TOKTBL  0,0
+
+kt245          TOKTBL  '$',0,tok_chrS
+               TOKTBL  0,0
+
+kt244          TOKTBL  'I',kt246
+               TOKTBL  0,0
+
+kt246          TOKTBL  'N',0,tok_chain
+               TOKTBL  0,0
+
+kt239          TOKTBL  'R',kt247
+               TOKTBL  'S',kt248
+               TOKTBL  'L',kt249
+               TOKTBL  0,0
+
+kt249          TOKTBL  'L',0,tok_call
+               TOKTBL  0,0
+
+kt248          TOKTBL  'E',0,tok_case
+               TOKTBL  0,0
+
+kt247          TOKTBL  'R',kt250
+               TOKTBL  0,0
+
+kt250          TOKTBL  'I',kt251
+               TOKTBL  0,0
+
+kt251          TOKTBL  'E',kt252
+               TOKTBL  0,0
+
+kt252          TOKTBL  'R',0,tok_carrier
+               TOKTBL  0,0
+
+kt2            TOKTBL  'E',kt253
+               TOKTBL  'G',kt254
+               TOKTBL  'O',kt255
+               TOKTBL  'P',kt256
+               TOKTBL  'R',kt257
+               TOKTBL  0,0
+
+kt257          TOKTBL  'E',kt258
+               TOKTBL  0,0
+
+kt258          TOKTBL  'A',kt259
+               TOKTBL  0,0
+
+kt259          TOKTBL  'K',0,tok_break
+               TOKTBL  0,0
+
+kt256          TOKTBL  'U',kt260
+               TOKTBL  0,0
+
+kt260          TOKTBL  'T',0,tok_bput
+               TOKTBL  0,0
+
+kt255          TOKTBL  'T',kt261
+               TOKTBL  0,0
+
+kt261          TOKTBL  'H',0,tok_both
+               TOKTBL  0,0
+
+kt254          TOKTBL  'E',kt262
+               TOKTBL  0,0
+
+kt262          TOKTBL  'T',0,tok_bget
+               TOKTBL  0,0
+
+kt253          TOKTBL  'E',kt263
+               TOKTBL  0,0
+
+kt263          TOKTBL  'P',0,tok_beep
+               TOKTBL  0,0
+
+kt1            TOKTBL  'N',kt264
+               TOKTBL  'B',kt265
+               TOKTBL  'S',kt266
+               TOKTBL  0,0
+
+kt266          TOKTBL  'C',0,tok_asc
+               TOKTBL  0,0
+
+kt265          TOKTBL  'S',0,tok_abs
+               TOKTBL  0,0
+
+kt264          TOKTBL  'D',0,tok_and
+               TOKTBL  0,0
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/tokenise b/StraySrc/Libraries/Sapphire/sail/sh/tokenise
new file mode 100644 (file)
index 0000000..8c3db02
--- /dev/null
@@ -0,0 +1,33 @@
+;
+; tokenise.sh
+;
+; Tokenise a Termite script
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  tokenise
+
+               [       :LNOT::DEF:tokenise__dfn
+               GBLL    tokenise__dfn
+
+; --- tokenise ---
+;
+; On entry:    R11 == pointer to Termite upcall block
+;              R12 == pointer to script anchor
+;
+; On exit:     May return an error
+;
+; Use:         Tokenises a Termite script into an output buffer.
+
+               IMPORT  tokenise
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/tokens b/StraySrc/Libraries/Sapphire/sail/sh/tokens
new file mode 100644 (file)
index 0000000..3a3067c
--- /dev/null
@@ -0,0 +1,156 @@
+;
+; tokens.sh
+;
+; Define constants for the tokens (generated)
+;
+; © 1995 Straylight
+;
+
+               [       :LNOT::DEF:tokens__dfn
+               GBLL    tokens__dfn
+
+               ^       &80
+tok_and                #       1
+tok_abs                #       1
+tok_asc                #       1
+tok_beep       #       1
+tok_bget       #       1
+tok_both       #       1
+tok_bput       #       1
+tok_break      #       1
+tok_carrier    #       1
+tok_case       #       1
+tok_chain      #       1
+tok_chrS       #       1
+tok_close      #       1
+tok_cls                #       1
+tok_call       #       1
+tok_data       #       1
+tok_def                #       1
+tok_div                #       1
+tok_dim                #       1
+tok_download   #       1
+tok_end                #       1
+tok_endproc    #       1
+tok_endwhile   #       1
+tok_endif      #       1
+tok_endcase    #       1
+tok_else       #       1
+tok_eval       #       1
+tok_error      #       1
+tok_errorS     #       1
+tok_eof                #       1
+tok_eor                #       1
+tok_exec       #       1
+tok_ext                #       1
+tok_for                #       1
+tok_false      #       1
+tok_finish     #       1
+tok_finished   #       1
+tok_fn         #       1
+tok_goto       #       1
+tok_getS       #       1
+tok_gosub      #       1
+tok_hangup     #       1
+tok_if         #       1
+tok_instr      #       1
+tok_lclear     #       1
+tok_lecho      #       1
+tok_leftS      #       1
+tok_len                #       1
+tok_let                #       1
+tok_linkey     #       1
+tok_linkeyS    #       1
+tok_linput     #       1
+tok_lget       #       1
+tok_lgetS      #       1
+tok_local      #       1
+tok_lnewlineS  #       1
+tok_log                #       1
+tok_midS       #       1
+tok_mod                #       1
+tok_newsession #       1
+tok_next       #       1
+tok_not                #       1
+tok_of         #       1
+tok_off                #       1
+tok_on         #       1
+tok_or         #       1
+tok_openin     #       1
+tok_openout    #       1
+tok_openup     #       1
+tok_oscli      #       1
+tok_otherwise  #       1
+tok_ptr                #       1
+tok_proc       #       1
+tok_rclear     #       1
+tok_return     #       1
+tok_repeat     #       1
+tok_read       #       1
+tok_recho      #       1
+tok_rem                #       1
+tok_remote     #       1
+tok_report     #       1
+tok_restore    #       1
+tok_rightS     #       1
+tok_rinkey     #       1
+tok_rinkeyS    #       1
+tok_rinput     #       1
+tok_rnd                #       1
+tok_rget       #       1
+tok_rgetS      #       1
+tok_rnewlineS  #       1
+tok_step       #       1
+tok_sgn                #       1
+tok_spool      #       1
+tok_strS       #       1
+tok_stringS    #       1
+tok_swap       #       1
+tok_sys                #       1
+tok_syscall    #       1
+tok_then       #       1
+tok_time       #       1
+tok_timeS      #       1
+tok_to         #       1
+tok_true       #       1
+tok_until      #       1
+tok_upload     #       1
+tok_val                #       1
+tok_wait       #       1
+tok_watch      #       1
+tok_watchfor   #       1
+tok_while      #       1
+tok_when       #       1
+tok_LE         #       1
+tok_LG         #       1
+tok_GE         #       1
+tok_LL         #       1
+tok_GG         #       1
+tok_GGG                #       1
+tok_DT         #       1
+tok_DD         #       1
+tok_PE         #       1
+tok_ME         #       1
+tok_TE         #       1
+tok_DE         #       1
+
+               ^       1
+tClass_andOp   #       1
+tClass_fn      #       1
+tClass_instr   #       1
+tClass_streamOp        #       1
+tClass_option  #       1
+tClass_pseud   #       1
+tClass_multOp  #       1
+tClass_orOp    #       1
+tClass_odd     #       1
+tClass_multArg #       1
+tClass_noise   #       1
+tClass_relOp   #       1
+tClass_addOp   #       1
+tClass_assign  #       1
+tClass_powOp   #       1
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/tree b/StraySrc/Libraries/Sapphire/sail/sh/tree
new file mode 100644 (file)
index 0000000..a79401e
--- /dev/null
@@ -0,0 +1,66 @@
+;
+; tree.sh
+;
+; Another attempt at symbol table management
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  tree_add
+;  tree_find
+;  str_cmp
+
+               [       :LNOT::DEF:tree__dfn
+               GBLL    tree__dfn
+
+; --- tree_add ---
+;
+; On entry:    R0 == type number
+;              R1 == address of name
+;              R2 == size of user data
+;
+; On exit:     R0 == address of user data in new node
+;              CS if node already exists, else CC
+;              May return an error
+;
+; Use:         Adds a node into a symbol table tree.
+
+               IMPORT  tree_add
+
+; --- tree_find ---
+;
+; On entry:    R0 == type number
+;              R1 == pointer to the name
+;
+; On exit:     CS if the variable was found, and
+;                R0 == pointer to the variable block
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Tries to find a node with the given type and name in
+;              the symbol tree.
+
+               IMPORT  tree_find
+
+; --- str_cmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         Case-sensitively compares two strings.  You can use the
+;              normal ARM condition codes after the compare, so you can
+;              treat this fairly much like a normal CMP.
+
+               IMPORT  str_cmp
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/upcalls b/StraySrc/Libraries/Sapphire/sail/sh/upcalls
new file mode 100644 (file)
index 0000000..ad450b1
--- /dev/null
@@ -0,0 +1,112 @@
+;
+; termScript.sh
+;
+; Definitions for the Termite script interface
+;
+; © 1995 Straylight
+;
+
+;----- Termite entry points -------------------------------------------------
+
+                       ^       0
+termite_makeBeep       #       4               ;Bleep at the user
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_sendRemote     #       4               ;Send data to serial port
+                                               ;Entry: R2 == ptr to block
+                                               ;       R3 == size of block
+                                               ;Exit:  --
+
+termite_reportMessage  #       4               ;Report non-multitaskingly
+                                               ;Entry: R0 == ptr to message
+                                               ;Exit:  --
+
+termite_printMessage   #       4               ;Report multitaskingly
+                                               ;Entry: R0 == ptr to message
+                                               ;Exit:  --
+
+termite_sendLocal      #       4               ;Queue bogus input data
+                                               ;Entry: R2 == ptr to block
+                                               ;       R3 == size (0-256)
+                                               ;Exit:  --
+
+termite_logFileAdd     #       4               ;Add to session log
+                                               ;Entry: R0 == ptr to message
+                                               ;Exit:  --
+
+termite_clearScreen    #       4               ;Clear session window
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_downLoad       #       4               ;Download file or files
+                                               ;Entry: R2 == protocol name
+                                               ;       R3 == dir/file, or 0
+                                               ;Exit:  --
+
+termite_upLoad         #       4               ;Upload file or files
+                                               ;Entry: R2 == protocol name
+                                               ;       R3 == list of files
+                                               ;Exit:  --
+
+termite_checkCarrier   #       4               ;Checks for a carrier
+                                               ;Entry: --
+                                               ;Exit:  R0 == 0 if no carrier
+
+termite_sysCall                #       4               ;Performs a SWI
+                                               ;Entry: R0-R8 params 2-10
+                                               ;       R9 param 1
+                                               ;Exit: ???
+
+termite_readRemote     #       4               ;Gets a byte from the buffer
+                                               ;Entry: --
+                                               ;Exit:  R0 == byte, or -1
+
+termite_readLocal      #       4               ;Gets a byte from the buffer
+                                               ;Entry: --
+                                               ;Exit:  R0 == byte, or -1
+
+termite_clearRemote    #       4               ;Clears the input buffer
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_clearLocal     #       4               ;Clears the input buffer
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_sendBreak      #       4               ;Sends a break to the modem
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_dropCarrier    #       4               ;Drops the carrier
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_finishSession  #       4               ;Finishes the current session
+                                               ;Entry: --
+                                               ;Exit:  --
+
+termite_newSession     #       4               ;Createsa new session
+                                               ;Entry: R0 == base style name
+                                               ;       R1 == style name
+                                               ;       R2 == see spec!
+                                               ;Exit:  --
+
+termite_checkFinished  #       4               ;Check the session is finish
+                                               ;Entry: --
+                                               ;Exit:  R0 == not, 1 == is
+
+termite_sysNumString   #       4               ;Convert string to number
+                                               ;Entry: R9 == SYSCALL string
+                                               ;Exit:  SYSCALL number, or VS
+
+               MACRO
+$label         TCALL   $call
+$label         MOV     R14,PC
+               ADD     PC,R11,#$call
+               MEND
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
+
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/value b/StraySrc/Libraries/Sapphire/sail/sh/value
new file mode 100644 (file)
index 0000000..31abf60
--- /dev/null
@@ -0,0 +1,74 @@
+;
+; value.sh
+;
+; r/value evaluation
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  val_readExp
+;  val__readP1
+;  val_readLvalue
+
+               [       :LNOT::DEF:value__dfn
+               GBLL    value__dfn
+
+; --- val_readExp ---
+;
+; On entry:    R8 == lookahead token
+;              R9 == current line number
+;              R10 == pointer into the tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor block pointer
+;
+; On exit:     R0 == value of the rvalue
+;              R1 == type of the variable
+;              R8 == new lookahead token
+;              R11 == moved on to the first character after the rvalue
+;              May return an error
+;
+; Use:         Tries to read an rvalue from the current program location.
+
+               IMPORT  val_readExp
+
+; --- val__readP1 ---
+;
+; On entry:    R9 == current line number
+;              R10 == pointer into the tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor block pointer
+;
+; On exit:     R0 == next character to look at
+;
+; Use:         Evaluates a precedence 4 type expression and store the
+;              result on the stack.  The first unused character is
+;              placed in R0.
+
+               IMPORT  val__readP1
+
+; --- val_readLvalue ---
+;
+; On entry:    R7 == 0 to read as an rvalue, 1 for lvalue
+;              R8 == next token to read
+;              R9 == current line number
+;              R10 == pointer into the tokenised buffer
+;              R11 == evaluation stack pointer
+;              R12 == anchor block pointer
+;
+; On exit:     R0 == pointer to the variable block if R7 == 1
+;              R8 == new next token to read
+;              May return an error
+;
+; Use:         Tries to read an lvalue from the current program location.
+
+               IMPORT  val_readLvalue
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/sh/var b/StraySrc/Libraries/Sapphire/sail/sh/var
new file mode 100644 (file)
index 0000000..65afd97
--- /dev/null
@@ -0,0 +1,76 @@
+;
+; var.sh
+;
+; Variable handling
+;
+; © 1995 Straylight
+;
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  var_create
+;  var_find
+
+               [       :LNOT::DEF:var__dfn
+               GBLL    var__dfn
+
+; --- var_create ---
+;
+; On entry:    R0 == type of variable
+;              R1 == pointer to variable name
+;              R2 == file address of label or DEF
+;              R3 == line number of label or DEF
+;              R12 == pointer to the anchor block
+;
+; On exit:     R0 == pointer to the variable
+;              May return an error
+;
+; Use:         Tries to find the variable given, and return a pointer
+;              to it if it is found. Otherwise it will try to create the
+;              variable and return a pointer to the new one.
+
+               IMPORT  var_create
+
+; --- var_find ---
+;
+; On entry:    R0 == type of the variable
+;              R1 == name of the variable
+;
+; On exit:     CS if the variable was found, and
+;                R0 == pointer to the variable block
+;              CC otherwise
+;
+; Use:         Tries to find the given variable in the current tree.
+
+               IMPORT  var_find
+
+;----- Workspace ------------------------------------------------------------
+
+               ; --- Variable types ---
+
+               ^       0
+vType_integer  #       1                       ;Integer
+vType_string   #       1                       ;String
+vType_dimInt   #       1                       ;DIM of integers
+vType_dimStr   #       1                       ;DIM of strings
+vType_label    #       1                       ;Label
+vType_proc     #       1                       ;Procedure name
+vType_fn       #       1                       ;Function name
+
+               ; --- Lvalue types ---
+
+vType_lvInt    #       1                       ;Integer variable lvalue
+vType_lvString #       1                       ;String variable lvalue
+vType_lvWord   #       1                       ;Word lvalue (from `!' op)
+vType_lvByte   #       1                       ;Byte lvalue (from `?' op)
+vType_lvBytes  #       1                       ;String lvalue (from `$' op)
+vType_lvIntArr #       1                       ;Integer array lvalue
+vType_lvStrArr #       1                       ;String array lvalue
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sail/tableGen,ffb b/StraySrc/Libraries/Sapphire/sail/tableGen,ffb
new file mode 100644 (file)
index 0000000..650daa1
Binary files /dev/null and b/StraySrc/Libraries/Sapphire/sail/tableGen,ffb differ
diff --git a/StraySrc/Libraries/Sapphire/sh/_colSelect/kernel b/StraySrc/Libraries/Sapphire/sh/_colSelect/kernel
new file mode 100644 (file)
index 0000000..d5d686a
--- /dev/null
@@ -0,0 +1,70 @@
+;
+; _cs.kernel.sh
+;
+; Colour selector kernel routines
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   cs_colChange
+;   cs_immediate
+;   cs_resolution
+
+; --- cs_colChange ---
+;
+; On entry:    R10 == currently selected dialogue box
+;
+; On exit:     --
+;
+; Use:         Updates the colour selector's colour display.
+
+               IMPORT  cs_colChange
+
+; --- cs_immediate ---
+;
+; On entry:    R10 == currently selected dialogue box
+;
+; On exit:     CS if immediate operations are enabled, or CC
+;
+; Use:         Informs the caller whether sliders and arrows should cause
+;              immediate update of the dialogue box, or wait until the
+;              operation has completed.
+
+               IMPORT  cs_immediate
+
+; --- cs_resolution ---
+;
+; On entry:    R10 == currently selected dialogue box
+;
+; On exit:     R0 == quality value, from 0 (pixel) to 3 (grotty)
+;
+; Use:         Returns the current resolution value.  This is interpreted
+;              in a model-dependent manner.
+
+               IMPORT  cs_resolution
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/_colSelect/models b/StraySrc/Libraries/Sapphire/sh/_colSelect/models
new file mode 100644 (file)
index 0000000..4a7a156
--- /dev/null
@@ -0,0 +1,42 @@
+;
+; _cs.models.sh
+;
+; Declarations for colour selector models
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+
+               IMPORT  rgb_open
+               IMPORT  hsv_open
+
+;----- Colour models defined ------------------------------------------------
+
+               ^       0
+cMod_rgb       #       1
+cMod_hsv       #       1
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/_colSelect/vars b/StraySrc/Libraries/Sapphire/sh/_colSelect/vars
new file mode 100644 (file)
index 0000000..406d808
--- /dev/null
@@ -0,0 +1,86 @@
+;
+; _cs.vars.sh
+;
+; Colour selector variables and workspace
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   None.
+
+;----- Internal event codes -------------------------------------------------
+
+csEvent__close EQU     &C0000001               ;Kernel wants to close pane
+csEvent__newRes        EQU     &C0000002               ;User changed diag resolution
+csEvent__reset EQU     &C0000003               ;Reset pane from cs__colour
+csEvent__read  EQU     &C0000004               ;Write data to cs__colour
+
+;----- Data structures ------------------------------------------------------
+
+               ^       0
+col_rgb                #       4                       ;RGB palette entry for colour
+col_model      #       4                       ;Colour model for colour
+col_data       #       4                       ;Colour data for model
+col_size       #       0
+
+;----- Workspace layout -----------------------------------------------------
+
+               ^       0,R10
+cs__dStart     #       0
+
+               ; --- Colour selector kernel ---
+
+cs__frameDb    #       4                       ;Main colour selector dbox
+cs__modelDb    #       4                       ;Current model pane dbox
+cs__resolution #       4                       ;Current display resolution
+cs__address    #       4                       ;The address of his colour
+cs__colour     #       col_size                ;The actual colour (packed)
+
+               ; --- Colour selector model data ---
+
+cs__modelData  #       52                      ;Working data for models
+
+cs__dSize      EQU     {VAR}-cs__dStart
+
+
+               ; --- RGB model data ---
+
+               ^       :INDEX: cs__modelData,R10
+
+rgb__sl1Val    #       8                       ;Value/colour of x slider
+rgb__xPos      #       4                       ;Cached x position
+rgb__sl2Val    #       8                       ;Value/colour of y slider
+rgb__yPos      #       4                       ;Cached y position
+rgb__sl3Val    #       8                       ;Value/colour of z slider
+rgb__zPos      #       4                       ;Cached z position
+
+rgb__mapping   #       4                       ;The current mapping
+rgb__red       #       4                       ;Address of red value
+rgb__green     #       4                       ;Address of green value
+rgb__blue      #       4                       ;Address of blue value
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/_tms/tmsCreate b/StraySrc/Libraries/Sapphire/sh/_tms/tmsCreate
new file mode 100644 (file)
index 0000000..abc9733
--- /dev/null
@@ -0,0 +1,84 @@
+;
+; tmsCreate.sh
+;
+; Creation, recreation and destruction of tearoff menus
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  tms_create
+;  tms__destroy
+;  tms__width
+;  tms_recreate
+
+; --- tms_create ---
+;
+; On entry:    R0 == pointer to a menu block
+;              R1 == pointer to event handler for the menu section
+;              R2 == R10 value to pass to the event handler
+;              R3 == R12 value to pass to the event handler
+;
+; On exit:     R0 == tearoff handle for this menu
+;              May return an error
+;
+; Use:         Creates a new menu, or adds sections to an existing one.
+
+               IMPORT  tms_create
+
+; --- tms__destroy ---
+;
+; On entry:    R0 == handle of tearoff menu to destroy
+;
+; On exit:     --
+;
+; Use:         Zaps a tearoff menu entirely, leaving no survivors
+
+               IMPORT  tms__destroy
+
+; --- tms__width ---
+;
+; On entry:    R10 == pointer to the menu
+;
+; On exit:     CS if the width has changed, CC otherwise
+;
+; Use:         Calculates what the appropriate width fields of the given
+;              menu should be.
+
+               IMPORT  tms__width
+
+; --- tms_recreate ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Recreates the existing menu structure, making changes where
+;              appropriate.
+
+               IMPORT  tms_recreate
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/_tms/tmsGlobal b/StraySrc/Libraries/Sapphire/sh/_tms/tmsGlobal
new file mode 100644 (file)
index 0000000..00a1b6d
--- /dev/null
@@ -0,0 +1,231 @@
+;
+; tmsWS.sh
+;
+; Internal workspace layout for tearoff menus
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         SKIP    $mask,$size,$reg1,$reg2
+$label         TST     $reg1,#$mask
+               ADDNE   $reg2,$reg2,#$size
+               MEND
+
+               MACRO
+$label         SKPITEM $reg1,$reg2
+$label         SKIP    mFlag_shade,4,$reg1,$reg2
+               SKIP    mFlag_iShade,4,$reg1,$reg2
+               SKIP    mFlag_switch,4,$reg1,$reg2
+               SKIP    mFlag_radio,8,$reg1,$reg2
+               SKIP    mFlag_sprite,8,$reg1,$reg2
+               SKIP    mFlag_subMenu,8,$reg1,$reg2
+               MEND
+
+;----- Useful values --------------------------------------------------------
+
+mFlag_tearoff  EQU     (1<<1)                  ;Menu has a tearoff bar
+mFlag_makeMe   EQU     (1<<2)                  ;Recreate menu on adjust
+mFlag_maxHeight        EQU     (1<<3)                  ;Menu has a maximum height
+mFlag_global   EQU     (1<<4)                  ;Menu is `global' for app
+
+mFlag_indirect EQU     (1<<0)                  ;Item text is indirected
+mFlag_shortcut EQU     (1<<1)                  ;Item has a keyboard shortcut
+mFlag_iShortcut        EQU     (1<<2)                  ;Item has an indirected S/C
+mFlag_shade    EQU     (1<<3)                  ;Item is shadable
+mFlag_iShade   EQU     (1<<4)                  ;Item is inverse shadable
+mFlag_switch   EQU     (1<<5)                  ;Item is a switch
+mFlag_radio    EQU     (1<<6)                  ;Item is a radio item
+mFlag_sprite   EQU     (1<<7)                  ;Menu item has a sprite
+mFlag_halfSize EQU     (1<<8)                  ;Sprite is halfsize
+mFlag_subWarn  EQU     (1<<9)                  ;Warn client if submenu warn
+mFlag_subMenu  EQU     (1<<10)                 ;Item has menu to be opened
+
+mFlag_R12      EQU     (1<<16)                 ;Use R12 for runtime data
+mFlag_noWarn   EQU     (1<<17)                 ;Don't warn on shaded items
+mFlag_ruleOff  EQU     (1<<18)                 ;Put a ruleoff after item
+
+mFlag_end      EQU     (1<<31)                 ;No more items
+
+; --- Event types ---
+
+mEvent_select  EQU     0                       ;Normal menu selection
+                                               ;  R1 == index of item
+mEvent_arrow   EQU     1                       ;Sub menu warning
+                                               ;  R1 == index of item
+mEvent_deleted EQU     2                       ;Menu has been deleted
+mEvent_help    EQU     3                       ;Menu help requested
+                                               ;  R1 == ndex of item
+                                               ;  R2 == ptr to packed itmdef
+
+;----- The TWIN global area -------------------------------------------------
+
+               ^       0
+twin_flags     #       4                       ;Various useful flags
+twin_trans     #       4                       ;The current transient window
+twin_tmsHook   #       4                       ;A hook to the TMS system
+twin_size      #       0                       ;The size of the global area
+
+twinFlag_recrt EQU     (1<<0)                  ;Menu will be recreated
+
+;----- Workspace ------------------------------------------------------------
+
+; --- Header definition for each menu ---
+
+               ^       0
+hText          #       4                       ;Pointer to the text string
+hMaxHeight     #       4                       ;The maximum height of menu
+hHandler       #       4                       ;The handler to call
+hR10           #       4                       ;The R10 value to use
+hR12           #       4                       ;The R12 value to use
+hDefinition    #       4                       ;Pointer to packed definition
+hFlags         #       4                       ;The flags for the menu
+hHandle                #       4                       ;The window handle of menu
+hPrevMenu      #       4                       ;Pointer to the previous menu
+hSprWidth      #       4                       ;The width of widest sprite
+hTextWidth     #       4                       ;The width of the menu
+hKeyWidth      #       4                       ;Width of longest keystring
+hTitleWidth    #       4                       ;Width of the title
+hTotWidth      #       4                       ;The total width
+hHeight                #       4                       ;The height of the menu
+hSelected      #       4                       ;The currently selected item
+hSubMenu       #       0                       ;Pointer to current submenu
+hDbox          #       4                       ;Ooooo... a union
+hNextTorn      #       4                       ;Pointer to the next torn off
+hFromItem      #       4                       ;The item menu was from
+hItems         #       4                       ;Pointer to the items
+
+hSize          #       0                       ;Size of the header defn
+
+; --- Header flags ---
+
+hFlag__tearable        EQU     (1<<0)                  ;The menu is tearable
+hFlag__torn    EQU     (1<<1)                  ;The menu has been torn off
+hFlag__folded  EQU     (1<<2)                  ;The menu has been folded
+hFlag__scrBar  EQU     (1<<3)                  ;The menu has a scrollbar
+hFlag__warned  EQU     (1<<4)                  ;Client's been warned submenu
+hFlag__tIndir  EQU     (1<<5)                  ;Title data is indirected
+hFlag__global  EQU     (1<<6)                  ;Menu is `global' for app
+
+hFlag__dbox    EQU     (1<<15)                 ;There is a dbox
+
+; --- The item definition ---
+
+               ^       0
+iNumber                #       4                       ;The number of items in group
+iDefinition    #       4                       ;Pointer to the icon defn
+iHandler       #       4                       ;Pointer to the event handler
+iR10           #       4                       ;R10 value to use
+iR12           #       4                       ;R12 value to use
+iItems         #       4                       ;Pointer to next grp of items
+iHdrSize       #       0                       ;Size of this structure
+
+               ^       0
+iText          #       4                       ;Pointer to the text string
+iKeyCode       #       4                       ;Code of keyboard shortcut
+iFlags         #       4                       ;The item flags
+iyCoord                #       4                       ;The y coordinate of the item
+iSubMenu       #       0                       ;Menu handle of sub menu
+iDbox          #       4                       ;Exciting isn't it!
+iSprName       #       4                       ;Pointer to sprite name
+iSprArea       #       4                       ;And its sprite area
+iSprCsum       #       4                       ;Checksum of sprite name
+iItemSize      #       0                       ;Size of this structure
+
+; --- Item flags ---
+
+iFlag__shaded  EQU     (1<<0)                  ;The item is shaded
+iFlag__ticked  EQU     (1<<1)                  ;The item is ticked
+iFlag__radio   EQU     (1<<2)                  ;The item is splodged
+iFlag__dotted  EQU     (1<<3)                  ;The item is folled by a line
+iFlag__arrow   EQU     (1<<4)                  ;The item has an arrow
+iFlag__sprite  EQU     (1<<5)                  ;The item has a sprite
+iFlag__halfSize        EQU     (1<<6)                  ;Display sprite at half size
+iFlag__noWarn  EQU     (1<<7)                  ;Don't warn on shaded items
+
+iFlag__dbox    EQU     (1<<15)                 ;Item has a dialogue box
+
+iFlag__newTick EQU     (1<<27)                 ;Need to redraw ticks etc.
+iFlag__newSpr  EQU     (1<<28)                 ;Need to redraw sprite
+iFlag__newText EQU     (1<<29)                 ;Text of item has changed
+iFlag__newKey  EQU     (1<<30)                 ;Key string has changed
+iFlag__newArrow        EQU     (1<<31)                 ;Need to redraw arrow thingy
+
+; --- Miscellaneous values ---
+
+tms__barHeight EQU     24                      ;The height of tearoff bar
+
+; --- Program workspace ---
+
+               ^       0,R12
+tms__wStart    #       0
+
+tms__flags     #       4                       ;The flags word
+
+tms__twin      #       4                       ;Address of the TWIN area
+
+tms__zInit     #       0                       ;Zero-inited part of wspace
+
+tms__current   #       4                       ;The current transient menu
+tms__tornoffs  #       4                       ;Pointer to list of torn offs
+tms__prevLevel #       4                       ;Previous menu to opened from
+tms__orgTearoff        #       4                       ;The originating tearoff
+tms__itemOver  #       4                       ;Ptr into packed defn to item
+tms__itemBlock #       4                       ;Ptr to item block of item
+tms__currItem  #       4                       ;Ptr to the current item
+tms__currDbox  #       4                       ;The current dbox handle
+tms__dboxPrev  #       4                       ;Menu that dbox came from
+
+tms__creating  #       4                       ;Ptr to header of new menu
+tms__lastItems #       4                       ;Ptr to last item blk created
+tms__recreating        #       4                       ;Ptr to menu being recreated
+
+tms__coords    #       8                       ;(x,y) for menu
+tms__oldHandle #       4                       ;Hnd passed to idle claimer
+tms__itemIndex #       4                       ;Index into defn of item
+tms__alarmMenu #       4                       ;Menu alarm is for
+tms__alarmItem #       4                       ;Item alarm is for
+
+tms__zSize     EQU     {VAR}-tms__zInit        ;Size of zero-inited bit
+
+tms__fHandle   #       4                       ;The current wimp font handle
+tms__R11       #       4                       ;Address of the scratchpad
+
+tms__wSize     EQU     {VAR}-tms__wStart
+
+; --- Program flags ---
+
+tFlag__inited  EQU     (1<<0)                  ;We are initialised
+tFlag__iBar    EQU     (1<<1)                  ;The click was on icon bar
+tFlag__riscos3 EQU     (1<<2)                  ;We are on RISC OS 3
+tFlag__overArrow EQU   (1<<3)                  ;We are over RHS of a menu
+tFlag__close   EQU     (1<<4)                  ;Close the transient
+tFlag__newFont EQU     (1<<5)                  ;There has been a font change
+tFlag__nActive EQU     (1<<6)                  ;Menus are not active
+tFlag__subWait EQU     (1<<7)                  ;We're waiting for a submenu
+tFlag__doFake  EQU     (1<<8)                  ;Fake a NULL event
+tFlag__faking  EQU     (1<<9)                  ;We are faking a NULL event
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/_tms/tmsGlue b/StraySrc/Libraries/Sapphire/sh/_tms/tmsGlue
new file mode 100644 (file)
index 0000000..45866fd
--- /dev/null
@@ -0,0 +1,60 @@
+;
+; tmsGlue.sh
+;
+; Supplies underlying tms workings -- filters, window creation etc.
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  tms__createWindow
+;  tms_init
+
+; --- tms__createWindow ---
+;
+; On entry:    R0 == the menu height (-ve)
+;              R10 == pointer to the menu
+;
+; On exit:     V and R0 == The standard error block, if an error occured
+;              R0 == the window handle
+;
+; Use:         This call will create a window for the given menu. The
+;              block pointed to by R10 will be filled in appropriately
+;              with the handle.
+
+               IMPORT  tms__createWindow
+
+; --- tms_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the tms (Tearoff Menu System) unit.
+
+               IMPORT  tms_init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/_tms/tmsMain b/StraySrc/Libraries/Sapphire/sh/_tms/tmsMain
new file mode 100644 (file)
index 0000000..f689d48
--- /dev/null
@@ -0,0 +1,133 @@
+;
+; tmsMain.sh
+;
+; The Straylight Tearoff Menu Segment
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  tms__closeMenu
+;  tms__updateItem
+;  tmsh__subWaiting
+;  tmsh__openSub
+;  tms__cleanUp
+;  tms__wSpace
+;  tms__update
+;  tms__eventHandler
+;  tms_help
+
+; --- tms__closeMenu ---
+;
+; On entry:    R2 == pointer to menu to close
+;              R10 == pointer to the menu we are currently over
+;
+; On exit:     --
+;
+; Use:         Closes the menu structure pointed to, and destroys it
+
+               IMPORT  tms__closeMenu
+
+; --- tms__updateItem ---
+;
+; On entry:    R7 == pointer to the item to highlight
+;              R10 == pointer to the menu
+;
+; On exit:     --
+;
+; Use:         Forces an update of the textual part of an item.
+
+               IMPORT  tms__updateItem
+
+; --- tmsh__subWaiting ---
+;
+; On entry:    --
+;
+; On exit:     CS if we're waiting for a submenu, CC otherwise
+;
+; Use:         Informs transWin if a submenu is expected.
+
+               IMPORT  tmsh__subWaiting
+
+; --- tmsh__openSub ---
+;
+; On entry:    R0 == window handle to open
+;
+; On exit:     --
+;
+; Use:         Opens the given window as a submenu from a tms menu.
+
+               IMPORT  tmsh__openSub
+
+; --- tms__cleanUp ---
+;
+; On entry:    R0 == handle idle handler is called with (the menu)
+;
+; On exit:     --
+;
+; Use:         Called to clean up the system when the pointer has left
+;              a menu.
+
+               IMPORT  tms__cleanUp
+
+; --- tms__update ---
+;
+; On entry:    R0 == flags (as for doRedraw)
+;              R10 == pointer to the menu
+;
+; On exit:     --
+;
+; Use:         Updates the entire menu.
+
+               IMPORT  tms__update
+
+; --- tms__eventHandler ---
+;
+; On entry:    R0 == event, as returned from Wimp_Poll
+;              R1 == pointer to the event block
+;              R10 == pointer to the menu
+;
+; On exit:     --
+;
+; Use:         Deals with the event that has been sent to my window
+
+               IMPORT  tms__eventHandler
+
+; --- tms_help ---
+;
+; On entry:    R0 == pointer to base message tag
+;              R1 == index of menu item
+;
+; On exit:     --
+;
+; Use:         Adds a string to the help message found by adding the menu
+;              item number to the base message tag.
+
+               IMPORT  tms_help
+
+               IMPORT  tms__wSpace
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/akbd b/StraySrc/Libraries/Sapphire/sh/akbd
new file mode 100644 (file)
index 0000000..52e198f
--- /dev/null
@@ -0,0 +1,83 @@
+;
+; akbd.sh
+;
+; Keyboard handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  akbd_test
+;  akbd_translate
+;  akbd_pollKey
+
+               [       :LNOT::DEF:akbd__dfn
+               GBLL    akbd__dfn
+
+; --- akbd_test ---
+;
+; On entry:    R0 == internal key number to test
+;
+; On exit:     CS if key was pressed, CC otherwise
+;
+; Use:         Informs you whether a given key is currently being pressed.
+
+               IMPORT  akbd_test
+
+; --- akbd_translate ---
+;
+; On entry:    R0 == Wimp key number
+;
+; On exit:     R0 == Straylight extended keyset key number
+;
+; Use:         Translates a Wimp key number into one of the more specific
+;              Straylight key numbers.
+
+               IMPORT  akbd_translate
+
+; --- akbd_pollKey ---
+;
+; On entry:    --
+;
+; On exit:     CC if a key was in the buffer and
+;                R0 == wimp translated key code
+;              else CS and
+;                R0 corrupted
+;
+; Use:         Reports whether the user has typed ahead, and if so what the ;          keypress. Note that the keypresses returned are WIMP-type,
+;              not Straylight extended ones so you will have to use
+;              akbd_translate if you need the extended type.
+;
+;              This call could be used to allow buffering of keypresses:
+;              on a Key_Pressed event you would call this routine until
+;              it returns FALSE and store the codes it returns in a buffer
+;              along with the code from the event.
+
+               IMPORT  akbd_pollKey
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/alloc b/StraySrc/Libraries/Sapphire/sh/alloc
new file mode 100644 (file)
index 0000000..875a4a6
--- /dev/null
@@ -0,0 +1,128 @@
+;
+; alloc.sh
+;
+; Redirectable memory allocation
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  alloc_register
+;  alloc_useOSHeap
+;  alloc
+;  free
+;  alloc_init
+;  alloc_error
+
+               [       :LNOT::DEF:alloc__dfn
+               GBLL    alloc__dfn
+
+; --- alloc_register ---
+;
+; On entry:    R0 == pointer to allocator function
+;              R1 == pointer to free function
+;              R2 == workspace pointer to pass to them in R12
+;
+; On exit:     --
+;
+; Use:         Registers two functions to be used as a heap manager by
+;              alloc and free.
+;
+;              The allocator is entered with R0 as the size of block
+;              required, and should exit with CC and R0 == pointer to the
+;              block allocated if successful, CS if there wasn't enough
+;              memory and generate any other errors that occur.  Registers
+;              other than R0 must be preserved.
+;
+;              The freer is entered with R0 == pointer to block to free.
+;              It should exit with all registers preserved.  If anything
+;              goes wrong, it should generate an error.
+
+               IMPORT  alloc_register
+
+; --- alloc_useOSHeap ---
+;
+; On entry:    R1 == pointer to OS_Heap-managed heap to use
+;
+; On exit:     --
+;
+; Use:         Registers an OS_Heap heap to use to allocate memory when
+;              alloc is called.
+
+               IMPORT  alloc_useOSHeap
+
+; --- alloc ---
+;
+; On entry:    R0 == size of block to allocate from current heap
+;
+; On exit:     R0 == pointer to block and CC if it all worked
+;              CS if there wasn't enough memory (R0 corrupted)
+;
+; Use:         Allocates R0 bytes from a heap manager.  This routine will
+;              attempt to allocate memory from the current heaps in order
+;              of registration (i.e. the Sapphire OS_Heap first etc.) until
+;              either one which can service the request is found, or all
+;              the heaps have been tried.
+
+               IMPORT  alloc
+
+; --- free ---
+;
+; On entry:    R0 == pointer to block allocated by alloc
+;
+; On exit:     --
+;
+; Use:         Frees a block allocated by alloc, regardless of which heap
+;              it came from.
+
+               IMPORT  free
+
+; --- alloc_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the alloc system, and sets it up to use the
+;              kernel-provided OS_Heap area.
+
+               IMPORT  alloc_init
+
+; --- alloc_error ---
+;
+; On entry:    --
+;
+; On exit:     V set and R0 == pointer to an error about not having enough
+;              memory.
+;
+; Use:         Returns an error suitable for displaying to a user if there
+;              isn't enough memory left.
+
+               IMPORT  alloc_error
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/banner b/StraySrc/Libraries/Sapphire/sh/banner
new file mode 100644 (file)
index 0000000..07d64bf
--- /dev/null
@@ -0,0 +1,200 @@
+;
+; banner.sh
+;
+; A startup banner window
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  banner
+;  bnr_doBanner
+
+               [       :LNOT::DEF:banner__dfn
+               GBLL    banner__dfn
+
+;+             LIB     sapphire:^.bsh.banner
+
+; --- banner ---
+;
+; On entry:    R0 == pointer to definition block, or 0
+;              R1 == R12 value to pass to setup routine, if present
+;
+; On exit:     --
+;
+; Use:         Displays a startup banner and initialises the library and
+;              client.  This call should be used as a replacement for
+;              sapphire_libInit.
+;
+;              If R0 is 0 on entry, no banner window is used; instead
+;              an hourglass percentage is displayed to indicate the
+;              amount of initialisation performed so far.
+;
+;              Alternatively, it should point to a table consisting of
+;              a flags word and optional arguments specified by the flags
+;              in order.  The options you can specify are a slider and
+;              percentage count icon (used to display current progress),
+;              a setup routine, and the leafname of a sprites file to
+;              attach to the banner window.
+;
+;              The setup routine is passed the banner dialogue handle in
+;              R0.  It should fill in parts of the banner window, such as
+;              the licencee name and serial number that can't be determined
+;              until runtime (for safeness), and maybe version information
+;              too.
+
+               IMPORT  banner
+
+; --- bnr_doBanner ---
+;
+; On entry:    R0 == pointer to definition block, or 0
+;              R1 == R12 value to pass to setup routine, if present
+;              R2 == pointer to library initialisation table
+;
+; On exit:     --
+;
+; Use:         Displays a startup banner and initialises the library and
+;              client.  This routine is used to support dynamic linking.
+
+               IMPORT  bnr_doBanner
+
+;----- Flags ----------------------------------------------------------------
+
+bFlag_slider   EQU     (1<<0)                  ;Has a progress slider
+                                               ;+0 icon number for slider
+                                               ;+4
+
+bFlag_counter  EQU     (1<<1)                  ;Has a percentage indicator
+                                               ;+0 icon number for indicator
+                                               ;+4
+
+bFlag_setup    EQU     (1<<2)                  ;Needs a setup routine
+                                               ;+0 == address of routine
+                                               ;+4
+
+bFlag_sprites  EQU     (1<<3)                  ;Load a sprite file
+                                               ;+0 == name of sprite file
+                                               ;+n
+
+;----- Macros ---------------------------------------------------------------
+
+               GBLA    bnr__f
+               GBLA    bnr__c
+bnr__c         SETA    0
+
+; --- Macro: BANNER ---
+;
+; Arguments:   --
+;
+; Use:         Begins construction of a banner block.
+
+               MACRO
+$label         BANNER
+bnr__f         SETA    0
+               ALIGN
+$label
+               DCD     bnr__fl$bnr__c
+               MEND
+
+; --- Macro: BFLAG ---
+;
+; Arguments:   f == flag to set
+;
+; Use:         Sets a flag in the banner header, making sure they go in
+;              order.
+
+               MACRO
+               BFLAG   $f
+               [       bnr__f >= $f
+               !       1,"Banner flags built in wrong order"
+               ]
+bnr__f         SETA    bnr__f :OR: $f
+               MEND
+
+; --- Macro: BNSLIDE ---
+;
+; Arguments:   icon == icon number of slider in banner window
+;
+; Use:         Registers the banner window's slider.
+
+               MACRO
+               BNSLIDE $icon
+               BFLAG   bFlag_slider
+               DCD     $icon
+               MEND
+
+; --- Macro: BNCOUNT ---
+;
+; Arguments:   icon == icon number of percentage counter
+;
+; Use:         Registers the banner window's percentage counter.
+
+               MACRO
+               BNCOUNT $icon
+               BFLAG   bFlag_counter
+               DCD     $icon
+               MEND
+
+; --- Macro: BNSETUP ---
+;
+; Arguments:   rout == address of setup routine
+;
+; Use:         Registers the banner window's setup routine.
+
+               MACRO
+               BNSETUP $rout
+               BFLAG   bFlag_setup
+               DCD     $rout
+               MEND
+
+; --- Macro: BNSPRT ---
+;
+; Arguments:   name == leafname of sprite file
+;
+; Use:         Registers the banner window's sprite file name.
+
+               MACRO
+               BNSPRT  $name
+               BFLAG   bFlag_sprites
+               DCB     "$name",0
+               MEND
+
+; --- Macro: BNEND ---
+;
+; Arguments:   --
+;
+; Use:         Terminates a banner window definition.
+
+               MACRO
+               BNEND
+               ALIGN
+bnr__fl$bnr__c EQU     bnr__f
+bnr__c         SETA    bnr__c+1
+               MEND
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/buttons b/StraySrc/Libraries/Sapphire/sh/buttons
new file mode 100644 (file)
index 0000000..beb68d0
--- /dev/null
@@ -0,0 +1,185 @@
+;
+; buttons.sh
+;
+; Definitions for button blocks
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   buttons_setup
+;
+; Macros provided:
+;
+;   BUTTON
+;   BUTEND
+;   BCANCEL
+;   BOK
+;   BHELP
+;   BGAP
+
+               [       :LNOT::DEF:buttons__dfn
+               GBLL    buttons__dfn
+
+;+             LIB     sapphire:^.bsh.stdDbox
+
+; --- buttons_setup ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to buttons block
+;              R2 == buttons base icon
+;              R3 == number of buttons to allow
+;
+; On exit:     R2 == buttons flag mask
+;              R3 == cancel button icon, or -1
+;
+; Use:         Sets up a dialogue box's buttons according to a buttons
+;              block.
+
+               IMPORT  buttons_setup
+
+;----- Macros ---------------------------------------------------------------
+
+               GBLA    but__c
+but__c         SETA    0
+               GBLA    but__fl
+but__fl                SETA    0
+
+; --- Macro: BUTTON ---
+;
+; Arguments:   msg == message tag to put in button
+;
+; Use:         Inserts a text button into a buttons definition block.
+
+               MACRO
+$label         BUTTON  $msg
+but__f$but__c  EQU     but__fl
+but__c         SETA    but__c+1
+but__fl                SETA    bFlag_text
+$label         DCD     but__f$but__c
+               DCB     "$msg",0
+               ALIGN
+               MEND
+
+; --- Macro: BCANCEL ---
+;
+; Arguments:   text == optional text string (default is `Cancel')
+;
+; Use:         Inserts a cancel button into a buttons definition block.
+
+               MACRO
+$label         BCANCEL $text
+but__f$but__c  EQU     but__fl
+but__c         SETA    but__c+1
+but__fl                SETA    bFlag_cancel
+
+$label         DCD     but__f$but__c
+
+               [       "$text"<>""
+but__fl                SETA    but__fl :OR: bFlag_text
+               DCB     "$text",0
+               ]
+
+               MEND
+
+; --- Macro: BOK ---
+;
+; Arguments:   --
+;
+; Use:         Inserts an OK button into a buttons definition block.
+
+               MACRO
+$label         BOK
+but__f$but__c  EQU     but__fl
+but__c         SETA    but__c+1
+but__fl                SETA    bFlag_ok
+$label         DCD     but__f$but__c
+               MEND
+
+; --- Macro: BHELP ---
+;
+; Arguments:   --
+;
+; Use:         Inserts a help button into a buttons definition block.
+
+               MACRO
+$label         BHELP
+but__f$but__c  EQU     but__fl
+but__c         SETA    but__c+1
+but__fl                SETA    bFlag_help
+$label         DCD     but__f$but__c
+               MEND
+
+; --- Macro: BGAP ---
+;
+; Arguments:   --
+;
+; Use:         Omits a button in a buttons definition block.
+
+               MACRO
+$label         BGAP
+but__f$but__c  EQU     but__fl
+but__c         SETA    but__c+1
+but__fl                SETA    0
+$label         DCD     but__f$but__c
+               MEND
+
+; --- Macro: BUTEND ---
+;
+; Arguments:   --
+;
+; Use:         Terminates a buttons definition block.
+
+               MACRO
+$label         BUTEND
+but__f$but__c  EQU     but__fl+bFlag_last
+but__c         SETA    but__c+1
+$label
+               MEND
+
+
+
+;----- Button block formats -------------------------------------------------
+
+bFlag_cancel   EQU     (1<<0)                  ;This is the cancel button
+                                               ;+0
+
+bFlag_ok       EQU     (1<<1)                  ;This is the OK button
+                                               ;+0
+
+bFlag_help     EQU     (1<<2)                  ;This is the help button
+                                               ;+0
+
+bFlag_text     EQU     (1<<3)                  ;This button contains text
+                                               ;+0 == message tag
+                                               ;+n
+
+bFlag_last     EQU     (1<<31)                 ;This is the last item
+                                               ;+0
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/choices/choices b/StraySrc/Libraries/Sapphire/sh/choices/choices
new file mode 100644 (file)
index 0000000..92010f3
--- /dev/null
@@ -0,0 +1,84 @@
+;
+; choices.choices.sh
+;
+; Locate user-configurable resource files
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  choices_useChoices
+;  choices_find
+
+               [       :LNOT::DEF:choices__dfn
+               GBLL    choices__dfn
+
+; --- choices_useChoices ---
+;
+; On entry:    R0 == 0 to disable use of `Choices', >0 to enable, or <0 to
+;                      read
+;
+; On exit:     R0 == previous setting
+;
+; Use:         This call allows an application to determine whether its
+;              user-configurable resources are looked for in Acorn's
+;              `Choices' directory, or only in the application's directory.
+;
+;              An application would typically make this call after parsing
+;              its command-line options, to allow a Network Manager to
+;              enable the `Choices' support.
+
+               IMPORT  choices_useChoices
+
+; --- choices_find ---
+;
+; On entry:    R0 == pointer to resource filename
+;              R1 == pointer to buffer to build filename in
+;              R2 == flags:
+;                      bit 0 == file will be written to (use Choices$Write)
+;
+; On exit:     R0 == pointer to filename
+;              R1 == pointer to terminating NULL
+;              CS if the file was found, else CC
+;
+; Use:         Locates a user-configurable resource file.  The search order
+;              depends on (a) whether the file will be written (bit 0 of R2)
+;              and (b) whether the use of Acorn's `Choices' system is
+;              enabled.
+;
+;              The search order is as follows:
+;
+;              * Choices:appName.leaf / <Choices$Write>.appName.leaf
+;              * res_find(leaf)
+;
+;              (i.e. it looks in the `Choices' structure first, and if that
+;              fails, it will use res_find).
+
+               IMPORT  choices_find
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/choices/options b/StraySrc/Libraries/Sapphire/sh/choices/options
new file mode 100644 (file)
index 0000000..7f4cefb
--- /dev/null
@@ -0,0 +1,367 @@
+;
+; choices.options.sh
+;
+; Read options from an options chunk
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  options_read
+;  options_write
+;  optType_string
+;  optType_integer
+;  optType_literal
+;  optType_enum
+;  optType_bool
+;  optType_version
+
+               [       :LNOT::DEF:options__dfn
+               GBLL    options__dfn
+
+;+             LIB     sapphire:^.bsh.options
+
+; --- options_read ---
+;
+; On entry:    R0 == chunk file handle
+;              R1 == pointer to a chunk name
+;              R2 == pointer to options definition
+;              R3,R4 specify address of output block
+;
+; On exit:     --
+;
+; Use:         Claims the specified options chunk, and reads the data in
+;              it into a binary block.  Because the output data might be
+;              in a flex block, the two registers R3,R4 which define its
+;              address work as follows:
+;
+;              R3 == address or offset of data
+;              R4 == -1 if R3 is address, else flex anchor address
+
+               IMPORT  options_read
+
+; --- options_write ---
+;
+; On entry:    R0 == terminator character to write, 0 for none, or -1 for
+;                      quoting with 's
+;              R1 == pointer to name to save
+;
+; On exit:     May return an error
+;
+; Use:         Writes out an option name, terminated with the character
+;              given in R0 (which will normally be a space or an `=' sign).
+
+               IMPORT  options_write
+
+; --- optType_string ---
+;
+; Flags:       --
+;
+; Data:                (word) buffer size of string
+;
+; Use:         Handles string data.  The binary representation is a ctrl
+;              terminated string.  The textual representation is a sequence
+;              of characters, which is always output in single quotes,
+;              although this is not necessary for the input.  The string
+;              will be truncated to fit in the buffer during reading.
+
+               IMPORT  optType_string
+
+; --- optType_integer ---
+;
+; Flags:       bit 8 == use given default base
+;
+; Data:                (word) default base, if bit 8 set
+;
+; Use:         Handles integer data.  The binary representation is a 32-
+;              bit integer value.  The textual representation is the normal
+;              RISC OS style of numbers (i.e. the base_value notation is
+;              supported).  Numbers are always output in the default base
+;              given (or in decimal if there is none given).  Numbers
+;              being read may always have a sign; numbers will only be
+;              output with a sign if the default base is decimal.  Uppercase
+;              letters will be used for output, but any case is acceptable
+;              for input.
+;
+;              Special prefixes allowed are `%' for binary and `&' for hex.
+;              Such numbers are always output with these prefixes.
+
+               IMPORT  optType_integer
+
+; --- optType_literal ---
+;
+; Flags:       --
+;
+; Data:                (string) data to write out (*null* terminated)
+;
+; Use:         Reads nothing; leave the name blank.  Writes out the data
+;              literally.  Note that an extra linefeed is added to the
+;              end, so don't overdo it.
+
+               IMPORT  optType_literal
+
+; --- optType_enum ---
+;
+; Flags:       bit 8 == quote output string
+;              bit 9 == don't put an `=' sign in output
+;
+; Data:                See below
+;
+; Use:         The data is a collection of ctrl-terminated strings, itself
+;              terminated by a zero-length entry.  The textual
+;              representation is one of these strings, or an abbreviation
+;              of one.  The binary representation is a word containing the
+;              index into the list.
+
+               IMPORT  optType_enum
+
+; --- optType_bool ---
+;
+; Flags:       bit 8 == make flag active low
+;              bit 9 == use `on'/`off' rather than `true'/`false'; also
+;                      suppresses the `=' sign
+;
+; Data:                (word) bit mask to OR or BIC within word
+;
+; Use:         Handles a boolean option.  It will translate between the
+;              strings `true' or `false' and a bit (or set of bits) within
+;              a word.
+
+               IMPORT  optType_bool
+
+; --- optType_version ---
+;
+; Flags:       --
+;
+; Data:                --
+;
+; Use:         Converts between version number strings (of the form
+;              <int>[.[<digit>[<digit>]]]) and integers.  The version
+;              number is stored multiplied by 100.
+
+               IMPORT  optType_version
+
+               ]
+
+;----- Data structures ------------------------------------------------------
+
+; --- Options definition block ---
+
+               ^       0
+opt_flags      #       4                       ;Flags for this item
+opt_length     #       4                       ;Size of this table entry
+opt_offset     #       4                       ;Offset in block of data
+opt_type       #       4                       ;Address of type handler
+opt_name       #       0                       ;Name of this option
+
+; --- Option block flags ---
+
+optFlag_last   EQU     (1<<0)                  ;This is the last block
+optFlag_ignore EQU     (1<<1)                  ;Don't read this option
+
+; --- Integer type flags ---
+
+intFlag_base   EQU     (1<<8)                  ;Default base specified
+
+; --- Enumeration type flags ---
+
+enumFlag_quote EQU     (1<<8)                  ;Quote the output string
+enumFlag_noEq  EQU     (1<<9)                  ;Don't output an `=' sign
+
+; --- Boolean type flags ---
+
+boolFlag_cpl   EQU     (1<<8)                  ;Flag is complemented
+boolFlag_onOff EQU     (1<<9)                  ;Use `on'/`off' notation
+
+; --- Type handler reason codes ---
+;
+; All enter with:
+;
+;  R0 == reason code
+;  R7 == flags read from table
+;  R8 == address of option name
+;  R9 == address of type-specific data
+; R10 == address of binary option
+
+               ^       0
+optReason_read #       1                       ;Read from option string
+                                               ;R1 == pointer to string
+
+optReason_write        #       1                       ;Write data to xsave file
+
+;----- Macros ---------------------------------------------------------------
+
+               GBLA    opt__f
+               GBLA    opt__c
+opt__c         SETA    0
+               GBLL    opt__p
+opt__p         SETL    {FALSE}
+
+; --- Macro: OPTION ---
+;
+; Arguments:   offset == offset of data into options block
+;              type == name of data type
+;              name == name of option tag
+;
+; Use:         Starts building an entry in the options table.
+
+               MACRO
+$label         OPTION  $offset,$type,$name
+               ALIGN
+
+               [       opt__p
+opt__sz$opt__c EQU     {PC}-opt__a$opt__c
+               ]
+opt__f$opt__c  EQU     opt__f
+opt__c         SETA    opt__c+1
+opt__p         SETL    {TRUE}
+
+$label
+
+opt__f         SETA    0
+opt__a$opt__c
+
+               DCD     opt__f$opt__c
+               DCD     opt__sz$opt__c
+               DCD     $offset
+               DCD     $type
+               DCB     "$name",0
+               ALIGN
+
+               MEND
+
+; --- Macro: OPTFLAG --
+;
+; Arguments:   bit == bit to set
+;
+; Use:         Sets a bit in the flags word for the current option.
+
+               MACRO
+               OPTFLAG $bit
+opt__f         SETA    opt__f :OR: $bit
+               MEND
+
+; --- Macro: OPTEND ---
+;
+; Arguments:   --
+;
+; Use:         Terminates an options block.
+
+               MACRO
+               OPTEND
+               OPTFLAG optFlag_last
+               ALIGN
+               [       opt__c<>0
+opt__sz$opt__c EQU     {PC}-opt__a$opt__c
+               ]
+opt__f$opt__c  EQU     opt__f
+opt__c         SETA    opt__c+1
+opt__p         SETL    {FALSE}
+               MEND
+
+; --- Macro: OPTSTR ---
+;
+; Arguments:   offset == offset into block to write integer
+;              name == tag for option
+;              size == buffer size for string
+;
+; Use:         Adds a `string' option.
+
+               MACRO
+$label         OPTSTR  $offset,$name,$size
+$label         OPTION  $offset,optType_string,$name
+               DCD     $size
+               MEND
+
+; --- Macro: OPTINT ---
+;
+; Arguments:   offset == offset into block to write integer
+;              name == tag for option
+;              base == (optional) default base to use
+;
+; Use:         Adds an `integer' option.
+
+               MACRO
+$label         OPTINT  $offset,$name,$base
+$label         OPTION  $offset,optType_integer,$name
+               [       "$base"<>""
+               OPTFLAG intFlag_base
+               DCD     $base
+               ]
+               MEND
+
+; --- Macro: OPTLIT ---
+;
+; Arguments:   --
+;
+; Use:         Writes out the following text to the options chunk.
+
+               MACRO
+$label         OPTLIT
+$label         OPTION  0,optType_literal,""
+               OPTFLAG optFlag_ignore
+               MEND
+
+; --- Macro: OPTENUM ---
+;
+; Arguments:   offset == offset into block to write integer
+;              name == tag for option
+;
+; Use:         Adds an `enumeration' option.  Follow by null-terminated
+;              list of null-terminated strings.
+
+               MACRO
+$label         OPTENUM $offset,$name
+$label         OPTION  $offset,optType_enum,$name
+               MEND
+
+; --- Macro: OPTBOOL ---
+;
+; Arguments:   offset == offset into block to write flags
+;              name == tag for option
+;              flag == flag bit to set
+;
+; Use:         Adds a `boolean' option.
+
+               MACRO
+$label         OPTBOOL $offset,$name,$flag
+$label         OPTION  $offset,optType_bool,$name
+               DCD     $flag
+               MEND
+
+; --- Macro: OPTVSN ---
+;
+; Arguments:   offset == offset into block to write integer
+;              name == tag for option
+;
+; Use:         Adds a `version number' option.
+
+               MACRO
+$label         OPTVSN  $offset,$name
+$label         OPTION  $offset,optType_version,$name
+               MEND
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/choices/prefs b/StraySrc/Libraries/Sapphire/sh/choices/prefs
new file mode 100644 (file)
index 0000000..ab38e47
--- /dev/null
@@ -0,0 +1,63 @@
+;
+; choices.prefs.sh
+;
+; Management of application's preferences file
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  prefs_find
+;  prefs_init
+
+               [       :LNOT::DEF:prefs__dfn
+               GBLL    prefs__dfn
+
+; --- prefs_find ---
+;
+; On entry:    --
+;
+; On exit:     R0 == chunk handle of loaded preferences file
+;
+; Use:         Returns the chunk handle of the preferences file.  You can
+;              then claim your chunk of options from the preferences file
+;              using options_read.
+
+               IMPORT  prefs_find
+
+; --- prefs_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Loads the application's preferences file.
+
+               IMPORT  prefs_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/chunk b/StraySrc/Libraries/Sapphire/sh/chunk
new file mode 100644 (file)
index 0000000..ab9adc2
--- /dev/null
@@ -0,0 +1,150 @@
+;
+; chunk.sh
+;
+; Loading and management of options chunks
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  chunk_create
+;  chunk_destroy
+;  chunk_claim
+;  chunk_makeBinary
+;  chunk_read
+;  chunk_enum
+;  chunk_save
+
+               [       :LNOT::DEF:chunk__dfn
+               GBLL    chunk__dfn
+
+; --- chunk_create ---
+;
+; On entry:    --
+;
+; On exit:     R0 == chunk file handle
+;              May return an error
+;
+; Use:         Creates a new chunk file structure and returns a handle to
+;              it.
+
+               IMPORT  chunk_create
+
+; --- chunk_destroy ---
+;
+; On entry:    R0 == chunk file handle
+;
+; On exit:     --
+;
+; Use:         Removes a chunk file structure from memory.  Chunk data in
+;              flex blocks is freed; chunk claimers who free flex blocks
+;              should clear the anchors to 0.
+
+               IMPORT  chunk_destroy
+
+; --- chunk_claim ---
+;
+; On entry:    R0 == chunk file handle
+;              R1 == pointer to chunk name
+;              R2 == pointer to saver routine, or 0 for none, or -1 for no
+;                      change
+;              R3 == R10 value to pass to saver
+;              R4 == R12 value to pass to saver
+;
+; On exit:     R1 == chunk handle/anchor
+;              CS if the chunk already existed
+;              May return an error
+;
+; Use:         Claims a chunk, installing a save handler for it.  The chunk
+;              handle returned is actually the address of a flex anchor for
+;              the chunk's data (use flex_size to find the block's size).
+;              If the save handle is 0, the data in the flex block (which
+;              may be modified) is saved directly from the block.  Otherwise
+;              the save routine is expected to save its data, using xsave.
+;
+;              The anchor is followed by 3 unused words -- you can use them
+;              for whatever you want.
+;
+;              Warning: this routine may move flex blocks.
+
+               IMPORT  chunk_claim
+
+; --- chunk_makeBinary ---
+;
+; On entry:    R0 == chunk file handle
+;              R1 == chunk handle
+;
+; On exit:     --
+;
+; Use:         Marks a given chunk as containing binary data.
+
+               IMPORT  chunk_makeBinary
+
+; --- chunk_read ---
+;
+; On entry:    R0 == chunk file handle
+;              R1 == address of a flex anchor
+;
+; On exit:     May return an error
+;
+; Use:         Merges the data contained in the flex block with that already
+;              in the chunk file.  If the chunk file is empty, this is
+;              equivalent to a load.  Data from the flex block is appended
+;              to chunks already loaded where appropriate.
+;
+;              Warning: this routine may move flex blocks.
+
+               IMPORT  chunk_read
+
+; --- chunk_enum ---
+;
+; On entry:    R0 == chunk file handle
+;              R1 == 0 for first call or continuation value
+;
+; On exit:     CC if this isn't over yet, and
+;                R1 == continuation value for next call
+;                R2 == pointer to chunk name
+;              else CS and
+;                R1 == 0
+;                R2 preserved
+;
+; Use:         Allows you to enumerate the chunks in a chunk file structure.
+
+               IMPORT  chunk_enum
+
+; --- chunk_save ---
+;
+; On entry:    R0 == chunk file handle
+;
+; On exit:     May return an error
+;
+; Use:         Saves a chunk file to xsave's current output.
+
+               IMPORT  chunk_save
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/cmdLine b/StraySrc/Libraries/Sapphire/sh/cmdLine
new file mode 100644 (file)
index 0000000..8328424
--- /dev/null
@@ -0,0 +1,79 @@
+;
+; cmdLine.sh
+;
+; Command line parsing
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  cl_next
+
+               [       :LNOT::DEF:cmdLine__dfn
+               GBLL    cmdLine__dfn
+
+; --- cl_next ---
+;
+; On entry:    R0 == pointer to a command line string (ctrl terminated)
+;              R1 == pointer to a buffer (may be equal to R0)
+;
+; On exit:     CS if another word found, and
+;                R0 == updated past next word
+;                R1 preserved, buffer filled with null terminated string
+;                R2 == pointer to terminating null character
+;              else CC and
+;                R0 == pointer to terminating character
+;                R1 preserved, buffer preserved
+;                R2 corrupted
+;
+; Use:         Extracts the next word from a command line string.  If the
+;              string is in a writable buffer, you can set R1 == R0 to
+;              start with.  You can build up a C-like argv array like this:
+;
+;                      ; R0 == pointer to command line in writable buffer
+;
+;                              MOV     R1,R0
+;                              ADR     R3,argv
+;                              MOV     R4,#0
+;                      loop    BL      cl_next
+;                              MOVCC   R1,#0
+;                              STR     R1,[R3],#4
+;                              ADDCS   R4,#0
+;                              BCS     loop
+;
+;                      ; R0-R3 corrupted
+;                      ; R4 == argc
+;
+;              This routine will handle quoted strings, considering them
+;              to be single arguments.  Either type of quote will do,
+;              quote doubling is required to insert quotes in quoted
+;              strings.
+
+               IMPORT  cl_next
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/coRoutine b/StraySrc/Libraries/Sapphire/sh/coRoutine
new file mode 100644 (file)
index 0000000..36d4006
--- /dev/null
@@ -0,0 +1,93 @@
+;
+; coRoutine.sh
+;
+; Basic coroutine handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  coRout_create
+;  coRout_switch
+;  coRout_destroy
+;  coRout_end
+
+               [       :LNOT::DEF:coRoutine__dfn
+               GBLL    coRoutine__dfn
+
+; --- coRout_create ---
+;
+; On entry:    R0 == pointer to coroutine
+;              R1 == R10 value to pass to coroutine
+;              R2 == R12 value to pass to coroutine
+;              R3 == size of stack to pass (0 for default)
+;
+; On exit:     R0 == coroutine handle
+;              May return an error
+;
+; Use:         Creates a new coroutine.  It may be given control using
+;              coRout_switch.  Its registers are on entry:
+;
+;              R0 == its coroutine handle
+;              R10 == value passed to coRout_create in R1
+;              R12 == value passed to coRout_create in R2
+;              R13 == pointer to the stack created for it
+
+               IMPORT  coRout_create
+
+; --- coRout_switch ---
+;
+; On entry:    R0 == coroutine to switch to, or 0 for main
+;
+; On exit:     --
+;
+; Use:         Switches context to another coroutine.
+
+               IMPORT  coRout_switch
+
+; --- coRout_destroy ---
+;
+; On entry:    R0 == coroutine handle to destroy
+;
+; On exit:     --
+;
+; Use:         Destroys a coroutine.
+
+               IMPORT  coRout_destroy
+
+; --- coRout_end ---
+;
+; On entry:    --
+;
+; On exit:     Doesn't.
+;
+; Use:         Terminates the current coroutine.
+
+               IMPORT  coRout_end
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/colSelect b/StraySrc/Libraries/Sapphire/sh/colSelect
new file mode 100644 (file)
index 0000000..6c93c71
--- /dev/null
@@ -0,0 +1,76 @@
+;
+; colSelect.sh
+;
+; The Sapphire Colour Selector dialogue box
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   colSelect
+
+               [       :LNOT::DEF:colSelect__dfn
+               GBLL    colSelect__dfn
+
+; --- colSelect ---
+;
+; On entry:    R0 == address of a colour block
+;              R1 == pointer to routine to call when done
+;              R2 == R10 to call routine with
+;              R3 == R12 to call routine with
+;
+; On exit:     R0 = colour selector handle
+;              May return an error
+;
+; Use:         Displays a colour selector dialogue box.  It allows the user
+;              to edit a colour (understatement....)
+
+               IMPORT  colSelect
+
+;----- The colour selector handler ------------------------------------------
+;
+; The routine you pass to colSelect is entered with R0 as a reason code,
+; and other registers containing values which depend on that.  Reason codes
+; defined are:
+
+               ^       0
+
+csEvent_choice #       1                       ;User has chosen a colour
+                                               ;R1 == pointer to colour blk
+
+csEvent_close  #       1
+
+;----- Data structures ------------------------------------------------------
+
+               ^       0
+col_rgb                #       4                       ;RGB palette entry for colour
+col_model      #       4                       ;Colour model for colour
+col_data       #       4                       ;Colour data for model
+col_size       #       0
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/colourBox b/StraySrc/Libraries/Sapphire/sh/colourBox
new file mode 100644 (file)
index 0000000..633208b
--- /dev/null
@@ -0,0 +1,63 @@
+;
+; colourBox.sh
+;
+; Gives you a nice box from which the user may choose a WIMP colour
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  colourBox
+
+               [       :LNOT::DEF:colourbox__dfn
+               GBLL    colourbox__dfn
+
+; --- colourBox ---
+;
+; On entry:    R0 == pointer to a title string (message tag)
+;              R1 == the current colour in bottom byte, and flags:
+;                      bit 8 == allow transparent colour
+;              R2 == event handler to call
+;              R3 == R10 value to pass to handler
+;              R4 == R12 value to pass to handle
+;
+; On exit:     May return an error
+;
+; Use:         Opens a dialogue box which allows the user to choose
+;              one of the wimp colours.  A transparent colour is supported,
+;              and represented as colour 255.
+
+               IMPORT  colourBox
+
+               ]
+
+;----- Events --------------------------------------------------------------
+
+               ^       0
+cbEvent_select #       1                       ;User selected a colour
+                                               ;R1 == colour selected
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/dbox b/StraySrc/Libraries/Sapphire/sh/dbox
new file mode 100644 (file)
index 0000000..ff50a3f
--- /dev/null
@@ -0,0 +1,542 @@
+;
+; dbox.sh
+;
+; Dialogue box handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  dbox_create
+;  dbox_fromEmbedded
+;  dbox_fromDefn
+;  dbox_destroy
+;  dbox_init
+;  dbox_open
+;  dbox_close
+;  dbox_writePos
+;  dbox_select
+;  dbox_shade
+;  dbox_selectMany
+;  dbox_shadeMany
+;  dbox_isSelected
+;  dbox_radio
+;  dbox_slab
+;  dbox_unslab
+;  dbox_setField
+;  dbox_getField
+;  dbox_eventHandler
+;  dbox_renderTitle
+;  dbox_setEmbeddedTitle
+;  dbox_setClickDrag
+;  dbox_hasTitle
+;  dbox_window
+;  dbox_help
+
+               [       :LNOT::DEF:dbox__dfn
+               GBLL    dbox__dfn
+
+; --- dbox_create ---
+;
+; On entry:    R0 == pointer to dialogue template name
+;
+; On exit:     R0 == dialogue box handle for the dialogue
+;              May return an error
+;
+; Use:         Creates a dialogue box from a template definition.
+
+               IMPORT  dbox_create
+
+; --- dbox_fromEmbedded ---
+;
+; On entry:    R0 == pointer to an embedded template
+;
+; On exit:     R0 == dialogue box handle
+;              May return an error
+;
+; Use:         Creates a dialogue box from an embedded template definition.
+
+               IMPORT  dbox_fromEmbedded
+
+; --- dbox_fromDefn ---
+;
+; On entry:    R0 == pointer to a window definition
+;
+; On exit:     R0 == dialogue box handle for the dialogue
+;              May return an error
+;
+; Use:         Creates a dialogue box from an immediate window definition,
+;              rather than a template.  There are several things you need
+;              to be aware of when you use this call to create a dialogue
+;              box:
+;
+;              * The window definition is not copied, but used directly
+;                for the duration the dialogue box exists.  It must
+;                not move for this duration.  When the dialogue is
+;                destroyed, you can release the memory for the definition,
+;                although this is your responsibility.
+;
+;              * The indirected data is not copied either, so you'll have
+;                to copy it yourself if you want multiple dialogues from
+;                the same window definition.
+;
+;              * The window definition and the indirected data must both
+;                be writable.
+
+               IMPORT  dbox_fromDefn
+
+; --- dbox_destroy ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Destroys a dialogue box, freeing all the memory it took
+;              up etc.
+
+               IMPORT  dbox_destroy
+
+; --- dbox_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the dbox system.
+
+               IMPORT  dbox_init
+
+; --- dbox_open ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == how to open the dialogue box
+;              Other registers depend on R1, and are described at the end
+;              of this header file
+;
+; On exit:     --
+;
+; Use:         Displays the dialogue box on the screen in the given manner.
+
+               IMPORT  dbox_open
+
+; --- dbox_close ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Closes a dialogue box, by clearing the current menu if
+;              necessary.
+
+               IMPORT  dbox_close
+
+; --- dbox_writePos ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Saves the dialogue's current position so that it will be
+;              opened here the next time it is created.  If the dialogue
+;              box was created from a template, the template is updated.
+;              Otherwise, the new state is written back to the definition
+;              supplied to dbox_fromDefn.
+
+               IMPORT  dbox_writePos
+
+; --- dbox_select ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number
+;              R2 == 0 to deselect the icon, 1 to select it, 2 to toggle
+;                    its current selected state
+;
+; On exit:     --
+;
+; Use:         Selects or deselects the specified icon in the Acorn sense
+;              (i.e. by flipping its selected bit).  The state is only
+;              changed if required, to reduce flicker.
+
+               IMPORT  dbox_select
+
+; --- dbox_shade ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number
+;              R2 == 0 to unshade the icon, 1 to shade it, 2 to toggle its
+;                    current shaded state
+;
+; On exit:     --
+;
+; Use:         Makes the icon look dimmer, to indicate that it is not
+;              available.  It uses its own shading algorithms, rather than
+;              the WindowManager's, so there are some things you must watch
+;              out for:
+;
+;              * Don't use any other method of shading icons
+;
+;              * Don't assume that a shaded icon isn't going to give you
+;                events.  At the user level, this should have been tidied
+;                up, but at the Sapphire level, it's still a problem.
+;                There is a routine in winUtils which will tell you if an
+;                icon is shaded.
+;
+;              This routine has been written so that it only flickers icons
+;              when they actually need it.
+
+               IMPORT  dbox_shade
+
+; --- dbox_selectMany ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to icon handle list, -1 terminated
+;              R2 == select action (0 == unselect, 1 == select, 2 == toggle)
+;
+; On exit:     --
+;
+; Use:         Changes the select state of a group of icons.
+
+               IMPORT  dbox_selectMany
+
+; --- dbox_shadeMany ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to icon handle list, -1 terminated
+;              R2 == shade action (0 == unshade, 1 == shade, 2 == toggle)
+;
+; On exit:     --
+;
+; Use:         Changes the shade state of a group of icons.
+
+               IMPORT  dbox_shadeMany
+
+; --- dbox_isSelected ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number
+;
+; On exit:     CS if the icon is selected, CC otherwise
+;
+; Use:         Returns whether an icon is currently selected.
+
+               IMPORT  dbox_isSelected
+
+; --- dbox_radio ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon handle
+;
+; On exit:     --
+;
+; Use:         Checks to see if the icon is a radio button as defined by
+;              Sapphire, i.e. button type 3 (debounced) and non-zero ESG.
+;              If it is, it selects it, and deselects all other icons with
+;              this ESG.
+
+               IMPORT  dbox_radio
+
+; --- dbox_slab ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon handle
+;
+; On exit:     May return an error
+;
+; Use:         Slabs an icon in properly, to give visual feedback when you
+;              click it.
+
+               IMPORT  dbox_slab
+
+; --- dbox_unslab ---
+;
+; On entry:    --
+;
+; On exit:     CS if there are no more slabbed icons after this one, CC
+;              if there are more left.
+;
+; Use:         Unslabs an icon slabbed with dbox_slab.  Icons are unslabbed
+;              in reverse order to that in which they were slabbed.  The
+;              carry flag is returned as an indication of whether there
+;              are any more icons left in the list -- you can unslab all
+;              icons in one go by doing:
+;
+;                              BL      dbox_unslab
+;                              SUBCC   PC,PC,#12       ;Avoids a label!
+;
+;              It is recommended that, if you are going to close a window,
+;              you unslab icons within it *after* you close, but before you
+;              actually destroy it, e.g.
+;
+;                              LDR     R0,my_dbox
+;                              BL      dbox_close
+;                              BL      dbox_unslab
+;                              BL      dbox_destroy
+
+               IMPORT  dbox_unslab
+
+; --- dbox_setField ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number to write to (may be -1 for title)
+;                    flags in top byte if not -1:
+;                      dbFlag_dots (bit 31) == add `...' if text overflows
+;              R2 == pointer to string to use
+;
+; On exit:     --
+;
+; Use:         Writes the string specified into the indirection buffer
+;              for the given icon.  If the icon is not indirected, an
+;              error is generated.  If the indirected buffer is too small,
+;              the string is shortened by chopping off the beginning or
+;              the end, according to the setting of the icon's right
+;              justify flag.
+;
+;              The icon is only flickered if the text has actually changed.
+;              The caret is moved correctly if it is within the icon to
+;              prevent it `falling off' the end and deleting the validation
+;              string, or being positioned incorrectly in centred icons if
+;              the length changes.
+;
+;              Note that this routine requires a string to already be in
+;              the buffer, and doesn't perform any substitution or other
+;              transformations.  This helps to prevent buffer full errors
+;              and similar problems.
+
+               IMPORT  dbox_setField
+
+; --- dbox_getField ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number to interrogate
+;
+; On exit:     R0, R1 preserved
+;              R2 == pointer to the icon text
+;
+; Use:         Returns a pointer to the text associated with an icon.
+;              Note that if the icon is *not* indirected, the text will
+;              be copied into the scratchpad.  Otherwise you get a pointer
+;              to the actual indirected data.  You shouldn't write to the
+;              string returned at all -- dbox_setField is specially
+;              designed to do that sort of thing very well (i.e. not
+;              flickering the text unless it has to, truncating if it's too
+;              long, and handling the caret correctly).  You *are* allowed
+;              to zero terminate the string if you want to, though.
+;
+;              Despite all the PRM's assurances to the contrary, chances
+;              are the text will be terminated by some weird control char,
+;              so you'll have to handle this, and not just assume it's
+;              going to be null-terminated.
+;
+;              Note: The indirected case is immensely quick -- just load a
+;              pointer.  The non-indirected case has been optimised as much
+;              as possible.
+
+               IMPORT  dbox_getField
+
+; --- dbox_eventHandler ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to handler routine
+;              R2 == value to pass to handler in R10
+;              R3 == value to pass to handler in R12
+;
+; On exit:     R0 preserved
+;              R1 == pointer to old handler
+;              R2 == old R10 value
+;              R3 == old R12 value
+;
+; Use:         Sets up an event handler for a dialogue box, and returns
+;              the previous one.  If the pointer to handler is 0, there is
+;              no dialogue box event handler.
+
+               IMPORT  dbox_eventHandler
+
+; --- dbox_renderTitle ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to redraw block
+;
+; On exit:     --
+;
+; Use:         Renders a dialogue box's embedded title if there is one.
+
+               IMPORT  dbox_renderTitle
+
+; --- dbox_setEmbeddedTitle ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon which should contain the embedded title
+;
+; On exit:     --
+;
+; Use:         Declares a given dialogue box as requiring an embedded title
+;              (rather than the one the WindowManager put on).
+
+               IMPORT  dbox_setEmbeddedTitle
+
+; --- dbox_setClickDrag ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Sets a given dialogue box so that the user can move it by
+;              dragging from any part of the window, not just the title
+;              bar.
+
+               IMPORT  dbox_setClickDrag
+
+; --- dbox_hasTitle ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     CS if the dialogue box has a title bar, CC if not
+;
+; Use:         Informs the caller whether the dialogue box has a title bar.
+;              This is mainly useful for other library sections which
+;              conditionally add in embedded titles etc.
+
+               IMPORT  dbox_hasTitle
+
+; --- dbox_window ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     R0 == the dialogue box's window handle
+;
+; Use:         Returns the Wimp window handle associated with a dialogue
+;              box.  This may be useful if you want to perform lowlevel
+;              Wimp operation on it, or to subclass it using win.
+
+               IMPORT  dbox_window
+
+; --- dbox_help ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Adds a help line to the current help message, read by
+;              scanning the icon to which the help was sent for an `H'
+;              validation string.
+
+               IMPORT  dbox_help
+
+;----- Useful constants -----------------------------------------------------
+
+; --- Ways of opening dialogue boxes ---
+
+               ^       0
+dbOpen_current #       1                       ;In its current position
+dbOpen_centre  #       1                       ;Centred on the screen
+dbOpen_pointer #       1                       ;Centred over the pointer
+dbOpen_givenY  #       1                       ;At a given height on screen
+                                               ;  R2 == y coordinate to open
+dbOpen_givenXY #       1                       ;At a given position
+                                               ;  R2 == x coordinate
+                                               ;  R3 == y coordinate
+
+dbOpen_trans   EQU     &00                     ;Make the dbox transient
+dbOpen_persist EQU     &80                     ;Make the dbox persistent
+dbOpen_nonSub  EQU     &40                     ;Don't open as a submenu
+
+; --- Dialogue box event codes ---
+
+dbEvent_close  EQU     -2                      ;The user closed the dialogue
+                                               ;C flag ignored on exit
+
+dbEvent_help   EQU     -3                      ;The user wants some help
+                                               ;R1 == icon number
+                                               ;C flag ignored on exit
+
+dbEvent_OK     EQU     -4                      ;The user clicked OK
+                                               ;R1 == mouse button status
+                                               ;C flag ignored on exit
+
+dbEvent_cancel EQU     -5                      ;The user clicked Cancel
+                                               ;R1 == mouse button status
+                                               ;C flag ignored on exit
+
+dbEvent_redraw EQU     -6                      ;Redraw a single rectangle
+                                               ;R1 == pointer to redraw blk
+                                               ;R2,R3 == coords of origin
+                                               ;CS => don't do default draw
+
+dbEvent_menu   EQU     -7                      ;User clicked Menu button
+                                               ;R1 == icon handle clicked
+                                               ;C flag ignored on exit
+
+dbEvent_drag   EQU     -8                      ;User dragged an icon
+                                               ;R1 == mouse button status
+                                               ;R2 == icon handle dragged
+                                               ;C flag ignored on exit
+
+dbEvent_save   EQU     -9                      ;User wants to import data
+                                               ;R1 == icon handle dropped on
+                                               ;R2 == filetype of data
+                                               ;R3 == pointer to filename
+                                               ;R4 == estimated file size
+                                               ;C flag ignored on exit
+
+dbEvent_load   EQU     -10                     ;User wants to load data
+                                               ;R1 == icon handle dropped on
+                                               ;R2 == filetype of data
+                                               ;R3 == pointer to filename
+                                               ;R4 == estimated file size
+                                               ;C flag ignored on exit
+
+dbEvent_key    EQU     -11                     ;User pressed a key
+                                               ;R1 == key code received
+                                               ;R2 == icon handle with caret
+                                               ;CC => unknown keypress
+                                               ;Key code has been translated
+
+dbEvent_hint   EQU     -12                     ;Received a hint message
+                                               ;R2 == pointer to hint string
+
+dbEvent_enter  EQU     -13                     ;Pointer has entered window
+
+dbEvent_leave  EQU     -14                     ;Pointer has left window
+
+dbEvent_lifeCycle EQU  -15                     ;Interesting points in cycle
+                                               ;R1 == life cycle code
+
+; --- Life cycle codes ---
+
+               ^       0
+dblc_create    #       1                       ;Creation (used by dbx)
+dblc_open      #       1                       ;Opening
+dblc_close     #       1                       ;Closing
+dblc_destroy   #       1                       ;Destruction
+
+; --- Other values ---
+
+dbFlag_dots    EQU     (1<<31)                 ;Add dots if text overflows
+                                               ;  in dbox_setField
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/dbx/_dbxMacs b/StraySrc/Libraries/Sapphire/sh/dbx/_dbxMacs
new file mode 100644 (file)
index 0000000..412c45c
--- /dev/null
@@ -0,0 +1,52 @@
+;
+; _dbxMacs.sh
+;
+; Macros for DBX controls
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Macros provided:
+;
+;   DBXWS
+
+; --- Macro; DBXWS ---
+;
+; Arguments:   addr == address of workspace offset
+;
+; Use:         Creates the workspace-location entry in the dbx control
+;              table, working out the correct R11 offset.
+
+               MACRO
+               DBXWS   $addr
+
+               IMPORT  |__sph_workoff|,WEAK
+
+               DCD     $addr
+               DCD     |__sph_workoff|+4
+
+               MEND
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/dbx/arrow b/StraySrc/Libraries/Sapphire/sh/dbx/arrow
new file mode 100644 (file)
index 0000000..ab64afe
--- /dev/null
@@ -0,0 +1,76 @@
+;
+; dbx.arrow.sh
+;
+; Implementation of arrow icons as dbx controls
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  arrow
+;
+; Macros provided:
+;
+;   ARROW
+
+               GET     sapphire:dbx.dbx
+
+               [       :LNOT::DEF:arrow__dfn
+               GBLL    arrow__dfn
+
+; --- arrow ---
+;
+; Control data:        +0 == increment when clicked with Select
+;              +4
+;
+; Workspace:   --
+;
+; Flags:       --
+;
+; Use:         Control type for an arrow button.
+
+               IMPORT  arrow
+
+;----- Macros and symbols ---------------------------------------------------
+
+               MACRO
+$label         ARROW   $icon,$inc
+
+$label         CONTROL $icon,arrow,,0
+               DCD     $inc
+               ECTRL
+
+               MEND
+
+; --- Arrow event codes ---
+
+arrow_event    EQU     &80000002               ;Click on an arrow button
+                                               ;R1 == icon handle
+                                               ;R2 == increment value or 0
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/dbx/colourPot b/StraySrc/Libraries/Sapphire/sh/dbx/colourPot
new file mode 100644 (file)
index 0000000..c056e02
--- /dev/null
@@ -0,0 +1,83 @@
+;
+; colourPot.sh
+;
+; dbx control for selecting Wimp colours
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Controls provided:
+;
+;   colourPot
+;
+; Macros provided:
+;
+;   COLPOT
+
+               GET     sapphire:dbx.dbx
+
+               [       :LNOT::DEF:colourPot__dfn
+               GBLL    colourPot__dfn
+
+; --- colourPot ---
+;
+; Control data:        +0 == null terminated title string, or empty for default
+;              +n
+;
+; Workspace:   +0 == current colour selected
+;              +1
+;
+; Flags:       bit 8 == allow transparent
+;
+; Use:         Provides a `colour button' which allows the user to choose
+;              a Wimp colour.  Transparent is represented by 255.
+
+               IMPORT  colourPot
+
+;----- Macros and constants -------------------------------------------------
+
+               MACRO
+$label         COLPOT  $icon,$baseReg,$data,$flags,$title
+
+$label         CONTROL $icon,colourPot,$baseReg,$flags,$data
+               DCB     "$title",0
+               ALIGN
+               ECTRL
+
+               MEND
+
+; --- Flags ---
+
+cpFlag_trans   EQU     (1<<8)                  ;Allow transparent colour
+
+; --- Event codes ---
+
+colourPot_event        EQU     &80000006               ;User has changed the colour
+                                               ;R1 == icon handle
+                                               ;R2 == new colour
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/dbx/dbx b/StraySrc/Libraries/Sapphire/sh/dbx/dbx
new file mode 100644 (file)
index 0000000..adf784f
--- /dev/null
@@ -0,0 +1,270 @@
+;
+; dbx.dbx.sh
+;
+; Managing dialogue box control types
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  dbx_declare
+;  dbx_sendEvent
+;  dbx_findData
+;  dbx_controlBBox
+;  dbx_update
+;  dbx_qUpdate
+;
+; Macros provided:
+;
+;   CONTROL
+;   ECTRL
+;   DBXEND
+
+               [       :LNOT::DEF:dbx__dfn
+               GBLL    dbx__dfn
+
+;+             LIB     sapphire:^.bsh.dbx
+
+; --- dbx_declare ---
+;
+; On entry:    R0 == dialogue box handle from dbox
+;              R1 == pointer to dialogue box definition block
+;
+; On exit:     --
+;
+; Use:         Declares a dialogue box to be dbx-managed, and declares the
+;              control types of all its controls.
+
+               IMPORT  dbx_declare
+
+; --- dbx_sendEvent ---
+;
+; On entry:    R0 == event code to send
+;              R1-R7 == depend on the event code
+;              R10 == dialogue box handle
+;
+; On exit:     C flag as set by event handler
+;
+; Use:         Sends an event to the specified dialogue box.  This is
+;              intended to be used by control handlers, hence the unusual
+;              placing of the dialogue handle in R10.
+
+               IMPORT  dbx_sendEvent
+
+; --- dbx_findData ---
+;
+; On entry:    R0 == icon handle
+;              R10 == dialogue box handle
+;
+; On exit:     If found, CS and
+;                R8 == pointer to writable control data
+;                R9 == pointer to static control data
+;              else CC and
+;                R8, R9 corrupted
+;
+; Use:         Allows a control to find its data when called by client
+;              code.
+
+               IMPORT  dbx_findData
+
+; --- dbx_controlBBox ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == control icon number
+;
+; On exit:     R0,R1 preserved
+;              R2-R5 == inclusive screen coordinates of icon bounding box
+;
+; Use:         Calculates the position *on the screen* of the given control
+;              icon, and returns it to you as a set of four inclusive
+;              coordinates (*not* inclusive-exclusve as the WIMP tends to
+;              return to you)
+
+               IMPORT  dbx_controlBBox
+
+; --- dbx_update ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number of control to update
+;
+; On exit:     --
+;
+; Use:         Redraws the specified control immediately.  If the control
+;              does not redraw itself, this call does nothing.
+
+               IMPORT  dbx_update
+
+; --- dbx_qUpdate ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number of control to update
+;
+; On exit:     --
+;
+; Use:         Makes a control quickly update itself in whichever way it
+;              needs to in order to be perfect again.  It is anticipated
+;              that this is used to update EORed areas of the control.
+
+               IMPORT  dbx_qUpdate
+
+;----- Creating dialogue definitions ----------------------------------------
+
+; --- Some internal definitions ---
+
+               GBLA    dbx__c
+dbx__c         SETA    0
+
+; --- Macro: CONTROL ---
+;
+; Arguments:   icon == icon number for control
+;              control == pointer to control definition
+;              baseReg == base register for data
+;              flags == other flags for this control
+;              data == offset within data area
+;
+; Use:         Creates a control header block.  Intended to be used by
+;              specifiec control defining macros.
+
+               MACRO
+$label         CONTROL $icon,$control,$baseReg,$flags,$data
+
+dbx__c         SETA    dbx__c+1
+
+               ALIGN
+$label
+dbx__s$dbx__c
+
+               LCLA    ctf
+ctf            SETA    $flags
+
+               DCD     $icon
+               DCD     $control
+
+               [ "$baseReg" = "R10"
+ctf            SETA    ctf :OR: dbxFlag_dataR10
+               ]
+
+               [ "$baseReg" = "R12"
+ctf            SETA    ctf :OR: dbxFlag_dataR12
+               ]
+
+               DCD     ctf
+               DCD     dbx__sz$dbx__c
+
+               [ ctf :AND: 3 <> 0
+               DCD     $data
+               ]
+
+               MEND
+
+; --- Macro: ECTRL ---
+;
+; Arguments:   --
+;
+; Use:         Ends a control definition
+
+               MACRO
+               ECTRL
+
+               ALIGN
+dbx__sz$dbx__c EQU     {PC}-dbx__s$dbx__c
+
+               MEND
+
+; --- Macro: DBXEND ---
+;
+; Arguments:   --
+;
+; Use:         Terminates a list of control entries for a dialogue box.
+
+               MACRO
+               DBXEND
+               DCD     -1
+               MEND
+
+;----- Standard dbx flags ---------------------------------------------------
+;
+; Individual controls may have their own flags starting at bit 8.
+
+dbxFlag_dataR10        EQU     (1<<0)                  ;Has R10-relative data
+dbxFlag_dataR12        EQU     (1<<1)                  ;Has R12-relative data
+
+;----- dbx event codes ------------------------------------------------------
+;
+; All events have:
+;
+;              R0 == event code
+;              R1 == icon handle of control
+;              R8 == pointer to control workspace
+;              R9 == pointer to control definition body
+;              R10 == dialogue box handle
+;              R12 == control handler workspace
+
+               ^       0
+dbxEvent_click #       1                       ;Mouse click on the control
+                                               ;R2 == button status
+
+dbxEvent_redraw        #       1                       ;Redraw or update the control
+                                               ;R2-R5 == coords of control
+                                               ;R6 == ptr to graphics window
+
+dbxEvent_key   #       1                       ;Key pressed
+                                               ;R2 == key code
+
+dbxEvent_drop  #       1                       ;File dropped on control
+                                               ;R2 == filetype
+                                               ;R3 == pointer to filename
+                                               ;R4 == estimated file size
+                                               ;R5 == subreason code
+
+dbxEvent_help  #       1                       ;Help request for control
+
+dbxEvent_update #      1                       ;Quick update request
+                                               ;R2-R5 == coords of control
+                                               ;R6 == ptr to graphics window
+
+dbxEvent_lifeCycle #   1                       ;Dialogue state change
+                                               ;R1 == dblc lifecycle code
+
+; --- dbxEvent_drop subreason codes ---
+
+               ^       0
+dbxDrop_load   #       1
+dbxDrop_save   #       1
+
+; --- dbx event masks ---
+
+dbxMask_click  EQU     (1<<dbxEvent_click)
+dbxMask_redraw EQU     (1<<dbxEvent_redraw)
+dbxMask_key    EQU     (1<<dbxEvent_key)
+dbxMask_drop   EQU     (1<<dbxEvent_drop)
+dbxMask_help   EQU     (1<<dbxEvent_help)
+dbxMask_update EQU     (1<<dbxEvent_update)
+dbxMask_lifeCycle EQU  (1<<dbxEvent_lifeCycle)
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/dbx/fileIcon b/StraySrc/Libraries/Sapphire/sh/dbx/fileIcon
new file mode 100644 (file)
index 0000000..d079277
--- /dev/null
@@ -0,0 +1,114 @@
+;
+; dbx.fileIcon.sh
+;
+; Draggable file icons as dbx controls
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  fileIcon_sprName
+;  fileIcon_reAppear
+;  fileIcon_closed
+;
+; Controls provided:
+;
+;   fileIcon
+;
+; Macros provided:
+;
+;   FILEICN
+
+               GET     sapphire:dbx.dbx
+
+               [       :LNOT::DEF:fileIcon__dfn
+               GBLL    fileIcon__dfn
+
+; --- fileIcon_sprName ---
+;
+; On entry:    R0 == filetype
+;              R1 == pointer to filename
+;
+; On exit:     R0 == pointer to sprite name to use
+;
+; Use:         Works out the sprite name to use for the given filetype and
+;              name pair.
+
+               IMPORT  fileIcon_sprName
+
+; --- fileIcon_reAppear ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Makes the currently vanished file icon reappear.
+
+               IMPORT  fileIcon_reAppear
+
+; --- fileIcon_closed ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Informs fileIcon that the specified dialogue box has closed.
+
+               IMPORT  fileIcon_closed
+
+; --- fileIcon ---
+;
+; Control data:        +0
+;
+; Workspace:   +0 == filetype of object to display
+;              +4 == address of filename
+;              +8
+;
+; Flags:       --
+;
+; Use:         Control which displays a filetype icon, and allows it to
+;              be dragged.
+
+               IMPORT  fileIcon
+
+;----- Macros and symbols ---------------------------------------------------
+
+               MACRO
+$label         FILEICN $icon,$baseReg,$data
+
+$label         CONTROL $icon,fileIcon,$baseReg,0,$data
+               ECTRL
+
+               MEND
+
+fIcon_event    EQU     &80000003               ;File icon dropped
+                                               ;R1 == icon handle
+                                               ;R2 == dest window handle
+                                               ;R3 == dest icon handle
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/dbx/numWrite b/StraySrc/Libraries/Sapphire/sh/dbx/numWrite
new file mode 100644 (file)
index 0000000..1621dcb
--- /dev/null
@@ -0,0 +1,146 @@
+;
+; dbx.numWrite.sh
+;
+; Numeric writable icons
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  numWrite_set
+;  numWrite_read
+;  numWrite_bump
+;
+; Controls provided:
+;
+;   numWrite
+;
+; Macros provided:
+;
+;   NUMWRT
+
+               GET     sapphire:dbx.dbx
+
+               [       :LNOT::DEF:numWrite__dfn
+               GBLL    numWrite__dfn
+
+; --- numWrite ---
+;
+; Control data:        +0 == minimum value
+;              +4 == maximum value
+;              +8
+;
+; Workspace:   +0
+;
+; Flags:       --
+;
+; Use:         Control type for numeric writable icons.
+
+               IMPORT  numWrite
+
+; --- numWrite ---
+;
+; Control data:        +0 == minimum value
+;              +4 == maximum value
+;              +8
+;
+; Workspace:   +0
+;
+; Flags:       --
+;
+; Use:         Control type for numeric writable icons.
+
+               IMPORT  numWrite
+
+; --- numWrite_set ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon number within dialogue
+;              R2 == value to set in the icon
+;
+; On exit:     R2 == value actually set
+;
+; Use:         Writes the specified numeric value into the given writable
+;              icon.  The icon must be a dbx control with numWrite type
+;              for this to work.
+
+               IMPORT  numWrite_set
+
+; --- numWrite_read ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon handle
+;
+; On exit:     CC if icon contains a valid integer, and
+;                R2 == value shown in the icon
+;              else CS and
+;                R2 == 0
+;
+; Use:         Reads the numeric value within the icon specifed.
+
+               IMPORT  numWrite_read
+
+; --- numWrite_bump ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon handle
+;              R2 == increment to apply to it
+;
+; On exit:     R2 == updated value in the icon
+;
+; Use:         Adjusts the value in a writable icon by a given increment.
+
+               IMPORT  numWrite_bump
+
+; --- Macro: NUMWRT ---
+;
+; Arguments:   icon == icon handle of control
+;              min == minimum representable value
+;              max == maximum representable value
+;
+; Use:         Inserts a definition of a numerical writable icon into
+;              a dbx dialogue definition table.
+
+               MACRO
+$label         NUMWRT  $icon,$min,$max
+$label         CONTROL $icon,numWrite,,0
+               DCD     $min
+               DCD     $max
+               ECTRL
+               MEND
+
+;----- Constants ------------------------------------------------------------
+
+numWrite_event EQU     &80000004               ;R1 == icon number changed
+                                               ;R2 == subreason code
+                                               ;R3 == new value of icon
+
+numWrite_change        EQU     0                       ;Subreason -- number changed
+numWrite_move  EQU     1                       ;Subreason -- cursor moved
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/dbx/slider b/StraySrc/Libraries/Sapphire/sh/dbx/slider
new file mode 100644 (file)
index 0000000..cc32ba7
--- /dev/null
@@ -0,0 +1,94 @@
+;
+; dbx.slider.sh
+;
+; Implementation of sliders as a dbx control
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Controls provided:
+;
+;  slider
+;
+; Macros provided:
+;
+;   SLIDER
+
+               GET     sapphire:dbx.dbx
+
+               [       :LNOT::DEF:slider__dfn
+               GBLL    slider__dfn
+
+; --- slider ---
+;
+; Control data:        +0 == slider colour (if flags bit 9 clear)
+;              +1 == background colour
+;              +2 == separator colour
+;              +3 == reserved
+;              +4 == maximum slider value
+;              +8
+;
+; Workspace:   +0 == current slider value
+;              +4 == slider colour (if flags bit 9 set)
+;              +5 == reserved, must be 0
+;              +8
+;
+; Flags:       Bit 8 == slider is horizontal if clear, vertical is set
+;
+; Use:         Control type for a slider.
+
+               IMPORT  slider
+
+;----- Macros and symbols ---------------------------------------------------
+
+               MACRO
+$label         SLIDER  $icon,$baseReg,$data,$flags,$slidC,$backC,$sepC,$max
+
+$label         CONTROL $icon,slider,$baseReg,$flags,$data
+               DCB     $slidC,$backC,$sepC,0
+               DCD     $max
+               ECTRL
+
+               MEND
+
+; --- Direction flags ---
+
+slFlag_vertical        EQU     (1<<8)
+slFlag_horizontal EQU  0
+slFlag_colData EQU     (1<<9)
+
+; --- Slider event codes ---
+
+slider_event   EQU     &80000001               ;Something happened to slider
+                                               ;R1 == subreason code
+                                               ;R2 == icon handle
+                                               ;R3 == new value of slider
+
+slider_sliding EQU     0
+slider_slid    EQU     1
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/dbx/stringSet b/StraySrc/Libraries/Sapphire/sh/dbx/stringSet
new file mode 100644 (file)
index 0000000..bda2ba1
--- /dev/null
@@ -0,0 +1,94 @@
+;
+; stringSet.sh
+;
+; String set dialogue box control
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  stringSet_setValue
+;
+; Controls provided:
+;
+;  stringSet
+;
+; Macros provided:
+;
+;   STRSET
+
+               GET     sapphire:dbx.dbx
+
+               [       :LNOT::DEF:stringSet__dfn
+               GBLL    stringSet__dfn
+
+; --- stringSet ---
+;
+; Control data:        +0 == address of menu definition
+;              +4 == address of string table
+;              +8 == icon number in which to write string
+;              +12
+;
+; Workspace:   +0 == current value of radio selection
+;              +4
+;
+; Flags:       --
+;
+; Use:         Provides handling for a `menu button' -- when clicked, a
+;              menu of possible values appears, from which the user may
+;              choose an entry.  The chosen string is copied to the icon.
+
+               IMPORT  stringSet
+
+; --- stringSet_setValue ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == icon handle
+;
+; On exit:     --
+;
+; Use:         Sets the contents of the display area attached to a string
+;              set control from the current state of the control.
+
+               IMPORT  stringSet_setValue
+
+;----- Macros and symbols ---------------------------------------------------
+
+stringSet_event        EQU     &80000005               ;Value of stringset changed
+                                               ;R1 == icon number of
+
+               MACRO
+$label         STRSET  $icon,$base,$data,$menu,$strings,$display
+
+$label         CONTROL $icon,stringSet,$base,0,$data
+               DCD     $menu,$strings,$display
+               ECTRL
+
+               MEND
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/defHandler b/StraySrc/Libraries/Sapphire/sh/defHandler
new file mode 100644 (file)
index 0000000..d201258
--- /dev/null
@@ -0,0 +1,54 @@
+;
+; defHandler.sh
+;
+; Default event handler
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  defHandler
+
+               [       :LNOT::DEF:defHandler__dfn
+               GBLL    defHandler__dfn
+
+; --- defHandler ---
+;
+; On entry:    R0 == Wimp_Poll reason code
+;              R1 == pointer to Wimp_Poll event block
+;
+; On exit:     CS if we handled the event, CC otherwise.
+;
+; Use:         Handles events no-one else is interested in.  It's basically
+;              a catch-all for things that probably should have been
+;              handled elsewhere, and does some useful tidying up
+;              operations (like calling Wimp_ProcessKey on key events).
+
+               IMPORT  defHandler
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/divide b/StraySrc/Libraries/Sapphire/sh/divide
new file mode 100644 (file)
index 0000000..fed6848
--- /dev/null
@@ -0,0 +1,130 @@
+;
+; divide.sh
+;
+; Various routines of a division-related nature (MDW/TMA)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  divide
+;  div_unsigned
+;  div10
+;  div_round
+;  div_u64x32
+
+               [       :LNOT::DEF:divide__dfn
+               GBLL    divide__dfn
+
+; --- divide ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         A standard divide routine.  Fairly speedy, hopefully.
+;              The results are always such that
+;
+;                      |quotient| <= |(divisor/dividend)|,
+;
+;                      |remainder| < |divisor|
+;
+;              and
+;
+;                      quotient * divisor + remainder == dividend
+
+               IMPORT  divide
+
+; --- div_unsigned ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         As for divide, except that it considers its operands to be
+;              unsigned.
+
+               IMPORT  div_unsigned
+
+; --- div10 ---
+;
+; On entry:    R0 == integer to divide
+;
+; On exit:     R0 == quotient after division by 10
+;              R1 == remainder after division by 10
+;
+; Use:         Divides an integer very quickly by 10.
+;
+; [Generated by Straylight divc]
+
+               IMPORT  div10
+
+; --- div_round ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+;
+; On exit:     R0 == quotient, rounded to nearest integer
+;              R1 == remainder
+;
+; Use:         Calculates a rounded-to-nearest quotient, rather than one
+;              rounded towards zero, which is what divide returns you.
+;
+;              The remainder is fiddled during this process, so that the
+;              properties
+;
+;                      quotient * divisor + remainder == dividend
+;
+;              and
+;
+;                      |remainder| < |divisor|
+;
+;              still hold (so the remainder's sign may well change).
+
+               IMPORT  div_round
+
+; --- div_u64x32 ---
+;
+; On entry:    R0,R1 == dividend (high word in R1)
+;              R2 == divisor
+;
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; Use:         Divides a 64-bit unsigned value by a 32-bit unsigned value
+;              yielding 32-bit unsigned quotient and remainder.  If there
+;              are more than 32 bits of quotient, the return values are
+;              undefined.
+
+               IMPORT  div_u64x32
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/drag b/StraySrc/Libraries/Sapphire/sh/drag
new file mode 100644 (file)
index 0000000..e1a3248
--- /dev/null
@@ -0,0 +1,178 @@
+;
+; drag.sh
+;
+; Support code for dragging operations
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  drag_start
+;  drag_scroll
+;  drag_setDash
+;  drag_cancel
+;  drag_redraw
+;  drag_eorColour
+
+               [       :LNOT::DEF:drag__dfn
+               GBLL    drag__dfn
+
+; --- drag_start ---
+;
+; On entry:    R0 == window containing the drag
+;              R1 == flags word (see flags below)
+;              R2 == pointer to drag routine
+;              R3 == magic number to pass in R9
+;              R4 == value to pass to routine in R10
+;              R5 == value to pass to routine in R12
+;
+; On exit:     --
+;
+; Use:         Starts a drag operation.  Any outstanding drag operation
+;              is cancelled on the assumption that someone stole our
+;              UserDragBox event.
+
+               IMPORT  drag_start
+
+; --- drag_scroll ---
+;
+; On entry:    R1 == pointer to window state block
+;
+; On exit:     R2,R3 == new scroll positions to set
+;              R14 == R1+20 (pointer to scroll offsets)
+;
+; Use:         Works out the scroll positions which should be set to auto-
+;              scroll the window.  The algorithm is simple: the window is
+;              scrolled so that the point beneath the mouse pointer is
+;              within the window's visible work area.
+
+               IMPORT  drag_scroll
+
+; --- drag_setDash ---
+;
+; On entry:    R0 == dash pattern byte
+;
+; On exit:     --
+;
+; Use:         Sets the dash pattern to be the given value.
+
+               IMPORT  drag_setDash
+
+; --- drag_cancel ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Cancels the current drag operation.
+
+               IMPORT  drag_cancel
+
+; --- drag_redraw ---
+;
+; On entry:    R1 == pointer to redraw block
+;
+; On exit:     --
+;
+; Use:         Redraws the drag box, if the redraw takes place in the
+;              currently dragging window.
+
+               IMPORT  drag_redraw
+
+; --- drag_eorColour ---
+;
+; On entry:    R0 == colour A
+;              R1 == colour B
+;
+; On exit:     --
+;
+; Use:         Sets the foreground colour to be an EOR colour such that
+;              when painted over Wimp colour A, it appears as Wimp colour B.
+
+               IMPORT  drag_eorColour
+
+;----- Flags ----------------------------------------------------------------
+
+drFlag_noUpdate        EQU     (1<<0)                  ;Don't generate update events
+
+;----- Drag handler events --------------------------------------------------
+
+; --- Note ---
+;
+; The events which request that you draw something are called for each
+; rectangle of the draw operation -- i.e. do not call Wimp_GetRectangle
+; because this is done for you.
+
+               ^       0
+drEvent_draw   #       1                       ;Draw dragged object
+                                               ;R1 == pointer to redraw blk
+                                               ;R2,R3 == drag start posn
+                                               ;R4,R5 == drag current posn
+                                               ;R6,R7 == window origin
+                                               ;Dash pattern set up
+
+drEvent_undraw #       1                       ;Undraw dragged object
+                                               ;Regs as for drEvent_draw
+                                               ;Normally use the same code
+
+drEvent_update #       1                       ;Redraw dragged object in
+                                               ;place
+                                               ;Regs as for drEvent_draw
+                                               ;Dash pattern set up so that
+                                               ;single plot will rotate box,
+                                               ;so may share code with
+                                               ;drEvent_draw
+
+drEvent_trans  #       1                       ;Translate coordinates
+                                               ;R1 == ptr to window state
+                                               ;R4,R5 == pointer position
+                                               ;R6,R7 == window origin
+                                               ;Translate pointer position
+                                               ;to internal coordinates if
+                                               ;this is useful to you.
+                                               ;Return new coords in R4,R5
+
+drEvent_getPos #       1                       ;Read pointer position
+                                               ;R1 == ptr to window state
+                                               ;R2,R3 == start position
+                                               ;R4,R5 == pointer position
+                                               ;R6,R7 == window origin
+                                               ;Used to read pointer posn.
+                                               ;Do any grid snapping here
+                                               ;and return with R4,R5 as
+                                               ;coords to use.
+
+drEvent_done   #       1                       ;Drag operation completed
+                                               ;R1 == ptr to window state
+                                               ;R2,R3 == drag start posn
+                                               ;R4,R5 == drag current posn
+
+drEvent_cancel #       1                       ;Drag operation aborted
+                                               ;No other registers set up
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/draw b/StraySrc/Libraries/Sapphire/sh/draw
new file mode 100644 (file)
index 0000000..945f908
--- /dev/null
@@ -0,0 +1,78 @@
+;
+; draw.sh
+;
+; Renders DrawFiles
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  draw_render
+;  draw_checkValid
+
+               [       :LNOT::DEF:draw__dfn
+               GBLL    draw__dfn
+
+; --- draw_render ---
+;
+; On entry:    R0 == scale to plot drawfile (16.16 form)
+;              R1 == pointer to a redraw block
+;              R2 == pointer to drawfile in memory
+;              R3 == size of drawfile block
+;
+; On exit:     --
+;
+; Use:         Renders a DrawFile in a window.  Objects which aren't
+;              recognised are not rendered.  The objects which are handled
+;              are as follows:
+;
+;              * Font table objects
+;              * Text objects (in fonts, or in system font)
+;              * Draw path objects, filled and unfilled, including
+;                dotted outlines
+;              * Group objects
+;              * Tagged objects
+;              * Sprite objects, rendered as well as we can make it
+;              * Transformed text, only on RISC OS 3
+;              * Transformed sprite, only on RISC OS 3
+
+               IMPORT  draw_render
+
+; --- draw_checkValid ---
+;
+; On entry:    R0 == pointer to start of drawfile
+;
+; On exit:     May return an error
+;
+; Use:         Checks whether a drawfile is basically sound.  This checking
+;              isn't compulsory, and just checks the initial word and the
+;              format version number -- nothing very exciting.
+
+               IMPORT  draw_checkValid
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/dynPtr b/StraySrc/Libraries/Sapphire/sh/dynPtr
new file mode 100644 (file)
index 0000000..7b62725
--- /dev/null
@@ -0,0 +1,48 @@
+;
+; dynPtr.sh
+;
+; Dynamic pointer changing
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  dynPtr_change
+
+; --- dynPtr_change ---
+;
+; On entry:    R0 == pointer to string to use
+;              R1 == pointer to pointer name
+;              R2 == x hot spot
+;              R3 == y hot spot
+;
+; On exit:     --
+;
+; Use:         Attaches a string to the default pointer shape.
+
+               IMPORT  dynPtr_change
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/errorBox b/StraySrc/Libraries/Sapphire/sh/errorBox
new file mode 100644 (file)
index 0000000..211d43a
--- /dev/null
@@ -0,0 +1,96 @@
+;
+; errorBox.sh
+;
+; Reports errors in an error box
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  errorBox_init
+;  errorBox_beep
+;  errorBox
+
+               [       :LNOT::DEF:errorBox__dfn
+               GBLL    errorBox__dfn
+
+; --- errorBox_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Initialises the errorBox system nicely.  It creates the
+;              dialogue box now, and just uses it for the rest of the
+;              time.
+
+               IMPORT  errorBox_init
+
+; --- errorBox_beep ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sounds the bell (VDU 7) if the CMOS settings dictate that
+;              error boxes should cause a beep.
+
+               IMPORT  errorBox_beep
+
+; --- errorBox ---
+;
+; On entry:    R0 == pointer to error block
+;              R1 == button style code, or pointer to buttons block
+;
+; On exit:     R0 == icon number clicked (ordered from the right)
+;              CS if R0 == 0, else CC
+;
+; Use:         Displays an error box on the screen.  The error block
+;              doesn't have to have a sensible error number, and doesn't
+;              have to be word aligned, either.
+;
+;              Since errorBox claims a dialogue box handle on
+;              initialisation, it isn't possible for this call to fail.
+;              Hence it is ideal for reporting problems like `Out of
+;              memory' or `Too many windows'.
+;
+;              The buttons in the error box may be given either by a code
+;              or by a pointer to a buttons block (these may easily be
+;              distinguished, since the codes are lower than &8000).
+;
+;              Standard button arrangements are given by codes, as follows:
+;
+;              0 == Cancel
+;              1 == OK
+;              2 == OK, Cancel
+;              4 == OK, Help
+;              5 == OK, Cancel, Help
+
+               IMPORT  errorBox
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/event b/StraySrc/Libraries/Sapphire/sh/event
new file mode 100644 (file)
index 0000000..0a247dd
--- /dev/null
@@ -0,0 +1,121 @@
+;
+; event.sh
+;
+; Event handling routines
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  event_preFilter
+;  event_fakeHandler
+;  event_postFilter
+;  event_poll
+;  event_last
+;  event_init
+
+               [       :LNOT::DEF:event__dfn
+               GBLL    event__dfn
+
+; --- event_preFilter ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R12 value to call routine
+;
+; On exit:     May return an error
+;
+; Use:         Adds a routine to the pre-filter list. Later added
+;              routines are called first.
+
+               IMPORT  event_preFilter
+
+; --- event_fakeHandler ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R12 value to call routine
+;
+; On exit:     May return an error
+;
+; Use:         Adds a routine to the fake handler list. Later added
+;              routines are called first.
+
+               IMPORT  event_fakeHandler
+
+; --- event_postFilter ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R12 value to call routine
+;
+; On exit:     May return an error
+;
+; Use:         Adds a routine to the post-poll list. Later added
+;              routines are called first.
+
+               IMPORT  event_postFilter
+
+; --- event_poll ---
+;
+; On entry:    R0 == event mask and flags
+;              R1 == pointer to block to use
+;              R2 == earliest time to return with NULL event
+;              R3 == optional pointer to poll word
+;
+; On exit:     R0 == reason code
+;              CS if the event was claimed, CC otherwise
+;
+; Use:         This call perform a Wimp_Poll, and dispatches events to
+;              interested parties.
+
+               IMPORT  event_poll
+
+; --- event_last ---
+;
+; On entry:    --
+;
+; On exit:     R0 == last event code received from Wimp_Poll
+;              R1 == pointer to accompanying event data
+;
+; Use:         Allows you to read the full event information.  The event
+;              is the same one currently being or most recently dispatched
+;              to the postfilter list, i.e. fake events are also returned
+;              by this call.  If no event has yet been received, the return
+;              values are undefined.
+
+               IMPORT  event_last
+
+; --- event_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the event system.
+
+               IMPORT  event_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/except b/StraySrc/Libraries/Sapphire/sh/except
new file mode 100644 (file)
index 0000000..770addc
--- /dev/null
@@ -0,0 +1,109 @@
+;
+; except.sh
+;
+; Sapphire exception handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  except_init
+;  except_fatal
+;  except_atExit
+;  except_returnPt
+
+               [       :LNOT::DEF:except__dfn
+               GBLL    except__dfn
+
+; --- except_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the exception handler.
+
+               IMPORT  except_init
+
+; --- except_fatal ---
+;
+; On entry:    R0 == pointer to an error block
+;
+; On exit:     Doesn't
+;
+; Use:         Reports an error to our /caller's/ error handler.  We quit
+;              and die at this point.  Don't use unless you have absolutely
+;              no choice in the matter.
+
+               IMPORT  except_fatal
+
+; --- except_atExit ---
+;
+; On entry:    R0 == pointer to routine to call on exit
+;              R1 == R12 value to call with
+;
+; On exit:     --
+;
+; Use:         Registers a routine to get called when the application quits.
+;              Later-registered routines are called earlier than earlier-
+;              registered routines, so everything closes down in a nice
+;              manner.
+
+               IMPORT  except_atExit
+
+; --- except_returnPt ---
+;
+; On entry:    R0 == pointer to exception handler routine
+;              R1 == R12 value to enter routine with
+;              R2 == R13 value to enter routine with
+;
+; On exit:     --
+;
+; Use:         Sets up a routine to be called whenever there's an error.
+;              The idea is that it should ask the user whether to quit,
+;              and if not, resume to some known (safe?) state.
+;
+;              The routine is called with R0 == pointer to error block, and
+;              R12 and R13 being the values set up here(*).  It should
+;              return with R0 == pointer to a routine to resume at, and R1
+;              being the value to pass to the resume routine in R12.  If
+;              you decide to quit, just call OS_Exit -- this should tidy
+;              everything up.
+;
+;              Note that the error is held in the scratchpad buffer, so
+;              you can't use the first 256 bytes of that until you've
+;              finished with the error message.
+;
+;              (*) Actually, R13 is 4 bytes lower because it's assumed that
+;              it points to a full descending stack that we can use.  This
+;              shouldn't make any difference as long as you're using R13
+;              as a full descending stack pointer.
+
+               IMPORT  except_returnPt
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/fastMove b/StraySrc/Libraries/Sapphire/sh/fastMove
new file mode 100644 (file)
index 0000000..0b25d31
--- /dev/null
@@ -0,0 +1,54 @@
+;
+; fastMove.sh
+;
+; Fast memory manipulation
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  fastMove
+
+               [       :LNOT::DEF:fastMove__dfn
+               GBLL    fastMove__dfn
+
+; --- fastMove ---
+;
+; On entry:    R0 == destination pointer
+;              R1 == source pointer
+;              R2 == number of bytes to move
+;
+; On exit:     --
+;
+; Use:         A very fast block moving routine.  Word aligning is not
+;              necessary, and the blocks may overlap.  This is basically
+;              the routine from PRM 2, hacked to cope with overlapping.
+
+               IMPORT  fastMove
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/fixedPt b/StraySrc/Libraries/Sapphire/sh/fixedPt
new file mode 100644 (file)
index 0000000..0839434
--- /dev/null
@@ -0,0 +1,98 @@
+;
+; fixedPt.sh
+;
+; Provides fixed point operations such as trignometry
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  fxp_atan
+;  fxp_pol
+;  fxp_sin
+;  fxp_cos
+
+               [       :LNOT::DEF:fixedPt__dfn
+               GBLL    fixedPt__dfn
+
+; --- fxp_atan ---
+;
+; On entry:    R0 == x, in 16.16 fixed point form
+;
+; On exit:     R0 == arctan x, in degrees, in 16.16 fixed point
+;
+; Use:         Calculates arctan x, hopefully fairly swiftly. The
+;              accuracy of the result is open to doubt, although
+;              it's usually good to about 3 significant figures.
+;              It uses a small lookup table and linear interpolation
+;              to calculate the result.
+
+               IMPORT  fxp_atan
+
+; --- fxp_pol ---
+;
+; On entry:    R0 == x coordinate
+;              R1 == y coordinate
+;
+; On exit:     R0 == angle in degrees, in 16.16 form
+;
+; Use:         Calculates the angle a vector makes with the +ve x axis.
+;              The angle is given in degrees, rather than radians,
+;              although this isn't really overly significant; it just
+;              makes it slightly easier to work with, because it's
+;              bigger.
+;
+;              This routine uses the arctan table and linear
+;              interpolation, so it's fairly quick, but the accuracy
+;              of its results is restricted to about 3 significant figures.
+
+               IMPORT  fxp_pol
+
+; --- fxp_sin ---
+;
+; On entry:    R0 == angle in degrees, in 16.16 form
+;
+; On exit:     R0 == sin of angle, in 16.16 form
+;
+; Use:         Calculates a sin of an angle with a degree of swiftness and
+;              a lot less accuracy.
+
+               IMPORT  fxp_sin
+
+; --- fxp_cos ---
+;
+; On entry:    R0 == angle in degrees, in 16.16 form
+;
+; On exit:     R0 == cos of angle, in 16.16 form
+;
+; Use:         Calculates a cos of an angle with a degree of swiftness and
+;              a lot less accuracy.
+
+               IMPORT  fxp_cos
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/flex b/StraySrc/Libraries/Sapphire/sh/flex
new file mode 100644 (file)
index 0000000..939be8a
--- /dev/null
@@ -0,0 +1,237 @@
+;
+; flex.sh
+;
+; Flexible memory handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  flex_reduce
+;  flex_compact
+;  flex_free
+;  flex_alloc
+;  flex_size
+;  flex_extend
+;  flex_midExtend
+;  flex_init
+;  flex_stackPtr
+;  flex_save
+;  flex_load
+;  flex_dump
+;
+; Macros provided:
+;
+;   FSAVE
+;   FLOAD
+
+               [       :LNOT::DEF:flex__dfn
+               GBLL    flex__dfn
+
+;+             LIB     sapphire:^.bsh.flex
+
+; --- flex_reduce ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Compacts the flex heap by one iteration.
+
+               IMPORT  flex_reduce
+
+; --- flex_compact ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Completely compacts the flex heap.
+
+               IMPORT  flex_compact
+
+; --- flex_free ---
+;
+; On entry:    R0 == pointer to the flex anchor
+;
+; On exit:     --
+;
+; Use:         Frees a flex block allocated by flex_alloc.
+
+               IMPORT  flex_free
+
+; --- flex_alloc ---
+;
+; On entry:    R0 == pointer to a flex anchor
+;              R1 == desired size of flex block
+;
+; On exit:     CS if no memory could be allocated, CC otherwise
+;
+; Use:         Allocates a block in the shifting heap.
+
+               IMPORT  flex_alloc
+
+; --- flex_size ---
+;
+; On entry:    R0 == pointer to flex anchor
+;
+; On exit:     R0 == size of allocated block
+;
+; Use:         Reads the size of a flex block.
+
+               IMPORT  flex_size
+
+; --- flex_extend ---
+;
+; On entry:    R0 == pointer to flex anchor
+;              R1 == new size of block to set
+;
+; On exit:     CS if it failed due to lack of memory, CC otherwise
+;
+; Use:         Alters the size of a block to the given value.
+
+               IMPORT  flex_extend
+
+; --- flex_midExtend ---
+;
+; On entry:    R0 == pointer to a flex anchor
+;              R1 == `at' -- position in block to extend from
+;              R2 == `by' -- how many bytes to extend (may be -ve)
+;
+; On exit:     CS if it failed due to lack of memory, CC otherwise
+;
+; Use:         Either creates a gap in a block (by>0) or deletes bytes
+;              from a block.  This is always done in such a way that the
+;              byte originally at offset `at' is now at offset `at'+`by'.
+
+               IMPORT  flex_midExtend
+
+; --- flex_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the flex heap for use.
+
+               IMPORT  flex_init
+
+; --- flex_stackPtr ---
+;
+; On entry:    R0 == 0 to read, or value to set
+;
+; On exit:     R0 == old value
+;
+; Use:         Either reads or writes the flex stack pointer.  This sort
+;              of thing is useful in exception handlers etc.
+
+               IMPORT  flex_stackPtr
+
+; --- flex_save ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Saves some registers on the flex relocation stack.  R13
+;              and R14 cannot be saved -- these registers are corrupted
+;              during this routine's execution.
+;
+;              Values saved on the flex relocation stack are adjusted as
+;              flex moves blocks of memory around, so that they still point
+;              to the same thing as they did before.  Obviously, values
+;              which aren't pointers into flex blocks may be corrupted.
+;              Values pointing to objects deleted (either free blocks, or
+;              areas removed by flex_midExtend) may also be corrupted.
+;
+;              Since this routine takes no arguments, some other method has
+;              to be used.  The method chosen is to follow the call to
+;              flex_save with a LDM or STM instruction containing the
+;              registers to be saved.  This instruction is skipped by the
+;              routine, and thus not executed.
+;
+;              Note that if you give the LDM or STM the same condition code
+;              as the BL preceding it, it will never be executed, since
+;              flex_save skips it if the condition is true and it can't be
+;              executed if the condition is false.
+
+               IMPORT  flex_save
+
+; --- flex_load ---
+;
+; On entry:    --
+;
+; On exit:     Registers loaded from relocation stack as requested
+;
+; Use:         Restores registers saved on flex's relocation stack.  See
+;              flex_save for calling information and details about the
+;              relocation stack.
+
+               IMPORT  flex_load
+
+;----- Useful macros --------------------------------------------------------
+
+; --- Macro: FSAVE ---
+;
+; Arguments:   rList == quoted register list to save on relocation stack
+;
+; Use:         Assembles code to write the given register list on the
+;              flex relocation stack.  The register list should be in the
+;              same form as that for an STM or LDM instruction.
+;
+;              For full details about the flex relocation stack, see
+;              flex_save.
+
+               MACRO
+$label         FSAVE   $rList
+$label
+               BL      flex_save
+               STMEA   R14!,{$rList}
+
+               MEND
+
+; --- Macro: FLOAD ---
+;
+; Arguments:   rList == quoted register list to read from relocation stack
+;
+; Use:         Assembles code to read the given register list from the
+;              flex relocation stack.  The register list should be in the
+;              same form as that for an STM or LDM instruction.
+;
+;              For full details about the flex relocation stack, see
+;              flex_save.
+
+               MACRO
+$label         FLOAD   $rList
+$label
+               BL      flex_load
+               LDMEA   R14!,{$rList}
+
+               MEND
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/fontmenu b/StraySrc/Libraries/Sapphire/sh/fontmenu
new file mode 100644 (file)
index 0000000..6cf02b7
--- /dev/null
@@ -0,0 +1,96 @@
+;
+; fontMenu.sh
+;
+; Fontmenu creation
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  fm_create
+;  fm_tickFont
+;  fm_init
+
+               [       :LNOT::DEF:fontMenu__dfn
+               GBLL    fontMenu__dfn
+
+; --- fm_create ---
+;
+; On entry:    R0 == current font name
+;              R1 == handler to call when selection made
+;              R2 == R10 value to call with
+;              R3 == R12 value to call with
+;              R4 == pointer to routine to call to create submenu
+;                    (ie. menu_create or tms_create)
+;
+; On exit:     CS if any fonts exist and
+;                 R0 == pointer to a menu definition
+;                R1 == event handler to call
+;                R2 == R10 value for event handler
+;                R3 == R12 value for event handler
+;              else CC and
+;                R0-R3 corrupted
+;              May return an error
+;
+; Use:         Creates a user menu definition suitable for passing directly
+;              to (menu|tms)_create. Note however, that the menu defintion
+;              does *not* include any title; this must be created first.
+;              If you require items such as the system font, then
+;              add these to the menu before creating the menu returned
+;              from this call.
+
+               IMPORT  fm_create
+
+; --- fm_tickFont ---
+;
+; On entry:    R0 == name to tick
+;
+; On exit:     --
+;
+; Use:         Ticks the font with tht given name in the fontmenu. If
+;              no font exists then the existing ticks are removed
+
+               IMPORT  fm_tickFont
+
+; --- fm_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the font menu system.
+
+               IMPORT  fm_init
+
+               ]
+
+;----- Events ---------------------------------------------------------------
+
+               ^       0
+fmEvent_select #       1                       ;User selected a font
+                                               ;R1 == pointer to name
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/gallery b/StraySrc/Libraries/Sapphire/sh/gallery
new file mode 100644 (file)
index 0000000..a4592d5
--- /dev/null
@@ -0,0 +1,91 @@
+;
+; gallery.sh
+;
+; Background-drawing viewers
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  gallery_eventHandler
+;  gallery_drawBox
+;  gallery_removeBox
+;  gallery_reset
+
+               [       :LNOT::DEF:gallery__dfn
+               GBLL    gallery__dfn
+
+; --- gallery_eventHandler ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == pointer to handler routine
+;              R2 == R10 value to pass to handler
+;              R3 == R12 value to pass to handler
+;
+; On exit:     --
+;
+; Use:         Sets up an event handler for the viewer, and adds in
+;              gallery's own special processing for background drawing.
+
+               IMPORT  gallery_eventHandler
+
+; --- gallery_drawBox ---
+;
+; On entry:    R0-R3 == window relative coords of box to plot
+;
+; On exit:     --
+;
+; Use:         Draws a box to indicate tht this item hasn't been
+;              displayed yet.  Use this routine to give a consistant
+;              look to applications which use the gallery.
+
+               IMPORT  gallery_drawBox
+
+; --- gallery_removeBox ---
+;
+; On entry:    R0-R3 == window relative coords of box to remove
+;
+; On exit:     --
+;
+; Use:         Removes a previously draw temporary box.  It is assumed that
+;              the background colour of the viewere is 1.
+
+               IMPORT  gallery_removeBox
+
+; --- gallery_reset ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Resets all the icons in the gallery to their `undrawn' state.
+;              Use this before opening the window etc.
+
+               IMPORT  gallery_reset
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/heap b/StraySrc/Libraries/Sapphire/sh/heap
new file mode 100644 (file)
index 0000000..c2dc518
--- /dev/null
@@ -0,0 +1,120 @@
+;
+; heap.sh
+;
+; A resizing, nonshifting heap
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  heap_init
+;  heap_useHeap
+;  heap_info
+;  heap_alloc
+;  heap_free
+;  heap_reAlloc
+
+               [       :LNOT::DEF:heap__dfn
+               GBLL    heap__dfn
+
+; --- heap_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the heap system for use.
+
+               IMPORT  heap_init
+
+; --- heap_useHeap ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Registers the resizing heap as the current allocator.
+
+               IMPORT  heap_useHeap
+
+; --- heap_info ---
+;
+; On entry:    --
+;
+; On exit:     R0 == current heap size
+;              R1 == amount of memory free in the heap
+;              R2 == size of the largest block free
+;
+; Use:         Describes the heap's current status.
+
+               IMPORT  heap_info
+
+; --- heap_alloc ---
+;
+; On entry:    R0 == size of block wanted
+;
+; On exit:     CC if enough memory was found and
+;                R0 == pointer to the block allocated
+;              else CS and
+;                R0 corrupted
+;
+; Use:         Allocates a block of at least a given size from a heap.  If
+;              the heap is not big enough, more is claimed from the
+;              operating system.
+
+               IMPORT  heap_alloc
+
+; --- heap_free ---
+;
+; On entry:    R0 == pointer to a block created with heap_alloc
+;
+; On exit:     --
+;
+; Use:         Frees a block allocated using heap_alloc.  It tries to
+;              shrink the heap as much as possible afterwards.
+
+               IMPORT  heap_free
+
+; --- heap_reAlloc ---
+;
+; On entry:    R0 == pointer to block whose size we want to change
+;              R1 == the new size of the block
+;
+; On exit:     CC if block was resized, and
+;                R0 == pointer to the block (which may have moved)
+;              else CS and
+;                R0 corrupted
+;
+; Use:         Changes the size of a heap block.  If possible, the block's
+;              position is unchanged, but this may not always be the case.
+;
+;              Note that changing a block's size to 0 is permitted.
+
+               IMPORT  heap_reAlloc
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/help b/StraySrc/Libraries/Sapphire/sh/help
new file mode 100644 (file)
index 0000000..2b1c195
--- /dev/null
@@ -0,0 +1,84 @@
+;
+; help.sh
+;
+; Sending and handling help messages
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  help_init
+;  help_sendHints
+;  help_add
+;  help_reset
+
+; --- help_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the help system for use.
+
+               IMPORT  help_init
+
+; --- help_sendHints ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Should be called on a pointer-entering-window event.  It
+;              enables hint requests for the window beneath the pointer.
+
+               IMPORT  help_sendHints
+
+; --- help_add ---
+;
+; On entry:    R0 == pointer to message string to add
+;
+; On exit:     --
+;
+; Use:         Adds a line to the help message being built currently.  Note
+;              that overflows are trapped, and errors are generated if one
+;              would occur.
+
+               IMPORT  help_add
+
+; --- help_reset ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Resets the help system so that a hint request is sent to an
+;              icon that the pointer is already over. The proposed use
+;              is that the caller can change a help message for a given
+;              icon as soon as it is clicked on.
+
+               IMPORT  help_reset
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/hour b/StraySrc/Libraries/Sapphire/sh/hour
new file mode 100644 (file)
index 0000000..b852674
--- /dev/null
@@ -0,0 +1,157 @@
+;
+; hour.sh
+;
+; Handling of the hourglass
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  hour_init
+;  hour_on
+;  hour_off
+;  hour_percent
+;  hour_leds
+;  hour_suspend
+;  hour_save
+;  hour_resume
+;  hour_restore
+
+               [       :LNOT::DEF:hour__dfn
+               GBLL    hour__dfn
+
+; --- hour_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the hour system, so it will display an hourglass
+;              when necessary.
+;
+;              Since this gets called at a random point during the Sapphire
+;              initialisation, and we can rely on Hourglass keeping its
+;              own count, the suggested way of handling everything properly
+;              is as follows:
+;
+;                              SWI     Hourglass_On
+;                              BL      sapphire_init
+;                              SWI     Hourglass_Off
+
+               IMPORT  hour_init
+
+; --- hour_on ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Turns the Hourglass on only if it isn't on already.
+;              Otherwise its status is left as it was.
+
+               IMPORT  hour_on
+
+; --- hour_off ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Turns the Hourglass off if it's only been turned on once.
+;              If the Hourglass gets turned off, all the information about
+;              it (percentage and LEDs) get forgotten.
+
+               IMPORT  hour_off
+
+; --- hour_percent ---
+;
+; On entry:    R0 == percentage value to display, or -1 to remove
+;
+; On exit:     --
+;
+; Use:         Attaches a percentage display to the Hourglass.
+
+               IMPORT  hour_percent
+
+; --- hour_leds ---
+;
+; On entry:    R0 == LED mask EOR value
+;              R1 == LED mask AND value
+;
+; On exit:     --
+;
+; Use:         Changes the Hourglass LED status.
+
+               IMPORT  hour_leds
+
+; --- hour_suspend ---
+;
+; On entry:    R0 == pointer to 2 word block to save status in
+;
+; On exit:     --
+;
+; Use:         Saves the Hourglass state in a block you've pointed at,
+;              and disables the Hourglass.  Useful if you want to do some
+;              user interaction without polling (e.g. an error box).
+
+               IMPORT  hour_suspend
+
+; --- hour_save ---
+;
+; On entry:    R0 == pointer to 2 word block to save status in
+;
+; On exit:     --
+;
+; Use:         Saves the current Hourglass status without altering it.
+
+               IMPORT  hour_save
+
+; --- hour_resume, hour_restore ---
+;
+; On entry:    R0 == pointer to 2 words filled by hour_suspend or hour_save
+;
+; On exit:     --
+;
+; Use:         Restores the Hourglass state to that saved away by one
+;              of the previous two calls.  This routine has two names.
+
+               IMPORT  hour_resume
+
+; --- hour_resume, hour_restore ---
+;
+; On entry:    R0 == pointer to 2 words filled by hour_suspend or hour_save
+;
+; On exit:     --
+;
+; Use:         Restores the Hourglass state to that saved away by one
+;              of the previous two calls.  This routine has two names.
+
+               IMPORT  hour_resume
+               IMPORT  hour_restore
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/ibicon b/StraySrc/Libraries/Sapphire/sh/ibicon
new file mode 100644 (file)
index 0000000..8442ca5
--- /dev/null
@@ -0,0 +1,117 @@
+;
+; ibicon.sh
+;
+; Icon bar icon handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  ibicon_create
+;  ibicon_changeSprite
+;  ibicon_changeText
+;  ibicon_remove
+;  ibicon_init
+
+               [       :LNOT::DEF:ibicon__dfn
+               GBLL    ibicon__dfn
+
+; --- ibicon_create ---
+;
+; On entry:    R0 == pointer to sprite name
+;              R1 == pointer to text buffer (must be writable if you
+;                    intend to change the text)
+;              R2 == icon bar position indicator (`window handle')
+;              R3 == icon bar priority/icon handle
+;              R4 == pointer to event handler
+;              R5 == value to pass in R10
+;              R6 == value to pass in R12
+;
+; On exit:     R0 == ibicon icon handle
+;              May return an error
+;
+; Use:                 Places an icon on the icon bar. Your handler is called when
+;              an event occurs on the icon. On entry to the handler, R10
+;              and R12 are set up as for above, R0 is the event type, and
+;              R1 is the ibicon pointer.
+
+               IMPORT  ibicon_create
+
+; --- ibicon_changeSprite ---
+;
+; On entry:    R0 == ibicon pointer
+;              R1 == pointer to sprite name
+;
+; On exit:     --
+;
+; Use:         Changes the sprite of the ibicon passed to it.
+
+               IMPORT  ibicon_changeSprite
+
+; --- ibicon_changeText ---
+;
+; On entry:    R0 == ibicon pointer
+;              R1 == pointer to new text
+;
+; On exit:     --
+;
+; Use:         Changes the sprite of the ibicon passed to it.
+
+               IMPORT  ibicon_changeText
+
+; --- ibicon_remove ---
+;
+; On entry:    R0 == ibicon icon handle
+;
+; On exit:     --
+;
+; Use:         Removes the given icon from the icon bar.
+
+               IMPORT  ibicon_remove
+
+; --- ibicon_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the ibicon unit.
+
+               IMPORT  ibicon_init
+
+;----- Event types ----------------------------------------------------------
+
+               ^       0
+ibEvent_select #       1
+ibEvent_menu   #       1
+ibEvent_adjust #       1
+ibEvent_save   #       1
+ibEvent_load   #       1
+ibEvent_help   #       1
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/idle b/StraySrc/Libraries/Sapphire/sh/idle
new file mode 100644 (file)
index 0000000..d5e097e
--- /dev/null
@@ -0,0 +1,124 @@
+;
+; idle.sh
+;
+; Idle event and alarm handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  idle_handler
+;  idle_removeHandler
+;  idle_setAlarm
+;  idle_removeAlarm
+;  idle_removeAllAlarms
+;  idle_init
+
+               [       :LNOT::DEF:idle__dfn
+               GBLL    idle__dfn
+
+; --- idle_handler ---
+;
+; On entry:    R0 == how frequently to call
+;              R1 == pointer to routine to call
+;              R2 == R10 value to call routine with
+;              R3 == R12 value to call routine with
+;
+; On exit:     May return an error
+;
+; Use:         Adds a routine to the idle handler list. Later added
+;              routines are called first. The idle handing routine
+;              may corrupt R10 and R12.
+
+               IMPORT  idle_handler
+
+; --- idle_removeHandler ---
+;
+; On entry:    R0 == How frequently it was called
+;              R1 == pointer to routine called
+;              R2 == R10 value routine is called with
+;              R3 == R12 value routine is called with
+;
+; On exit:     --
+;
+; Use:         Removes a routine from the idle handler list.
+
+               IMPORT  idle_removeHandler
+
+; --- idle_setAlarm ---
+;
+; On entry:    R3 == Time to call
+;              R1 == pointer to routine to call
+;              R2 == R10 value to call routine with
+;              R3 == R12 value to call routine with
+;
+; On exit:     May return an error
+;
+; Use:         Adds a alarm to be called. The idle handing routine
+;              may corrupt R10 and R12.
+
+               IMPORT  idle_setAlarm
+
+; --- idle_removeAlarm ---
+;
+; On entry:    R0 == When it was to be called
+;              R1 == pointer to routine called
+;              R2 == R10 value routine is called with
+;              R3 == R12 value routine is called with
+;
+; On exit:     --
+;
+; Use:         Removes a routine from the idle handler list. It has
+;              no effect if it doesn't exist.
+
+               IMPORT  idle_removeAlarm
+
+; --- idle_removeAllAlarms ---
+;
+; On entry:    R0 == R10 value to look for
+;
+; On exit:     --
+;
+; Use:         Removes all alarms with the handle that was passed to them
+;              to be put into R10.  You should not remove an alarm within
+;              an alarm handler.
+
+
+               IMPORT  idle_removeAllAlarms
+
+; --- idle_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the idle system.
+
+               IMPORT  idle_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/intKeys b/StraySrc/Libraries/Sapphire/sh/intKeys
new file mode 100644 (file)
index 0000000..321942b
--- /dev/null
@@ -0,0 +1,150 @@
+;
+; intKeys.sh
+;
+; Definitions for Acorn internal key numbers
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               [       :LNOT::DEF:intKeys__dfn
+               GBLL    intKeys__dfn
+
+intk_Esc       EQU     112
+intk_F1                EQU     113
+intk_F2                EQU     114
+intk_F3                EQU     115
+intk_F4                EQU     20
+intk_F5                EQU     116
+intk_F6                EQU     117
+intk_F7                EQU     22
+intk_F8                EQU     118
+intk_F9                EQU     119
+intk_F10       EQU     30
+intk_F11       EQU     28
+intk_F12       EQU     29
+
+intk_0         EQU     39
+intk_1         EQU     48
+intk_2         EQU     49
+intk_3         EQU     17
+intk_4         EQU     18
+intk_5         EQU     19
+intk_6         EQU     24
+intk_7         EQU     36
+intk_8         EQU     21
+intk_9         EQU     38
+
+intk_BackQ     EQU     45
+intk_Minus     EQU     40
+intk_Equals    EQU     93
+intk_Pound     EQU     46
+intk_Backspace EQU     47
+
+intk_LSquare   EQU     56
+intk_RSquare   EQU     88
+intk_Backslash EQU     120
+intk_Semicolon EQU     87
+intk_Quote     EQU     79
+intk_LAngle    EQU     102
+intk_RAngle    EQU     103
+intk_Slash     EQU     104
+
+intk_Tab       EQU     96
+
+intk_Ctrl      EQU     1
+intk_LCtrl     EQU     4
+intk_RCtrl     EQU     7
+
+intk_Shift     EQU     0
+intk_LShift    EQU     3
+intk_RShift    EQU     6
+intk_CapsLock  EQU     64
+
+intk_Alt       EQU     2
+intk_LAlt      EQU     5
+intk_RAlt      EQU     8
+
+intk_A         EQU     65
+intk_B         EQU     100
+intk_C         EQU     82
+intk_D         EQU     50
+intk_E         EQU     34
+intk_F         EQU     67
+intk_G         EQU     83
+intk_H         EQU     84
+intk_I         EQU     37
+intk_J         EQU     69
+intk_K         EQU     70
+intk_L         EQU     86
+intk_M         EQU     101
+intk_N         EQU     85
+intk_O         EQU     54
+intk_P         EQU     55
+intk_Q         EQU     16
+intk_R         EQU     51
+intk_S         EQU     81
+intk_T         EQU     35
+intk_U         EQU     53
+intk_V         EQU     99
+intk_W         EQU     33
+intk_X         EQU     66
+intk_Y         EQU     68
+intk_Z         EQU     97
+
+intk_Print     EQU     32
+intk_ScrollLock        EQU     62
+intk_Break     EQU     44
+
+intk_Insert    EQU     61
+intk_Home      EQU     62
+intk_PageUp    EQU     63
+intk_Delete    EQU     89
+intk_Copy      EQU     105
+intk_PageDown  EQU     78
+
+intk_Up                EQU     57
+intk_Left      EQU     25
+intk_Down      EQU     41
+intk_Right     EQU     121
+
+intk_NumLock   EQU     77
+intk_kSlash    EQU     74
+intk_kStar     EQU     91
+intk_kHash     EQU     90
+intk_kMinus    EQU     59
+intk_kPlus     EQU     58
+intk_kEnter    EQU     60
+intk_kDot      EQU     76
+
+intk_k0                EQU     106
+intk_k1                EQU     107
+intk_k2                EQU     124
+intk_k3                EQU     108
+intk_k4                EQU     122
+intk_k5                EQU     123
+intk_k6                EQU     26
+intk_k7                EQU     27
+intk_k8                EQU     42
+intk_k9                EQU     43
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/keyMap b/StraySrc/Libraries/Sapphire/sh/keyMap
new file mode 100644 (file)
index 0000000..83aee12
--- /dev/null
@@ -0,0 +1,325 @@
+;
+; keyMap.sh
+;
+; Definitions for the Straylight extended keyset
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               [       :LNOT::DEF:keyMap__dfn
+               GBLL    keyMap__dfn
+
+key_cA         EQU     &001
+key_cB         EQU     &002
+key_cC         EQU     &003
+key_cD         EQU     &004
+key_cE         EQU     &005
+key_cF         EQU     &006
+key_cG         EQU     &007
+key_cH         EQU     &008
+key_cI         EQU     &009
+key_cJ         EQU     &00A
+key_cK         EQU     &00B
+key_cL         EQU     &00C
+key_cM         EQU     &00D
+key_cN         EQU     &00E
+key_cO         EQU     &00F
+key_cP         EQU     &010
+key_cQ         EQU     &011
+key_cR         EQU     &012
+key_cS         EQU     &013
+key_cT         EQU     &014
+key_cU         EQU     &015
+key_cV         EQU     &016
+key_cW         EQU     &017
+key_cX         EQU     &018
+key_cY         EQU     &019
+key_cZ         EQU     &01A
+
+key_scA                EQU     &101
+key_scB                EQU     &102
+key_scC                EQU     &103
+key_scD                EQU     &104
+key_scE                EQU     &105
+key_scF                EQU     &106
+key_scG                EQU     &107
+key_scH                EQU     &108
+key_scI                EQU     &109
+key_scJ                EQU     &10A
+key_scK                EQU     &10B
+key_scL                EQU     &10C
+key_scM                EQU     &10D
+key_scN                EQU     &10E
+key_scO                EQU     &10F
+key_scP                EQU     &110
+key_scQ                EQU     &111
+key_scR                EQU     &112
+key_scS                EQU     &113
+key_scT                EQU     &114
+key_scU                EQU     &115
+key_scV                EQU     &116
+key_scW                EQU     &117
+key_scX                EQU     &118
+key_scY                EQU     &119
+key_scZ                EQU     &11A
+
+key_Esc                EQU     &01B
+key_sEsc       EQU     &11B
+key_cEsc       EQU     &13B
+key_scEsc      EQU     &15B
+
+key_Backspace  EQU     &01C
+key_sBackspace EQU     &11C
+key_cBackspace EQU     &13C
+key_scBackspace        EQU     &15C
+
+key_Return     EQU     &01D
+key_sReturn    EQU     &11D
+key_cReturn    EQU     &13D
+key_scReturn   EQU     &15D
+
+key_Insert     EQU     &1CD
+key_sInsert    EQU     &1DD
+key_cInsert    EQU     &1ED
+key_scInsert   EQU     &1FD
+
+key_Home       EQU     &01E
+key_sHome      EQU     &11E
+key_cHome      EQU     &13E
+key_scHome     EQU     &15E
+
+key_Delete     EQU     &07F
+key_sDelete    EQU     &17F
+key_cDelete    EQU     &01F
+key_scDelete   EQU     &11F
+
+key_Copy       EQU     &18B
+key_sCopy      EQU     &19B
+key_cCopy      EQU     &1AB
+key_scCopy     EQU     &1BB
+
+key_Tab                EQU     &18A
+key_sTab       EQU     &19A
+key_cTab       EQU     &1AA
+key_scTab      EQU     &1BA
+
+key_Space      EQU     &020
+key_sSpace     EQU     &120
+key_cSpace     EQU     &000
+key_scSpace    EQU     &100
+
+key_c0         EQU     &130
+key_c1         EQU     &131
+key_c2         EQU     &132
+key_c3         EQU     &133
+key_c4         EQU     &134
+key_c5         EQU     &135
+key_c6         EQU     &136
+key_c7         EQU     &137
+key_c8         EQU     &138
+key_c9         EQU     &139
+
+key_sc0                EQU     &150
+key_sc1                EQU     &151
+key_sc2                EQU     &152
+key_sc3                EQU     &153
+key_sc4                EQU     &154
+key_sc5                EQU     &155
+key_sc6                EQU     &156
+key_sc7                EQU     &157
+key_sc8                EQU     &158
+key_sc9                EQU     &159
+
+key_k0         EQU     &1C0
+key_k1         EQU     &1C1
+key_k2         EQU     &1C2
+key_k3         EQU     &1C3
+key_k4         EQU     &1C4
+key_k5         EQU     &1C5
+key_k6         EQU     &1C6
+key_k7         EQU     &1C7
+key_k8         EQU     &1C8
+key_k9         EQU     &1C9
+
+key_sk0                EQU     &1D0
+key_sk1                EQU     &1D1
+key_sk2                EQU     &1D2
+key_sk3                EQU     &1D3
+key_sk4                EQU     &1D4
+key_sk5                EQU     &1D5
+key_sk6                EQU     &1D6
+key_sk7                EQU     &1D7
+key_sk8                EQU     &1D8
+key_sk9                EQU     &1D9
+
+key_ck0                EQU     &1E0
+key_ck1                EQU     &1E1
+key_ck2                EQU     &1E2
+key_ck3                EQU     &1E3
+key_ck4                EQU     &1E4
+key_ck5                EQU     &1E5
+key_ck6                EQU     &1E6
+key_ck7                EQU     &1E7
+key_ck8                EQU     &1E8
+key_ck9                EQU     &1E9
+
+key_sck0       EQU     &1F0
+key_sck1       EQU     &1F1
+key_sck2       EQU     &1F2
+key_sck3       EQU     &1F3
+key_sck4       EQU     &1F4
+key_sck5       EQU     &1F5
+key_sck6       EQU     &1F6
+key_sck7       EQU     &1F7
+key_sck8       EQU     &1F8
+key_sck9       EQU     &1F9
+
+key_cLSquare   EQU     &12B
+key_scLSquare  EQU     &14B
+
+key_cRSquare   EQU     &12D
+key_scRSquare  EQU     &14D
+
+key_cBackslash EQU     &12C
+key_scBackslash        EQU     &14C
+
+key_cMinus     EQU     &12F
+key_scMinus    EQU     &14F
+
+key_kSlash     EQU     &161
+key_kStar      EQU     &162
+key_kHash      EQU     &163
+key_kMinus     EQU     &164
+key_kPlus      EQU     &165
+key_kEnter     EQU     &166
+key_kDot       EQU     &167
+
+key_skSlash    EQU     &171
+key_skStar     EQU     &172
+key_skHash     EQU     &173
+key_skMinus    EQU     &174
+key_skPlus     EQU     &175
+key_skEnter    EQU     &176
+key_skDot      EQU     &177
+
+key_ckSlash    EQU     &121
+key_ckStar     EQU     &122
+key_ckHash     EQU     &123
+key_ckMinus    EQU     &124
+key_ckPlus     EQU     &125
+key_ckEnter    EQU     &126
+key_ckDot      EQU     &127
+
+key_sckSlash   EQU     &141
+key_sckStar    EQU     &142
+key_sckHash    EQU     &143
+key_sckMinus   EQU     &144
+key_sckPlus    EQU     &145
+key_sckEnter   EQU     &146
+key_sckDot     EQU     &147
+
+key_Print      EQU     &180
+key_F1         EQU     &181
+key_F2         EQU     &182
+key_F3         EQU     &183
+key_F4         EQU     &184
+key_F5         EQU     &185
+key_F6         EQU     &186
+key_F7         EQU     &187
+key_F8         EQU     &188
+key_F9         EQU     &189
+key_F10                EQU     &1CA
+key_F11                EQU     &1CB
+key_F12                EQU     &1CC
+
+key_sPrint     EQU     &190
+key_sF1                EQU     &191
+key_sF2                EQU     &192
+key_sF3                EQU     &193
+key_sF4                EQU     &194
+key_sF5                EQU     &195
+key_sF6                EQU     &196
+key_sF7                EQU     &197
+key_sF8                EQU     &198
+key_sF9                EQU     &199
+key_sF10       EQU     &1DA
+key_sF11       EQU     &1DB
+key_sF12       EQU     &1DC
+
+key_cPrint     EQU     &1A0
+key_cF1                EQU     &1A1
+key_cF2                EQU     &1A2
+key_cF3                EQU     &1A3
+key_cF4                EQU     &1A4
+key_cF5                EQU     &1A5
+key_cF6                EQU     &1A6
+key_cF7                EQU     &1A7
+key_cF8                EQU     &1A8
+key_cF9                EQU     &1A9
+key_cF10       EQU     &1EA
+key_cF11       EQU     &1EB
+key_cF12       EQU     &1EC
+
+key_scPrint    EQU     &1B0
+key_scF1       EQU     &1B1
+key_scF2       EQU     &1B2
+key_scF3       EQU     &1B3
+key_scF4       EQU     &1B4
+key_scF5       EQU     &1B5
+key_scF6       EQU     &1B6
+key_scF7       EQU     &1B7
+key_scF8       EQU     &1B8
+key_scF9       EQU     &1B9
+key_scF10      EQU     &1FA
+key_scF11      EQU     &1FB
+key_scF12      EQU     &1FC
+
+key_Left       EQU     &18C
+key_Right      EQU     &18D
+key_Down       EQU     &18E
+key_Up         EQU     &18F
+key_PageDown   EQU     &1CE
+key_PageUp     EQU     &1CF
+
+key_sLeft      EQU     &19C
+key_sRight     EQU     &19D
+key_sDown      EQU     &19E
+key_sUp                EQU     &19F
+key_sPageDown  EQU     &1DE
+key_sPageUp    EQU     &1DF
+
+key_cLeft      EQU     &1AC
+key_cRight     EQU     &1AD
+key_cDown      EQU     &1AE
+key_cUp                EQU     &1AF
+key_cPageDown  EQU     &1EE
+key_cPageUp    EQU     &1EF
+
+key_scLeft     EQU     &1BC
+key_scRight    EQU     &1BD
+key_scDown     EQU     &1BE
+key_scUp       EQU     &1BF
+key_scPageDown EQU     &1FE
+key_scPageUp   EQU     &1FF
+
+               ]
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/keyString b/StraySrc/Libraries/Sapphire/sh/keyString
new file mode 100644 (file)
index 0000000..9dca49f
--- /dev/null
@@ -0,0 +1,57 @@
+;
+; keyString.sh
+;
+; Translating key codes to strings
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  keyString
+
+               [       :LNOT::DEF:keyString__dfn
+               GBLL    keyString__dfn
+
+; --- keyString ---
+;
+; On entry:    R0 == key number, from Straylight extended keymap
+;              R1 == 0 => return full shortcuts (for e.g. writable icons)
+;                    1 => return abbreviated shortcuts (for e.g. menus)
+;
+; On exit:     CS if key number was recognised, and
+;                R0 == pointer to short cut string
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Translates a key number into a string suitable for
+;              displaying to a user, and returns a pointer to the
+;              translated string.
+
+               IMPORT  keyString
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/libOpts b/StraySrc/Libraries/Sapphire/sh/libOpts
new file mode 100644 (file)
index 0000000..5c63a45
--- /dev/null
@@ -0,0 +1,125 @@
+;
+; libOpts.sh
+;
+; Allow options for library units to be declared
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  libOpts_register
+;  libOpts_find
+;
+; Macros provided:
+;
+;  LIBOPT
+;  LOEND
+
+               [       :LNOT::DEF:libOpts__dfn
+               GBLL    libOpts__dfn
+
+;+             LIB     sapphire:^.bsh.libOpts
+
+; --- libOpts_register ---
+;
+; On entry:    R0 == address of an options block
+;
+; On exit:     --
+;
+; Use:         Adds the block given to the library options.
+
+               IMPORT  libOpts_register
+
+; --- libOpts_find ---
+;
+; On entry:    R0 == magic marker word
+;
+; On exit:     CS if found, and
+;                R0 == address of options block
+;              else CC, and
+;                R0 corrupted
+;
+; Use:         Tries to find an option with the given marker, which will
+;              normally be a four-character text string.  The first match
+;              found will be returned.  The options blocks are searched in
+;              reverse order of registration (i.e. blocks registered later
+;              will override blocks registered reviously).
+
+               IMPORT  libOpts_find
+
+;----- Macros ---------------------------------------------------------------
+
+               GBLA    lo__c
+lo__c          SETA    0
+               GBLL    lo__p
+lo__p          SETL    {FALSE}
+
+; --- Macro: LIBOPT ---
+;
+; Arguments:   name == name of this options subblock (4 characters)
+;
+; Use:         Sets up an options subblock with the given name.
+
+               MACRO
+$label         LIBOPT  $name
+               ALIGN
+
+               [       lo__p
+lo__sz$lo__c   EQU     {PC}-lo__a$lo__c
+               ]
+lo__c          SETA    lo__c+1
+
+$label
+               DCB     "$name"
+               DCD     lo__sz$lo__c
+lo__a$lo__c
+lo__p          SETL    {TRUE}
+
+               MEND
+
+; --- Macro: LOEND ---
+;
+; Arguments:   --
+;
+; Use:         Terminates a library options block.
+
+               MACRO
+               LOEND
+               ALIGN
+
+               [       lo__p
+lo__sz$lo__c   EQU     {PC}-lo__a$lo__c
+               ]
+lo__c          SETA    lo__c+1
+lo__p          SETL    {FALSE}
+
+               DCD     -1
+
+               MEND
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/listbox b/StraySrc/Libraries/Sapphire/sh/listbox
new file mode 100644 (file)
index 0000000..49ad442
--- /dev/null
@@ -0,0 +1,283 @@
+;
+; listbox.sh
+;
+; Nice listbox handling routines
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  lb_create
+;  lb_destroy
+;  lb_eventHandler
+;  lb_plotString
+;  lb_update
+;  lb_updateItem
+;  lb_select
+;  lb_isSelected
+;  lb_clearSelection
+;  lb_clickS
+;  lb_clickM
+;  lb_drag
+;  lb_inserted
+;  lb_removed
+;  lb_init
+
+               [       :LNOT::DEF:listbox__dfn
+               GBLL    listbox__dfn
+
+; --- lb_create ---
+;
+; On entry:    R0 == pointer to list manager description block
+;              R1 == pointer to the list
+;              R2 == pointer to a width function
+;              R3 == The height of each item
+;              R4 == parent window handle or
+;                    pointer to window block if R5 == -1
+;              R5 == parent icon handle or -1 if not a pane
+;
+; On exit:     R0 == listbox handle
+;              R1 == window handle of list box
+;              May return an error (R1 corrupted)
+
+               IMPORT  lb_create
+
+; --- lb_destroy ---
+;
+; On entry:    R0 == listbox handle
+;
+; On exit:     --
+;
+; Use:         Destroys the given listbox.
+
+               IMPORT  lb_destroy
+
+; --- lb_eventHandler ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == handler function
+;              R2 == R10 value to pass
+;              R3 == R12 value to pass
+;
+; On exit:     --
+;
+; Use:         Registers an event handler for the given listbox.
+
+               IMPORT  lb_eventHandler
+
+; --- lb_plotString ---
+;
+; On entry:    R0 == pointer to a string
+;              R1 == pointer to the list item
+;              R2-R5 == window coordinates to plot it
+;              R10 == pointer to the listbox
+;
+; On exit:     --
+;
+; Use:         Plots a list item consisting of a single string.  It assumes
+;              the default selection model.
+
+               IMPORT  lb_plotString
+
+; --- lb_update ---
+;
+; On entry:    R0 == listbox handle
+;
+; On exit:     May return an error
+;
+; Use:         Updates the entire listbox prettily
+
+               IMPORT  lb_update
+
+; --- lb_updateItem ---
+;
+; On entry:    R0 == list box handle
+;              R1 == list item handle
+;
+; On exit:     --
+;
+; Use:         Redraws a list item to reflect a change in its state.
+
+               IMPORT  lb_updateItem
+
+; --- lb_select ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == item handle
+;              R2 == 0 to unselect, 1 to select, or 2 to toggle
+;
+; On exit:     --
+;
+; Use:         Selects or deselects a listbox item, nicely and without
+;              flickering it.
+
+               IMPORT  lb_select
+
+; --- lb_isSelected ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == item handle
+;
+; On exit:     CS if item is selected, else CC
+;
+; Use:         Informs you whether an item is selected.
+
+               IMPORT  lb_isSelected
+
+; --- lb_clearSelection ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == item handle of item to ignore (or 0 for none)
+;
+; On exit:     --
+;
+; Use:         Deselects all items in the listbox.
+
+               IMPORT  lb_clearSelection
+
+; --- lb_clickS ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == pointer to list item
+;              R3 == mouse button status
+;
+; On exit:     --
+;
+; Use:         Provides a default action for clicking on an item in a
+;              list box.
+;
+;              Only one selection is possible at any one time.
+
+               IMPORT  lb_clickS
+
+; --- lb_clickM ---
+;
+; On entry:    R0 == listbox handle
+;              R1 == pointer to list item
+;              R3 == mouse button status
+;
+; On exit:     --
+;
+; Use:         Provides a default action for clicking on an item in a
+;              list box.
+;
+;              The multiple selection model is used.
+
+               IMPORT  lb_clickM
+
+; --- lb_drag ---
+;
+; On entry:    R1 == pointer to list item
+;              R2 == window relative y position
+;              R3 == mouse button status
+;              R10 == listbox handle
+;
+; On exit:     --
+;
+; Use:         Starts a drag operation to allow for easy multiple
+;              selection.
+
+               IMPORT  lb_drag
+
+; --- lb_inserted ---
+;
+; On entry:    R0 == pointer to the listbox
+;              R1 == pointer to the new item
+;
+; On exit:     --
+;
+; Use:         Informs the listbox that an item has been inserted,
+;              and causes a flicker free insert to occur if possible.
+
+               IMPORT  lb_inserted
+
+; --- lb_removed ---
+;
+; On entry:    R0 == pointer to the listbox
+;              R1 == index of item removed
+;
+; On exit:     --
+;
+; Use:         Informs the listbox that an item has been removed, and
+;              causes a flicker free remove to occur, if possible.
+
+               IMPORT  lb_removed
+
+; --- lb_window ---
+;
+; On entry:    R0 == listbox handle
+;
+; On exit:     R0 == window handle
+;
+; Use:         Returns the window handle of the listbox
+
+               IMPORT  lb_window
+
+; --- lb_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the listbox unit.
+
+               IMPORT  lb_init
+
+;----- List events ----------------------------------------------------------
+
+               ^       0
+lbEvent_close  #       1                       ;Listbox has been closed
+
+lbEvent_redraw #       1                       ;Redraw a list item
+                                               ;R1 == pointer to list item
+                                               ;R2-R5 == window coords
+lbEvent_click  #       1                       ;Click/Double on listbox
+                                               ;R1 == pointer to list item
+                                               ;R2 == window relative y pos
+                                               ;R3 == button type (10)
+lbEvent_menu   #       1                       ;Menu click
+                                               ;R1 == pointer to list item
+                                               ;R2 == window relative y pos
+                                               ;R3 == button type (10)
+lbEvent_drag   #       1                       ;Drag on listbox
+                                               ;R1 == pointer to list item
+                                               ;R2 == window relative y pos
+                                               ;R3 == button type (10)
+lbEvent_help   #       1                       ;R1 == pointer to list item
+lbEvent_drop   #       1                       ;R1 == pointer to list item
+                                               ;R2 == filetype
+                                               ;R3 == pointer to filename
+                                               ;R4 == estimated file size
+                                               ;R5 == subreason cde
+
+               ^       0
+lbDrop_load    #       1
+lbDrop_save    #       1
+
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/llistMan b/StraySrc/Libraries/Sapphire/sh/llistMan
new file mode 100644 (file)
index 0000000..54163c5
--- /dev/null
@@ -0,0 +1,223 @@
+;
+; llistMan.sh
+;
+; Linked List Management
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  llist_create
+;  llist_destroy
+;  llist_addItem
+;  llist_removeItem
+;  llist_reinsert
+;  llist_setFlags
+;  llist_items
+;  llist_enumerate
+;  llist_itemToIndex
+;  llist_indexToItem
+;  llist_registerSort
+;  llist_init
+;  llist_desc
+
+               [       :LNOT::DEF:llistMan__dfn
+               GBLL    llistMan__dfn
+
+; --- llist_create ---
+;
+; On entry:    R0 == pointer to 12 byte list head to fill in
+;              R1 == sort routine to use (0 for none)
+;
+; On exit:     List head filled in appropriately
+;
+; Use:         This call set up list. It must be made just once, before
+;              and other list alls are made. On entry, R0 must point to
+;              12 bytes in memory, which is filled in by this call.
+;              Example code may look like:
+;
+;                      ADR     R0,myList
+;                      LDR     R1,=myStrCmp
+;                      BL      llist_create
+;
+;                        .
+;                         .
+;                        .
+;
+;                      mylist  DCD     0,0
+
+               IMPORT  llist_create
+
+; --- llist_destroy ---
+;
+; On entry:    R0 == pointer to list head
+;
+; On exit:     R0 corrupted
+;
+; Use:         Destroys the given list.
+
+               IMPORT  llist_destroy
+
+; --- llist_addItem ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == pointer to user data (or 0 if none to copy)
+;              R2 == size of user data
+;
+; On exit:     R0 preserved
+;              R1 == pointer to the new user data
+;              May return an error
+;
+; Use:         This call will add an item to a list. Notice that the
+;              item is entirely allocated by the list manager, it does not
+;              point to the data that you supply it, instead it
+;              copies the data into the newly created item. For this reason
+;              if 0 is supplied as the user data, nothing is copied.
+;              It is the returned user data pointer, that must be
+;              used to reference the item in other llist calls.
+
+               IMPORT  llist_addItem
+
+; --- llist_removeItem ---
+;
+; On entry:    R0 == list head pointer
+;              R1 == pointer to item to remove (as returned by addItem)
+;
+; On exit:     --
+;
+; Use:         This call removes the item from the given list. All
+;              memory taken up by the item is freed. If the value
+;              passed in R1 is not an item in the list, then all hell is
+;              likely to break loose, so I don't advise making this mistake.
+
+               IMPORT  llist_removeItem
+
+; --- llist_reinsert ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == item to reinsert
+;
+; On exit:     --
+;
+; Use:         Reinserts the given item into the list. This call is
+;              used if the item is updated in such a way that its
+;              position in the list may change.
+
+               IMPORT  llist_reinsert
+
+; --- llist_setFlags ---
+;
+; On entry:    R1 == pointer to list item
+;              R2 == BIC word
+;              R3 == EOR word
+;
+; On exit:     R2 == the new flags word
+;
+; Use:         Sets the flags associated with the given item. If you
+;              just wish to read them, set R2 and R3 to 0.
+
+               IMPORT  llist_setFlags
+
+; --- llist_items ---
+;
+; On entry:    R0 == pointer to list head
+;
+; On exit:     R1 == number of items in list
+;
+; Use:         Returns the number of items in the list given. This is
+;              a cached value, and so is very fast.
+
+               IMPORT  llist_items
+
+; --- llist_enumerate ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == pointer to item (0 for first)
+;              R2 == mask word
+;              R3 == test word
+;
+; On exit:     CS and R1 == next item that matches
+;              CC and R1 corrupted if no more items
+;
+; Use:         This calls return each item in the list, one at a time,
+;              as long as the item matches the pattern given.
+
+               IMPORT  llist_enumerate
+
+; --- llist_itemToIndex ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == point to the item
+;
+; On exit:     R1 == index of the item, -1 if it's not there
+;
+; Use:         Returns the index of the item given, indexed from 0.
+
+               IMPORT  llist_itemToIndex
+
+; --- llist_indexToItem ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == point to the index (indexed from 0)
+;
+; On exit:     R1 == the item itself, or 0 if index doesn't exist
+;
+; Use:         Returns the index of the item given, indexed from 0.
+
+               IMPORT  llist_indexToItem
+
+; --- llist_registerSort ---
+;
+; On entry:    R0 == pointer to list head
+;              R1 == pointer to new sort routine
+;
+; On exit:     --
+;
+; Use:         Registers a new sort routine to be used on the given
+;              list. This call will also cause a complete resort
+;              of the given list using a mergesort algorithm -- O(n log n).
+
+               IMPORT  llist_registerSort
+
+; --- llist_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the llistMan unit.
+
+               IMPORT  llist_init
+
+; --- llist_desc ---
+;
+; A llist decription for use with listbox
+
+               IMPORT  llist_desc
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/mbox b/StraySrc/Libraries/Sapphire/sh/mbox
new file mode 100644 (file)
index 0000000..ade9451
--- /dev/null
@@ -0,0 +1,60 @@
+;
+; mbox.sh
+;
+; Handling for monologue boxes
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  mbox
+
+               [       :LNOT::DEF:mbox__dfn
+               GBLL    mbox__dfn
+
+; --- mbox ---
+;
+; On entry:    R0 == dialogue box handle
+;              R1 == pointer to help message tag for dialogue box
+;              R2 == icon handle for embedded title
+;
+; On exit:     --
+;
+; Use:         Displays a `monologue' box (i.e. a dialogue box which just
+;              displays information to the user) on the screen and sets up
+;              an event handler for it.  The dialogue box is destroyed when
+;              it is closed.
+;
+;              If the dialogue box does not have a title bar (read by
+;              dbox_hasTitle) then R2 is used to give the monologue box
+;              an embedded title.  R2 is not used otherwise, and thus may
+;              safely contain any old rubbish.
+
+               IMPORT  mbox
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/mem b/StraySrc/Libraries/Sapphire/sh/mem
new file mode 100644 (file)
index 0000000..7775478
--- /dev/null
@@ -0,0 +1,54 @@
+;
+; mem.sh
+;
+; Operations on memory blocks
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  mem_set
+
+               [       :LNOT::DEF:mem__dfn
+               GBLL    mem__dfn
+
+; --- mem_set ---
+;
+; On entry:    R0 == pointer to a block of memory (word-aligned)
+;              R1 == size of the block
+;              R2 == word value to store in the block
+;
+; On exit:     --
+;
+; Use:         Initialises a block by filling every word within it with the
+;              same value.  This is normally 0, although maybe MOVS PC,#0
+;              might be useful too.
+
+               IMPORT  mem_set
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/menu b/StraySrc/Libraries/Sapphire/sh/menu
new file mode 100644 (file)
index 0000000..3eb1dd5
--- /dev/null
@@ -0,0 +1,82 @@
+;
+; menu.sh
+;
+; RISC OS menu handling facilities
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  menu_create
+;  menu_help
+;  menu_init
+
+               [       :LNOT::DEF:menu__dfn
+               GBLL    menu__dfn
+
+; --- menu_create ---
+;
+; On entry:    R0 == pointer to menu definition table
+;              R1 == event handler to use
+;              R2 == R10 value for handler
+;              R3 == R12 value for handler
+;
+; On exit:     --
+;
+; Use:         Creates a menu from the given menu definition
+;              table. If this call is called more than once before
+;              a menu is opened then the menu definiton are concatenated
+;              into a large menu. Only the first menu title read is
+;              taken notice of. Notice therefore, that the call doesn't
+;              actually open a menu.
+
+               IMPORT  menu_create
+
+; --- menu_help ---
+;
+; On entry:    R0 == pointer to base message tag
+;              R1 == index of menu item
+;
+; On exit:     --
+;
+; Use:         Adds a string to the help message found by adding the menu
+;              item number to the base message tag.
+
+               IMPORT  menu_help
+
+; --- menu_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the menu system.
+
+               IMPORT  menu_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/menuDefs b/StraySrc/Libraries/Sapphire/sh/menuDefs
new file mode 100644 (file)
index 0000000..77ff988
--- /dev/null
@@ -0,0 +1,544 @@
+;
+; menuDefs.sh
+;
+; Constant definitions and macros for dealing with menus
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Macros provided:
+;
+;   BITSPEC
+;   SETBIT
+;   NEWITEM
+;   MENU
+;   MENUI
+;   TEAROFF
+;   TEAROFFI
+;   R12DATA
+;   MAKEME
+;   MHEIGHT
+;   GLOBALM
+;   ITEM
+;   ITEWI
+;   SHADE
+;   ISHADE
+;   SWITCH
+;   RADIO
+;   SPRITE
+;   HALFSZ
+;   SUBWARN
+;   SUBMENU
+;   NOWARN
+;   RULEOFF
+;   MENUEND
+
+               [       :LNOT::DEF:menuDefs__dfn
+               GBLL    menuDefs__dfn
+
+;+             LIB     sapphire:^.bsh.menuDefs
+
+;----- Constants for menus --------------------------------------------------
+;
+; In the descriptions of flags below, the data required in the packed menu
+; definition is shown in the comments.  Insert items in the order of the
+; bit precedences of the flags.
+;
+; Note -- a (*) following a description means the flag is only supported by
+; tms (the tearoff system), and a (+) means that the flag is only supported
+; by menu (the WIMP system).
+
+; --- Flags for menu titles and items ---
+
+mFlag_indirect EQU     (1<<0)                  ;Data string is indirect
+                                               ;+0 == offset of text pointer
+                                               ;+4
+
+mFlag_R12      EQU     (1<<16)                 ;Use R12 for writable data
+                                               ;+0
+
+mFlag_noTrans  EQU     (1<<19)                 ;Don't translate messages
+                                               ;+0
+
+; --- Menu title flags ---
+
+mFlag_tearoff  EQU     (1<<1)                  ;Menu may be torn off (*)
+                                               ;+0
+
+mFlag_makeMe   EQU     (1<<2)                  ;Menu recreated by client (+)
+                                               ;+0 == pointer to recreate fn
+                                               ;+4
+
+mFlag_maxHeight        EQU     (1<<3)                  ;Menu has a max height (*)
+                                               ;+0 == max height in OS units
+                                               ;+4
+
+mFlag_global   EQU     (1<<4)                  ;Menu is `global' (*)
+                                               ;+0
+
+; --- Menu item flags ---
+
+mFlag_shortCut EQU     (1<<1)                  ;Item has a shortcut
+                                               ;+0 == shortcut key number
+                                               ;+4
+
+mFlag_iShortCut        EQU     (1<<2)                  ;Item has indirected shortcut
+                                               ;+0 == offset of key number
+                                               ;+4
+
+mFlag_shade    EQU     (1<<3)                  ;Item may be shaded
+                                               ;+0 == bitspec of shade bit
+                                               ;+4
+
+mFlag_invShade EQU     (1<<4)                  ;Item may be unshaded
+                                               ;+0 == bitspec of unshade bit
+                                               ;+4
+
+mFlag_switch   EQU     (1<<5)                  ;Item is a switch (tickable)
+                                               ;+0 == bitspec of tick bit
+                                               ;+4
+
+mFlag_radio    EQU     (1<<6)                  ;Item is a radio button
+                                               ;+0 == offset of grp selector
+                                               ;+4 == number of item in grp
+                                               ;+8
+
+mFlag_sprite   EQU     (1<<7)                  ;Item contains a sprite (*)
+                                               ;For WIMP menus:
+                                               ;+0 == ptr to validation str
+                                               ;+4
+                                               ;For TMS menus:
+                                               ;+0 == offset of name pointer
+                                               ;+4 == sprite area (-1==res)
+                                               ;+8
+
+mFlag_halfSize EQU     (1<<8)                  ;Display sprite half sized
+                                               ;+0
+
+mFlag_subWarn  EQU     (1<<9)                  ;Make event on opening sub
+                                               ;+0
+
+mFlag_subMenu  EQU     (1<<10)                 ;Item has a submenu
+                                               ;+0 == pointer to submenu def
+                                               ;+4
+
+mFlag_noWarn   EQU     (1<<17)                 ;Don't open sub when shaded
+                                               ;+0
+
+mFlag_ruleOff  EQU     (1<<18)                 ;Rule off after the item
+                                               ;+0
+
+mFlag_end      EQU     (1<<31)                 ;There are no more items
+                                               ;+0
+
+; --- Event codes ---
+;
+; Event codes are returned in R0, with R1 being the item number within
+; the packed menu definition, indexed from 0.
+;
+; Note: mEvent_deleted is only sent to the topmost menu title by the
+; standard menu system, but is sent to the titles of all menus being closed
+; by TMS.  If you are converting from one to the other, bear this in mind.
+
+mEvent_select  EQU     0                       ;The user chose a menu item
+                                               ;R1 == item number
+                                               ;R2 == address of packed def
+
+mEvent_subMenu EQU     1                       ;A submenu is about to open
+                                               ;R1 == item number
+
+mEvent_deleted EQU     2                       ;A menu has just closed
+
+mEvent_help    EQU     3                       ;Help is wanted for an item
+                                               ;R1 == item number
+                                               ;R2 == address of packed def
+
+;----- Menu creation macros -------------------------------------------------
+
+; --- Note to reader ---
+;
+; These macros make a lot of use of private constants and variables.  Try to
+; avoid examining these too closely, because you'll probably get lost.
+
+; --- Set up the variables ---
+
+               GBLA    md__i
+md__i          SETA    0
+               GBLA    md__f
+md__f          SETA    0
+
+; --- Macro: BITSPEC ---
+;
+; Arguments:   offset == offset into workspace of target word
+;              bit == bitmask with a 1 in the position of the bit
+;
+; Use:         Assembles a bit specification referencing the described bit.
+;              The bit is described by a mask word rather than a bit
+;              position, because it is expected that you will already have
+;              set up constants for bit masks.
+
+               MACRO
+               BITSPEC $offset,$bit
+
+               LCLA    bn
+bn             SETA    0
+               LCLA    bv
+bv             SETA    $bit
+               [       bv = 0
+               !       1,"Bit mask is 0 in BITSPEC"
+               ]
+
+               WHILE   (bv :AND: 1)=0
+bn             SETA    bn+1
+bv             SETA    bv >> 1
+               WEND
+
+               DCD     ($offset << 5) :OR: bn
+               MEND
+
+; --- Macro: SETBIT ---
+;
+; Arguments:   flag == which menu flag above to set
+;
+; Use:         Sets a bit within the current item or menu title's flags
+;              word.  It ensures that items are inserted in the correct
+;              order.
+
+               MACRO
+               SETBIT  $flag
+               [       (md__f :AND: &ffff) >= $flag
+               !       1,"Flags built in bad order in menuDefs"
+               ]
+md__f          SETA    md__f :OR: $flag
+               MEND
+
+; --- Macro: NEWITEM ---
+;
+; Arguments:   --
+;
+; Use:         Starts a new menu item or menu title.  It also inserts a new
+;              flags word in the current position.
+
+               MACRO
+$label         NEWITEM
+               ALIGN
+$label
+md__F$md__i    EQU     md__f
+md__f          SETA    0
+md__i          SETA    md__i+1
+               DCD     md__F$md__i
+               MEND
+
+; --- Macro: MENU ---
+;
+; Arguments:   title == the menu's title string/message tag
+;
+; Use:         Creates a nonindirected menu title and starts a new menu.
+
+               MACRO
+$label         MENU    $title
+$label         NEWITEM
+               [       :LEN:"$title">12
+               !       1,"Menu title too long"
+               ]
+               DCB     "$title",0
+               ALIGN
+               MEND
+
+; --- Macro: MENUI ---
+;
+; Arguments:   title == offset to title pointer in client's workspace
+;
+; Use:         Creates an indirected menu title and starts a new menu.
+
+               MACRO
+$label         MENUI   $title
+$label         NEWITEM
+               SETBIT  mFlag_indirect
+               DCD     $title
+               MEND
+
+; --- Macro: TEAROFF ---
+;
+; Arguments:   title == menu's title string/message tag
+;
+; Use:         Creates a nonindirected tearoff menu title and starts a new
+;              menu.
+
+               MACRO
+$label         TEAROFF $title
+$label         NEWITEM
+               DCB     "$title",0
+               ALIGN
+               SETBIT  mFlag_tearoff
+               MEND
+
+; --- Macro: TEARI ---
+;
+; Arguments:   title == offset to title pointer in client's workspace
+;
+; Use:         Creates an indirected tearoff menu title and starts a new
+;              menu.
+
+               MACRO
+$label         TEARI   $title
+$label         NEWITEM
+               SETBIT  mFlag_indirect
+               DCD     $title
+               SETBIT  mFlag_tearoff
+               MEND
+
+; --- Macro: R12DATA ---
+;
+; Arguments:   --
+;
+; Use:         Sets the current menu item or menu title to use the client's
+;              R12 pointer rather than its R10 pointer for workspace.
+
+               MACRO
+               R12DATA
+               SETBIT  mFlag_R12
+               MEND
+
+; --- Macro: NOTRANS ---
+;
+; Arguments:   --
+;
+; Use:         Disables message translation of the current item or menu
+;              title.  This is useful if you're building the item or title
+;              text dynamically.
+
+               MACRO
+               NOTRANS
+               SETBIT  mFlag_noTrans
+               MEND
+
+; --- Macro: MAKEME ---
+;
+; Arguments:   makeProc == pointer to procedure which will remake the menu
+;
+; Use:         Sets the current menu to require being remade from scratch
+;              when being updated (e.g. after an item is selected).
+
+               MACRO
+               MAKEME  $makeProc
+               SETBIT  mFlag_makeMe
+               DCD     $makeProc
+               MEND
+
+; --- Macro: MHEIGHT ---
+;
+; Arguments:   height == maximum permitted height for menu in OS units
+;
+; Use:         Sets the menu's maximum allowable height.
+
+               MACRO
+               MHEIGHT $height
+               SETBIT  mFlag_maxHeight
+               DCD     $height
+               MEND
+
+; --- Macro: GLOBALM ---
+;
+; Arguments:   --
+;
+; Use:         Sets the menu's maximum allowable height.
+
+               MACRO
+               GLOBALM
+               SETBIT  mFlag_global
+               MEND
+
+; --- Macro: ITEM ---
+;
+; Arguments:   text == item's text string/message tag
+;
+; Use:         Creates a new nonindirected menu item.
+
+               MACRO
+$label         ITEM    $text
+$label         NEWITEM
+               DCB     "$text",0
+               ALIGN
+               MEND
+
+; --- Macro: ITEMI ---
+;
+; Arguments:   text == offset of pointer to menu text
+;
+; Use:         Creates a new indirected menu item
+
+               MACRO
+$label         ITEMI   $text
+$label         NEWITEM
+               SETBIT  mFlag_indirect
+               DCD     $text
+               MEND
+
+; --- Macro: SHADE ---
+;
+; Arguments:   $offset,$bit == bitspec of item's `shaded' bit
+;
+; Use:         Sets the current item to be shadable.
+
+               MACRO
+               SHADE   $offset,$bit
+               SETBIT  mFlag_shade
+               BITSPEC $offset,$bit
+               MEND
+
+; --- Macro: ISHADE ---
+;
+; Arguments:   offset,$bit == bitspec of item's `unshaded' bit
+;
+; Use:         Sets the current item to be inverse shadable.
+
+               MACRO
+               ISHADE  $offset,$bit
+               SETBIT  mFlag_invShade
+               BITSPEC $offset,$bit
+               MEND
+
+; --- Macro: SWITCH ---
+;
+; Arguments:   offset,$bit == bitspec of item's `ticked' bit
+;
+; Use:         Sets the current item to be tickable.
+
+               MACRO
+               SWITCH  $offset,$bit
+               SETBIT  mFlag_switch
+               BITSPEC $offset,$bit
+               MEND
+
+; --- Macro: RADIO ---
+;
+; Arguments:   group == offset of this item's radio group selector
+;              selector == value of selector to blob this item
+;
+; Use:         Marks this item as a radio item, so that it is blobbed (or
+;              ticked under the WIMP menu system) when the selector in the
+;              client's workspace matches the item's selector.
+
+               MACRO
+               RADIO   $group,$selector
+               SETBIT  mFlag_radio
+               DCD     $group,$selector
+               MEND
+
+; --- Macro: SPRITE ---
+;
+; Arguments:   sprite == EITHER address of validation string, OR offset of
+;                sprite name pointer (if area argument given)
+;              area == (optional) sprite area, or -1 for resspr_area
+;
+; Use:         Adds a sprite to the menu item definition.
+
+               MACRO
+               SPRITE  $sprite,$area
+               SETBIT  mFlag_sprite
+               DCD     $sprite
+               [ "$area"<>""
+               DCD     $area
+               ]
+               MEND
+
+; --- Macro: HALFSZ ---
+;
+; Arguments:   --
+;
+; Use:         Sets the item to display its sprite at half size
+
+               MACRO
+               HALFSZ
+               SETBIT  mFlag_halfSize
+               MEND
+
+; --- Macro: SUBWARN ---
+;
+; Arguments:   --
+;
+; Use:         Sets the item to generate submenu warnings when its submenu
+;              arrow is pointed at.
+
+               MACRO
+               SUBWARN
+               SETBIT  mFlag_subWarn
+               MEND
+
+; --- Macro: SUBMENU ---
+;
+; Arguments:   subMenu == pointer to packed definition of the submenu
+;              handler == pointer to handler routine
+;
+; Use:         Attaches the given menu as a submenu of this item.
+
+               MACRO
+               SUBMENU $subMenu,$handler
+               SETBIT  mFlag_subMenu
+               DCD     $subMenu,$handler
+               MEND
+
+; --- Macro: NOWARN ---
+;
+; Arguments:   --
+;
+; Use:         Prevents this item from returning submenu events if it is
+;              shaded.
+
+               MACRO
+               NOWARN
+               SETBIT  mFlag_noWarn
+               MEND
+
+; --- Macro: RULEOFF ---
+;
+; Arguments:   --
+;
+; Use:         Inserts a ruleoff after the current item, assuming there are
+;              some more items after it.
+
+               MACRO
+               RULEOFF
+               SETBIT  mFlag_ruleOff
+               MEND
+
+; --- Macro: MENUEND ---
+;
+; Arguments:   --
+;
+; Use:         Finishes off the current menu.
+
+               MACRO
+               MENUEND
+md__F$md__i    EQU     md__f
+md__f          SETA    0
+md__i          SETA    md__i+1
+               DCD     mFlag_end
+               MEND
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/msgs b/StraySrc/Libraries/Sapphire/sh/msgs
new file mode 100644 (file)
index 0000000..b7abba3
--- /dev/null
@@ -0,0 +1,108 @@
+;
+; msgs.sh
+;
+; Message file handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  msgs_load
+;  msgs_build
+;  msgs_error
+;  msgs_lookup
+;  msgs_init
+
+               [       :LNOT::DEF:msgs__dfn
+               GBLL    msgs__dfn
+
+; --- msgs_load ---
+;
+; On entry:    R0 == pointer to filename
+;
+; On exit:     May return an error
+;
+; Use:         Reads in the given messages file.
+
+               IMPORT  msgs_load
+
+; --- msgs_build ---
+;
+; On entry:    R0 == pointer to a message string
+;              R1 == pointer to output buffer
+;
+; On exit:     R0 == pointer to buffer (R1 on entry)
+;              R1 == pointer to terminating null
+;
+; Use:         Builds a message string, by substituting message references
+;              by their values.  Each reference of the form `$tag' (or
+;              optionally `$(tag)', to avoid having to have a trailing)
+;              space is replaced by the actual message.  A literal `$' sign
+;              may be represented as `$$'.
+
+               IMPORT  msgs_build
+
+; --- msgs_error ---
+;
+; On entry:    R0 == pointer to an error skeleton string:
+;                      R0+0 == error number
+;                      R0+4 == message tag-and-default (null-terminated)
+;              R2-R11 == filler strings (not message tags)
+;
+; On exit:     R0 == pointer to translated error message (in error buffer)
+;              R1 == pointer to null terminator of message
+;
+; Use:         Performs string sustitution on an error message (as done by
+;              str_subst), but translating the error string.
+
+               IMPORT  msgs_error
+
+; --- msgs_lookup ---
+;
+; On entry:    R0 == message tag (and default message)
+;
+; On exit:     R0 == pointer to located message
+;
+; Use:         Returns the real message from its tag. If the tag does not
+;              exist, then the default message is used. If that is not
+;              supplied, then the tag name itself is returned (ie. R0
+;              is preserved).
+
+               IMPORT  msgs_lookup
+
+; --- msgs_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the message system.
+
+               IMPORT  msgs_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/ncs b/StraySrc/Libraries/Sapphire/sh/ncs
new file mode 100644 (file)
index 0000000..8926c9a
--- /dev/null
@@ -0,0 +1,125 @@
+;
+; colSelect.sh
+;
+; Definitions for the colour selector
+;
+; © 1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+; Macros provided:
+;
+; Controls provided:
+
+               [       :LNOT::DEF:colSelect__dfn
+               GBLL    colSelect__dfn
+
+;----- Definition of a colour -----------------------------------------------
+
+; --- A colour block ---
+;
+; The first word is the only bit which applications should really be
+; interested in: it's a colour in RGB format suitable for passing to
+; ColourTrans_SetColour or similar.
+;
+; The model id is used by the colour selector to ensure that the colour
+; is edited in the correct way.  The date area is specific to a particular
+; colour model, and its format is not described here.  However, the model-
+; specific data must not contain pointers to external data areas or other
+; references to session-specific information.  Applications are permitted
+; to save colour blocks to disk and expect them to work properly when read
+; back.
+
+               ^       0
+csColour_rgb   #       4                       ;A ColourTrans RGB colour
+csColour_model #       4                       ;A ColSelect model ID
+csColour_data  #       24                      ;Model-specific data
+csColour_size  #       0                       ;Size of a colour block
+
+;----- Colour model interface -----------------------------------------------
+
+; --- A colour model definition block ---
+
+               ^       0
+csModel_id     #       4                       ;Colour model ID number
+csModel_size   #       4                       ;Size of workspace required
+csModel_handler        #       4                       ;Pointer to handler routine
+csModel_name   #       0                       ;Null terminated name string
+
+; --- Colour selector event codes ---
+
+csEvent_base   EQU     &C0000000
+
+               ^       csEvent_base
+csEvent_res    #       1                       ;Diagram changed resolution
+csEvent_get    #       1                       ;Get colour; reset panel
+
+; --- Resolution codes ---
+
+               ^       0
+csRes_perfect  #       1
+csRes_high     #       1
+csRes_medium   #       1
+csRes_low      #       1
+
+; --- Known colour models ---
+
+csModelId_trans        EQU     0                       ;The `transparent' colour
+csModelId_rgb  EQU     1                       ;Standard red/green/blue
+csModelId_cmyk EQU     2                       ;Cyan/Magenta/Yellow/Black
+csModelId_hsv  EQU     3                       ;Hue/Saturation/Value
+csModelId_named        EQU     4                       ;Named colours
+
+; --- Colour selector data layout ---
+
+               ^       0,R10
+csData_frame   #       4                       ;Dialogue handle of frame
+csData_panel   #       4                       ;Dialogue handle of panel
+csData_colour  #       csColour_size           ;Working copy of colour data
+csData_res     #       4                       ;Diagram resolution
+csData_flags   #       4                       ;Various useful flags
+csData_userCol #       4                       ;Pointer to user's colour
+csData_model   #       0                       ;Model-specific data
+csData_size    EQU     {VAR} - csData_frame
+
+; --- cs_addModel ---
+;
+; On entry:    R0 = pointer to model definition block
+;              R1 = pointer to model workspace
+;
+; On exit:     May return an error.
+;
+; Use:         Registers a colour model with the colour selector.
+;
+;              The colour model block contains a pointer to a handler
+;              routine, csModel_handler, which is called to create the
+;              model's panel.  It is called as follows:
+;
+;              R10 = pointer to colour selector data
+;              R12 = workspace value passed to cs_addModel in R1
+;
+;              The handler returns a dialogue box handle in R0.  Further
+;              requests are sent to the dialogue box as events
+
+               IMPORT  cs_addModel
diff --git a/StraySrc/Libraries/Sapphire/sh/nopoll b/StraySrc/Libraries/Sapphire/sh/nopoll
new file mode 100644 (file)
index 0000000..676230a
--- /dev/null
@@ -0,0 +1,108 @@
+;
+; nopoll.sh
+;
+; Handling nonpolling dialogue boxes
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  nopoll_open
+;  nopoll_close
+;  nopoll_init
+;  nopoll_process
+
+               [       :LNOT::DEF:nopoll__dfn
+               GBLL    nopoll__dfn
+
+; --- nopoll_open ---
+;
+; On entry:    R0 == a window handle to take over
+;
+; On exit:     --
+;
+; Use:         Sets up the window with the given handle to be a nonpolling
+;              dialogue box.  The window must already be open on the screen.
+;              This call will force it to be painted on the screen, and
+;              then start faking events for it.
+
+               IMPORT  nopoll_open
+
+; --- nopoll_close ---
+;
+; On entry:    R0 == return value for nopoll_process (can be anything)
+;
+; On exit:     --
+;
+; Use:         Tells nopoll that the nonpolling window has been killed,
+;              and hence that polling can return to normal again.  You can
+;              specify a return value to give from nopoll_process (if that
+;              system is being used).
+
+               IMPORT  nopoll_close
+
+; --- nopoll_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises nopoll so it can be used.
+
+               IMPORT  nopoll_init
+
+; --- nopoll_process ---
+;
+; On entry:    --
+;
+; On exit:     R0 == value passed to nopoll_close
+;
+; Use:         Processes a nonpolling window until it calls nopoll_close.
+;              It then returns the value passed to nopoll_close in R0,
+;              which can be defined in any way you want.
+;
+;              Some notes on the use of this routine:
+;
+;              * It calls event_poll, so any functions that get called
+;                after the normal event_poll don't get called.  Since the
+;                Wimp isn't actually being polled at all, this isn't a
+;                real problem as long as your handlers are registered at the
+;                event filter level or higher (e.g. win event handlers or
+;                even dbox handlers).
+;
+;              * It uses up an extra 256 bytes of stack for a poll block.
+;                If you think you might miss this stack space, then you'd
+;                better not use this routine.
+;
+;              * It isn't reentrant, but then again, nor is the rest of the
+;                nopoll system -- you can only have one nonpolling box open
+;                at a time.
+
+               IMPORT  nopoll_process
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/note b/StraySrc/Libraries/Sapphire/sh/note
new file mode 100644 (file)
index 0000000..11a15b6
--- /dev/null
@@ -0,0 +1,50 @@
+;
+; note.sh
+;
+; Handling of a Note box
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  note
+
+               [       :LNOT::DEF:note__dfn
+               GBLL    note__dfn
+
+; --- note ---
+;
+; On entry:    R0 == pointer to a piece of text to display
+;
+; On exit:     --
+;
+; Use:         Displays some text in a small window.
+
+               IMPORT  note
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/pane b/StraySrc/Libraries/Sapphire/sh/pane
new file mode 100644 (file)
index 0000000..802fe9a
--- /dev/null
@@ -0,0 +1,139 @@
+;
+; pane.sh
+;
+; Pane handling facilities
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  pane_add
+;  pane_remove
+;  pane_closed
+;  pane_deleted
+;  pane_swap
+;  pane_open
+;  pane_init
+
+               [       :LNOT::DEF:pane__dfn
+               GBLL    pane__dfn
+
+; --- pane_add ---
+;
+; On entry:    R0 == window handle of parent window
+;              R1 == icon handle in parent window
+;              R2 == window handle of pane window
+;
+; On exit:     May return an error
+;
+; Use:         This call registers a pane to be associated with the given
+;              window. The pane is always opened to fit exactly within
+;              the given icon -- border widths are taken into account
+;              if there are scroll bars etc.
+;
+;              You must call pane_closed if the parent window is closed,
+;              since there is no way for pane to trap this occurence.
+
+               IMPORT  pane_add
+
+; --- pane_remove ---
+;
+; On entry:    R0 == window handle for which pane was registered
+;              R1 == window handle of the pane window itself
+;
+; On exit:     --
+;
+; Use:         Removes the pane from the given window. This call will
+;              close the given pane, but will not actually delete it
+;              (ie. with a Wimp_DeleteWindow).
+
+               IMPORT  pane_remove
+
+; --- pane_closed ---
+;
+; On entry:    R0 == window handle of parent
+;
+; On exit:     --
+;
+; Use:         Informs pane that a parent window has closed.
+;              All associated panes are then closed.
+
+               IMPORT  pane_closed
+
+; --- pane_deleted ---
+;
+; On entry:    R0 == window handle of parent
+;
+; On exit:     --
+;
+; Use:         Informs pane that a parent window has been deleted.
+;              All associated panes are then closed, and there
+;              registration with the pane library module is
+;              terminated.
+
+               IMPORT  pane_deleted
+
+; --- pane_swap ---
+;
+; On entry:    R0 == window handle of parent window
+;              R1 == icon handle within parent window
+;              R2 == window handle of new pane
+;
+; On exit:     --
+;
+; Use:         This call will replace the pane in associated with icon R1
+;              in window R0, with the pane in R2.
+;
+;              The exisiting pane is closed, and the new pane is
+;              opened in it's place. No error is generated if the existing
+;              pane does not exist; this allows the caller to delete the
+;              window before doing the swap.
+
+               IMPORT  pane_swap
+
+; --- pane_open ---
+;
+; On entry:    R0 == window handle
+;
+; On exit:     --
+;
+; Use:         Opens all the panes associated with the given window.
+
+               IMPORT  pane_open
+
+; --- pane_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the pane unit.
+
+               IMPORT  pane_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/progInfo b/StraySrc/Libraries/Sapphire/sh/progInfo
new file mode 100644 (file)
index 0000000..0b0ee25
--- /dev/null
@@ -0,0 +1,52 @@
+;
+; progInfo.sh
+;
+; The `About this program' box
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  progInfo
+
+               [       :LNOT::DEF:progInfo__dfn
+               GBLL    progInfo__dfn
+
+; --- progInfo ---
+;
+; On entry:    R0 == pointer to purpose string
+;              R1 == pointer to author string
+;              R2 == pointer to version string
+;
+; On exit:     May return an error
+;
+; Use:         Displays an `About this program' dialogue box on the screen.
+
+               IMPORT  progInfo
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/ptr b/StraySrc/Libraries/Sapphire/sh/ptr
new file mode 100644 (file)
index 0000000..16e81dd
--- /dev/null
@@ -0,0 +1,98 @@
+;
+; ptr.sh
+;
+; Pointer changing and caret blinking
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  ptr_setShape
+;  ptr_resetShape
+;  ptr_blinkOn
+;  ptr_blinkOff
+;  ptr_init
+
+               [       :LNOT::DEF:ptr__dfn
+               GBLL    ptr__dfn
+
+; --- ptr_setShape ---
+;
+; On entry:    R0 == sprite name
+;              R1 == x offset of hot spot
+;              R2 == y offset of hot spot
+;
+; On exit:     --
+;
+; Use:         Set the pointer sprite to the given name. The sprite area
+;              used is that returned from resspre_area.
+
+               IMPORT  ptr_setShape
+
+; --- ptr_resetShape ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Resets the pointer shape to the default.
+
+               IMPORT  ptr_resetShape
+
+; --- ptr_blinkOn ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Makes the caret blink while it is in a window owned by your
+;              application.
+
+               IMPORT  ptr_blinkOn
+
+; --- ptr_blinkOff ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Turns the caret blinking off.
+
+               IMPORT  ptr_blinkOff
+
+; --- ptr_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the ptr system.
+
+               IMPORT  ptr_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/rand b/StraySrc/Libraries/Sapphire/sh/rand
new file mode 100644 (file)
index 0000000..fe7015a
--- /dev/null
@@ -0,0 +1,92 @@
+;
+; rand.sh
+;
+; Generating random numbers
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  rand
+;  rand_setSeed
+;  rnd
+;  rand_init
+
+               [       :LNOT::DEF:rand__dfn
+               GBLL    rand__dfn
+
+; --- rand ---
+;
+; On entry:    --
+;
+; On exit:     R0 == a pseudorandom number between 0 and &7FFFFFFF
+;
+; Use:         Returns a pseudorandom number.  The algorithm used is the
+;              additive generator found in Knuth.  The table is generated
+;              from the current monotonic time using a linear congruential
+;              generator.  Randomness is fairly good, and it's very quick.
+
+               IMPORT  rand
+
+; --- rand_setSeed ---
+;
+; On entry:    R0 == a pseudorandom seed
+;
+; On exit:     --
+;
+; Use:         Sets up the random number generator (rand) to the given start
+;              position.  The table of values is initialised from the seed
+;              in a psuedorandom manner, using a linear congruential
+;              generator.
+
+               IMPORT  rand_setSeed
+
+; --- rnd ---
+;
+; On entry:    R0 == start value (inclusive)
+;              R1 == end value (inclusive)
+;
+; On exit:     R0 == random number between the boundaries given
+;
+; Use:         Returns a random integer between the boundaries given.
+;              The distribution is slightly skewed towards lower numbers,
+;              but there's not a lot I can do about this, folks.
+
+               IMPORT  rnd
+
+; --- rand_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialise the random number table.
+
+               IMPORT  rand_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/repeater b/StraySrc/Libraries/Sapphire/sh/repeater
new file mode 100644 (file)
index 0000000..73c48d9
--- /dev/null
@@ -0,0 +1,74 @@
+;
+; repeater.sh
+;
+; Handles things that should auto-repeat
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  repeater
+;  rpt_end
+
+               [       :LNOT::DEF:repeater__dfn
+               GBLL    repeater__dfn
+
+; --- repeater ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R10 value to pass to routine
+;              R2 == R12 value to pass to routine
+;
+; On exit:     --
+;
+; Use:         Calls a routine (a) immediately, (b) after the configured
+;              keyboard delay rate and (c) repeatedly after the configured
+;              keyboard repeat rate.  Calls stop when the user stops
+;              pressing the mouse button.
+;
+;              The routine is called with R0 containing either the number
+;              of missed calls since the last one (normally this is 1) --
+;              this is intended to be used to implement a kind of buffering
+;              of repeats if the operation being performed is a lengthy one
+;              -- and with 0 to indicate that the operation is now
+;              completed.
+
+               IMPORT  repeater
+
+; --- rpt_end ---
+;
+; On entry:    --
+;
+; On exit:     --
+;               
+; Use:         Ends a repeater before the drag is released. No final
+;              0 is sent to the handler.
+
+               IMPORT  rpt_end
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/report b/StraySrc/Libraries/Sapphire/sh/report
new file mode 100644 (file)
index 0000000..d50a376
--- /dev/null
@@ -0,0 +1,80 @@
+;
+; report.sh
+;
+; A simple report box handler
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  report_register
+;  report_catchAll
+;  report_error
+
+               [       :LNOT::DEF:report__dfn
+               GBLL    report__dfn
+
+; --- report_register ---
+;
+; On entry:    R0 == pointer to routine to use
+;              R1 == R12 to pass to the routine
+;              R2 == stack pointer to set when it gets control
+;
+; On exit:     --
+;
+; Use:         Registers a resume point so that the application can recover
+;              from errors.  Error messages are reported using errorBox.
+
+               IMPORT  report_register
+
+; --- report_catchAll ---
+;
+; On entry:    --
+;
+; On exit:     R13 modified
+;
+; Use:         Sets up an exception handler to catch errors and other SEH
+;              exceptions.  Errors are reported in the usual way, and the
+;              user is given the option to close the application.  Other
+;              exceptions are reported as errors.
+
+               IMPORT  report_catchAll
+
+; --- report_error ---
+;
+; On entry:    R0 == pointer to error
+;
+; On exit:     --
+;
+; Use:         Prompts the user about quitting the application in response
+;              to a really bad error.  If the user decides to quit, we
+;              quit.  Otherwise we return.
+
+               IMPORT  report_error
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/res b/StraySrc/Libraries/Sapphire/sh/res
new file mode 100644 (file)
index 0000000..95c1910
--- /dev/null
@@ -0,0 +1,99 @@
+;
+; res.sh
+;
+; Locating resources
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  res_exists
+;  res_country
+;  res_find
+;  res_init
+
+               [       :LNOT::DEF:res__dfn
+               GBLL    res__dfn
+
+; --- res_exists ---
+;
+; On entry:    R0 == pointer to pathname
+;
+; On exit:     CS if the file exists, CC otherwise
+;
+; Use:         Tries to find the named file.  The file is deemed to exist
+;              if OS_File can return a valid object type for it (i.e. not
+;              `non-existant object' or actually raising errors).
+
+               IMPORT  res_exists
+
+; --- res_country ---
+;
+; On entry:    R0 == pointer to a buffer to use
+;
+; On exit:     R0 == pointer to country name (may not be in the buffer)
+;
+; Use:         Reads the name of the current country.  If no name can be
+;              found, it returns a pointer to the string `UK' which should
+;              do as a suitable default
+
+               IMPORT  res_country
+
+; --- res_find ---
+;
+; On entry:    R0 == pointer to resource filename
+;              R1 == pointer to buffer to build filename in
+;
+; On exit:     R0 == pointer to start of full pathname (R1 on entry)
+;              R1 == pointer to terminating null character
+;              CS if the file could actually be found, CC otherwise
+;
+; Use:         Locates a resource file.  It searches, in order:
+;
+;              * resPrefix.Resources.leaf[suffix]
+;              * resPrefix.Resources.country.leaf[suffix]
+;              * resPrefix.leaf[suffix]
+;
+;              returning the last if none of them could be found.  Note
+;              that `country' here is the currently configured country
+;              setting, and `suffix' is the WIMP mode aspect ratio suffix
+;              for the current mode (RISC OS 3 only).
+
+               IMPORT  res_find
+
+; --- res_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Initialises the resource prefix to <appname$Dir>
+
+               IMPORT  res_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/resources b/StraySrc/Libraries/Sapphire/sh/resources
new file mode 100644 (file)
index 0000000..2ac9a55
--- /dev/null
@@ -0,0 +1,75 @@
+;
+; resources.sh
+;
+; Access to shared resource DLL
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  resource_init
+;  resource_find
+
+               [       :LNOT::DEF:resources__dfn
+               GBLL    resources__dfn
+
+; --- resources_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the shared resource system, setting up the
+;              link to the SapphRes DLL.  Note that this initialisation is
+;              /not/ performed automatically.
+
+               IMPORT  resources_init
+
+; --- resources_find ---
+;
+; On entry:    R0 == resource code
+;              R1 == pointer to name (only for rsType_template)
+;
+; On exit:     CS if found, and
+;                R0 == pointer to resource
+;                R1 == pointer to resource limit (only for rsType_message)
+;              else CC and
+;                R0,R1 preserved
+;
+; Use:         Locates resources in the shared resource DLL.
+
+               IMPORT  resources_find
+
+;----- Resource types -------------------------------------------------------
+
+               ^       0
+rsType_sprite  #       1
+rsType_message #       1
+rsType_template        #       1
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/resspr b/StraySrc/Libraries/Sapphire/sh/resspr
new file mode 100644 (file)
index 0000000..c37e02c
--- /dev/null
@@ -0,0 +1,80 @@
+;
+; resspr.sh
+;
+; Handling of the application's private sprite area
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  resspr_load
+;  resspr_area
+;  resspr_init
+
+               [       :LNOT::DEF:resspr__dfn
+               GBLL    resspr__dfn
+
+; --- resspr_load ---
+;
+; On entry:    R0 == pointer to filename
+;
+; On exit:     May return an error
+;
+; Use:         Loads a sprite file into memory and allows it to be
+;              referenced through resspr_area.  Note that Straylight's
+;              Sprinkle module must be loaded if more than one sprite file
+;              is to be used for resources.
+
+               IMPORT  resspr_load
+
+; --- resspr_area ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to application's sprite area
+;
+; Use:         Locates the application's `Sprites' resource in memory and
+;              returns a pointer to it.  If the resource has not been
+;              loaded, 1 is returned, to indicate to use the WIMP area.
+;              If multiple sprite files have been loaded, this call returns
+;              the address of the first: they will have been linked together
+;              so that Sprinkle will treat them as one big area.
+
+               IMPORT  resspr_area
+
+; --- resspr_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Initalises resspr, loading the Sprites resource.
+
+               IMPORT  resspr_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/roVersion b/StraySrc/Libraries/Sapphire/sh/roVersion
new file mode 100644 (file)
index 0000000..936d219
--- /dev/null
@@ -0,0 +1,61 @@
+;
+; roVersion.sh
+;
+; Handling of the RISC OS version
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  rov_init
+;  rov_version
+
+               [       :LNOT::DEF:roVersion__dfn
+               GBLL    roVersion__dfn
+
+; --- rov_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets up the OS version in a cache.
+
+               IMPORT  rov_init
+
+; --- rov_version ---
+;
+; On entry:    --
+;
+; On exit:     R0 == current RISC OS version
+;
+; Use:         Returns the current operating system version number.
+
+               IMPORT  rov_version
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/sapphire b/StraySrc/Libraries/Sapphire/sh/sapphire
new file mode 100644 (file)
index 0000000..a35c9fb
--- /dev/null
@@ -0,0 +1,238 @@
+;
+; sapphire.sh
+;
+; Initialise a Sapphire application and libraries
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  sapphire_init
+;  sapphire_libInit
+;  sapphire_disable
+;  sapphire_doInit
+;  sapphire_doLibInit
+;  sapphire_doDisable
+;  sapphire_heapAddr
+;  sapphire_appName
+;  sapphire_resetStack
+;  sapphire_global
+;
+; Macros provided:
+;
+;   WSPACE
+
+               [       :LNOT::DEF:sapphire__dfn
+               GBLL    sapphire__dfn
+
+; --- sapphire_init ---
+;
+; On entry:    R0 == pointer to application name
+;              R1 == application's workspace size
+;              R2 == size of stack required
+;
+; On exit:     R10 == pointer to heap base
+;              R11 == pointer to ScratchPad
+;              R12 == pointer to application workspace
+;              R13 == pointer to full descending stack
+;              Other registers are corrupted
+;
+; Use:         Initialises the Sapphire kernel, sets up the memory map,
+;              and allocates workspace for library and client units.  The
+;              initialisation performed is fairly minimal; in particular,
+;              the library units are not initialised -- you must call
+;              sapphire_libInit for this to take place.  This allows you
+;              to check command line arguments etc. before initialising
+;              the Wimp.
+
+               IMPORT  sapphire_init
+
+; --- sapphire_disable ---
+;
+; On entry:    R0 == pointer to 0-terminated list of initialise routines
+;
+; On exit:     --
+;
+; Use:         Prevents the given initialisation routines from being called.
+;              This is mainly useful in the dynamic-linking environment,
+;              where all Sapphire units are normally active.  This routine
+;              allows you to inactivate units which for example do not
+;              have the resources they require, or use up unnecesary
+;              memory.
+
+               IMPORT  sapphire_disable
+
+; --- sapphire_libInit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the Sapphire library and client units.
+
+               IMPORT  sapphire_libInit
+
+; --- sapphire_doInit ---
+;
+; On entry:    R0 == pointer to application name
+;              R1 == client workspace size
+;              R2 == requested stack size
+;              R3 == pointer to initialisation table
+;
+; On exit:     R10 == base address of Sapphire heap
+;              R11 == pointer to scratchpad and global data
+;              R12 == pointer to client global workspace
+;              R13 == pointer to a full descendion stack
+;
+; Use:         Performs initialisation of the Sapphire library and the
+;              client's sections.  This is intended for use by the Sapphire
+;              stub, while initialising the dynamically linked version of
+;              Sapphire.
+
+               IMPORT  sapphire_doInit
+
+; --- sapphire_doLibInit ---
+;
+; On entry:    R0 == address of library initialisation table
+;
+; On exit:     --
+;
+; Use:         Initialises all currently uninitialised library units.
+
+               IMPORT  sapphire_doLibInit
+
+; --- sapphire_doDisable ---
+;
+; On entry:    R0 == pointer to list of initialise routines to disable
+;              R1 == pointer to initialisation table
+;
+; On exit:     --
+;
+; Use:         Prevents the given initialisation routines from being
+;              called.  This is mainly useful in a dynamically linked
+;              environment.
+
+               IMPORT  sapphire_doDisable
+
+; --- sapphire_heapAddr ---
+;
+; On entry:    --
+;
+; On exit:     R1 == pointer to the heap base (for passing to OS_Heap)
+;
+; Use:         Returns the address of the Sapphire heap.
+
+               IMPORT  sapphire_heapAddr
+
+; --- sapphire_appName ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to application name (NULL terminated)
+;
+; Use:         Returns a pointer to the application's name.
+
+               IMPORT  sapphire_appName
+
+; --- sapphire_resetStack ---
+;
+; On entry:    --
+;
+; On exit:     R13 == stack pointer
+;
+; Use:         Resets R13 to point to the top of the stack.
+
+               IMPORT  sapphire_resetStack
+
+; --- sapphire_global ---
+;
+; On entry:    R0 == magic identifier for global variable
+;              R1 == size of area required
+;
+; On exit:     R0 == pointer to area
+;              CS if the area already exists, CC otherwise
+;
+; Use:         Locates (and creates if necessary) a `named' global area
+;              which can be used for inter-section communication without
+;              the necessity for dependencies.
+;
+;              There is a limit on the number of global areas allowed, but
+;              this can be raised fairly easily if necessary.
+;
+;              If an area can't be created, an error is generated.
+
+               IMPORT  sapphire_global
+
+; --- Data relative to R11 ---
+
+               ^       0,R11
+sapph__R11     #       0                       ;Make a symbol for R11
+
+sapph_scratchpad EQU   sapph__R11-0            ;Scratchpad data area
+               [       :LNOT::DEF: sapph__specialWorkspace
+sapph_workspace        EQU     sapph__R11-4            ;Workspace base address
+               ]
+sapph_stackBase        EQU     sapph__R11-8            ;The top of the system stack
+sapph_heapBase EQU     sapph__R11-12           ;Base address of the heap
+sapph_appName  EQU     sapph__R11-16           ;Pointer to application name
+sapph_clientWS EQU     sapph__R11-20           ;Address of client's space
+
+; --- Macro: WSPACE ---
+;
+; Arguments:   addr == address of a word containing the workspace offset
+;              reg == (optional) destination register -- default is R12
+;              off == (optional) offset from R11 -- default is -4
+;
+; Use:         Locates a unit's workspace.  The code generated will corrupt
+;              R14.  Therefore you must save this register.
+
+               MACRO
+$label         WSPACE  $addr,$reg
+
+               IMPORT  |__sph_workoff|,WEAK
+
+               LCLS    r
+
+               [       "$reg"=""
+r              SETS    "R12"
+               |
+r              SETS    "$reg"
+               ]
+
+               ALIGN
+$label
+               LDR     $r,$addr
+
+;              LDR     R14,sapph_workspace
+               DCD     |__sph_workoff| + &E51BE004
+
+               ADD     $r,R14,$r
+
+               MEND
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/saveWarn b/StraySrc/Libraries/Sapphire/sh/saveWarn
new file mode 100644 (file)
index 0000000..42f4d93
--- /dev/null
@@ -0,0 +1,93 @@
+;
+; saveWarn.sh
+;
+; Warn the user about saving a document
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  saveWarn
+;  saveWarn_saved
+;  saveWarn_close
+
+; --- saveWarn ---
+;
+; On entry:    R0 == estimated size of data
+;              R1 == file type of the data
+;              R2 == pointer to name of the file
+;              R3 == pointer to handler block
+;              R4 == value to pass to handlers in R10
+;              R5 == value to pass to handlers in R12
+;              R6 == flags (in bottom two bits)
+;
+; On exit:     --
+;
+; Use:         Displays a warning box allowing the user to save a modified
+;              document.  The flags in R6 are as follows:
+;
+;              Bit 0   File is safe; don't give a warning
+;              Bit 1   File's name is sensible; display it in the warning
+;
+;              The handler block is the same as that passed to saveAs (q.v.)
+;              with an extra entry point on the very beginning, which is
+;              expected to remove the document from memory.  This entry
+;              point is not passed any arguments except for R10 and R12.
+;
+;              In order for the system to work, you must call various
+;              saveWarn routines from your saveAs entry points:
+;
+;              saveWarn_saved from saEntry__success
+;              saveWarn_close from saEntry__closed
+
+               IMPORT  saveWarn
+
+; --- saveWarn_saved ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Informs saveWarn that the document has been saved.  If
+;              saveWarn is not operating, this call is ignored.  You should
+;              only call this routine if the document is *safe*, rather than
+;              RAM transferred to another application, for example.
+
+               IMPORT  saveWarn_saved
+
+; --- saveWarn_close ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Informs saveWarn that the save dialogue box has been closed.
+;              If the document is now saved, then it is removed from
+;              memory.
+
+               IMPORT  saveWarn_close
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/screen b/StraySrc/Libraries/Sapphire/sh/screen
new file mode 100644 (file)
index 0000000..a06c1e5
--- /dev/null
@@ -0,0 +1,98 @@
+;
+; screen.sh
+;
+; Screen mode information caching
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  screen_getInfo
+;  screen_cache
+;  screen_justChangedMode
+;  screen_init
+
+               [       :LNOT::DEF:screen__dfn
+               GBLL    screen__dfn
+
+; --- screen_getInfo ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to screen information block
+;
+; Use:         This call returns a pointer to a block of information
+;              about the current screen modes.  The format of this block
+;              is defined above.
+
+               IMPORT  screen_getInfo
+
+; --- screen_cache ---
+;
+; On entry:    R12 points to workspace
+;
+; On exit:     --
+;
+; Use:         Caches screen information for the current mode.
+
+               IMPORT  screen_cache
+
+; --- screen_justChangedMode ---
+;
+; On entry:    --
+;
+; On exit:     CS if last event was a mode change, CC otherwise
+;
+; Use:         Informs the caller if the last event was a mode change.
+;              The system ignores open window requests when making it's
+;              decision.
+
+               IMPORT  screen_justChangedMode
+
+; --- screen_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the screen unit.
+
+               IMPORT  screen_init
+               
+;----- Data offsets ---------------------------------------------------------
+
+               ^       0
+screen_xEig    #       4
+screen_yEig    #       4
+screen_bpp     #       4
+screen_width   #       4
+screen_height  #       4
+screen_dx      #       4
+screen_dy      #       4
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/seh b/StraySrc/Libraries/Sapphire/sh/seh
new file mode 100644 (file)
index 0000000..ee616ef
--- /dev/null
@@ -0,0 +1,133 @@
+;
+; seh.sh
+;
+; Structured Exception Handling, the Sapphire way
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  seh_try
+;  seh_unTry
+;  seh_throw
+;  seh_throwErrors
+;  seh_setListBase
+;  seh_init
+
+               [       :LNOT::DEF:seh__dfn
+               GBLL    seh__dfn
+
+; --- seh_try ---
+;
+; On entry:    R0 == pointer to catch definition block
+;
+; On exit:     R13 dropped by a (small) amount
+;
+; Use:         Inserts an exception handler at the current position.
+;              Exceptions are matched against those described in the catch
+;              block.  If there is a handler for the exception, the
+;              corresponding handler is called, and expected to resume
+;              normally.  Otherwise the tidy-up routine is called and we
+;              unwind the stack further to find an appropriate handler.
+;
+;              The catch block has the following format:
+;
+;              word    B to tidy-up routine
+;              word    1st exception mask
+;              word    1st B to catch routine
+;              word    2nd exception mask
+;              word    2nd B to catch routine
+;              ...
+;              word    0
+;
+;              An exception mask contains two halfwords.  Bits 16-31 are the
+;              class to match, or -1 for all classes.  Bits 0-15 are the
+;              subtype to match, or -1 for all subtypes.  You can do really
+;              odd things if you set bits 16-31 to -1 and leave 0-15
+;              matching specific subtypes -- do this at your own risk.
+
+               IMPORT  seh_try
+
+; --- seh_unTry ---
+;
+; On entry:    --
+;
+; On exit:     R13 moved to position before corresponding seh_try
+;
+; Use:         Removes the try block marker in the stack at the current
+;              position.  Note that the stack will be unwound to where it
+;              was when seh_try was called.
+
+               IMPORT  seh_unTry
+
+; --- seh_throw ---
+;
+; On entry:    R0 == exception to match
+;              R1-R3 == useful bits of information
+;
+; On exit:     Doesn't return, unless you've done something /really/ odd
+;
+; Use:         Throws an exception.  The stack is unwound until we find
+;              a handler which can cope.  If there is no handler, we abort
+;              the program.
+
+               IMPORT  seh_throw
+
+; --- seh_throwErrors ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets up an except-style error handler to throw errors
+;              as SEH exceptions.
+
+               IMPORT  seh_throwErrors
+
+; --- seh_setListBase ---
+;
+; On entry:    R0 == pointer to try block list base, or 0 to use global
+;
+; On exit:     --
+;
+; Use:         Sets the try block list base.  This should only be used by
+;              coroutine providers, like coRoutine and thread.
+
+               IMPORT  seh_setListBase
+
+; --- seh_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises SEH's facilities.
+
+               IMPORT  seh_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/sprite b/StraySrc/Libraries/Sapphire/sh/sprite
new file mode 100644 (file)
index 0000000..fe47a1e
--- /dev/null
@@ -0,0 +1,88 @@
+;
+; sprite.sh
+;
+; Nice operations on sprites
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  sprite_op
+;  sprite_getTable
+;  sprite_plot
+
+               [       :LNOT::DEF:sprite__dfn
+               GBLL    sprite__dfn
+
+; --- sprite_op ---
+;
+; On entry:    R0,R2-R7 ==  SpriteOp parameters (R1 set up here)
+;
+; On exit:     Registers and flags altered as for the SpriteOp
+;
+; Use:         Performs an OS_SpriteOp with the given arguments, using
+;              the appication's Sprites resource as the sprite area.
+
+               IMPORT  sprite_op
+
+; --- sprite_getTable ---
+;
+; On entry:    R0 == pointer to a sprite
+;              R1 == pointer to buffer for translate table
+;
+; On exit:     --
+;
+; Use:         Creates a colour translate table for the given sprite in
+;              the specified buffer.
+;
+;              If you have a sprite name but no pointer, use OS_SpriteOp
+;              24 to find the pointer -- this will make further sprite ops
+;              on the sprite much quicker.
+
+               IMPORT  sprite_getTable
+
+; --- sprite_plot ---
+;
+; On entry:    R0 == pointer to a sprite
+;              R1 == x coordinate to plot at
+;              R2 == y coordinate to plot at
+;              R3 == pointer to scale block, or 0 for 1:1
+;
+; On exit:     CS if the sprite was plotted OK, else CC
+;
+; Use:         Plots a sprite on the screen.  The scaling refers to the
+;              sprite proper: /this/ routine takes care of odd pixel
+;              sizes and things, so sprites don't appear squashed or
+;              stretched unless you really want them to.
+;
+;              We return C clear on exit if we couldn't plot the sprite;
+;              typically this would be if the sprite's mode is undefined.
+
+               IMPORT  sprite_plot
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/sqrt b/StraySrc/Libraries/Sapphire/sh/sqrt
new file mode 100644 (file)
index 0000000..610f560
--- /dev/null
@@ -0,0 +1,52 @@
+;
+; sqrt.sh
+;
+; Fast square root routines
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  sqrt
+
+               [       :LNOT::DEF:sqrt__dfn
+               GBLL    sqrt__dfn
+
+; --- sqrt ---
+;
+; On entry:    R0 == value to square-root
+;
+; On exit:     R0 == the result
+;
+; Use:         Evaluates the square root of the number given.  This routine
+;              is constructed from the information supplied by David Seal,
+;              and is *extremely* fast.
+
+               IMPORT  sqrt
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/string b/StraySrc/Libraries/Sapphire/sh/string
new file mode 100644 (file)
index 0000000..461d595
--- /dev/null
@@ -0,0 +1,203 @@
+;
+; string.sh
+;
+; String handling routines (control terminated)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  str_cpy
+;  str_len
+;  str_cmp
+;  str_icmp
+;  str_index
+;  str_match
+;  str_subst
+;  str_error
+;  str_buffer
+
+               [       :LNOT::DEF:string__dfn
+               GBLL    string__dfn
+
+; --- str_cpy ---
+;
+; On entry:    R0 == destination string
+;              R1 == source string
+;
+; On exit:     R0 == pointer to terminator of destination
+;
+; Use:         Copies a string from one block to another.  It leaves the
+;              destination pointer at the end of the string so that any
+;              subsequent copies concatenate other bits on the same string.
+;              Single characters can of course be appended with
+;
+;                      MOV     Rx,#&cc
+;                      STRB    Rx,[R0],#1
+
+               IMPORT  str_cpy
+
+; --- str_len ---
+;
+; On entry:    R0 == pointer to string
+;
+; On exit:     R0 == length of the string
+;
+; Use:         Calculates the length of a string.
+
+               IMPORT  str_len
+
+; --- str_cmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         Case-sensitively compares two strings.  You can use the
+;              normal ARM condition codes after the compare, so you can
+;              treat this fairly much like a normal CMP.
+
+               IMPORT  str_cmp
+
+; --- str_icmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;
+; On exit:     Flags as appropriate
+;
+; Use:         As for str_cmp above, but case-insensitive.
+
+               IMPORT  str_icmp
+
+; --- str_index ---
+;
+; On entry:    R0 == pointer to name table
+;              R1 == index into name table
+;
+; On exit:     CS if index good, and
+;                R0 == address of R0th string in table
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Finds an indexed string in a table.  The table consists of
+;              ctrl-terminated strings, with no separation.  The table is
+;              terminated by a zero-length entry.
+
+               IMPORT  str_index
+
+; --- str_find ---
+;
+; On entry:    R0 == pointer to name table
+;              R1 == string to match in table
+;
+; On exit:     CS if match found, and
+;                R0 == index of string matched
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Looks up a string in a table.  The table consists of
+;              ctrl-terminated strings, with no separation.  The table is
+;              terminated by a zero-length entry.
+
+               IMPORT  str_match
+
+; --- str_subst ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R1 == Pointer to output buffer
+;              R2-R11 == Pointer to filler strings (optional)
+;
+; On exit:     R0 == Pointer to start of buffer
+;              R1 == Pointer to terminating null
+;
+; Use:         Performs string substitution, filling in a skeleton string
+;              containing placeholders with `filler' strings.  The
+;              placeholders are actually rather powerful.  The syntax of
+;              these is as follows:
+;
+;                      `%' [<type>] <digit>
+;
+;              (spaces are for clarity -- in fact you must not include
+;              spaces in the format string.)
+;
+;              <digit> is any charater between `0' and `9'.  It refers to
+;              registers R2-R11 (so `0' means R2, `5' is R7 etc.)  How the
+;              value is interpreted is determined by <type>.
+;
+;              <type> is one of:
+;
+;              s       String.  This is the default.  The register is
+;                      considered to be a pointer to an ASCII string
+;                      (control terminated).
+;
+;              i       Integer.  The (signed) decimal representation is
+;                      inserted.  Leading zeros are suppressed.
+;
+;              x       Hex fullword.  The hexadecimal representation of the
+;                      register is inserted.  Leading zeros are included.
+;
+;              b       Hex byte.  The hexadecimal representation of the
+;                      least significant byte is inserted.  Leading zeros
+;                      are included.
+;
+;              c       Character.  The ASCII character corresponding to the
+;                      least significant byte is inserted.
+
+               IMPORT  str_subst
+
+; --- str_error ---
+;
+; On entry:    R0 == Pointer to skeleton
+;              R2-R11 == Pointers to fillin strings
+;
+; On exit:     R0 == Pointer to error in buffer
+;              R1 == Pointer to terminator
+;
+; Use:         Fills in an error skeleton (containing a 4 byte error number
+;              and a control terminated skeleton string as for str_subst)
+;              and returns the address of the filled in error block.  The
+;              error block is stored in a buffer obtained from str_buffer.
+;
+;              Filler strings may be held in the scratchpad.
+
+               IMPORT  str_error
+
+; --- str_buffer ---
+;
+; On entry:    --
+;
+; On exit:     R1 == pointer to the next free buffer
+;
+; Use:         Returns a pointer to a 256-byte buffer.  There are at present
+;              2 buffers, which are returned alternately.
+
+               IMPORT  str_buffer
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/subAlloc b/StraySrc/Libraries/Sapphire/sh/subAlloc
new file mode 100644 (file)
index 0000000..af315b5
--- /dev/null
@@ -0,0 +1,79 @@
+;
+; suballoc.sh
+;
+; Handling of requests for small link blocks
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  sub_alloc
+;  sub_free
+;  sub_init
+
+               [       :LNOT::DEF:suballoc__dfn
+               GBLL    suballoc__dfn
+
+; --- sub_alloc ---
+;
+; On entry:    R0 == size of block to allocate
+;
+; On exit:     R0 == pointer to block allocated
+;              May return an error
+;
+; Use:         Allocates a block of the size specified, typically very
+;              quickly indeed.
+;
+;              If the size is not one of those supported (currently
+;              supported sizes are 8-40 inclusive in 4 byte increments),
+;              the behaviour is undefined (but very predictable).
+
+               IMPORT  sub_alloc
+
+; --- sub_free ---
+;
+; On entry:    R0 == pointer to block
+;              R1 == size of the block
+;
+; On exit:     --
+;
+; Use:         Frees a block allocated using sub_alloc.
+
+               IMPORT  sub_free
+
+; --- sub_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the suballocation system for use.
+
+               IMPORT  sub_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/template b/StraySrc/Libraries/Sapphire/sh/template
new file mode 100644 (file)
index 0000000..03e33b0
--- /dev/null
@@ -0,0 +1,122 @@
+;
+; template.sh
+;
+; Load window template resources
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  template_find
+;  template_copy
+;  template_embedded
+;  template_free
+;  template_load
+;  template_init
+
+               [       :LNOT::DEF:template__dfn
+               GBLL    template__dfn
+
+; --- template_find ---
+;
+; On entry:    R0 == pointer to name to match
+;
+; On exit:     R0 == pointer to window definition if found
+;              May return an error
+;
+; Use:         Locates a template in the list and gives you a pointer to
+;              the corresponding window defintion.  You may update the
+;              definition to store an updated window state if you really
+;              want to.
+
+               IMPORT  template_find
+
+; --- template_copy ---
+;
+; On entry:    R0 == pointer to name to match
+;
+; On exit:     R0 == pointer to copy of a window definition
+;              May return an error
+;
+; Use:         Returns a copy of a window template (for the use of the
+;              dialogue box system mainly), including all indirected data
+;              set up properly and everything.  The copy is writable.  To
+;              get rid of the copy, call template_free.
+
+               IMPORT  template_copy
+
+; --- template_embedded ---
+;
+; On entry:    R0 == pointer to embedded template definition
+;
+; On exit:     R0 == pointer to copy (as for template_copy)
+;
+; Use:         Extracts an embedded template into a template block.
+;              Embedded templates can be generated using the templAOF
+;              program, and then linked into your application.
+
+               IMPORT  template_embedded
+
+; --- template_free ---
+;
+; On entry:    R0 == pointer to block allocated with template_copy
+;
+; On exit:     --
+;
+; Use:         Frees a template copy created using template_copy.
+
+               IMPORT  template_free
+
+; --- template_load ---
+;
+; On entry:    R0 == pointer to name of template file to load
+;
+; On exit:     May return an error
+;
+; Use:         Loads the specified template file, and adds its window
+;              definitions into the template list so they can be used when
+;              creating dialogue boxes or windows.
+;
+;              If the templates can't be loaded (e.g. there isn't enough
+;              memory) an error is generated (and can be caught using the
+;              standard Sapphire except mechanism).
+
+               IMPORT  template_load
+
+; --- template_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Initialises the template list and font array, and loads the
+;              `Templates' resource file.
+
+               IMPORT  template_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/thread b/StraySrc/Libraries/Sapphire/sh/thread
new file mode 100644 (file)
index 0000000..d5ce215
--- /dev/null
@@ -0,0 +1,317 @@
+;
+; thread.sh
+;
+; Preemptive multitasking of idle threads
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  thread_create
+;  thread_setPriority
+;  thread_setTimeSlice
+;  thread_destroy
+;  thread_suspend
+;  thread_resume
+;  thread_yield
+;  thread_createSem
+;  thread_destroySem
+;  thread_threaded
+;  thread_wait
+;  thread_signal
+;  thread_init
+;  thread_enterCrit
+;  thread_leaveCrit
+;  thread_errorHandler
+
+               [       :LNOT::DEF:thread__dfn
+               GBLL    thread__dfn
+
+; --- thread_create ---
+;
+; On entry:    R0 == size of stack to allocate, or 0 for a default
+;              R1 == pointer to thread routine
+;              R2 == workspace pointer to pass in R10
+;              R3 == workspace pointer to pass in R12
+;
+; On exit:     R0 == thread handle for the thread
+;              May return an error
+;
+; Use:         Creates a new thread running `in the background' (i.e. over
+;              idle events).
+;
+;              The thread is passed control with the registers R10 and R12
+;              set up from R1 and R2 passed to this routine and R13 pointing
+;              to the top of a stack chunk.  R0 on entry contains the
+;              thread's handle.  The thread is passed the scratchpad
+;              address (in R11).  The values of other registers are
+;              indeterminate and must not be relied upon.
+;
+;              The default stack size for a new thread is 1K, although this
+;              may change in future.
+;
+;              The thread may exit by calling thread_destroy or by
+;              returning in the normal way.
+
+               IMPORT  thread_create
+
+; --- thread_setPriority ---
+;
+; On entry:    R0 == thread handle
+;              R1 == new priority to set
+;
+; On exit:     --
+;
+; Use:         Changes the priority of a thread.  The priority if a thread
+;              is a signed integer.  The highest priority thread is the one
+;              which runs.  If more than one thread has maximum priority,
+;              they are run in a cyclical order.
+
+               IMPORT  thread_setPriority
+
+; --- thread_setTimeSlice ---
+;
+; On entry:    R0 == thread handle
+;              R1 == new timeslice size, in centiseconds
+;
+; On exit:     --
+;
+; Use:         Changes a thread's timeslice size.  Specify 0 to indicate
+;              that thread shouldn't be pre-empted.
+
+               IMPORT  thread_setTimeSlice
+
+; --- thread_destroy ---
+;
+; On entry:    R0 == thread handle to destroy, if not executing a thread
+;
+; On exit:     --
+;
+; Use:         Destroys either the current thread or a thread with the
+;              the given handle if no thread is executing currently.  You
+;              can't destroy an arbitrary thread while running in one.
+;
+;              If a thread is waiting for a semaphore, it is removed from
+;              the waiting list.
+
+               IMPORT  thread_destroy
+
+; --- thread_suspend ---
+;
+; On entry:    R0 == thread handle, or 0 for the current thread
+;
+; On exit:     --
+;
+; Use:         Suspends a thread's execution.  If a thread is currently
+;              running, that thread is suspended.  Otherwise, any thread
+;              may be suspended.
+;
+;              If the thread is currently claiming semaphores, the
+;              semaphores are not released, because we don't whether the
+;              system is in a fit state for this.
+;
+;              Thread suspensions are counted.  i.e. if you suspend a thread
+;              5 times, you have to resume it 5 times for it to become
+;              active again.
+
+               IMPORT  thread_suspend
+
+; --- thread_resume ---
+;
+; On entry:    R0 == thread handle
+;
+; On exit:     --
+;
+; Use:         Allows a suspended thread to continue operations.  If you
+;              resume a thread more times than it has been suspended,
+;              any excess resumes are ignored.  You can't resume a thread
+;              to stop it being blocked by a semaphore.
+
+               IMPORT  thread_resume
+
+; --- thread_yield ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Pauses the thread for a while.  You only need to use this
+;              call if you have stopped the current thread from being
+;              timesliced.
+
+               IMPORT  thread_yield
+
+; --- thread_createSem ---
+;
+; On entry:    R0 == initial value for semaphore (0 for counter, 1 for
+;                    mutex)
+;
+; On exit:     R0 == semaphore handle and V clear if all went well
+;              R0 == pointer to error and V set if something went wrong
+;
+; Use:         Creates a semaphore with the given initial counter value.
+;
+;              The semaphore can be used to provide serialised access to
+;              a resource by initialising its value to 1 and performing the
+;              following:
+;
+;              thread_wait(mySemaphore)
+;              //
+;              // Do things with the resource
+;              //
+;              thread_signal(mySemaphore)
+;
+;              Or you can inform a thread that it has items in its input
+;              queue by having the following in the thread code:
+;
+;              while true
+;                thread_wait(theSemaphore)
+;                getFromQueue(myQueue,item)
+;                process(item)
+;              endWhile
+;
+;              and when inserting queue items:
+;
+;              addToQueue(item)
+;              thread_signal(theSemaphore)
+;
+;              It is distinctly possible that input queue management will
+;              be introduced in a separate Sapphire module.
+
+               IMPORT  thread_createSem
+
+; --- thread_destroySem ---
+;
+; On entry:    R0 == semaphore handle
+;
+; On exit:     --
+;
+; Use:         Destroys a semaphore when it's no use any more.  If threads
+;              are waiting for it, an error is generated.
+
+               IMPORT  thread_destroySem
+
+; --- thread_threaded ---
+;
+; On entry:    --
+;
+; On exit:     CS if currently running a thread, CC otherwise
+;
+; Use:         Informs the caller whether a thread is currently executing.
+
+               IMPORT  thread_threaded
+
+; --- thread_wait ---
+;
+; On entry:    R0 == semaphore handle
+;
+; On exit:     If successful, R0 preserved and V clear.
+;              If failed, R0 == pointer to error block and V set
+;
+; Use:         Waits on a sempahore.  The algorithm actually is as follows:
+;
+;              if semaphore.counter == 0 then
+;                addToWaitingList(semaphore,currentThread)
+;                suspend(currentThread)
+;              else
+;                semaphore.counter -= 1
+;              endIf
+;
+;              See thread_createSem for suggestions on how to make use of
+;              semaphores.
+
+               IMPORT  thread_wait
+
+; --- thread_signal ---
+;
+; On entry:    R0 == semaphore handle
+;
+; On exit:     --
+;
+; Use:         Increments a semaphore's counter if no threads are waiting
+;              for it, or releases a thread waiting for the semaphore.
+;
+;              The actual algorithm is shown below:
+;
+;              if semaphore.waitingList != 0 then
+;                thread = removeFromWaitingList(semaphore)
+;                unSuspend(thread)
+;              else
+;                semaphore.counter += 1;
+;              endif
+;
+;              See thread_createSem for suggestions on how to make use of
+;              semaphores.
+
+               IMPORT  thread_signal
+
+; --- thread_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the thread system for use.
+
+               IMPORT  thread_init
+
+; --- thread_enterCrit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Declares that the current thread is about to enter a
+;              critical section and must not be interrupted.
+
+               IMPORT  thread_enterCrit
+
+; --- thread_leaveCrit ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Declares that the current thread has left the critical
+;              section and can be interrupted again.
+
+               IMPORT  thread_leaveCrit
+
+; --- thread_errorHandler ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R12 value to call with
+;              R2 == R13 value to call with
+;
+; On exit:     --
+;
+; Use:         Sets up the error handler for a thread.
+
+               IMPORT  thread_errorHandler
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/tms b/StraySrc/Libraries/Sapphire/sh/tms
new file mode 100644 (file)
index 0000000..646c0a8
--- /dev/null
@@ -0,0 +1,87 @@
+;
+; tms.sh
+;
+; The Straylight Tearoff Menu Segment
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   tms_create
+;   tms_recreate
+;   tms_help
+;   tms_init
+
+;---- Functions provided ----------------------------------------------------
+
+; --- tms_create ---
+;
+; On entry:    R0 == pointer to a menu block
+;              R1 == pointer to event handler for the menu section
+;              R2 == R10 value to pass to the event handler
+;              R3 == R12 value to pass to the event handler
+;
+; On exit:     R0 == tearoff handle for this menu
+;              VS and R0 == pointer to error block if it failed, as normal
+;
+; Use:         Creates a new menu, or adds sections to an existing one.
+
+               IMPORT  tms_create
+
+; --- tms_recreate ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Recreates the existing menu structure, making changes where
+;              appropriate.
+
+               IMPORT  tms_recreate
+
+; --- tms_help ---
+;
+; On entry:    R0 == pointer to base message tag
+;              R1 == index of menu item
+;
+; On exit:     --
+;
+; Use:         Adds a string to the help message found by adding the menu
+;              item number to the base message tag.
+
+               IMPORT  tms_help
+
+; --- tms_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the tearoff menu segment
+
+               IMPORT  tms_init
+
+;----- That's all, folks ----------------------------------------------------
+
+       END
diff --git a/StraySrc/Libraries/Sapphire/sh/transWin b/StraySrc/Libraries/Sapphire/sh/transWin
new file mode 100644 (file)
index 0000000..c2db103
--- /dev/null
@@ -0,0 +1,95 @@
+;
+; transWin.sh
+;
+; Transient window handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  transWin_subWaiting
+;  transWin_openSub
+;  transWin_register
+;  transWin_close
+;  transWin_init
+
+               [       :LNOT::DEF:transWin__dfn
+               GBLL    transWin__dfn
+
+; --- transWin_subWaiting ---
+;
+; On entry:    --
+;
+; On exit:     CS if a submenu is waiting to be opened, CC otherwise
+;
+; Use:         Informs the caller whether the menu system is waiting for
+;              a submenu to be attached.
+
+               IMPORT  transWin_subWaiting
+
+; --- transWin_openSub ---
+;
+; On entry:    R0 == window handle to open
+;
+; On exit:     --
+;
+; Use:         Opens the given window as a submenu.
+
+               IMPORT  transWin_openSub
+
+; --- transWin_register ---
+;
+; On entry:    R0 == window handle to register
+;
+; On exit:     --
+;
+; Use:         Registers a window as being the current transient window.
+
+               IMPORT  transWin_register
+
+; --- transWin_close ---
+;
+; On entry:    R0 == window handle to close
+;
+; On exit:     --
+;
+; Use:         Closes the current transient window.
+
+               IMPORT  transWin_close
+
+; --- transWin_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the transWin system.
+
+               IMPORT  transWin_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/tspr b/StraySrc/Libraries/Sapphire/sh/tspr
new file mode 100644 (file)
index 0000000..58a1585
--- /dev/null
@@ -0,0 +1,79 @@
+;
+; tspr.sh
+;
+; Toolsprite hacking for things like border sizes
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  tspr_getSprAddr
+;  tspr_borderWidths
+;  tspr_adjustBox
+
+               [       :LNOT::DEF:tspr__dfn
+               GBLL    tspr__dfn
+
+; --- tspr_getSprAddr ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to tool sprites, or 0 if none
+;
+; Use:         Returns a pointer to the toolsprites. If the user is using
+;              RISC OS 2, or there are no toolsprites defined, then
+;              0 is returned.
+
+               IMPORT  tspr_getSprAddr
+
+; --- tspr_borderWidths ---
+;
+; On entry:    --
+;
+; On exit:     R0 == title bar height
+;              R1 == vertical scroll bar width
+;              R2 == horizontal scroll bar height
+;
+; Use:         Return the width of window tools by looking at the
+;              sprites associated with them, rather than creating
+;              a temporary window.
+
+               IMPORT  tspr_borderWidths
+
+; --- tspr_adjustBox ---
+;
+; On entry:    R1 == pointer to Wimp_OpenWindow block to modify
+;
+; On exit:     Block updated in place
+;
+; Use:         Updates the open block to ensure that the window is opened
+;              on the screen.
+
+               IMPORT  tspr_adjustBox
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/viewer b/StraySrc/Libraries/Sapphire/sh/viewer
new file mode 100644 (file)
index 0000000..82c3206
--- /dev/null
@@ -0,0 +1,357 @@
+;
+; viewer.sh
+;
+; Filer-like windows with re-arranging icons
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  viewer_create
+;  viewer_destroy
+;  viewer_open
+;  viewer_close
+;  viewer_eventHandler
+;  viewer_select
+;  viewer_isSelected
+;  viewer_selectAll
+;  viewer_click
+;  viewer_dragSelection
+;  viewer_window
+;  viewer_update
+;  viewer_setTitle
+;  viewer_rescan
+
+               [       :LNOT::DEF:viewer__dfn
+               GBLL    viewer__dfn
+
+; --- viewer_create ---
+;
+; On entry:    R0 == pointer to a viewer definition block
+;              R1 == pointer to a list
+;              R2 == sprite area for window
+;
+; On exit:     R0 == viewer handle
+;              May return an error
+;
+; Use:         Creates a viewer window.  The viewer definition block
+;              contains various interesting bits of information about the
+;              viewer which are likely to be known at assembly time:
+;
+;              (word)   address of a list manager definition block
+;              (word)   address of a shape handler function (or 0)
+;              (word)   standard width of icons
+;              (word)   standard height of icons
+;              (string) banner text message tag, or empty
+;
+;              The shape function is used to allow viewer icons to have a
+;              non-rectangular shape.  The function is called with a reason
+;              code in R0; entry and exit conditions depend on this:
+;
+;                                                      vwShape_size
+;              On entry
+;                R1 == pointer to list item
+;                R2 == standard width of icon
+;                R3 == standard height of icon
+;
+;              On exit
+;                R2 == width of this icon
+;                R3 == height of this icon
+;
+;              Use
+;                This routine is used to find the actual size of an icon.
+;                The icons are aligned on a grid according to the largest
+;                one: this routine is used to find out which one that is.
+;
+;                                                      vwShape_intersects
+;              On entry
+;                R1 == pointer to list item
+;                R2 == address of bounding box of this icon
+;                R3 == address of bounding box to compare
+;
+;              On exit
+;                CS if boxes intersect, else CC
+;
+;              Use
+;                For detecting mouse clicks etc. on an icon.  viewer has
+;                already ensured that the box in R3 intersects with the
+;                bounding box, so for rectangular icons, you can just return
+;                with C set always.  This entry is provided so that you
+;                can check against the sprite and text of a text+sprite
+;                icon separately.
+;
+;              More reason codes may be added later; it will always be
+;              sensible to return immediately preserving all registers and
+;              flags.
+
+               IMPORT  viewer_create
+
+; --- viewer_destroy ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Destroys a viewer, removing it from the screen etc.
+
+               IMPORT  viewer_destroy
+
+; --- viewer_open ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == opening style
+;              R2,R3 == extra arguments
+;
+; On exit:     --
+;
+; Use:         Opens a viewer window on the screen.
+
+               IMPORT  viewer_open
+
+; --- viewer_close ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Closes a viewer window.
+
+               IMPORT  viewer_close
+
+; --- viewer_eventHandler ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == pointer to event handler
+;              R2 == value to pass in R10
+;              R3 == value to pass in R12
+;
+; On exit:     R1-R3 == old values
+;
+; Use:         Sets up the event handle for the viewer.
+
+               IMPORT  viewer_eventHandler
+
+; --- viewer_select ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == icon handle
+;              R2 == 0 to unselect, 1 to select or 2 to toggle
+;
+; On exit:     --
+;
+; Use:         Selects an icon, or maybe unselects it.  Whatever, it doesn't
+;              flicker if it doesn't need to.
+
+               IMPORT  viewer_select
+
+; --- viewer_isSelected ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == icon handle
+;
+; On exit:     CS if icon is selected, else CC
+;
+; Use:         Informs you whether an icon is selected.
+
+               IMPORT  viewer_isSelected
+
+; --- viewer_selectAll ---
+;
+; On entry:    R0 == viewer handle
+;              R2 == 0 to deselect, or 1 to select
+;
+; On exit:     --
+;
+; Use:         Selects or deselects all the icons in a viewer.
+
+               IMPORT  viewer_selectAll
+
+; --- viewer_click ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == icon handle (or 0)
+;              R2 == mouse button state
+;
+; On exit:     --
+;
+; Use:         Handles a click, drag etc. according to the standard
+;              selection model.
+
+               IMPORT  viewer_click
+
+; --- viewer_dragSelection ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Starts a drag of the icons within the viewer.  When the drag
+;              is finished, you get sent a vwEvent_dragged event.
+
+               IMPORT  viewer_dragSelection
+
+; --- viewer_window ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     R0 == window handle
+;
+; Use:         Returns the window handle of the viewer.
+
+               IMPORT  viewer_window
+
+; --- viewer_update ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == icon handle
+;
+; On exit:     --
+;
+; Use:         Updates (redraws) a given icon.
+
+               IMPORT  viewer_update
+
+; --- viewer_setTitle ---
+;
+; On entry:    R0 == viewer handle
+;              R1 == title string
+;
+; On exit:     --
+;
+; Use:         Sets the viewer window's title.
+
+               IMPORT  viewer_setTitle
+
+; --- viewer_rescan ---
+;
+; On entry:    R0 == viewer handle
+;
+; On exit:     --
+;
+; Use:         Rescans all the icons in the viewer and forces a redraw,
+;              in case icons have been added or deleted (or renamed).  Note
+;              that the redraw is done *anyway* -- it's your responsibility
+;              to avoid calling this routine when you don't need to.
+
+               IMPORT  viewer_rescan
+
+;----- Shape function reason codes ------------------------------------------
+
+               ^       0
+vwShape_size   #       1                       ;Read an icon's size
+                                               ;Entry: R1 == list item
+                                               ;       R2,R3 == std size
+                                               ;Exit:  R2,R3 == actual size
+
+vwShape_intersects #   1                       ;Does icon intersect box?
+                                               ;Entry: R1 == list item
+                                               ;       R2 == ptr to icon box
+                                               ;       R3 == ptr to box
+                                               ;Exit:  CS if intersect
+
+vwShape_slowBit        #       1                       ;Does icon need slow redraw
+                                               ;Entry: R1 == list item
+                                               ;       R2 == ptr to icon box
+                                               ;       R3 == ptr to box
+
+;----- Viewer event codes ---------------------------------------------------
+
+               ^       0
+vwEvent_close  #       1                       ;User has closed the window
+
+vwEvent_click  #       1                       ;User has clicked an icon
+                                               ;R1 == icon handle (or 0)
+                                               ;R2 == mouse status
+
+vwEvent_double #       1                       ;User has double-clicked
+                                               ;R1 == icon handle (or 0)
+                                               ;R2 == mouse status
+
+vwEvent_drag   #       1                       ;User has dragged the mouse
+                                               ;R1 == icon handle (or 0)
+                                               ;R2 == mouse status
+
+vwEvent_menu   #       1                       ;User has clicked menu
+                                               ;R1 == icon handle (or 0)
+                                               ;R2 == mouse status
+
+vwEvent_redraw #       1                       ;Redraw a viewer icon
+                                               ;R1 == icon handle
+                                               ;R2 == pointer to coords blk
+                                               ;R3 == pointer to clip blk
+                                               ;R5,R6 == window origin
+
+vwEvent_drop   #       1                       ;File dropped on the viewer
+                                               ;R1 == filetype of data
+                                               ;R2 == estimated size
+                                               ;R3 == address of filename
+                                               ;R4 == drop type
+
+vwEvent_help   #       1                       ;Help request for the viewer
+                                               ;R1 == icon handle, or 0
+
+vwEvent_key    #       1                       ;Key pressed
+                                               ;R1 == key code (translated)
+                                               ;Return CS if used, else CC
+
+vwEvent_dragged        #       1                       ;Icons dropped on a window
+                                               ;R1 == destination window
+                                               ;R2 == destination icon
+
+vwEvent_sprite #       1                       ;Return sprite name to use
+                                               ;Entry: R1 == icon handle
+                                               ;         (-1 for many)
+                                               ;Exit:  CS if sprite found,
+                                               ;       R0 == ptr to spr area
+                                               ;       R1 == pointer to name
+                                               ;       else CC
+
+vwEvent_open   #       1                       ;The viewer has been moved
+                                               ;R1 == ptr to open/state blk
+
+vwEvent_draw   #       1                       ;Fully draw icon
+                                               ;R1 == icon handle
+                                               ;R2 == pointer to coords blk
+                                               ;R3 == pointer to clip blk
+                                               ;R5,R6 == window origin
+                                               ;(Event only used by gallery)
+
+vwEvent_unDraw #       1                       ;Undraw temporary part
+                                               ;R1 == icon handle
+                                               ;R2 == pointer to coords blk
+                                               ;R3 == pointer to clip blk
+                                               ;R5,R6 == window origin
+                                               ;(Event only used by gallery)
+
+               ; --- Drop event subreason codes ---
+
+               ^       0
+vwDrop_save    #       1                       ;File from another app
+vwDrop_load    #       1                       ;File from filing system
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/warning b/StraySrc/Libraries/Sapphire/sh/warning
new file mode 100644 (file)
index 0000000..602cdf2
--- /dev/null
@@ -0,0 +1,69 @@
+;
+; warning.sh
+;
+; Displays warning boxes
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  warning
+;  warn_init
+
+               [       :LNOT::DEF:warning__dfn
+               GBLL    warning__dfn
+
+; --- warning ---
+;
+; On entry:    R0 == pointer to warning text to display
+;              R1 == pointer to buttons block
+;
+; On exit:     R0 == button that was clicked
+;              CS if this was default, CC otherwise
+;
+; Use:         Displays a warning to the user.  The warning box can have up
+;              to five buttons (because it's too small for any more than
+;              that).  These are placed in a column on the right hand side
+;              of the dialogue.  The buttons are numbered from 0 up to 4
+;              from the bottom upwards, 0 being the default.  You can
+;              choose one button to be `Cancel', in which case pressing
+;              escape will activate it.
+
+               IMPORT  warning
+
+; --- warn_init ---
+;
+; On entry:    R0 == program name
+;
+; On exit:     --
+;
+; Use:         Sets up the Warning dialogue box for use.
+
+               IMPORT  warn_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/wimp b/StraySrc/Libraries/Sapphire/sh/wimp
new file mode 100644 (file)
index 0000000..a7f65a5
--- /dev/null
@@ -0,0 +1,93 @@
+;
+; wimp.sh
+;
+; Starting and ending of Wimp tasks
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  wimp_init
+;  wimp_taskHandle
+;  wimp_version
+;  wimp_strWidth
+
+               [       :LNOT::DEF:wimp__dfn
+               GBLL    wimp__dfn
+
+; --- wimp_init ---
+;
+; On entry:    R0 == pointer to application name
+;
+; On exit:     --
+;
+; Use:         Initialises the WindowManager, and stores away useful
+;              snippets of information, like the task handle we've been
+;              given.  It also registers an exit handler so that the Wimp
+;              gets closed down.
+
+               IMPORT  wimp_init
+
+; --- wimp_taskHandle ---
+;
+; On entry:    --
+;
+; On exit:     R0 == the application's task handle
+;
+; Use:         Returns the application's task handle.
+
+               IMPORT  wimp_taskHandle
+
+; --- wimp_version ---
+;
+; On entry:    --
+;
+; On exit:     R0 == the WIMP's version number (may not be the one the
+;                    client asked for)
+;
+; Use:         Returns the WindowManager's version number.
+
+               IMPORT  wimp_version
+
+; --- wimp_strWidth ---
+;
+; On entry:    R0 == pointer to a string
+;
+; On exit:     R0 == width of the string in OS units
+;
+; Use:         Returns the width of a string, as it would be displayed in
+;              an icon (i.e. taking into account things like the current
+;              desktop font etc.)  The width is exact, so if you want to
+;              e.g. draw a box round it, you'll have to add on a little
+;              clearance at each end.  8 OS units seems to be a good size
+;              for the clearance (so the total width you'd use is given by
+;              wimp_strWidth(string)+16, because it has two ends).
+
+               IMPORT  wimp_strWidth
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/win b/StraySrc/Libraries/Sapphire/sh/win
new file mode 100644 (file)
index 0000000..0c56d15
--- /dev/null
@@ -0,0 +1,142 @@
+;
+; win.sh
+;
+; Window event dispatching
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  win_eventHandler
+;  win_removeEventHandler
+;  win_swapWindow
+;  win_windowDeleted
+;  win_unknownHandler
+;  win_removeUnknownHandler
+;  win_init
+
+               [       :LNOT::DEF:win__dfn
+               GBLL    win__dfn
+
+; --- win_eventHandler ---
+;
+; On entry:    R0 == window handle
+;              R1 == pointer to routine to call
+;              R2 == R10 value to call routine with
+;              R3 == R12 value to call routine with
+;
+; On exit:     May return an error
+;
+; Use:         Adds a routine to the event handler list. Later added
+;              routines are called first. The event handing routine
+;              must preserve all the registers, but may alter the carry
+;              flag. If it returns with carry set, then no more event
+;              handlers, OR post-filters, will be called.
+
+               IMPORT  win_eventHandler
+
+; --- win_removeEventHandler ---
+;
+; On entry:    R0 == window handle
+;              R1 == pointer to routine called
+;              R2 == R10 value routine is called with
+;              R3 == R12 value routine is called with
+;
+; On exit:     --
+;
+; Use:         Removes a routine to the event handler list.
+
+               IMPORT  win_removeEventHandler
+
+; --- win_swapWindow ---
+;
+; On entry:    R0 == old window handle
+;              R1 == new window handle
+;
+; On exit:     --
+;
+; Use:         Searches for all the event handlers for window R0, and
+;              changes the window handle for R1.  This is designed for
+;              situations in wihich a window has been deleted and
+;              recreated.
+
+               IMPORT  win_swapWindow
+
+; --- win_windowDeleted ---
+;
+; On entry:    R0 == window handle
+;
+; On exit:     --
+;
+; Use:         Removes all the event handlers associated with the given
+;              window handle.  It is intended to be used when a window
+;              has been deleted.
+
+               IMPORT  win_windowDeleted
+
+; --- win_unknownHandler ---
+;
+; On entry:    R0 == pointer to routine to call
+;              R1 == R4 value to call routine with
+;              R2 == R10 value to call routine with
+;              R3 == R12 value to call routine with
+;
+; On exit:     May return an error
+;
+; Use:         Adds a rountine to the event handler list. Later added
+;              routines are called first. The event handing routine
+;              must preserve all the registers, but may alter the carry
+;              flag. If it returns with carry set, then no more event
+;              handlers, OR post-filters, will be called.
+
+               IMPORT  win_unknownHandler
+
+; --- win_removeUnknownHandler ---
+;
+; On entry:    R0 == pointer to routine called
+;              R1 == R4 value routine is called with
+;              R2 == R10 value routine is called with
+;              R3 == R12 value routine is called with
+;
+; On exit:     --
+;
+; Use:         Removes a routine to the unknown handler list.
+
+               IMPORT  win_removeUnknownHandler
+
+; --- win_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the win system.
+
+               IMPORT  win_init
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/winUtils b/StraySrc/Libraries/Sapphire/sh/winUtils
new file mode 100644 (file)
index 0000000..355a133
--- /dev/null
@@ -0,0 +1,115 @@
+;
+; winUtils.sh
+;
+; Various window utility functions
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  winUtils_setTitle
+;  winUtils_setPosition
+;  winUtils_findValid
+;  winUtils_shaded
+
+               [       :LNOT::DEF:winUtils__dfn
+               GBLL    winUtils__dfn
+
+; --- winUtils_setTitle ---
+;
+; On entry:    R0 == pointer to string to set in title
+;              R1 == pointer to title bar buffer
+;              R2 == window handle to write to
+;
+; On exit:     --
+;
+; Use:         Sets a window's title string.  If the string is different,
+;              the title is redrawn.  The contortion to do this is
+;              unpleasant, and is not to be performed in public.
+
+               IMPORT  winUtils_setTitle
+
+; --- winUtils_setPosition ---
+;
+; On entry:    R0 == window opening style
+;              R1 == pointer to window state block
+;              R2,R3 == extra arguments for displaying the window
+;
+; On exit:     R2,R3 contain position for opening with Wimp_CreateMenu
+;
+; Use:         Modifies the window state block pointed to by R0 so that the
+;              window appears as required in the given opening style.  The
+;              window is always moved to the top.
+
+               IMPORT  winUtils_setPosition
+
+; --- winUtils_findValid ---
+;
+; On entry:    R0 == pointer to icon block
+;              R1 == character to find in block (not case-sensitive)
+;              R2 == old pointer to search from, or 0
+;
+; On exit:     R1 == character forced to lower case
+;              CS if found, and
+;                R2 points to command string
+;              else CC and
+;                R2 corrupted
+;
+; Use:         Tries to find a validation string command in the given
+;              icon block.
+
+               IMPORT  winUtils_findValid
+
+; --- winUtils_shaded ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;
+; On exit:     CS if icon is shaded, CC otherwise
+;
+; Use:         Informs caller whether an icon is shaded in the Sapphire
+;              sense (ESG 31 or shaded bit set).
+
+               IMPORT  winUtils_shaded
+
+; --- Opening styles for winUtils_setPosition ---
+;
+; These are actually the same as the dbox_open styles, without the flags
+; bits.
+
+               ^       0
+wStyle_current #       1                       ;In its current position
+wStyle_centre  #       1                       ;Centred on the screen
+wStyle_pointer #       1                       ;Centred over the pointer
+wStyle_givenY  #       1                       ;At a given height on screen
+                                               ;  R2 == y coordinate to open
+wStyle_givenXY #       1                       ;At a given position on scrn
+                                               ;  R2 == x coordinate
+                                               ;  R3 == y coordinate
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/writable b/StraySrc/Libraries/Sapphire/sh/writable
new file mode 100644 (file)
index 0000000..15c7c21
--- /dev/null
@@ -0,0 +1,130 @@
+;
+; writable.sh
+;
+; Writable dialogue boxes
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;   writable
+;   wrt_init
+;
+; Macros provided:
+;
+;   WRTABLE
+
+               [       :LNOT::DEF:writable__dfn
+               GBLL    writable__dfn
+
+;+             LIB     sapphire:^.bsh.stdDbox
+
+; --- writable ---
+;
+; On entry:    R0 == pointer to writable dialogue block
+;              R1 == pointer to default string to display, or 0 for null
+;              R2 == pointer to routine to call when string set
+;              R3 == value to pass to routine in R10
+;              R4 == value to pass to routine in R12
+;
+; On exit:     R0 == dialogue handle of created dialogue box
+;              May return an error
+;
+; Use:         Displays a writable dialogue box, i.e. one with a writable
+;              icon and OK button, used instead of writable menu items,
+;              for reasons to do with caret blinking and pointer changing.
+;
+;              The writable dialogue block consists of:
+;
+;              Size    Meaning
+;              ~~~~    ~~~~~~~
+;              4       Flags (see below)
+;              n       Validation string to use, may be null
+;              m       Title string (message tag) to display
+;
+;              The flags are:
+;
+;              Bit     Meaning
+;              ~~~     ~~~~~~~
+;              0-7     Maximum string length
+;              8       Right align text in writable icon
+;              9-31    Reserved; must be 0
+;
+;              The routine returns a dialogue handle because you may want
+;              to attach a numWrite control to the writable icon, which
+;              is icon number 0.
+;
+;              The handler routine is passed:
+;
+;              R0 == pointer to string typed in
+;              R1 == dialogue box handle (for numWrite again)
+;              R10, R12 as set up here
+;
+;              It must preserve all registers.  If the carry flag is set
+;              on exit, the dialogue box will not be closed.  If it is
+;              clear, the dialogue may be closed depending on the button
+;              status.
+;
+;              Note that this routine does *not* require a template --
+;              a suitable window is generated at run-time.
+
+               IMPORT  writable
+
+; --- wrt_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the writable dialogue box for use.
+
+               IMPORT  wrt_init
+
+; --- Useful constants ---
+
+wrtFlag_rAlign EQU     (1<<8)                  ;Right align text in icon
+
+; --- Macro: WRTABLE ---
+;
+; Arguments:   len == maximum string length to allow
+;              flags == other flags to set
+;              valid == (optional) validation string
+;              title == title message tag string
+;
+; Use:         Builds a writable definition block.
+
+               MACRO
+$label         WRTABLE $len,$flags,$valid,$title
+               ALIGN
+$label
+               DCD     $len :OR: $flags
+               DCB     "$valid",0
+               DCB     "$title",0
+               MEND
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/xfer/load b/StraySrc/Libraries/Sapphire/sh/xfer/load
new file mode 100644 (file)
index 0000000..f73aba7
--- /dev/null
@@ -0,0 +1,188 @@
+;
+; load.sh
+;
+; Loading and importing of files
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  load
+;  load_initBuf
+;  load_killBuf
+;  load_extendBuf
+;  load_doneBuf
+;  load_file
+
+               [       :LNOT::DEF:load__dfn
+               GBLL    load__dfn
+
+; --- load ---
+;
+; On entry:    R0 == pointer to entry point block
+;              R1 == value of R10 to pass to entry points
+;              R2 == value of R12 to pass to entry points
+;
+; On exit:     --
+;
+; Use:         Attempts to load a file after receipt of a Message_DataSave,
+;              Message_DataLoad or Message_DataOpen.  If user entries for
+;              RAM transfer are provided, this is attempted, although the
+;              entries must also be aware that file transfer may be
+;              required.
+
+               IMPORT  load
+
+; --- load_initBuf ---
+;
+; On entry:    R1 == estimated file size
+;              R2 == pointer to flex anchor (unallocated)
+;
+; On exit:     R0 == pointer to buffer start
+;              R1 == buffer size
+;              May return an error
+;
+; Use:         Initialises a flex block for use as a RAM transfer buffer.
+;              This routine is suitable for use as the initBuf routine for
+;              RAM transfer loading.
+
+               IMPORT  load_initBuf
+
+; --- load_killBuf ---
+;
+; On entry:    R2 == pointer to flex anchor
+;
+; On exit:     --
+;
+; Use:         Frees a flex block.  This routine should be used to free
+;              the buffer used for RAM transfer.
+
+               IMPORT  load_killBuf
+
+; --- load_extendBuf ---
+;
+; On entry:    R0 == pointer to previous buffer
+;              R1 == size of previous buffer
+;              R2 == pointer to flex anchor
+;
+; On exit:     R0 == pointer to a new buffer
+;              R1 == size of the new buffer
+;              May return an error
+;
+; Use:         Extends the flex block if it was initially too small.
+;              This routine is designed to be used as the extend routine
+;              during RAM transfer.
+
+               IMPORT  load_extendBuf
+
+; --- load_doneBuf ---
+;
+; On entry:    R1 == actual size of data
+;              R2 == pointer to flex anchor
+;
+; On exit:     --
+;
+; Use:         Sets the block into which the data has been loaded to the
+;              correct exact size.
+
+               IMPORT  load_doneBuf
+
+; --- load_file ---
+;
+; On entry:    R1 == pointer to filename to load
+;              R2 == pointer to flex anchor
+;
+; On exit:     R0 == size of file loaded
+;              May return an error
+;
+; Use:         Loads a named file into a flex block for your delectation.
+
+               IMPORT  load_file
+
+;----- User entry points ----------------------------------------------------
+
+               ^       0
+
+lEntry__initBuf        #       4                       ;Create a load buffer
+                                               ;On entry:
+                                               ;  R0 == ptr to `filename'
+                                               ;  R1 == estimated file size
+                                               ;  R2 == 0
+                                               ;On exit:
+                                               ;  R0 == ptr to buffer start
+                                               ;  R1 == ptr to buffer end
+                                               ;  R2 == buffer `handle'
+                                               ;  R10 may be updated
+
+lEntry__killBuf        #       4                       ;Destroy the load buffer
+                                               ;On entry:
+                                               ;  R0 == ptr to buffer start
+                                               ;  R1 == ptr to buffer end
+                                               ;  R2 == buffer `handle'
+                                               ;On exit:
+                                               ;  --
+
+lEntry__extend #       4                       ;Extend the load buffer
+                                               ;On entry:
+                                               ;  R0 == ptr to buffer start
+                                               ;  R1 == ptr to buffer end
+                                               ;  R2 == buffer `handle'
+                                               ;On exit:
+                                               ;  R0-R2 updated
+
+lEntry__doneBuf        #       4                       ;All data is now loaded
+                                               ;On entry:
+                                               ;  R0 == ptr to `filename'
+                                               ;  R1 == total size of data
+                                               ;  R2 == buffer `handle'
+                                               ;On exit:
+                                               ;  --
+
+lEntry__file   #       4                       ;Load data from a file
+                                               ;On entry:
+                                               ;  R0 == ptr to `filename'
+                                               ;  R1 == file to load
+                                               ;  R2 == 0 if file unsafe
+                                               ;On exit:
+                                               ;  R10 may be updated
+
+lEntry__done   #       4                       ;Completed loading
+                                               ;On entry:
+                                               ;  R0 == ptr to `filename'
+                                               ;  R1 == safeness indicator
+                                               ;On exit:
+                                               ;  --
+
+lEntry__failed #       4                       ;Failed to load file
+                                               ;On entry:
+                                               ;  R0 == pointer to error
+                                               ;  R1 == 1
+                                               ;On exit:
+                                               ;  --
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/xfer/save b/StraySrc/Libraries/Sapphire/sh/xfer/save
new file mode 100644 (file)
index 0000000..887e484
--- /dev/null
@@ -0,0 +1,99 @@
+;
+; save.sh
+;
+; Saving data to other applications
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  save
+
+               [       :LNOT::DEF:save__dfn
+               GBLL    save__dfn
+
+; --- save ---
+;
+; On entry:    R0 == window handle to send to
+;              R1 == icon handle to send to
+;              R2 == estimated size of the data
+;              R3 == file type of data to send and flag:
+;                    bit 31: use R8 as below
+;              R4 == pointer to name of file (may be full path)
+;              R5 == address of handler block
+;              R6 == value to pass handlers in R10
+;              R7 == value to pass handlers in R12
+;              R8 == pointer to extra handler block (only if bit 31 of R3)
+;
+; On exit:     --
+;
+; Use:         Starts a save operation to another application.  The extra
+;              handler is used by systems like saveas which need to be
+;              aware of data transfer start/end conditions without
+;              interfering with the normal entry table.  This will not
+;              normally concern applications however.
+
+               IMPORT  save
+
+;----- The save handler -----------------------------------------------------
+
+               ^       0
+sEntry__save   #       4                       ;Write to a file
+                                               ;Entry:
+                                               ;  R0 == pointer to file name
+                                               ;  R1 == 0 if file unsafe,
+                                               ;        non-0 if safe
+                                               ;Exit:
+                                               ;  --
+
+sEntry__send   #       4                       ;Send a block of data
+                                               ;Entry:
+                                               ;  R2 == 0 for first call,
+                                               ;        or R2 from previous
+                                               ;Exit:
+                                               ;  R0 == pointer to block
+                                               ;  R1 == size of block
+                                               ;  R2 == value to pass to
+                                               ;        next call
+                                               ;  CS if this is the last one
+
+sEntry__success        #       4                       ;Data transfer has finished
+                                               ;Entry:
+                                               ;  R0 == pointer to filename
+                                               ;  R1 == safeness flag
+                                               ;Exit:
+                                               ;  --
+
+sEntry__failed #       4                       ;Data transfer failed
+                                               ;Entry:
+                                               ;  R0 == 0 or ptr to error
+                                               ;  R1 == 1
+                                               ;Exit:
+                                               ;  --
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/xfer/saveAs b/StraySrc/Libraries/Sapphire/sh/xfer/saveAs
new file mode 100644 (file)
index 0000000..bf1806e
--- /dev/null
@@ -0,0 +1,96 @@
+;
+; saveAs.sh
+;
+; Implementation of a save as dialogue box
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  saveAs
+
+               [       :LNOT::DEF:saveAs__dfn
+               GBLL    saveAs__dfn
+
+; --- saveAs ---
+;
+; On entry:    R0 == estimated size of data
+;              R1 == file type of the data
+;              R2 == pointer to name of the file
+;              R3 == pointer to handler block
+;              R4 == value to pass to handlers in R10
+;              R5 == value to pass to handlers in R12
+;
+; On exit:     May return an error
+;
+; Use:         Displays a save as dialogue box for you to save some data.
+
+               IMPORT  saveAs
+
+;----- The SaveAs handler block ---------------------------------------------
+;
+; The block begins with the message tag for the dialogue title, followed by
+; an align to word boundary and then branch instructions or 0 for:
+
+               ^       0
+saEntry__closed        #       4                       ;Save dialogue has closed
+                                               ;Entry:
+                                               ;  --
+                                               ;Exit:
+                                               ;  --
+
+saEntry__save  #       4                       ;Write to a file
+                                               ;Entry:
+                                               ;  R0 == pointer to file name
+                                               ;  R1 == 0 if file unsafe,
+                                               ;        non-0 if safe
+                                               ;Exit:
+                                               ;  --
+
+saEntry__send  #       4                       ;Send a block of data
+                                               ;Entry:
+                                               ;  --
+                                               ;Exit:
+                                               ;  R0 == pointer to block
+                                               ;  R1 == size of block
+                                               ;  CS if this is the last one
+
+saEntry__success       #       4               ;Data transfer has finished
+                                               ;Entry:
+                                               ;  R0 == safeness flag
+                                               ;Exit:
+                                               ;  --
+
+saEntry__failed        #       4                       ;Data transfer failed
+                                               ;Entry:
+                                               ;  R0 == 0 or ptr to error
+                                               ;  R1 == 1
+                                               ;Exit:
+                                               ;  --
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/xfer/xload b/StraySrc/Libraries/Sapphire/sh/xfer/xload
new file mode 100644 (file)
index 0000000..310518d
--- /dev/null
@@ -0,0 +1,178 @@
+;
+; xfer.xload.sh
+;
+; Simplified loading with coroutines
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  xload_file
+;  xload_initBuf
+;  xload_killBuf
+;  xload_extend
+;  xload_doneBuf
+;  xload_done
+;  xload_failed
+;  xload_byte
+;  xload_word
+;  xload_block
+
+               [       :LNOT::DEF:xload__dfn
+               GBLL    xload__dfn
+
+; --- xload_file ---
+;
+; On entry:    R0 == pointer to loader routine
+;              R1 == R10 value to pass to loader
+;              R2 == R12 value to pass to loader
+;              R3 == pointer to leafname of file (passed to loader in R0)
+;              R4 == pointer to filename to load from
+;              R5 == whether the file is safe (passed to loader in R1)
+;
+; On exit:     May return an error
+;
+; Use:         Calls a generalised loader routine to read data from a file.
+
+               IMPORT  xload_file
+
+; --- xload_initBuf ---
+;
+; On entry:    R0 == pointer to loader routine
+;              R1 == R10 value to pass to loader
+;              R2 == R12 value to pass to loader
+;              R3 == pointer to leafname of file (passed to loader in R0)
+;
+; On exit:     R0 == pointer to load buffer
+;              R1 == size of load buffer
+;              May return an error
+;
+; Use:         Starts a RAM transfer and starts up a generalised load
+;              routine.
+
+               IMPORT  xload_initBuf
+
+; --- xload_killBuf ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Does a buffer destroy for a failed load operation.
+
+               IMPORT  xload_killBuf
+
+; --- xload_extend ---
+;
+; On entry:    R1 == size of last buffer used for receiving
+;
+; On exit:     R0 == pointer to new buffer
+;              R1 == size of new buffer
+;              May return an error
+;
+; Use:         Performs a buffer extent operation during an xload RAM
+;              transfer.
+
+               IMPORT  xload_extend
+
+; --- xload_doneBuf ---
+;
+; On entry:    R1 == total size of data received
+;
+; On exit:     R0 corrupted
+;              May return an error
+;
+; Use:         Handles the last bufferful of a RAM load.
+
+               IMPORT  xload_doneBuf
+
+; --- xload_done ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Tidies up after a successful load job.
+
+               IMPORT  xload_done
+
+; --- xload_failed ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     --
+;
+; Use:         Tidies up a RAM transfer after an error.
+
+               IMPORT  xload_failed
+
+; --- xload_byte ---
+;
+; On entry:    --
+;
+; On exit:     CC if data read OK, and
+;                R0 == byte read
+;              else CC if end-of-file, and
+;                R0 corrupted
+;              May return an error
+;
+; Use:         Reads a byte from the current input.
+
+               IMPORT  xload_byte
+
+; --- xload_word ---
+;
+; On entry:    --
+;
+; On exit:     CC if data read OK, and
+;                R0 == word read
+;              else CS if end-of-file and
+;                R0 corrupted
+;              May return an error
+;
+; Use:         Reads a word from the current input.
+
+               IMPORT  xload_word
+
+; --- xload_block ---
+;
+; On entry:    R0 == pointer to buffer to read
+;              R1 == size of buffer to read
+;
+; On exit:     R0, R1 preserved
+;              R2 == number of bytes read
+;              CC if more data available, CS for end-of-file
+;              May return an error
+;
+; Use:         Reads in a block of data.  Data is buffered, so this is
+;              fairly quick for reading small objects.  Large data blocks
+;              are read directly to avoid buffering overhead.
+
+               IMPORT  xload_block
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/sh/xfer/xsave b/StraySrc/Libraries/Sapphire/sh/xfer/xsave
new file mode 100644 (file)
index 0000000..d07b937
--- /dev/null
@@ -0,0 +1,143 @@
+;
+; xfer.xsave.sh
+;
+; Simplified saving with coroutines
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  xsave_save
+;  xsave_send
+;  xsave_done
+;  xsave_failed
+;  xsave_byte
+;  xsave_word
+;  xsave_string
+;  xsave_block
+
+               [       :LNOT::DEF:xsave__dfn
+               GBLL    xsave__dfn
+
+; --- xsave_save ---
+;
+; On entry:    R0 == pointer to saver routine
+;              R1 == R10 value to pass to saver
+;              R2 == R12 value to pass to saver
+;              R3 == pointer to filename to save to
+;              R4 == filetype of file to save
+;
+; On exit:     May return an error
+;
+; Use:         Calls a generalised saver routine to write data to a file.
+
+               IMPORT  xsave_save
+
+; --- xsave_send ---
+;
+; On entry:    R0 == pointer to saver routine
+;              R1 == R10 value to pass to saver
+;              R2 == R12 value to pass to saver
+;
+; On exit:     R0 == pointer to block to send
+;              R1 == size of block
+;              CS if this is the last block, else CC
+;              May return an error
+;
+; Use:         Calls a generalised saver routine to write data to another
+;              application, using RAM transfer.  Note that you must call
+;              this routine from your send entry point throughout the
+;              save operation.
+
+               IMPORT  xsave_send
+
+; --- xsave_done ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Tidies up after a successful save job.
+
+               IMPORT  xsave_done
+
+; --- xsave_failed ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     --
+;
+; Use:         Tidies up a RAM transfer after an error.
+
+               IMPORT  xsave_failed
+
+; --- xsave_byte ---
+;
+; On entry:    R0 == byte to write in lowest 8 bits
+;
+; On exit:     May return an error
+;
+; Use:         Writes a single byte to the current output.
+
+               IMPORT  xsave_byte
+
+; --- xsave_word ---
+;
+; On entry:    R0 == word to write
+;
+; On exit:     May return an error
+;
+; Use:         Writes a single word to the current output.
+
+               IMPORT  xsave_word
+
+; --- xsave_string ---
+;
+; On entry:    R0 == pointer to a control-terminated string
+;
+; On exit:     May return an error
+;
+; Use:         Writes a control-terminated string to the current output.
+;              The string is null terminated in the output file.
+
+               IMPORT  xsave_string
+
+; --- xsave_block ---
+;
+; On entry:    R0 == pointer to buffer to write
+;              R1 == size of buffer to write
+;
+; On exit:     May return an error
+;
+; Use:         Writes out a block of data.  Data is buffered, so this is
+;              fairly quick for reading small objects.  Large data blocks
+;              are sent directly to avoid buffering overhead.
+
+               IMPORT  xsave_block
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/tms/s/tmsCreate b/StraySrc/Libraries/Sapphire/tms/s/tmsCreate
new file mode 100644 (file)
index 0000000..a7eb3f9
--- /dev/null
@@ -0,0 +1,861 @@
+;
+; tmsCreate.s
+;
+; Creation, recreation and destruction of tearoff menus (TMA)
+;
+; © 1994 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:heap
+               GET     sapphire:keyString
+               GET     sapphire:msgs
+               GET     sapphire:resspr
+               GET     sapphire:sapphire
+               GET     sapphire:string
+               GET     sapphire:wimp
+               GET     sapphire:win
+               GET     sapphire:winUtils
+
+               GET     sapphire:_tms.tmsGlobal
+               GET     sapphire:_tms.tmsMain
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- tms__bitSpec ---
+;
+; On entry:    R5 == pointer to base pointer (R10 or R12) for this item
+;              R9 == pointer to bit specification to work out
+;
+; On exit:     R9 has had 4 added to it
+;              C set or clear according to settedness of the bit
+;
+; Use:         Tells you whether a bit specification points at a bit which
+;              is set or clear by copying it to the carry flag
+
+tms__bitSpec   ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               LDR     R0,[R9],#4              ;Load the specification
+               MOV     R14,R0,LSR #5           ;Get the offset value
+               LDR     R14,[R5,R14]            ;Load the flags word out
+               AND     R0,R0,#31               ;Leave only bit spec bits
+               ADD     R0,R0,#1                ;To make it nice for shifting
+               MOVS    R14,R14,LSR R0          ;Copy bit to carry flag
+               LDMFD   R13!,{R0,R14}           ;Load registers again
+               ORRCSS  PC,R14,#C_flag          ;Set C if C set
+               BICCCS  PC,R14,#C_flag          ;Clear C if C clear
+
+               LTORG
+
+; --- tms__findBase ---
+;
+; On entry:    R2,R3 == R10 and R12 values to pass to event handler
+;              R8 == flags word from packed definition
+;
+; On exit:     R5 == correct base register for this item
+
+tms__findBase  ROUT
+
+               TST     R8,#mFlag_R12           ;Is the R12 flag on?
+               MOVNE   R5,R3                   ;Yes -- return R12 value
+               MOVEQ   R5,R2                   ;No -- return R10 value
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- tms__checksum ---
+;
+; On entry:    R2 == pointer to a name
+;
+; On exit:     R0 == checksum value
+;
+; Use:         Calculates a checksum value for the given name
+
+tms__checksum  ROUT
+
+               STMFD   R13!,{R2,R14}           ;Stack some registers
+               MVN     R0,#0                   ;Start with -1
+00             LDRB    R14,[R2],#1             ;Load a byte
+               CMP     R14,#' '                ;Are we at the end?
+               EORCS   R0,R14,R0,LSL #2        ;Add it on to the sum
+               BCS     %00tms__checksum        ;No -- keep going then
+               LDMFD   R13!,{R2,PC}^           ;Return to caller
+
+; --- tms__createTitle ---
+;
+; On entry:    R9 == pointer to packed title definition
+;
+; On exit:     R9 == pointer to packed item description
+;              R10 == pointer to header structure, filled in and glorious
+;              R0, R4-R8 corrupted
+;
+; Use:         Builds a menu header block
+
+tms__createTitle ROUT
+
+               BIC     R14,R14,#V_flag         ;Assume nothing can harm us
+               STMFD   R13!,{R14}              ;Save link register
+
+               MOV     R0,#hSize               ;Get the size we want
+               BL      heap_alloc              ;Allocate a block for it
+               BLCS    alloc_error             ;If no memory, get error msg
+               LDMVSFD R13!,{PC}               ;And return with V still set
+               MOV     R10,R0                  ;Keep this pointer safe
+               STR     R10,tms__creating       ;Store this pointer nicely
+               STR     R9,[R10,#hDefinition]   ;Store pack defn pointer
+               MOV     R0,#0                   ;Also want to zero item blk
+               STR     R0,tms__lastItems       ;No item blocks created yet
+               STR     R0,[R10,#hItems]        ;No items attached yet
+               STR     R0,[R10,#hKeyWidth]     ;No shortcuts found yet
+               STR     R0,[R10,#hTextWidth]    ;No items yet
+               STR     R0,[R10,#hSprWidth]     ;No sprites yet
+               STR     R0,[R10,#hHandle]       ;No window attached yet
+               STR     R0,[R10,#hNextTorn]     ;Not in torn list
+               STR     R0,[R10,#hDbox]         ;No dialogue box yet
+               STR     R0,[R10,#hFromItem]     ;We're not from an item
+
+               MOV     R6,#0                   ;No flags defined yet
+
+               LDR     R8,[R9],#4              ;Load the flags word out
+               BL      tms__findBase           ;Get the correct base pointer
+               TST     R8,#mFlag_indirect      ;Is this item indirected?
+               BEQ     %00tms__createTitle     ;No -- jump on then
+               STMFD   R13!,{R1}               ;Save a register nicely
+               LDR     R1,[R9],#4              ;Yes -- find offset nicely
+               LDR     R0,[R9],#4              ;...and the buffer size
+               LDR     R1,[R5,R1]              ;...get the pointer out
+
+               BL      heap_alloc              ;Allocate some memory
+               BLCS    alloc_error             ;Get the error message
+               MOVCS   R0,R10                  ;...point to the block
+               BLCS    heap_free               ;...free the memory
+               LDMCSFD R13!,{R1,PC}            ;...and return
+
+               STR     R0,[R10,#hText]         ;Store the text pointer
+               BL      str_cpy                 ;Copy the string into buffer
+               MOV     R0,R1                   ;Put the string in R0
+               LDMFD   R13!,{R1}               ;And restore R1 saved above
+               ORR     R6,R6,#hFlag__tIndir    ;Title is indirected
+               BNE     %10tms__createTitle     ;Skip past this next bit
+
+00             MOV     R0,R9                   ;Point to the message tag
+               BL      msgs_lookup             ;Translate the message
+05             LDRB    R14,[R9],#1             ;Get a message string byte
+               CMP     R14,#' '                ;Is it a terminator?
+               BGE     %05tms__createTitle     ;No -- get another one
+               ADD     R9,R9,#3                ;Add 3
+               BIC     R9,R9,#3                ;And word align the pointer
+               STR     R0,[R10,#hText]         ;Store the text pointer
+
+               ; --- Store the string and get its length ---
+
+10             BL      wimp_strWidth           ;Get the string's width
+               ADD     R0,R0,#32
+               STR     R0,[R10,#hTitleWidth]   ;Store as title width
+
+               ; --- Now handle other bits of the flags ---
+
+               TST     R8,#mFlag_tearoff       ;Are we tearable?
+               ORRNE   R6,R6,#hFlag__tearable  ;Yes -- set the bit nicely
+               TST     R8,#mFlag_global        ;Is menu `global'?
+               ORRNE   R6,R6,#hFlag__global    ;Yes -- set the bit nicely
+               STR     R6,[R10,#hFlags]        ;Store the flags word
+               
+               ; --- Now check for maximum height ---
+
+               TST     R8,#mFlag_maxHeight     ;Is there a maximum height?
+               LDRNE   R0,[R9],#4              ;Yes -- read it out then
+               MOVEQ   R0,#0                   ;No -- zero is a silly value
+               STR     R0,[R10,#hMaxHeight]    ;Store in the right place
+
+               ; --- Perform any other business ---
+
+               ADD     R0,R10,#hHandler        ;Point to the handler bitty
+               STMIA   R0,{R1-R3}              ;Store the 'handlers' away
+
+90             LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- tms_create ---
+;
+; On entry:    R0 == pointer to a menu block
+;              R1 == pointer to event handler for the menu section
+;              R2 == R10 value to pass to the event handler
+;              R3 == R12 value to pass to the event handler
+;
+; On exit:     R0 == tearoff handle for this menu
+;              May return an error
+;
+; Use:         Creates a new menu, or adds sections to an existing one.
+
+               EXPORT  tms_create
+tms_create     ROUT
+
+               BIC     R14,R14,#V_flag         ;Hope there's no error
+               STMFD   R13!,{R1-R10,R12,R14}   ;Save some registers away
+               LDR     R12,=tms__wSpace        ;Find my workspace pointer
+               WSPACE  [R12]                   ;And then my workspace
+               MOV     R9,R0                   ;Keep pointer to definition
+
+               ; --- Get the menu header we're working on ---
+
+               LDR     R10,tms__creating       ;Get the menu header pointer
+               CMP     R10,#0                  ;Is it actually defined?
+               BLEQ    tms__createTitle        ;No -- go away and create it
+               BVS     %99tms_create           ;It failed -- return an error
+
+               ; --- Update ---
+               ;
+               ; OK, the pointer to the first packed item is in R9, and
+               ; R10 contains a pointer to a menu header.
+
+               LDR     R8,[R9],#4              ;Load the item flags word
+               TST     R8,#mFlag_end           ;Is there only a title?
+               MOVNE   R0,R10                  ;Yes -- return the handle
+               LDMNEFD R13!,{R1-R10,R12,PC}^   ;Return to caller nicely
+
+               ; --- Now we need to scan through to count the items ---
+
+               MOV     R7,R9                   ;Current ptr in packed defn
+               MOV     R0,#iHdrSize            ;Count the fixed-size header
+               MOV     R4,#0                   ;Number of items I've found
+
+00tms_create   TST     R8,#mFlag_indirect      ;Is this item indirected?
+               ADDNE   R7,R7,#4                ;Yes -- skip the offset word
+               BNE     %02tms_create           ;And skip past the loop
+
+               ; --- Skip inline text string ---
+
+01tms_create   LDRB    R14,[R7],#1             ;Get a message string byte
+               CMP     R14,#' '                ;Is it a terminator?
+               BGE     %01tms_create           ;No -- get another one
+               ADD     R7,R7,#3                ;Add 3
+               BIC     R7,R7,#3                ;And word align the pointer
+
+               ; --- Now skip other optional blocks ---
+
+02tms_create   TST     R8,#mFlag_shortcut      ;Is ther a normal...
+               TSTEQ   R8,#mFlag_iShortcut     ;...or indirected shortcut?
+               ADDNE   R7,R7,#4                ;Yes -- skip over it then
+               SKPITEM R8,R7                   ;Skip past another item
+               ADD     R0,R0,#iItemSize        ;Add on size for another item
+               ADD     R4,R4,#1                ;And bump my counter too
+               LDR     R8,[R7],#4              ;Load the next flags word
+               TST     R8,#mFlag_end           ;Is this the end yet?
+               BEQ     %00tms_create           ;Yes -- continue with the fun
+
+               ; --- R0 now contains how much we want ---
+
+               BL      heap_alloc              ;Allocate the memory now
+               BLCS    alloc_error             ;If it failed, find an error
+               BVS     %99tms_create           ;And return it nicely
+
+               ; --- Mangle all the list stuff ---
+
+               MOV     R7,R0                   ;Keep the pointer safely
+               LDR     R6,tms__lastItems       ;Get the last item block
+               CMP     R6,#0                   ;Is there one defined?
+               STRNE   R7,[R6,#iItems]         ;Yes -- store in next field
+               STREQ   R7,[R10,#hItems]        ;No -- store as list head
+               STR     R7,tms__lastItems       ;This is the new last blk
+               MOV     R0,#0                   ;Want to terminate the list
+               STR     R0,[R7,#iItems]         ;Store it in the next field
+               STR     R0,[R7,#iDbox]          ;No dialogue box yet
+
+               ; --- Build the item block header ---
+
+               STR     R4,[R7,#iNumber]        ;Store item counter
+               SUB     R0,R9,#4                ;Point to definition start
+               STR     R0,[R7,#iDefinition]    ;Store in the pointer field
+               ADD     R0,R7,#iHandler         ;Point to the handler words
+               STMIA   R0,{R1-R3}              ;Store handler information
+
+               ; --- Now we actually want to build the block ---
+
+               LDR     R8,[R9,#-4]             ;Load the initial flags again
+               ADD     R7,R7,#iHdrSize         ;Skip past header part
+
+10tms_create   MOV     R0,#-1                  ;Get a NULL word
+               STR     R0,[R7,#iKeyCode]       ;No shortcut yet
+               BL      tms__findBase           ;Find base workspace register
+               TST     R8,#mFlag_indirect      ;Is this item indirected?
+               LDRNE   R0,[R9],#4              ;Yes -- find offset nicely
+               LDRNE   R0,[R5,R0]              ;And get the pointer out
+               BNE     %12tms_create           ;Skip past this next bit
+
+               MOV     R0,R9                   ;Point to the message tag
+               BL      msgs_lookup             ;Translate the message
+11tms_create   LDRB    R14,[R9],#1             ;Get a message string byte
+               CMP     R14,#' '                ;Is it a terminator?
+               BGE     %11tms_create           ;No -- get another one
+               ADD     R9,R9,#3                ;Add 2 (we added one in LDRB)
+               BIC     R9,R9,#3                ;And word align the pointer
+
+               ; --- Store the pointer and carry on ---
+
+12tms_create   STR     R0,[R7,#iText]          ;Store the text pointer
+               BL      wimp_strWidth           ;Find the item width
+               LDR     R14,[R10,#hTextWidth]   ;Load previous text width
+               CMP     R0,R14                  ;Is this bigger?
+               STRGT   R0,[R10,#hTextWidth]    ;Yes -- store it over
+
+               TST     R8,#mFlag_shortcut      ;Is there a menu short cut?
+               TSTEQ   R8,#mFlag_iShortcut     ;Or an indirected one?
+               BEQ     %15tms_create           ;No -- jump ahead
+               TST     R8,#mFlag_shortcut      ;Is there a menu short cut?
+               LDRNE   R0,[R9],#4              ;Yes -- load out key code
+               LDREQ   R0,[R9],#4              ;No -- Load offset of code
+               LDREQ   R0,[R5,R0]              ;...load out key code
+               STR     R0,[R7,#iKeyCode]       ;Store the key code
+               MOV     R1,#1                   ;Return short version
+               BL      keyString               ;Find correct string
+               BL      wimp_strWidth           ;Get the string width
+               ADD     R0,R0,#16               ;Put a gap on each side
+               LDR     R1,[R10,#hKeyWidth]     ;Get longest one so far
+               CMP     R0,R1                   ;Is this on longer?
+               STRGT   R0,[R10,#hKeyWidth]     ;Yes -- store it then
+
+               ; --- Severe cleverness warning ---
+               ;
+               ; The TST instructions clear Z iff the appropriate bit is
+               ; on.  tms__bitSpec sets C iff the appropriate bit read from
+               ; a bit spec is on.  We can actually combine testing for
+               ; (C && !Z) with the HI condition code.  This saves jumping
+               ; around a lot.
+
+15tms_create   MOV     R6,#0                   ;Current flags word
+
+               TST     R8,#mFlag_shade         ;Check shadedness bit
+               BLNE    tms__bitSpec            ;Handle the bit specification
+               ORRHI   R6,R6,#iFlag__shaded    ;If set, shade the item
+               BHI     %13tms_create           ;...and jump this next bit
+
+               TST     R8,#mFlag_iShade        ;Check shadedness bit
+               BLNE    tms__bitSpec            ;Handle the bit specification
+               ORRNE   R6,R6,#iFlag__shaded    ;Set shaded bit anyway
+               BICHI   R6,R6,#iFlag__shaded    ;Bit clear it again if set!
+
+13tms_create   TST     R8,#mFlag_switch        ;Check switchiness bit
+               BLNE    tms__bitSpec            ;Handle the bit specification
+               ORRHI   R6,R6,#iFlag__ticked    ;If set, tick it
+
+               TST     R8,#mFlag_radio         ;Check radioness bit
+               BEQ     %14tms_create           ;If not set, skip ahead
+               LDMIA   R9!,{R0,R1}             ;Load the information out
+               LDR     R0,[R5,R0]              ;Load the radio specifier
+               CMP     R0,R1                   ;Is this a match made in hvn?
+               ORREQ   R6,R6,#iFlag__radio     ;Yes -- attach the splodge
+
+               ; --- Deal with sprites ---
+
+14tms_create   TST     R8,#mFlag_sprite        ;Is there a sprite?
+               BEQ     %20tms_create           ;No -- jump ahead
+               STMFD   R13!,{R2-R6}            ;SpriteOp corrupts all these!
+               LDMIA   R9!,{R0,R1}             ;Load the information out
+               LDR     R2,[R5,R0]              ;Load the actual sprit addr
+               STR     R2,[R7,#iSprName]       ;Save the name value
+               BL      tms__checksum           ;Get the checksum
+               STR     R0,[R7,#iSprCsum]       ;And store it away
+               MOVS    R0,R1                   ;Get the sprite area
+               BLMI    resspr_area             ;Negative -- get app's one
+               MOV     R1,R0                   ;Put sprite area in R1 again
+               STR     R1,[R7,#iSprArea]       ;Save the sprite area
+               ORR     R6,R6,#iFlag__sprite    ;The item has a sprite
+               TST     R8,#mFlag_halfSize      ;Should we display at half sz
+               ORRNE   R6,R6,#iFlag__halfSize  ;Yes -- remember this
+               STR     R6,[R13,#16]            ;Save this for later
+
+               ; --- Find the width of the sprite ---
+
+               CMP     R1,#1                   ;Are we using WIMP area?
+               MOVNE   R0,#256+40              ;No -- on user area name
+               SWINE   OS_SpriteOp             ;...get information
+               MOVEQ   R0,#40                  ;Yes -- info please
+               SWIEQ   Wimp_SpriteOp           ;Get it then
+               MOV     R0,R6                   ;Get the sprite's mode
+               MOV     R1,#4                   ;Get the XEig factor
+               SWI     OS_ReadModeVariable     ;Read the value
+               MOV     R3,R3,LSL R2            ;Work out the width in OS
+               LDR     R0,[R10,#hSprWidth]     ;Load current sprite width
+               TST     R8,#mFlag_halfSize      ;Should we display at half sz
+               MOVNE   R3,R3,LSR #1            ;Yes -- then divide by 2
+               ADD     R3,R3,#16               ;Add on a little clearance
+               CMP     R3,R0                   ;Is this bigger than that?
+               STRGT   R3,[R10,#hSprWidth]     ;Yes -- then overwrite
+               LDMFD   R13!,{R2-R6}            ;Restore those registers
+
+20tms_create   TST     R8,#mFlag_ruleOff       ;Is there a ruleoff here
+               ORRNE   R6,R6,#iFlag__dotted    ;Yes -- add a dotted line
+               TST     R8,#mFlag_subWarn+mFlag_subMenu ;Arrow wanted?
+               ORRNE   R6,R6,#iFlag__arrow     ;Yes -- add the arrow
+
+               SKIP    mFlag_subMenu,8,R8,R9   ;Skip submenu bit nicely
+
+               TST     R8,#mFlag_noWarn        ;Do we warn on shaded items?
+               ORRNE   R6,R6,#iFlag__noWarn    ;No -- remember this
+
+               STR     R6,[R7,#iFlags]         ;Store the sussed out flags
+               MOV     R6,#0                   ;A NULL pointer
+               STR     R6,[R7,#iSubMenu]       ;No sub menu from here
+               ADD     R7,R7,#iItemSize        ;Point at the next item
+
+               ; --- Get the next flags word and loop ---
+
+               LDR     R8,[R9],#4              ;Get the next flags word
+               TST     R8,#mFlag_end           ;Is this an end marker?
+               BEQ     %10tms_create           ;No -- do the next one
+
+               ; --- Return interesting things to caller ---
+
+               MOV     R0,R10                  ;Give caller my header block
+               LDMFD   R13!,{R1-R10,R12,PC}^   ;Return to caller nicely
+
+99tms_create   ADD     R2,R0,#4                ;Point to the message
+               MOVS    R0,R10                  ;Point to menu header
+               BLNE    tms__destroy            ;Destroy it if it exists
+               ADR     R0,tms__noCreate        ;Point to error skeleton
+               BL      msgs_error              ;Translate the error
+               LDMFD   R13!,{R1-R10,R12,R14}   ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return with the error
+
+               LTORG
+
+tms__noCreate  DCD     1
+               DCB     "tmsCCTM:TMS cannot create menu: %s",0
+
+; --- tms__destroy ---
+;
+; On entry:    R0 == handle of tearoff menu to destroy
+;
+; On exit:     --
+;
+; Use:         Zaps a tearoff menu entirely, leaving no survivors
+
+               EXPORT  tms__destroy
+tms__destroy   ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+               MOV     R4,R0                   ;Preserve menu pointer
+
+               ; --- Delete the window, and remove its handler ---
+
+               ADD     R1,R0,#hHandle          ;Point to the handle
+               SWI     Wimp_CloseWindow        ;Close the window
+               SWI     Wimp_DeleteWindow       ;Then delete it
+               LDR     R0,[R4,#hHandle]        ;The window handle
+               LDR     R1,=tms__eventHandler   ;Point to the handler
+               MOV     R2,R4                   ;The handle passed
+               MOV     R3,R12                  ;Workspace passed in R3
+               BL      win_removeEventHandler  ;Remove the event handler
+               LDR     R0,[R4,#hFlags]         ;Load the header flags
+               TST     R0,#hFlag__tIndir       ;Is title indirected?
+               LDRNE   R0,[R4,#hText]          ;Yes -- load buffer pointer
+               BLNE    heap_free               ;And free it nicely
+               LDR     R1,[R4,#hItems]         ;Get the items pointer
+               MOV     R0,R4                   ;Point back to the block
+               BL      heap_free               ;Free the block
+
+00tms__destroy MOVS    R0,R1                   ;Point R0 at the block
+               LDMEQFD R13!,{R0-R4,PC}^        ;Return PDQ
+               LDR     R1,[R0,#iItems]         ;Get the next items pointer
+               BL      heap_free               ;Free the block
+               B       %00tms__destroy         ;Keep destorying blocks
+
+               LTORG
+
+; --- tms__width ---
+;
+; On entry:    R10 == pointer to the menu
+;
+; On exit:     CS if the width has changed, CC otherwise
+;
+; Use:         Calculates what the appropriate width fields of the given
+;              menu should be.
+
+               EXPORT  tms__width
+tms__width     ROUT
+
+               STMFD   R13!,{R0-R8,R14}        ;Stack some registers
+
+               MOV     R4,#0                   ;No sprite width
+               MOV     R5,#0                   ;No text width
+               MOV     R6,#0                   ;No shortcut width
+               LDR     R7,[R10,#hTotWidth]     ;Get the current width
+
+               LDR     R2,[R10,#hItems]        ;Point to the first items
+05tms__width   LDR     R3,[R2,#iNumber]        ;Load the number of items
+               ADD     R8,R2,#iHdrSize         ;Point to first item
+
+               ; --- Calculate string width ---
+
+10tms__width   LDR     R0,[R8,#iText]          ;Load the text pointer
+               BL      wimp_strWidth           ;Get the strings length
+               CMP     R0,R5                   ;Is it greater?
+               MOVGT   R5,R0                   ;Yes -- remember this then
+
+               ; --- Now the shortcut width ---
+
+               LDR     R0,[R8,#iKeyCode]       ;Load the key code
+               CMP     R0,#-1                  ;Is there one?
+               BEQ     %12tms__width           ;No -- jump ahead
+               MOV     R1,#1                   ;Return short version
+               BL      keyString               ;Find correct string
+               BL      wimp_strWidth           ;Get the string width
+               ADD     R0,R0,#16               ;Put a gap on each side
+               CMP     R0,R6                   ;Is this on longer?
+               MOVGT   R6,R0                   ;Yes -- remember that fact
+
+               ; --- Finally the sprite width ---
+
+12tms__width   STMFD   R13!,{R2-R6}            ;Save some registers
+               LDR     R14,[R8,#iFlags]        ;Get the flags word
+               TST     R14,#iFlag__sprite      ;Is there a sprite here?
+               LDMEQFD R13!,{R2-R6}            ;No -- restore registers
+               BEQ     %15tms__width           ;...jump ahead a little
+               LDR     R1,[R8,#iSprArea]       ;Get the sprite area
+               LDR     R2,[R8,#iSprName]       ;And the sprite name
+               CMP     R1,#1                   ;Are we using WIMP area?
+               MOVNE   R0,#256+40              ;No -- on user area name
+               SWINE   OS_SpriteOp             ;...get information
+               MOVEQ   R0,#40                  ;Yes -- info please
+               SWIEQ   Wimp_SpriteOp           ;Get it then
+               MOV     R0,R6                   ;Get the sprite's mode
+               MOV     R1,#4                   ;Get the XEig factor
+               SWI     OS_ReadModeVariable     ;Read the value
+               MOV     R3,R3,LSL R2            ;Work out the width in OS
+               TST     R14,#iFlag__halfSize    ;Should we display at half sz
+               MOVNE   R3,R3,LSR #1            ;Yes -- then divide by 2
+               ADD     R3,R3,#16               ;Add on a little clearance
+               MOV     R14,R3                  ;Remember this width
+               LDMFD   R13!,{R2-R6}            ;Restore those registers
+               CMP     R14,R4                  ;Is this bigger than that?
+               MOVGT   R4,R14                  ;Yes -- use this value then
+
+               ; --- Now do other items ---
+
+15tms__width   ADD     R8,R8,#iItemSize        ;Point to the next item
+               SUBS    R3,R3,#1                ;Decrement item count
+               BGT     %10tms__width           ;More to go -- do them
+
+               LDR     R2,[R2,#iItems]         ;Load the next items
+               CMP     R2,#0                   ;Are there any more?
+               BNE     %05tms__width           ;Yes -- look at them then
+
+               STR     R4,[R10,#hSprWidth]     ;Store the sprite width
+               STR     R5,[R10,#hTextWidth]    ;Store the text width
+               STR     R6,[R10,#hKeyWidth]     ;And shortcut width too
+
+               ADD     R4,R4,R5                ;Add them all together
+               ADD     R4,R4,R6                ;...
+               ADD     R4,R4,#64               ;Left and right + 16
+
+               LDR     R0,[R10,#hText]         ;Load the title pointer
+               BL      wimp_strWidth           ;Find the string width
+               ADD     R0,R0,#32               ;Add on some clearance
+               STR     R0,[R10,#hTitleWidth]   ;Store the title width
+               CMP     R0,R4                   ;Is this longer than rest?
+               MOVGT   R4,R0                   ;Yes -- use this width
+
+               STR     R4,[R10,#hTotWidth]     ;Store new total width
+
+               CMP     R4,R7                   ;Has the width changed?
+               BEQ     %95tms__width           ;No -- return
+
+               ; --- Change the extent of the window ---
+
+               LDR     R14,[R10,#hHandle]      ;Get the window handle
+               STR     R14,[R13,#-36]!         ;Get me a block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window state
+
+               SUB     R13,R13,#16             ;Get another block
+               MOV     R2,#0                   ;Minimum x extent
+               LDR     R3,[R10,#hHeight]       ;Get the window height
+               RSB     R3,R3,#0                ;Minimun y extent
+               MOV     R5,#0                   ;Maximum y extent
+               STMIA   R13,{R2-R5}             ;Store these in the block
+               MOV     R0,R14                  ;Get the window handle in R0
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetExtent          ;Set the extent
+
+               ADD     R13,R13,#16             ;Get the first block back
+               LDR     R0,[R13,#4]             ;Get visible x0
+               ADD     R0,R0,R4                ;Calculate x1
+               STR     R0,[R13,#12]            ;Store the maximum x extent
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_OpenWindow         ;Open the window
+
+               ADD     R13,R13,#36             ;Reclaim the stack
+
+               ; --- Force a complete redraw ---
+               ;
+               ; It's a shame, but there's nothing else for it.
+
+               LDR     R0,[R10,#hHandle]       ;Load the window handle
+               MOV     R1,#0                   ;Left hand side of window
+               LDR     R2,[R10,#hHeight]       ;Load the window height
+               RSB     R2,R2,#0                ;Make it nicely negative
+               LDR     R3,[R10,#hTotWidth]     ;Load the window width
+               MOV     R4,#0                   ;And the top of the window
+               SWI     Wimp_ForceRedraw        ;Aarggh boo spit spit
+
+90tms__width   LDMFD   R13!,{R0-R8,R14}        ;Get registers back
+               ORRS    PC,R14,#C_flag          ;Return with carry set
+
+95tms__width   LDMFD   R13!,{R0-R8,R14}        ;Get registers back
+               BICS    PC,R14,#C_flag          ;Return with carry clear
+
+               LTORG
+
+; --- tms__check ---
+;
+; On entry:    R0 == pointer to menu to check
+;              R12 == pointer to global tms workspace
+;
+; On exit:     --
+;
+; Use:         Checks to see if the given menu needs to be changed, and
+;              updates it as appropriate if it does.
+
+tms__check     ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Stack lots of registers
+
+               STR     R0,tms__recreating      ;Store a pointer to this menu
+               LDR     R9,[R0,#hDefinition]    ;Point to packed header defn
+               MOV     R7,R0                   ;Put structure in R7
+               LDR     R8,[R9],#4              ;Load the title flags word
+               LDR     R2,[R7,#hR10]           ;Load R10 value
+               LDR     R3,[R7,#hR12]           ;And R12 value
+               BL      tms__findBase           ;Put base in R5
+               TST     R8,#mFlag_indirect      ;Is the text indirected?
+               BEQ     %02tms__check           ;No -- just skip over string
+               LDR     R0,[R9],#4              ;Yes -- find offset
+               LDR     R1,[R9],#4              ;And buffer length
+               LDR     R0,[R5,R0]              ;And point to the string
+
+               ; --- Compare to find a difference ---
+
+               LDR     R1,[R7,#hText]          ;Point to current text string
+               BL      str_cmp                 ;Compare the strings
+               LDRNE   R2,[R7,#hHandle]        ;Load the window handle
+               BLNE    winUtils_setTitle       ;And set the title
+               B       %05tms__check           ;Jump ahead
+
+               ; --- Skip over embedded title string ---
+
+02tms__check   LDRB    R14,[R9],#1             ;Get a message string byte
+               CMP     R14,#' '                ;Is it a terminator?
+               BGE     %02tms__check           ;No -- get another one
+               ADD     R9,R9,#3                ;Add 3
+               BIC     R9,R9,#3                ;And word align the pointer
+
+               ; --- Now check the items ---
+
+05tms__check   LDR     R6,[R7,#hItems]         ;Point to first items
+06tms__check   LDR     R2,[R6,#iR10]           ;Load R10 value
+               LDR     R3,[R6,#iR12]           ;And R12 value
+
+               LDR     R9,[R6,#iDefinition]    ;Point to packed items defn
+               ADD     R7,R6,#iHdrSize         ;Point to first item
+               LDR     R8,[R9],#4              ;Load the flags word
+07tms__check   BL      tms__findBase           ;Get base in R5
+               LDR     R10,[R7,#iFlags]        ;Get the existing flags
+               BIC     R10,R10,#&FF000000      ;Clear redraw flags
+               STR     R10,[R7,#iFlags]        ;Store them back
+
+               ; --- First, compare the text strings ---
+
+               TST     R8,#mFlag_indirect      ;Is text indirected?
+               BEQ     %10tms__check           ;No -- just skip over string
+               LDR     R0,[R9],#4              ;Yes -- find offset
+               LDR     R0,[R5,R0]              ;And point to the string
+
+               ; --- Compare to find a difference ---
+
+               LDR     R1,[R7,#iText]          ;Point to current text string
+               BL      str_cmp                 ;Compare the strings
+               ORRNE   R10,R10,#iFlag__newText ;If different, remember it
+               STRNE   R0,[R7,#iText]          ;And store new text ptr
+               B       %11tms__check           ;And jump ahead if no change
+
+               ; --- Skip over embedded item string ---
+
+10tms__check   LDRB    R14,[R9],#1             ;Get a message string byte
+               CMP     R14,#' '                ;Is it a terminator?
+               BGE     %10tms__check           ;No -- get another one
+               ADD     R9,R9,#3                ;Add 3
+               BIC     R9,R9,#3                ;And word align the pointer
+
+               ; --- The shortcut may have changed ---
+
+11tms__check   TST     R8,#mFlag_iShortcut     ;Is there a indir. shortcut?
+               BEQ     %12tms__check           ;No -- skip ahead
+
+               LDR     R0,[R9]                 ;Get the value
+               LDR     R0,[R5,R0]              ;Load out the key code
+               LDR     R14,[R7,#iKeyCode]      ;Load current key code
+               CMP     R14,R0                  ;Has it changed?
+               STRNE   R0,[R7,#iKeyCode]       ;Yes -- store this value
+               ORRNE   R10,R10,#iFlag__newKey  ;...queue for redrawing
+
+               ; --- Now collect the item flags ---
+
+12tms__check   TST     R8,#mFlag_shortcut      ;Is there a shortcut?
+               TSTEQ   R8,#mFlag_iShortcut     ;Of any kind?
+               ADDNE   R9,R9,#4                ;Yes -- skip over it
+
+               MOV     R4,#0                   ;No flags set yet
+
+               TST     R8,#mFlag_shade         ;Check shadedness bit
+               BLNE    tms__bitSpec            ;Handle the bit specification
+               ORRHI   R4,R4,#iFlag__shaded    ;If set, shade the item
+               BHI     %13tms__check           ;...and jump this next bit
+
+               TST     R8,#mFlag_iShade        ;Check shadedness bit
+               BLNE    tms__bitSpec            ;Handle the bit specification
+               ORRNE   R4,R4,#iFlag__shaded    ;Set shaded bit anyway
+               BICHI   R4,R4,#iFlag__shaded    ;Bit clear it again if set!
+
+13tms__check   TST     R8,#mFlag_switch        ;Check switchiness bit
+               BLNE    tms__bitSpec            ;Handle the bit specification
+               ORRHI   R4,R4,#iFlag__ticked    ;If set, tick it
+
+               TST     R8,#mFlag_radio         ;Check radioness bit
+               BEQ     %14tms__check           ;If not set, skip ahead
+               LDMIA   R9!,{R0,R1}             ;Load the information out
+               LDR     R0,[R5,R0]              ;Load the radio specifier
+               CMP     R0,R1                   ;Is this a match made in hvn?
+               ORREQ   R4,R4,#iFlag__radio     ;Yes -- attach the splodge
+
+               ; --- Now check the sprite ---
+
+14tms__check   TST     R8,#mFlag_sprite        ;Is there a sprite here?
+               BEQ     %15tms__check           ;No skipitty jump aaawhooo
+               STMFD   R13!,{R2}               ;Don't corrupt R2
+               LDR     R2,[R9],#4              ;Yes -- load out name ptr ptr
+               LDR     R2,[R5,R2]              ;And get name ptr
+               BL      tms__checksum           ;Get the checksum
+               LDR     R1,[R7,#iSprCsum]       ;Load the current checksum
+               CMP     R0,R1                   ;Has it changed?
+               STRNE   R0,[R7,#iSprCsum]       ;Yes -- store the new one
+               STRNE   R2,[R7,#iSprName]       ;...and the new name
+               ORRNE   R10,R10,#iFlag__newSpr  ;...and queue for redraw
+               ADD     R9,R9,#4                ;Skip over sprite area
+               LDMFD   R13!,{R2}               ;Return to caller
+
+15tms__check
+               SKIP    mFlag_subMenu,8,R8,R9   ;Skip submenu bit nicely
+
+               ; --- Have the flags changed? ---
+
+               LDR     R14,[R7,#iFlags]        ;Get the current item flags
+               AND     R0,R14,#7               ;Clear unwanted flags
+               CMP     R0,R4                   ;Have flags changed?
+
+               BIC     R14,R14,#7              ;Clear relevant flags
+               ORR     R14,R14,R4              ;Set new flags up
+               MOV     R1,R14                  ;And remember them
+
+               ; --- Update text part ---
+
+               EOR     R14,R0,R4               ;Get flags which have changed
+
+               TST     R14,#iFlag__shaded      ;Has shaded state changed?
+               ORRNE   R10,R10,#&FF000000      ;Yes -- redraw the whole item
+               TST     R14,#iFlag__ticked+iFlag__radio ;Need to redraw left?
+               ORRNE   R10,R10,#iFlag__newTick ;Yes -- then queue an update
+               BIC     R10,R10,#7              ;Clear these flags
+               BIC     R1,R1,#&FF000000        ;Clear old update flags
+               ORR     R1,R1,R10               ;Add in update bits
+               STR     R1,[R7,#iFlags]         ;Store the new flags
+
+               ; --- Check following items ---
+
+20tms__check   ADD     R7,R7,#iItemSize        ;Point at the next item
+               LDR     R8,[R9],#4              ;Load the next flags word
+               TST     R8,#mFlag_end           ;Have we reached the end?
+               BEQ     %07tms__check           ;No -- keep check these items
+
+               LDR     R6,[R6,#iItems]         ;Point to next group of items
+               CMP     R6,#0                   ;Are there any more?
+               BNE     %06tms__check           ;Yes -- check them then
+
+               ; --- Maybe change menu width ---
+
+               LDR     R10,tms__recreating     ;Get the menu ptr
+               BL      tms__width              ;Recalculate the menu width
+               BCS     %90tms__check           ;If it redrew it, skip on
+
+               ; --- Now redraw items we queued above ---
+
+               MOV     R0,#0                   ;Only redraw queued bits
+               BL      tms__update             ;And update the window
+90tms__check   LDMFD   R13!,{R0-R10,PC}^       ;Return to caller
+
+               LTORG
+
+; --- tms_recreate ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Recreates the existing menu structure, making changes where
+;              appropriate.
+
+               EXPORT  tms_recreate
+tms_recreate   ROUT
+
+               ; --- A note to the wise ---
+               ;
+               ; We go through the data for every open tearoff menu, and
+               ; make any changes that are necessary. These include:
+               ;
+               ;   Making the menu wider or narrower, if necessary
+               ;   Changing textual strings where they are now different
+               ;   Adding or removing of ticks and blobs
+               ;   Shading or unshading of items
+
+               STMFD   R13!,{R0,R14}           ;Stack some registers
+               LDR     R12,=tms__wSpace        ;Point to workspace pointer
+               WSPACE  [R12]                   ;Load out workspace pointer
+
+               LDR     R0,tms__current         ;Load the current menu ptr
+               CMP     R0,#0                   ;Is there one open?
+               BEQ     %10tms_recreate         ;No -- look at torn ones
+00tms_recreate BL      tms__check              ;Check the menu, make changes
+               LDR     R0,[R0,#hSubMenu]       ;Get submenu pointer
+               CMP     R0,#0                   ;Is there one?
+               BNE     %00tms_recreate         ;Yes -- check it then
+
+               ; --- Now check the torn off menus ---
+
+10tms_recreate LDR     R0,tms__tornoffs        ;Get first torn off menu
+               CMP     R0,#0                   ;Have we finished yet?
+               BEQ     %90tms_recreate         ;Yes -- return then
+15tms_recreate BL      tms__check              ;Check the menu, make changes
+               LDR     R0,[R0,#hNextTorn]      ;Get the next torn menu
+               CMP     R0,#0                   ;Have we finished yet?
+               BNE     %15tms_recreate         ;No -- keep going then
+
+90tms_recreate LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/tms/s/tmsGlue b/StraySrc/Libraries/Sapphire/tms/s/tmsGlue
new file mode 100644 (file)
index 0000000..353586e
--- /dev/null
@@ -0,0 +1,480 @@
+;
+; tmsGlue.s
+;
+; Supplies underlying tms workings -- filters, window creation etc. (TMA)
+;
+; © 1994 Straylight
+;
+
+;----- Standard Header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     libs:tearSupt.sh.tearSupt
+
+               GET     sapphire:event
+               GET     sapphire:errorBox
+               GET     sapphire:heap
+               GET     sapphire:mem
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+               GET     sapphire:wimp
+               GET     sapphire:win
+
+               ; --- Internal header files ----
+
+               GET     sapphire:_tms.tmsGlobal
+               GET     sapphire:_tms.tmsMain
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+;----- Window creation ------------------------------------------------------
+
+; --- tms__calcHeight ---
+;
+; On entry:    R10 == pointer to menu
+;
+; On exit:     R0 == The height of the menu, including tearoff bar (-ve)
+;
+; Use:         Calculates the height of the window, and also sets up
+;              the yCoord fields in the items
+
+tms__calcHeight        ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Stack registers
+               MOV     R14,R10                 ;Keep this pointer
+               MOV     R0,#0                   ;The height so far
+               LDR     R3,[R14,#hFlags]        ;Get the flags word
+               TST     R3,#hFlag__tearable     ;Is there a tearoff bar?
+               SUBNE   R0,R0,#tms__barHeight   ;Yes -- allow for it
+               LDR     R14,[R14,#hItems]       ;Point to the items
+
+00             CMP     R14,#0                  ;Are we at the end
+               RSBEQ   R1,R0,#0                ;Get +ve height
+               STREQ   R1,[R10,#hHeight]       ;And store in height field
+               LDMEQFD R13!,{R1-R3,PC}^        ;Yes -- return
+               LDR     R1,[R14,#iNumber]       ;Get number of items in block
+               ADD     R2,R14,#iHdrSize        ;Point to the first item
+01             LDR     R3,[R2,#iFlags]         ;Get the item flags
+               STR     R0,[R2,#iyCoord]        ;Store this coordinate
+               SUB     R0,R0,#44               ;The size of one item
+               TST     R3,#iFlag__dotted       ;Is there a dotted line?
+               SUBNE   R0,R0,#24               ;Yes -- allow for it
+               SUBS    R1,R1,#1                ;Decrement item count
+               ADDNE   R2,R2,#iItemSize        ;Point to the next item
+               BNE     %01tms__calcHeight      ;...and count it
+               LDR     R14,[R14,#iItems]       ;If at end -- point to next
+               B       %00tms__calcHeight      ;...and count the next block
+
+               LTORG
+
+; --- tms__createWindow ---
+;
+; On entry:    R0 == the menu height (-ve)
+;              R10 == pointer to the menu
+;
+; On exit:     V and R0 == The standard error block, if an error occured
+;              R0 == the window handle
+;
+; Use:         This call will create a window for the given menu. The
+;              block pointed to by R10 will be filled in appropriately
+;              with the handle.
+
+               EXPORT  tms__createWindow
+tms__createWindow ROUT
+
+               BIC     R14,R14,#V_flag         ;Assume no error yet
+               STMFD   R13!,{R1-R9,R14}        ;Stack some registers
+
+               SUB     R13,R13,#88             ;Create a block
+               MOV     R9,R13                  ;Point to the block
+               MOV     R5,R0                   ;The menu height
+               LDR     R6,[R10,#hMaxHeight]    ;Get the maximum height
+               CMP     R6,#0                   ;Is there one?
+               BEQ     %05tms__createWindow    ;No -- jump this bit
+               CMN     R6,R5                   ;Is actual height greater?
+               MVNLE   R5,R6                   ;Yes -- make it maxHeight
+05             ADR     R0,tms__coords          ;Point to the coords
+               LDMIA   R0,{R0,R3}              ;And get them
+               LDR     R6,tms__flags           ;Get the flags
+               TST     R6,#tFlag__iBar         ;Is menu from icon bar
+               ADDEQ   R1,R3,R5                ;No -- miny = maxy-height
+               MOVNE   R1,#96                  ;Yes -- miny = 96
+               SUBNE   R3,R1,R5                ;...maxy = miny+height
+               BNE     %10tms__createWindow    ;Jump the next text
+               LDR     R6,[R10,#hFlags]        ;Get the header flags
+               TST     R6,#hFlag__tearable     ;Is there a tearoff bar?
+               ADDNE   R1,R1,#tms__barHeight   ;Yes -- shift up menu
+               ADDNE   R3,R3,#tms__barHeight   ;Up, up, up we go
+10             LDR     R2,[R10,#hSprWidth]     ;The sprite width
+               LDR     R4,[R10,#hTextWidth]    ;The text width
+               LDR     R5,[R10,#hKeyWidth]     ;The shortcut width
+               ADD     R2,R2,R4                ;Calculate the width
+               ADD     R2,R2,R5                ;Oh yes... Pleeeease!
+               ADD     R2,R2,#64               ;Left/Right edges+16 for luck
+               LDR     R14,[R10,#hTitleWidth]  ;Get the title width
+               CMP     R14,R2                  ;Is this greater?
+               MOVGT   R2,R14                  ;Yes -- use this later
+               STR     R2,[R10,#hTotWidth]     ;Remember this value
+               ADD     R2,R2,R0                ;And offset from x0
+               MOV     R4,#0                   ;Scroll x offset
+               MOV     R5,#0                   ;Scroll y offset
+               MOV     R6,#-1                  ;The behind value
+               LDR     R7,=&84000002           ;The wimp flags
+
+               ; --- Add a scroll bar if we need to ---
+
+               LDR     R14,[R10,#hFlags]       ;Get the flags word
+               TST     R14,#hFlag__folded      ;Is the menu folded?
+               BNE     %17tms__createWindow    ;Yes -- no bar needed
+               LDR     R8,[R10,#hHeight]       ;Get the actual height
+               LDR     R14,[R10,#hMaxHeight]   ;Get the maximum height
+               CMP     R14,#0                  ;Is there one?
+               BEQ     %12tms__createWindow    ;No -- compare to screen hght
+               CMP     R8,R14                  ;Is it greater than max?
+                BGT    %15tms__createWindow    ;Yes -- add scroll bar
+12             ADD     R8,R8,#50               ;Add 50 to actual
+               STMFD   R13!,{R0}               ;preserve R0
+               BL      screen_getInfo          ;Get screen information
+               LDR     R0,[R0,#screen_height]  ;Get the screen height
+               CMP     R8,R0                   ;Is menu taller than screen?
+               LDMFD   R13!,{R0}               ;Get R0 back
+               BLE     %17tms__createWindow    ;No -- don't add bar
+
+15             ORR     R7,R7,#(1<<28)          ;Give window a scroll bar
+               LDR     R14,[R10,#hFlags]       ;Get the menu flags
+               ORR     R14,R14,#hFlag__scrBar  ;There is a scroll bar
+               STR     R14,[R10,#hFlags]       ;Store the flags back
+               B       %20tms__createWindow    ;Jump ahead a bit
+
+17             LDR     R14,[R10,#hFlags]       ;Get the menu flags
+               BIC     R14,R14,#hFlag__scrBar  ;There is a scroll bar
+               STR     R14,[R10,#hFlags]       ;Store the flags back
+
+20             LDR     R8,=&00070207           ;Colours
+               LDR     R14,=&000c0103          ;More colours
+               STMIA   R9!,{R0-R8,R14}         ;Store in the block
+               SUB     R2,R2,R0                ;Get the real width back
+               MOV     R0,#0                   ;Workarea x0
+               LDR     R1,[R10,#hHeight]       ;Get the actual height
+               RSB     R1,R1,#0                ;Make it -ve
+               MOV     R3,#0                   ;y1 as for above
+               LDR     R4,=&00000139           ;The title bar flags
+               LDR     R5,=&00003000           ;The workarea button type
+               MOV     R6,#1                   ;The sprite area to use
+               MOV     R7,#0                   ;Minimum width/height
+               STMIA   R9!,{R0-R7}             ;Store in the block
+               LDR     R0,[R10,#hText]         ;Point to the text
+               MOV     R1,#-1                  ;no validation string
+               MOV     R2,#&ff                 ;The buffer length
+               MOV     R3,#0                   ;No items yet
+               STMIA   R9!,{R0-R3}             ;Store this data
+               MOV     R1,R13                  ;Point to the block
+               SWI     XWimp_CreateWindow      ;Try to create the window
+               ADD     R13,R13,#88             ;Get my block back
+               LDMVSFD R13!,{R1-R9,R14}        ;On error, get the registers
+               ORRVSS  PC,R14,#V_flag          ;...and return with error
+               STR     R0,[R10,#hHandle]       ;Store the handle in menu
+               LDMFD   R13!,{R1-R9,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Pre and Post fileters ------------------------------------------------
+
+; --- tms__open ---
+;
+; On entry:    R0 == pointer to menu to open
+;
+; On exit:     ---
+;
+; Use:         Opens the given tearoff menu in the right place
+
+tms__open      ROUT
+
+               STMFD   R13!,{R0-R3,R10,R14}    ;Stack some registers
+
+               ; --- Create the window ---
+
+               MOV     R10,R0                  ;Keep pointer to the menu
+               BL      tms__calcHeight         ;Work out the height of menu
+               BL      tms__createWindow       ;Create the window
+               MOVVS   R1,#1                   ;On error -- show 1 icon
+               BLVS    errorBox                ;...display the error
+               BVS     %99tms__open            ;...and return to caller
+
+               ; --- Set up an event handler for the menu ---
+
+               LDR     R1,=tms__eventHandler   ;Point to the event handler
+               MOV     R2,R10                  ;The handle of the menu
+               MOV     R3,R12                  ;R12 value to call with
+               BL      win_eventHandler        ;Add the handler
+
+               ; --- Now, open the window ---
+
+               SUB     R13,R13,#36             ;Get a block
+               STR     R0,[R13,#0]             ;Store the handle in block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window state
+               SWI     Wimp_OpenWindow         ;Open the window
+               ADD     R13,R13,#36             ;Get my block back
+
+               ; --- Fill in any extra information ---
+
+               LDR     R0,tms__current         ;Get the current transient
+               CMP     R0,#0                   ;Is there one
+               STREQ   R10,tms__current        ;No -- store this one then
+               BLEQ    wimp_taskHandle         ;...get the task handle
+               BLEQ    tearSupport_opened      ;...start tearoffsupt sending
+               LDR     R0,tms__prevLevel       ;Point to the previous menu
+               CMP     R0,#0                   ;Is there one?
+               STRNE   R10,[R0,#hSubMenu]      ;Yes -- store in sub menu ptr
+               STR     R0,[R10,#hPrevMenu]     ;Yes -- Point back to it
+               MOV     R0,#0                   ;Time to set some values
+               STR     R0,[R10,#hSelected]     ;No item selected yet
+               STR     R0,[R10,#hSubMenu]      ;No current submenu either
+
+               ; --- And return to the caller ---
+
+99tms__open    MOV     R0,#0                   ;We are no longer creating
+               STR     R0,tms__creating        ;So say that!
+               LDMFD   R13!,{R0-R3,R10,PC}^    ;Return
+
+               LTORG
+
+; --- tms__preFilter ---
+;
+; On entry:    R0 == event mask and flags
+;              R1 == pointer to block to use
+;              R2 == earliest time to return with NULL event
+;              R3 == pointer to fxp_poll word
+;
+; On exit:     --
+;
+; Use:         Called as an event pre-filter. Its purpose is to open
+;              a previously created menu in the right place.
+
+tms__preFilter ROUT
+
+               STMFD   R13!,{R0,R14}           ;Stack some registers
+               LDR     R0,tms__flags           ;Get the main flags word
+               TST     R0,#tFlag__doFake       ;Should we fake a NULL?
+               BNE     %10tms__preFilter       ;Yes -- jump ahead then
+
+               ; --- Open a menu if we need to ---
+
+               LDR     R0,tms__creating        ;Point to menu being created
+               CMP     R0,#0                   ;Is there one?
+               LDMEQFD R13!,{R0,PC}^           ;No -- return
+               BL      tms__open               ;Open the menu
+               LDMFD   R13!,{R0,PC}^           ;And return to the caller
+
+               ; --- Fake a NULL event ---
+
+10             BIC     R0,R0,#tFlag__doFake    ;Don't fake again
+               ORR     R0,R0,#tFlag__faking    ;Remember that we're faking
+               STR     R0,tms__flags           ;Store back the flags
+               MOV     R0,#0                   ;Return event 0 (NULL)
+               ADD     R13,R13,#4              ;Skip over old event code
+               LDMFD   R13!,{R14}              ;Load the link back
+               ORRS    PC,R14,#C_flag          ;And return with carry set
+
+               LTORG
+
+; --- tms__postFilter ---
+;
+; On entry:    R0 == wimp event
+;              R1 == the Wimp_Poll block
+;
+; On exit:     --
+;
+; Use:         Called as a post handle by event to look out for clever
+;              things such as button clicks
+
+tms__postFilter        ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some regisr
+               CMP     R0,#6                   ;Was it a button click?
+               BEQ     %10tms__postFilter      ;Yes -- deal with it
+               LDR     R2,tms__flags           ;Get the flags
+               BIC     R2,R2,#tFlag__iBar      ;It wasn't a click on ibar
+               STR     R2,tms__flags           ;Store the flags back
+               CMP     R0,#17                  ;User_Message?
+               CMPNE   R0,#18                  ;User_Message_Recorded?
+               BEQ     %20tms__postFilter      ;Yes -- check it out
+               LDMFD   R13!,{R0-R3,PC}^        ;Return
+
+               ; --- Deal with button click ---
+
+10             LDR     R0,[R1,#12]             ;Get the window handle
+               CMP     R0,#-2                  ;Is it the icon bar
+               LDR     R0,tms__flags           ;Get the flags
+               ORREQ   R0,R0,#tFlag__iBar      ;Yes -- set relevent bit
+               BICNE   R0,R0,#tFlag__iBar      ;No -- clear it then
+               STR     R0,tms__flags           ;Store the flags back
+               ADR     R2,tms__coords          ;Point to coords block
+               LDMIA   R1,{R0,R1}              ;Get x and y coords
+               SUB     R0,R0,#64               ;Correct the x coord
+               STMIA   R2,{R0,R1}              ;Store them in the block
+               LDMFD   R13!,{R0-R3,PC}^        ;Return
+
+               ; --- It was a message ---
+
+20             LDR     R2,[R1,#16]             ;Get the message type
+               LDR     R0,=&400C1              ;Mode change
+               CMP     R2,R0                   ;Is that the message?
+               LDRNE   R0,=&400CF              ;Fonts changed
+               CMPNE   R2,R0                   ;Check this one too
+               BEQ     %30tms__postFilter      ;Yes -- deal with it
+               LDR     R0,=&4A340              ;Button pressed message
+               CMP     R2,R0                   ;Is that the message?
+               BEQ     %50tms__postFilter      ;Yes -- deal with it
+               LDR     R0,=&4A341              ;Close menus
+               CMP     R2,R0                   ;Is that the message?
+               BEQ     %60tms__postFilter      ;Yes -- deal with it
+               LDMFD   R13!,{R0-R3,PC}^        ;Return
+
+               ; --- Mode change message ---
+
+30             LDR     R0,tms__oldHandle       ;Get idle event handler hnd
+               CMP     R0,#0                   ;Is there a current handler?
+               BLNE    tms__cleanUp            ;Yes -- clean up a bit
+               LDR     R2,tms__flags           ;Get the flags word
+               BIC     R2,R2,#tFlag__newFont   ;No font change yet
+               LDR     R1,tms__fHandle         ;Get the old handle
+               MOV     R0,#8                   ;Read the wimp font handle
+               SWI     XWimp_ReadSysInfo       ;Read if we can
+               MOVVS   R0,#0                   ;If error -- no font
+               CMP     R0,R1                   ;Compare the handles
+               ORRNE   R2,R2,#tFlag__newFont   ;If different, mark this
+               STRNE   R0,tms__fHandle         ;...and store new font handle
+               STR     R2,tms__flags           ;Store new flags
+               LDMFD   R13!,{R0-R3,PC}^        ;And return
+
+               ; --- Button pressed message ---
+               ;
+               ; We must check to see if we are clicking on one of
+               ; our menus, and close our current transient if we're not
+
+50             LDR     R2,[R1,#32]             ;Get the window handle
+               LDR     R3,tms__currDbox        ;Get the current dbox
+               CMP     R3,R2                   ;Is this what we clicked on?
+               BEQ     %70tms__postFilter      ;Yes -- return then
+               LDR     R0,tms__current         ;Get the current menu
+55             CMP     R0,#0                   ;Is there one?
+               BEQ     %60tms__postFilter      ;No -- close transient then
+               LDR     R1,[R0,#hHandle]        ;Get the window handle
+               CMP     R1,R2                   ;Are they the same
+               LDMEQFD R13!,{R0-R3,PC}^        ;Yes -- return
+               LDR     R0,[R0,#hSubMenu]       ;Get the submenu pointer
+               CMP     R0,R3                   ;Is it the dbox?
+               BNE     %55tms__postFilter      ;No -- check the submenus
+
+               ; --- Close the transient menu then ---
+
+60             LDR     R2,tms__current         ;Point to the transient
+               CMP     R2,#0                   ;Is there one?
+               LDREQ   R2,tms__currDbox        ;No -- load dbox handle
+               MOV     R0,R10                  ;Remember R10 value
+               MOV     R10,#0                  ;We're not over any menu
+               BL      tms__closeMenu          ;Close the menu
+               MOV     R10,R0                  ;Get R10 value back
+70             LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Initialisation -------------------------------------------------------
+
+; --- tms_init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises the tms (Tearoff Menu System) unit.
+
+               EXPORT  tms_init
+tms_init       ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Stack some registers
+               LDR     R12,=tms__wSpace        ;Locate my workspace pointer
+               WSPACE  [R12]                   ;And then my workspace
+
+               ; --- Return if we are initialised ---
+
+               LDR     R1,tms__flags           ;Get the flags word
+               TST     R1,#tFlag__inited       ;Are we initialised
+               LDMNEFD R13!,{R0-R2,R12,PC}^    ;Yes -- return
+
+               ; --- Initialise various systems ---
+
+               BL      win_init                ;Initialise win
+               BL      wimp_init               ;And wimp
+               BL      heap_init               ;And heap
+
+               ; --- Set up the workspace values ---
+
+               ORR     R1,R1,#tFlag__inited    ;We are initialised now
+               BL      wimp_version            ;What wimp version is this
+
+               CMP     R0,#300                 ;RISC OS 3?
+               ORRGE   R1,R1,#tFlag__riscos3   ;Yes -- remember this fact
+               STR     R1,tms__flags           ;Store the flags back
+
+               MOV     R0,#8                   ;Read current wimp font
+               SWI     XWimp_ReadSysInfo       ;Read it if possible
+               MOVVS   R0,#0                   ;If error -- no font
+               STR     R0,tms__fHandle         ;Store the handle away
+               ADR     R0,tms__zInit           ;Point to the correct block
+               MOV     R1,#tms__zSize          ;Get the size of the area
+               MOV     R2,#0                   ;Fill with zeros
+               BL      mem_set                 ;And do it *very* quickly
+
+               STR     R11,tms__R11            ;Save scratchpad address
+
+               ; --- Set up the filters ---
+
+               ADR     R0,tms__preFilter       ;Point to the routine
+               MOV     R1,R12                  ;Use this R12 value
+               BL      event_preFilter         ;Add the filter
+
+               ADR     R0,tms__postFilter      ;Point to the routine
+               MOV     R1,R12                  ;Use this R12 value
+               BL      event_postFilter        ;Add the filter
+
+               ; --- Set up the global area, and install hook ---
+
+               LDR     R0,tms__TWIN            ;Load the global area name
+               MOV     R1,#twin_size           ;Get the required size
+               BL      sapphire_global         ;Find its address
+               STR     R0,tms__twin            ;And store in my workspace
+               MOVCC   R1,#0                   ;Clear the values out...
+               MOVCC   R14,#0                  ;...if not already done
+               STMCCIA R0,{R1,R14}             ;Store the zeroes in there
+               ADR     R14,tms__hookTbl        ;Point to the hook table
+               STR     R14,[R0,#twin_tmsHook]  ;Save in the hook entry
+
+               ; --- Initialise tearSupt ---
+
+               BL      tearSupport_init        ;Initialise it
+
+               ; --- And return to the user ---
+
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller
+
+tms__TWIN      DCB     "TWIN"
+
+tms__hookTbl   B       tmsh__subWaiting
+               B       tmsh__openSub
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/tms/s/tmsMain b/StraySrc/Libraries/Sapphire/tms/s/tmsMain
new file mode 100644 (file)
index 0000000..7bec37c
--- /dev/null
@@ -0,0 +1,2438 @@
+;
+; tmsMain.s
+;
+; The Straylight Tearoff Menu Segment (TMA)
+;
+; © 1994 Straylight
+;
+
+;----- Don't forget to do these things --------------------------------------
+;
+; Do a good checksum
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External Dependencies ------------------------------------------------
+
+               GET     libs:tearSupt.sh.tearsupt
+
+               GET     sapphire:errorBox
+               GET     sapphire:help
+               GET     sapphire:idle
+               GET     sapphire:keyString
+               GET     sapphire:msgs
+               GET     sapphire:resspr
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+               GET     sapphire:string
+               GET     sapphire:tspr
+               GET     sapphire:wimp
+               GET     sapphire:win
+
+               ; --- Internal header files ---
+
+               GET     sapphire:_tms.tmsCreate
+               GET     sapphire:_tms.tmsGlobal
+               GET     sapphire:_tms.tmsGlue
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- tms__closeMenu ---
+;
+; On entry:    R2 == pointer to menu to close
+;              R10 == pointer to the menu we are currently over
+;
+; On exit:     --
+;
+; Use:         Closes the menu structure pointed to, and destroys it
+
+               EXPORT  tms__closeMenu
+tms__closeMenu ROUT
+
+               CMP     R2,#0                   ;Is there menu?
+               MOVEQS  PC,R14                  ;No -- return
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+               LDR     R14,tms__currDbox       ;Get the current dbox
+               CMP     R14,R2                  ;Is this what we are closing?
+               BEQ     %20tms__closeMenu       ;Yes -- close it then
+
+               LDR     R0,[R2,#hPrevMenu]      ;Get the previous menu
+               CMP     R0,#0                   ;Is there one?
+               BEQ     %03tms__closeMenu       ;No -- skip this bit then
+               CMP     R0,R10                  ;Are we over previous menu?
+               BLNE    tms__deselect           ;No -- deselect the item
+               LDREQ   R1,[R0,#hFlags]         ;Yes -- get its flags
+               BICEQ   R1,R1,#hFlag__warned    ;...clear the warned flag
+               STREQ   R1,[R0,#hFlags]         ;...store flags back again
+               MOV     R0,#0                   ;A NULL pointer
+
+               ; --- Tell the previous menu that we have closed ---
+
+               LDR     R1,[R2,#hFromItem]      ;Get the item we are from
+               CMP     R1,#0                   ;Is there one?
+               STRNE   R0,[R1,#iSubMenu]       ;Yes -- no submenu now
+
+               ; --- Update some globals ---
+
+03             STR     R0,tms__prevLevel       ;No previous level
+               STR     R0,tms__orgTearoff      ;No originating tearoff
+
+               ; --- Clear the previous field of torn menus ---
+
+               LDR     R1,tms__tornoffs        ;Get the head of the list
+               CMP     R1,#0                   ;Are we at the end?
+               BEQ     %05tms__closeMenu       ;Yes -- jump
+04             LDR     R4,[R1,#hPrevMenu]      ;Get the 'previous' field
+               CMP     R2,R4                   ;Does it point to this menu?
+               STREQ   R0,[R1,#hPrevMenu]      ;Yes -- make it NULL
+               LDR     R1,[R1,#hNextTorn]      ;Get the next torn menu
+               CMP     R1,#0                   ;Are we at the end?
+               BNE     %04tms__closeMenu       ;No -- keep looking
+
+               ; --- If we are closing the current transient, do this ---
+
+05             LDR     R0,tms__current         ;Point to current transient
+               CMP     R0,R2                   ;Are we closing it?
+               BNE     %09tms__closeMenu       ;No -- jump ahead
+               MOV     R0,#0                   ;Yes -- A NULL pointer
+               STR     R0,tms__current         ;...no current any more
+               BL      tearSupport_closed      ;Stop tearoffsupt sending
+
+               ; --- If dbox came from this menu, do this ---
+
+               LDR     R0,tms__dboxPrev        ;Get dbox parent
+               CMP     R0,R2                   ;Are we closing it?
+               MOVEQ   R0,#0                   ;Yes -- get a NULL word
+               STREQ   R0,tms__dboxPrev        ;And store that as the parent
+
+               ; --- Now close down the menu structure ---
+
+09             LDR     R3,tms__oldHandle       ;Get the old handle
+10             MOV     R0,R2                   ;Destroy this menu
+               LDR     R1,[R0,#hFlags]         ;Get the flags word
+               TST     R1,#hFlag__torn         ;Is the menu torn off?
+               LDMNEFD R13!,{R0-R4,PC}^        ;Yes -- return
+               LDR     R2,[R0,#hSubMenu]       ;Get the submenu pointer
+
+               ; --- Inform the owner about deletion ---
+
+               STMFD   R13!,{R0-R2,R10,R12}    ;Stack some registers
+               ADD     R0,R0,#hHandler         ;Point to the handler
+               LDMIA   R0,{R2,R10,R12}         ;Get values out
+               MOV     R0,#mEvent_deleted      ;The menu has been deleted
+               MOV     R1,#0                   ;No item in question
+               CMP     R2,#0                   ;Sanity check
+               MOV     R14,PC                  ;Set up return address
+               MOVNE   PC,R2                   ;Call the handler
+               LDMFD   R13!,{R0-R2,R10,R12}    ;Get registers back
+
+               ; --- Destroy the menu ---
+
+               BL      tms__destroy            ;Destroy the menu
+               CMP     R0,R3                   ;Were we over this menu?
+               BLEQ    tms__cleanUp            ;Yes -- clean up then
+
+               TST     R1,#hFlag__warned       ;Has there been a warning
+               LDMEQFD R13!,{R0-R4,PC}^        ;No -- return
+               CMP     R2,#0                   ;Is there a submenu?
+               LDMEQFD R13!,{R0-R4,PC}^        ;No -- Return to caller
+               TST     R1,#hFlag__dbox         ;Is this a dbox?
+               BEQ     %10tms__closeMenu       ;No -- keep going then
+
+               ; --- Its a window then ---
+
+20             LDR     R0,tms__dboxPrev        ;Get the previous menu
+               CMP     R0,#0                   ;Is there one?
+               BEQ     %25tms__closeMenu       ;No -- skip this bit then
+               CMP     R0,R10                  ;Are we over previous menu?
+               BLNE    tms__deselect           ;No -- deselect the item
+               LDREQ   R1,[R0,#hFlags]         ;Yes -- get its flags
+               BICEQ   R1,R1,#hFlag__warned    ;...clear the warned flag
+               STREQ   R1,[R0,#hFlags]         ;...store flags back again
+               MOV     R0,#0                   ;A NULL pointer
+
+               ; --- Tell the previous menu that we have closed ---
+
+               LDR     R1,tms__dboxPrev        ;Get the item we are from
+               CMP     R1,#0                   ;Is there one?
+               STRNE   R0,[R1,#iSubMenu]       ;Yes -- no submenu now
+
+               ; --- Now close the dialogue box ---
+
+25             LDR     R2,tms__currDbox        ;Load the dbox handle
+               STR     R2,[R13,#-4]!           ;Put handle on the stack
+               MOV     R1,R13                  ;Point to it
+               SWI     Wimp_CloseWindow        ;And close the window
+               ADD     R13,R13,#4              ;Reclaim my stack
+               MOV     R0,#0                   ;No current dbox
+               STR     R0,tms__currDbox        ;Make that clear
+               LDR     R1,tms__current         ;Get the current transient
+               CMP     R1,#0                   ;Is this what we are closing?
+               STREQ   R0,tms__current         ;Yes -- no transient now then
+               BLEQ    tearSupport_closed      ;Stop the messages please
+               LDR     R0,tms__flags           ;Load the main flags
+               ORR     R0,R0,#tFlag__doFake    ;Do a fake NULL event
+               STR     R0,tms__flags           ;Store the flags back again
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- tms__alarm1 ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         The first alarm to be called when waiting on an item.
+
+tms__alarm1    ROUT
+               STMFD   R13!,{R0-R2,R7,R8,R14}  ;Stack registers nicley
+
+               ; --- Set up the next alarm ---
+
+               MOV     R0,#161                 ;Read the CMOS ram
+               MOV     R1,#23                  ;Read the delay time
+               SWI     OS_Byte                 ;Read the delay then
+               LDR     R0,tms__flags           ;Load the tms flags
+               ORR     R0,R0,#tFlag__nActive   ;Menus are not active
+               STR     R0,tms__flags           ;Save the new flags
+               ADD     R2,R2,R2,LSL #2         ;Multiply delay by 5
+               MOV     R2,R2,LSL #1            ;And then by 2
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               ADD     R0,R0,R2                ;Set alarm for this time
+               ADR     R1,tms__alarm2          ;Call this handler
+               ADR     R2,tms__alarm1          ;Use this handle
+               MOV     R3,R12                  ;And pass workspace in R12
+               BL      idle_setAlarm           ;Set the alarm
+
+               ; --- Open the sub menu ---
+
+               LDR     R10,tms__alarmMenu      ;Get the menu alarm is for
+               LDR     R0,[R10,#hHandle]       ;Load the window handle
+               STR     R0,[R13,#-36]!          ;Store in a block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window state
+
+               LDR     R7,tms__alarmItem       ;Get the alarm item
+               LDR     R8,tms__itemBlock       ;Get item block address
+               BL      tms__subMenu            ;And open the menu
+
+               ADD     R13,R13,#36             ;Get the stack back
+               LDMFD   R13!,{R0-R2,R7,R8,PC}^  ;Return to caller
+
+               LTORG
+
+; --- tms__alarm2 ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Called as the second alarm, allowing selection of other
+;              items in the menu.
+
+tms__alarm2    ROUT
+
+               STMFD   R13!,{R14}              ;Stack some registers
+
+               LDR     R14,tms__flags          ;Load the tms flags
+               BIC     R14,R14,#tFlag__nActive ;Menus are not active
+               STR     R14,tms__flags          ;Save the new flags
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+; --- tms__findItem ---
+;
+; On entry:    R0 == x coordinate (menu relative)
+;              R1 == y coordinate (menu relative)
+;              R10 == pointer to the menu
+;
+; On exit:     R8 == pointer to the item block
+;              R7 == pointer to the actual item
+
+tms__findItem  ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+               MOV     R2,#0                   ;The y coordinate so far
+               LDR     R3,[R10,#hFlags]        ;Get the menu flags
+               TST     R3,#hFlag__tearable     ;Is there a tearoff bar?
+               SUBNE   R2,R2,#tms__barHeight   ;Yes -- move y position down
+               LDR     R8,[R10,#hItems]        ;Point to the items
+00tms__findItem        ADD     R7,R8,#iHdrSize         ;Point to the first item
+               LDR     R4,[R8,#iNumber]        ;Get the item count
+01tms__findItem        CMP     R1,R2                   ;Compare y coordinates
+               BGE     %90tms__findItem        ;If greater -- no item found
+               SUB     R2,R2,#44               ;The bottom of the item
+               CMP     R1,R2                   ;Compare y coordinates
+               BGE     %10tms__findItem        ;We've found it -- jump a bit
+               LDR     R3,[R7,#iFlags]         ;Get the item flags
+               TST     R3,#iFlag__dotted       ;Is there a dotted line?
+               SUBNE   R2,R2,#24               ;Subract that from y
+               SUBS    R4,R4,#1                ;Subtract the item count
+               ADDNE   R7,R7,#iItemSize        ;If some left, point to them
+               BNE     %01tms__findItem        ;...and try them
+               LDR     R8,[R8,#iItems]         ;Point to the next batch
+               CMP     R8,#0                   ;Are there any left
+               BNE     %00tms__findItem        ;Yes -- check them
+               B       %90tms__findItem        ;No -- return
+
+               ; --- We have found the item ---
+
+10tms__findItem        LDR     R1,[R8,#iDefinition]    ;Point to packed definition
+               LDR     R0,[R8,#iNumber]        ;Get the number of items
+               SUBS    R0,R0,R4                ;Get the index of item
+               STR     R0,tms__itemIndex       ;Store this index value
+               BEQ     %15tms__findItem        ;If we have found it -- jump
+11tms__findItem        LDR     R2,[R1],#4              ;Get the item flags
+               TST     R2,#mFlag_indirect      ;Is this item indirected?
+               ADDNE   R1,R1,#4                ;Yes -- skip the offset word
+               BNE     %13tms__findItem        ;And skip past the loop
+
+               ; --- Skip inline text string ---
+
+12tms__findItem        LDRB    R14,[R1],#1             ;Get a message string byte
+               CMP     R14,#' '                ;Is it a terminator?
+               BGE     %12tms__findItem        ;No -- get another one
+               ADD     R1,R1,#3                ;Add 3
+               BIC     R1,R1,#3                ;And word align the pointer
+
+               ; --- Skip over shortcut word ---
+
+13tms__findItem        TST     R2,#mFlag_shortcut      ;It there a shortcut?
+               TSTEQ   R2,#mFlag_iShortcut     ;Even an indirected one?
+               ADDNE   R1,R1,#4                ;Yes -- skip over value
+
+               ; --- Now skip other optional blocks ---
+
+               SKPITEM R2,R1                   ;Skip this item
+               SUBS    R0,R0,#1                ;Decrement my count
+               BGT     %11tms__findItem        ;Keep trying if some left
+15tms__findItem        STR     R1,tms__itemOver        ;Store this pointer
+               STR     R8,tms__itemBlock       ;And this one too
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               ; --- The pointer wasn't over an item ---
+
+90tms__findItem        MOV     R8,#0                   ;No item block found
+               MOV     R7,#0                   ;No item found either
+               LDMFD   R13!,{R0-R4,PC}^        ;Return now
+
+               LTORG
+
+; --- tms__updateItem ---
+;
+; On entry:    R7 == pointer to the item to highlight
+;              R10 == pointer to the menu
+;
+; On exit:     --
+;
+; Use:         Forces an update of the textual part of an item.
+
+               EXPORT  tms__updateItem
+tms__updateItem        ROUT
+
+               STMFD   R13!,{R0-R4,R11,R14}    ;Stack some registers
+
+               SUB     R13,R13,#44             ;Get a redraw block
+               LDR     R4,[R7,#iyCoord]        ;Get the y coordinate
+               LDR     R11,[R7,#iFlags]        ;Get the item flags
+
+               LDR     R0,[R10,#hHandle]       ;Get the window handle
+               MOV     R1,#24                  ;x0
+               LDR     R3,[R10,#hTotWidth]     ;Get the total width
+               ADD     R3,R3,#24               ;x1
+               SUB     R2,R4,#44               ;y0
+               STMIA   R13,{R0-R4}             ;Fill in the block
+               MOV     R1,R13                  ;Point to it
+               SUB     R13,R13,#32             ;Get another block
+               SWI     Wimp_UpdateWindow       ;Start the redraw
+00             CMP     R0,#0                   ;More to do?
+               ADDEQ   R13,R13,#(44+32)        ;Get the stack back
+               LDMEQFD R13!,{R0-R4,R11,PC}^    ;No -- return
+               BL      tms__redrawText         ;Perform the redrawing
+               BL      tms__redrawSprite       ;.,.,.,.,
+               BL      tms__redrawKey          ;...
+               SWI     Wimp_GetRectangle       ;Get another rectangle
+               B       %00tms__updateItem      ;And keep redrawing
+
+               LTORG
+
+; --- tms__highlight ---
+;
+; On entry:    R2 == pointer to item to highlight
+;              R10 == pointer to the menu for these items
+;
+; On exit:     --
+;
+; Use:         Highlights the item pointed to on entry
+
+tms__highlight ROUT
+
+               STMFD   R13!,{R0,R7,R14}        ;Stack some registers
+               LDR     R0,[R10,#hSelected]     ;Get the selected item
+               CMP     R2,R0                   ;Are they the same
+               STMEQFD R13!,{R0-R4,R7,PC}^     ;Yes -- return
+               MOV     R7,R2                   ;Point to the item
+               STR     R7,[R10,#hSelected]     ;This is now selected item
+               LDR     R0,[R7,#iFlags]         ;Get the item flags
+               TST     R0,#iFlag__shaded       ;Is the item shaded?
+               BLEQ    tms__updateItem         ;No -- update it
+               LDMFD   R13!,{R0,R7,PC}^        ;And return
+
+               LTORG
+
+; --- tms__unHighlight ---
+;
+; On entry:    R2 == pointer to item to un-highlight
+;              R10 == pointer to the menu for these items
+;
+; On exit:     --
+;
+; Use:         un-highlights the item pointed to on entry
+
+tms__unHighlight ROUT
+
+               STMFD   R13!,{R0,R7,R14}        ;Stack some registers
+               LDR     R0,[R10,#hSelected]     ;Get the selected item
+               CMP     R2,R0                   ;Are they the same?
+               LDMNEFD R13!,{R0,R7,PC}^        ;No -- return
+               MOV     R7,R2                   ;Point to the item
+               MOV     R0,#0                   ;No selected item
+               STR     R0,[R10,#hSelected]     ;Store the NULL pointer
+               LDR     R0,[R7,#iFlags]         ;Get the item flags
+               TST     R0,#iFlag__shaded       ;Is the item shaded?
+               BLEQ    tms__updateItem         ;No -- update it
+               LDMFD   R13!,{R0,R7,PC}^        ;And return
+
+               LTORG
+
+; --- tms__deselect ---
+;
+; On entry:    R0 == pointer to the menu
+;
+; On exit:     --
+;
+; Use:         Deselects the highlighted item in the given menu
+
+tms__deselect  ROUT
+
+               STMFD   R13!,{R2,R10,R14}       ;Stack some registers
+               LDR     R2,[R0,#hSelected]      ;Point to the selected item
+               CMP     R2,#0                   ;Is there one?
+               LDMEQFD R13!,{R2,R10,PC}^       ;No -- return then
+
+               MOV     R10,R0                  ;We need menu in R10
+               BL      tms__unHighlight        ;Unhighlight it then
+               LDR     R14,[R0,#hFlags]        ;Get the flags word
+               BIC     R14,R14,#hFlag__warned  ;We are no longer warned
+               STR     R14,[R0,#hFlags]        ;Store back modified flags
+               LDMFD   R13!,{R2,R10,PC}^       ;Return to caller
+
+               LTORG
+
+; --- tmsh__subWaiting ---
+;
+; On entry:    --
+;
+; On exit:     CS if we're waiting for a submenu, CC otherwise
+;
+; Use:         Informs transWin if a submenu is expected.
+
+               EXPORT  tmsh__subWaiting
+tmsh__subWaiting ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  tms__wSpace             ;Load my workspace address
+               LDR     R14,tms__flags          ;Load the flags word
+               TST     R14,#tFlag__subWait     ;Are we waiting for a submenu
+               LDMFD   R13!,{R12,R14}          ;Unstack the registers
+               ORRNES  PC,R14,#C_flag          ;Yes -- return CS then
+               BICEQS  PC,R14,#C_flag          ;No -- return CC then
+
+               LTORG
+
+; --- tmsh__openSub ---
+;
+; On entry:    R0 == window handle to open
+;
+; On exit:     --
+;
+; Use:         Opens the given window as a submenu from a tms menu.
+
+               EXPORT  tmsh__openSub
+tmsh__openSub  ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Save registers
+               WSPACE  tms__wSpace             ;Load my workspace address
+               STR     R0,[R13,#-36]!          ;Get a block
+               LDR     R1,tms__currItem        ;Point to the current item
+               STR     R0,[R1,#iDbox]          ;Store the window handle
+               LDR     R14,[R1,#iFlags]        ;Load the flags word
+               ORR     R14,R14,#iFlag__dbox    ;Say this is a dbox
+               STR     R14,[R1,#iFlags]        ;Save the flags back
+               STR     R0,tms__currDbox        ;Store it here too
+               LDR     R1,tms__orgTearoff      ;Load the originating tearoff
+               STR     R0,[R1,#hDbox]          ;Store the window handle
+               LDR     R14,[R1,#hFlags]        ;Load the flags word
+               ORR     R14,R14,#hFlag__dbox    ;Say this is a dbox
+               STR     R14,[R1,#hFlags]        ;Save the flags back
+               STR     R0,[R1,#hSubMenu]       ;Store as submenu
+               STR     R1,tms__dboxPrev        ;This is menu dbox came from
+
+               LDR     R14,tms__current        ;Load the current transient
+               CMP     R14,#0                  ;Is there one?
+               BLEQ    wimp_taskHandle         ;No -- get task handle  
+               BLEQ    tearSupport_opened      ;...start tearSupt then
+               
+               MOV     R1,R13                  ;Point to it
+               SWI     Wimp_GetWindowState     ;Get the window state
+               LDMIB   R1,{R0-R3}              ;Get the current coords
+               SUB     R2,R2,R0                ;Get the current width
+               SUB     R1,R3,R1                ;And its height
+               ADR     R0,tms__coords          ;Get coords to open at
+               LDMIA   R0,{R0,R3}              ;Load some coords then
+               SUB     R1,R3,R1                ;Calculate y0 coord
+               ADD     R2,R0,R2                ;And then x1
+               STMIB   R13,{R0-R3}             ;Store them back nicely
+               MOV     R0,#-1                  ;Open at the front please
+               STR     R0,[R13,#28]            ;Store this in the block
+               MOV     R1,R13                  ;Point back to the block
+               BL      tspr_adjustBox          ;Fit on screen properly
+               SWI     Wimp_OpenWindow         ;Open the window
+               ADD     R13,R13,#36             ;Restore stack
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- tms__subMenu ---
+;
+; On entry:    R1 == pointer to a window state for the menu
+;              R7 == pointer to the item
+;              R8 == pointer to item header block
+;              R10 == pointer to the menu
+;              R12 == workspace pointer
+;
+; On exit:     --
+;
+; Use:         Opens the sub menu correctly for the given item.
+
+tms__subMenu   ROUT
+               STMFD   R13!,{R0-R6,R14}        ;Stack some registers
+
+               ; --- Store the coords to open next menu ---
+
+               LDR     R4,[R1,#12]             ;Get the x1 coordinate
+               LDR     R5,[R1,#16]             ;...and y1
+               ADD     R4,R4,#2                ;Correct x1 a bit
+               LDR     R6,[R7,#iyCoord]        ;Get the y coord of item
+               ADD     R5,R5,R6                ;Calculate next y to open at
+               LDR     R6,[R1,#24]             ;Don't forget scroll offset
+               SUB     R5,R5,R6                ;No siree
+               ADR     R6,tms__coords          ;Point to the coords
+               STMIA   R6,{R4,R5}              ;Store the coordinates
+
+               ; --- Warn the user/open the menu if we need to ---
+
+               LDR     R6,[R10,#hFlags]        ;Get the menu flags
+               TST     R6,#hFlag__warned       ;Have we already been warned?
+               BNE     %35tms__subMenu         ;Yes -- skip this bit
+               ORR     R6,R6,#hFlag__warned    ;We have been now
+               STR     R6,[R10,#hFlags]        ;Store back the flags
+               LDR     R4,[R7,#iSubMenu]       ;Get the submenu ptr
+               CMP     R4,#0                   ;Is there one?
+               BLNE    tms__locateMenu         ;Yes -- try to find it
+               CMP     R4,#0                   ;Has it been returned?
+               BNE     %37tms__subMenu         ;Yes -- bring it back to us
+               STR     R6,[R10,#hFlags]        ;Store the flags back
+               TST     R6,#hFlag__torn         ;Is menu torn off?
+               STRNE   R10,tms__orgTearoff     ;Yes -- remember this fact
+               MOV     R5,#0                   ;A NULL pointer
+               STR     R5,[R10,#hSubMenu]      ;No current sub menu
+               STR     R10,tms__prevLevel      ;This is the previous menu
+               LDR     R4,tms__itemOver        ;Get packed defn for item
+               LDR     R3,[R4],#4              ;Get the flags word
+               TST     R3,#mFlag_subWarn       ;Do we require a warning?
+               BNE     %33tms__subMenu         ;Yes -- deal with it
+               TST     R3,#mFlag_indirect      ;Is this item indirected?
+               ADDNE   R4,R4,#4                ;Yes -- skip the offset word
+               BNE     %32tms__subMenu         ;And skip past the loop
+
+               ; --- Skip inline text string ---
+
+31tms__subMenu LDRB    R14,[R4],#1             ;Get a message string byte
+               CMP     R14,#' '                ;Is it a terminator?
+               BGE     %31tms__subMenu         ;No -- get another one
+               ADD     R4,R4,#3                ;Add 3
+               BIC     R4,R4,#3                ;And word align the pointer
+
+               ; --- Now skip other optional blocks ---
+
+32tms__subMenu TST     R3,#mFlag_shortcut      ;Is there a normal...
+               TSTEQ   R3,#mFlag_iShortcut     ;...or indirected shortcut?
+               ADDNE   R4,R4,#4                ;Yes -- skip over it
+               SKIP    mFlag_shade,4,R3,R4
+               SKIP    mFlag_iShade,4,R3,R4
+               SKIP    mFlag_switch,4,R3,R4
+               SKIP    mFlag_radio,8,R3,R4
+               SKIP    mFlag_sprite,8,R3,R4
+
+               ; --- We are now pointing at submenu information ---
+
+               LDR     R0,[R4,#0]              ;Point to packed definition
+               LDR     R1,[R4,#4]              ;Point to the event handler
+               LDR     R2,[R8,#iR10]           ;Use R10 from previous item
+               LDR     R3,[R8,#iR12]           ;Use R12 from previous item
+               BL      tms__searchForMenu      ;Does this menu exist?
+               BCS     %37tms__subMenu         ;Yes -- get it back then
+               BL      tms_create              ;Create the menu
+               STR     R0,[R7,#iSubMenu]       ;Store this in item defn
+               STR     R7,[R0,#hFromItem]      ;We came from this item
+               B       %40tms__subMenu         ;Now deal with real clicks
+
+               ; --- The user requires a submenu warning ---
+
+33tms__subMenu LDR     R0,[R7,#iFlags]         ;Get the item flags
+               TST     R0,#iFlag__shaded       ;Is the item shaded?
+               TSTNE   R0,#iFlag__noWarn       ;And we don't want warning?
+               BNE     %40tms__subMenu         ;Both -- return
+               MOV     R0,#mEvent_arrow        ;Send this event type
+               LDR     R1,tms__itemIndex       ;With this index
+               STR     R7,tms__currItem        ;Save the current item
+               STR     R10,tms__orgTearoff     ;The originating menu
+               LDR     R14,tms__flags          ;Load my current flags
+               ORR     R14,R14,#tFlag__subWait ;We're waiting for a submenu
+               STR     R14,tms__flags          ;Save the flags back
+               STMFD   R13!,{R10,R12}          ;Save these registers
+               ADD     R3,R8,#iHandler         ;Point to the handler
+               LDMIA   R3,{R3,R10,R12}         ;Load the values
+               ADDS    R0,R0,#0                ;Clear the carry flag
+               TEQ     R3,#0                   ;Sanity check
+               MOV     R14,PC                  ;Set up the return address
+               MOVNE   PC,R3                   ;Call the handler
+               LDMFD   R13!,{R10,R12}          ;Get my registers back
+               LDR     R14,tms__flags          ;Load my current flags
+               BIC     R14,R14,#tFlag__subWait ;Stopped waiting for submenu
+               STR     R14,tms__flags          ;Save the flags back
+
+               ; --- Use must return with menu in R0, and carry set if
+               ;     menu is already open.
+
+               STR     R0,[R7,#iSubMenu]       ;Store this in item defn
+               TEQ     R0,#0                   ;Has user returned NULL?
+               STRNE   R7,[R0,#hFromItem]      ;No -- we came from this item
+
+               MOVCS   R4,R0                   ;If carry set...
+               BCS     %37tms__subMenu         ;...reposition given menu
+               B       %40tms__subMenu         ;Return to caller
+
+               ; --- There has already been a warning ---
+
+35tms__subMenu LDR     R4,[R10,#hSubMenu]      ;Get the submenu pointer
+               CMP     R4,#0                   ;Is there one?
+               BEQ     %40tms__subMenu         ;No -- return to caller
+               LDR     R14,[R7,#iFlags]        ;Get the item flags
+               TST     R14,#iFlag__dbox        ;Is this a dbox?
+               BNE     %40tms__subMenu         ;Yes -- return to caller
+               LDR     R5,[R4,#hFlags]         ;Get flags for sub menu
+               TST     R5,#hFlag__warned       ;Does submenu have submenu?
+               BEQ     %36tms__subMenu         ;No -- jump this bit
+               LDR     R2,[R4,#hSubMenu]       ;Point to the submenu's sub
+               BL      tms__closeMenu          ;Close it down
+               MOV     R0,R4                   ;Point to the submenu
+               BL      tms__deselect           ;Deselect highlighted item
+
+               ; --- Reposition the sub menu ---
+
+36tms__subMenu SUB     R13,R13,#36             ;Get me a block
+               LDR     R5,[R4,#hHandle]        ;Get the window handle
+               STR     R5,[R13,#0]             ;Store it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window state then
+               LDR     R5,[R13,#12]            ;Get x1
+               LDR     R1,[R13,#4]             ;Get x0
+               SUB     R5,R5,R1                ;Get the window width
+               LDR     R1,tms__coords          ;Get the x position to open
+               STR     R1,[R13,#4]             ;Store this in the block
+               ADD     R5,R5,R1                ;Get new x1 position
+               STR     R5,[R13,#12]            ;Store this too
+
+               LDR     R5,[R13,#16]            ;Get y1
+               LDR     R1,[R13,#8]             ;Get y0
+               SUB     R5,R5,R1                ;Get the window height
+               LDR     R1,tms__coords+4        ;Get the y position to open
+               LDR     R3,[R4,#hFlags]         ;Get the menu flags
+               TST     R3,#hFlag__tearable     ;Is there a bar?
+               ADDNE   R1,R1,#tms__barHeight   ;Yes -- add this on
+               STR     R1,[R13,#16]            ;Store this in the block
+               SUB     R5,R1,R5                ;Get new y0 position
+               STR     R5,[R13,#8]             ;Store this too
+               MOV     R1,#-1                  ;Open in front
+               STR     R1,[R13,#28]            ;Store this value too
+               MOV     R1,R13                  ;Point to the block
+               BL      tspr_adjustBox          ;Mangle to fit on screen
+               SWI     Wimp_OpenWindow         ;Open the window
+               ADD     R13,R13,#36             ;Get my stack back
+               B       %40tms__subMenu         ;Deal with real clicks
+
+               ; --- We need to 'bring back' a torn off menu ---
+
+37tms__subMenu MOV     R5,R10                  ;Remember R10 value
+               MOV     R10,R4                  ;Point at found menu
+               BL      tms__unTearMenu         ;Un-tear it
+               BL      tms__updateBar          ;Update the tearoff bar
+               MOV     R10,R5                  ;Get R10 value back
+               STR     R4,[R7,#iSubMenu]       ;Store submenu pointer back
+               STR     R4,[R10,#hSubMenu]      ;...in places good
+               STR     R10,[R4,#hPrevMenu]     ;Store previous menu
+               STR     R7,[R4,#hFromItem]      ;Item menu was from
+               LDR     R5,tms__current         ;Get the current menu
+               CMP     R5,#0                   ;Is there one?
+               STREQ   R4,tms__current         ;No -- store this one then
+               BLEQ    wimp_taskHandle         ;...get the task handle
+               BLEQ    tearSupport_opened      ;...start tearoffsupt sending
+
+               B       %36tms__subMenu         ;And reposition it
+
+40tms__subMenu LDMFD   R13!,{R0-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- tms__buttons ---
+;
+; On entry:    R1 == pointer to mousepointer info block
+;              R10 == pointer to the menu
+;
+; On exit:     --
+;
+; Use:         Called when a button event is detected on a menu, or
+;              for NULL events (with button type 0)
+
+tms__buttons   ROUT
+
+               STMFD   R13!,{R0-R9,R14}        ;Stack some registers
+
+               LDR     R14,tms__flags          ;Get the current flags
+               TST     R14,#tFlag__nActive     ;Are we active?
+               BNE     %99tms__buttons         ;No -- return
+
+               ; --- First we deal with *any* button type ---
+
+               MOV     R9,R1                   ;Keep a pointer to the block
+               SUB     R13,R13,#36             ;Get a small block
+               MOV     R1,R13                  ;Point to the block
+               LDR     R2,[R10,#hHandle]       ;Get the window handle
+               STR     R2,[R1,#0]              ;Store the window handle
+               SWI     Wimp_GetWindowState     ;Get the window state
+               MOV     R8,R1                   ;Remember this pointer
+               LDR     R0,[R9,#0]              ;Get the mouse x coord
+               LDR     R2,[R8,#20]             ;Get the scroll x position
+               LDR     R3,[R8,#4]              ;Get the x0 position
+               ADD     R0,R0,R2                ;Calculate workarea relative
+               SUB     R0,R0,R3                ;...x position
+               LDR     R1,[R9,#4]              ;Get the mouse y coord
+               LDR     R2,[R8,#24]             ;Get the scroll y position
+               LDR     R3,[R8,#16]             ;Get the y1 position
+               ADD     R1,R1,R2                ;Calculate workarea relative
+               SUB     R1,R1,R3                ;...y position
+               STMIA   R9,{R0,R1}              ;Store back updated positions
+               LDR     R6,tms__flags           ;Get the flags
+               BL      tms__findItem           ;Find the item we are over
+               CMP     R8,#0                   ;Did we find an item
+               BEQ     %12tms__buttons         ;No -- jump ahead a bit
+               LDR     R5,[R10,#hTotWidth]     ;Get the width
+               SUB     R5,R5,#24               ;The right hand edge
+               CMP     R0,R5                   ;Are we over it?
+
+               ; --- Complex condition time ---
+               ;
+               ; The following code should only be executed if:
+               ;    we're over a sub menu arrow AND we were
+               ;    not over it before
+               ;  OR
+               ;    we are not over a submenu arrow at all AND the
+               ;    item isn't the alarm item
+
+               BIC     R6,R6,#tFlag__overArrow ;We are not over an arrow
+               BLT     %10tms__buttons         ;We cannot be over an arrow
+               LDR     R5,tms__itemOver        ;Get a pointer to the item
+               LDR     R5,[R5,#0]              ;Get the item flags
+               MVN     R5,R5                   ;Invert them!
+               AND     R5,R5,#mFlag_subMenu+mFlag_subWarn ; Keep these bits
+               CMP     R5,#mFlag_subMenu+mFlag_subWarn ;Is there no arrow?
+
+               ; Here, EQ if we are not over an arrow, NE otherwise ---
+
+               BEQ     %10tms__buttons         ;Jump if we're not over arrow
+               ORR     R6,R6,#tFlag__overArrow ;We are over an arrow
+               STR     R6,tms__flags           ;Store the flags
+               LDR     R5,[R10,#hSelected]     ;Get the selected item
+               CMP     R7,R5                   ;Are they the same?
+               BEQ     %30tms__buttons         ;Yes -- jump this section
+
+               ; --- Well, the condition has been met at this point ---
+
+10tms__buttons  STR    R6,tms__flags           ;Store the flags
+               LDR     R0,tms__alarmItem       ;Get item alarm is for
+               CMP     R0,R7                   ;Are they the same?
+               BEQ     %30tms__buttons         ;Yes -- jump this section
+               LDR     R0,tms__alarmItem       ;Get item alarm is for
+               CMP     R0,R7                   ;Are they the same?
+               BEQ     %30tms__buttons         ;Yes -- jump this section
+
+       ;       LDR     R6,[R10,#hFlags]        ;Get the menu flags
+       ;       TST     R6,#hFlag__tearable     ;Is there a bar?
+       ;       BEQ     %11tms__buttons         ;No -- jump ahead
+       ;       CMP     R1,#-tms__barHeight     ;Is it in the bar
+       ;       BGE     %12tms__buttons         ;Yes -- jump past this bit
+
+               ; --- Close the current RISCOS menu using tearoff support ---
+
+11tms__buttons STMFD   R13!,{R0-R1}            ;Stack these now
+               MOV     R0,#1                   ;Switch off SWI vectoring
+               BL      tearSupport_switch      ;Yes siree bob matey
+               MOV     R1,#-1                  ;No menu please Mr. Wimp
+               SWI     XWimp_CreateMenu        ;La de dar do
+               MOVVC   R0,#0                   ;Switch vectoring back on
+               BLVC    tearSupport_switch      ;Please
+               LDMFD   R13!,{R0-R1}            ;Get coords back back
+
+               ; --- If the menu is torn off, then close transient ---
+
+               LDR     R5,[R10,#hFlags]        ;Get the menu flags
+               TST     R5,#hFlag__torn         ;Has menu been torn off?
+               BEQ     %12tms__buttons         ;No -- skip ahead
+               LDR     R2,tms__current         ;Point to current transient
+               CMP     R2,#0                   ;Is there one?
+               LDREQ   R2,tms__currDbox        ;No -- load dbox handle
+               BL      tms__closeMenu          ;Close the menu
+               B       %13tms__buttons         ;Skip the next bit
+
+               ; --- If there is already a menu open from here, close it ---
+
+12tms__buttons LDR     R5,[R10,#hFlags]        ;Get the menu flags
+               TST     R5,#hFlag__warned       ;Has there been a warning?
+               BEQ     %13tms__buttons         ;No -- skip ahead
+               LDR     R2,[R10,#hSubMenu]      ;Get its submenu
+               BL      tms__closeMenu          ;Close the submenu
+               BIC     R5,R5,#hFlag__dbox      ;There is no dbox now
+               STR     R5,[R10,#hFlags]        ;Store the flags back
+               CMP     R7,#0                   ;Is there an item?
+               LDRNE   R6,[R7,#iFlags]         ;Yes -- get the menu flags
+               BICNE   R6,R6,#iFlag__dbox      ;...not a dbox
+               STRNE   R6,[R7,#iFlags]         ;...store flags back again
+               MOV     R2,#0                   ;A NULL pointer
+               STR     R2,[R10,#hSubMenu]      ;No sub menu any more
+
+               ; --- Cause a fake event if we just closed a dbox ---
+
+13tms__buttons LDR     R0,tms__flags           ;Load the flags word
+               TST     R0,#tFlag__doFake       ;Should we do a fake?
+               BNE     %90tms__buttons         ;Yes -- return to caller
+
+               ; --- Do the selecting/deselecting ---
+
+               LDR     R5,[R10,#hSelected]     ;Get the selected item
+               CMP     R7,R5                   ;Are they the same?
+               BEQ     %15tms__buttons         ;Yes -- do nothing here
+               CMP     R5,#0                   ;Is there a selected item
+               BEQ     %14tms__buttons         ;No -- skipitty jump
+               LDR     R6,[R5,#iFlags]         ;Get the flags for this item
+               TST     R6,#iFlag__shaded       ;Is it shaded?
+               BNE     %14tms__buttons         ;Yes -- skipitty jump
+               MOV     R2,R5                   ;Unhighlight this item
+               BL      tms__unHighlight        ;Unhighlight it then
+14tms__buttons MOVS    R2,R7                   ;Point to the item
+               BLNE    tms__highlight          ;Yes -- highlight the item
+               STR     R2,[R10,#hSelected]     ;Store pointer to item
+               ADRL    R0,tms__alarm1          ;Remove alarms with this hnd
+               BL      idle_removeAllAlarms    ;Do it then
+               MOV     R0,#-1                  ;No alarm set
+               STR     R0,tms__alarmItem       ;So say that
+
+               ; --- Do we need to set an alarm? ---
+
+15tms__buttons CMP     R7,#0                   ;Is there an item?
+               BEQ     %20tms__buttons         ;No -- don't set an alarm
+               LDR     R6,[R7,#iFlags]         ;Get the flags word
+               TST     R6,#iFlag__arrow        ;Are we over an arrow?
+               BEQ     %20tms__buttons         ;No -- don't set an alarm
+
+               LDR     R0,tms__alarmItem       ;Get the current alarm item
+               CMP     R0,#-1                  ;Is there one?
+               BNE     %20tms__buttons         ;Yes -- skip ahead
+               BL      wimp_version            ;Get the wimp version
+               CMP     R0,#300                 ;Higher than RISC OS 2?
+               BLT     %20tms__buttons         ;No -- don't do this then
+
+               ; --- Check with the CMOS setting ---
+
+               MOV     R0,#161                 ;Read CMOS
+               MOV     R1,#197                 ;The wimp flags
+               SWI     XOS_Byte                ;Read them then
+               TST     R2,#&80                 ;Is the bit set?
+               BEQ     %20tms__buttons         ;No -- don't do this then
+               MOV     R0,#161                 ;Read CMOS
+               MOV     R1,#23                  ;Read the delay time
+               SWI     XOS_Byte                ;Read it then
+               CMP     R2,#0                   ;Is there a sensible time?
+               BEQ     %20tms__buttons         ;No -- don't do this then
+
+               ; --- Right, set the alarm ---
+
+               STR     R10,tms__alarmMenu      ;Alarm is for this menu
+               STR     R7,tms__alarmItem       ;And for this item
+               ADD     R1,R2,R2,LSL #2         ;Multiply time by 5
+               MOV     R1,R1,LSL #1            ;And then by 2 (10 in all)
+               SWI     OS_ReadMonotonicTime    ;Read the current time
+               ADD     R0,R0,R1                ;Set alarm for this time
+               ADRL    R1,tms__alarm1          ;Point to handler function
+               MOV     R2,R0                   ;Use that as the handle
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      idle_setAlarm           ;And set the alarm
+
+               ; --- Correct some 'variables' ---
+
+20tms__buttons LDR     R6,[R10,#hFlags]        ;Get the menu flags
+               BIC     R6,R6,#hFlag__warned    ;We haven't been warned
+               BIC     R6,R6,#hFlag__dbox      ;And there is not a dbox
+               STR     R6,[R10,#hFlags]        ;Store the flags back again
+               CMP     R7,#0                   ;Is there an item?
+               MOV     R6,#0                   ;A NULL pointer
+               STR     R6,tms__prevLevel       ;No previous level
+               STR     R6,tms__orgTearoff      ;No originating tearoff
+
+               ; --- Well, that lots over, no where near finished though ---
+
+               ; --- Are we over a sub menu arrow? ---
+
+30tms__buttons CMP     R7,#0                   ;Is there an item?
+               BEQ     %40tms__buttons         ;No -- deal with real clicks
+               LDR     R6,tms__flags           ;Get the flags word
+               TST     R6,#tFlag__overArrow    ;Are we over an arrow?
+               BEQ     %40tms__buttons         ;No -- skip this bit
+
+               ; --- The pointer is over an arrow ---
+
+               MOV     R1,R13                  ;Point to the window state
+               BL      tms__subMenu            ;Open the sub menu
+
+               ; --- Deal with real buttons clicks ---
+
+40tms__buttons LDR     R2,[R9,#8]              ;Get the button status
+               CMP     R2,#0                   ;Was a button pressed?
+               BEQ     %90tms__buttons         ;No -- return
+
+               ; --- Was the click on the tearoff bar? ---
+
+               LDR     R0,tms__flags           ;Get the flags word
+               TST     R2,#6                   ;Select or menu pressed?
+               ORRNE   R0,R0,#tFlag__close     ;Yes -- close the transient
+               BICEQ   R0,R0,#tFlag__close     ;No -- keep it open
+               STR     R0,tms__flags           ;Store the flags back
+               LDMIA   R9,{R0,R1}              ;Get the coordiantes
+               LDR     R2,[R10,#hFlags]        ;Get the menu flags
+               TST     R2,#hFlag__tearable     ;Is there a bar?
+               BEQ     %50tms__buttons         ;No -- branch ahead
+               CMP     R1,#-tms__barHeight     ;Did we click in the bar?
+               BLT     %50tms__buttons         ;No -- branch ahead
+               CMP     R1,#-4                  ;The top of the icon
+               BGT     %90tms__buttons         ;Not in icon -- return
+               CMP     R1,#-(tms__barHeight-4) ;The bottom level
+               BLT     %90tms__buttons         ;Not in icon -- return
+               TST     R2,#hFlag__torn         ;Has the menu been torn off
+               BNE     %45tms__buttons         ;Yes -- deal with that
+
+               ; --- Was the click in the tear icon? ---
+
+               CMP     R0,#4                   ;The left hand side
+               BLT     %90tms__buttons         ;Not in icon -- return
+               CMP     R0,#68                  ;The right hand side
+               BGT     %90tms__buttons         ;Not in icon -- return
+               BL      tms__tearMenu           ;Tear the menu off
+               B       %90tms__buttons         ;Return to caller
+
+               ; --- The menu is torn off -- what did we click in? ---
+
+45tms__buttons  CMP    R0,#4                   ;The left hand side
+               BLT     %90tms__buttons         ;Not in icon -- return
+               CMP     R0,#70                  ;The right hand side
+               BLLE    tms__closeTornMenu      ;Tear the menu off
+               BLE     %90tms__buttons         ;Return to caller
+
+               ; --- Was it in the fold icon ---
+
+46tms__buttons LDR     R2,[R10,#hTotWidth]     ;The total menu width
+               SUB     R2,R2,#60               ;LHS of tear icon
+               CMP     R0,R2                   ;Where did we click?
+               BLT     %90tms__buttons         ;Not in it, that's for sure
+               ADD     R2,R2,#56               ;RHS of tear icon
+               CMP     R0,R2                   ;Where did we click?
+               BGT     %90tms__buttons         ;Not in it, that's for sure
+               BL      tms__foldMenu           ;Fold the menu then
+               B       %90tms__buttons         ;Return to caller
+
+               ; --- The click was on an item ---
+
+50tms__buttons CMP     R7,#0                   ;Is there an item here?
+               BEQ     %90tms__buttons         ;No -- return
+               LDR     R0,[R7,#iFlags]         ;Get the item flags
+               TST     R0,#iFlag__shaded       ;Is the item shaded
+               BNE     %90tms__buttons         ;Yes -- return then
+
+               MOV     R3,#3                   ;Flash this many times
+               MOV     R0,#19                  ;VSync
+51tms__buttons SWI     OS_Byte                 ;Wait for it
+               SWI     OS_Byte                 ;Wait for it again
+               MOV     R2,R7                   ;Point to the item
+               BL      tms__unHighlight        ;Unhighlight item
+               SWI     OS_Byte                 ;Wait for VSync
+               SWI     OS_Byte                 ;Wait for it again
+               MOV     R2,R7                   ;Point to the item
+               BL      tms__highlight          ;Highlight item
+               SUBS    R3,R3,#1                ;Decrement counter
+               BNE     %51tms__buttons         ;Flash more times if needed
+
+               ; --- Close the menu structure if we need to ---
+
+               LDR     R0,tms__flags           ;Get the flags word
+               TST     R0,#tFlag__close        ;Should I close the menu?
+               LDRNE   R2,tms__current         ;Yes -- point to current menu
+               BLNE    tms__closeMenu          ;...and close the transient
+
+               ; --- Finally, report event to the user ---
+
+               STMFD   R13!,{R10,R12}          ;Save these registers
+               MOV     R0,#mEvent_select       ;Item has been selected
+               LDR     R1,tms__itemIndex       ;The items index
+               ADD     R3,R8,#iHandler         ;Point to the handler
+               LDMIA   R3,{R3,R10,R12}         ;Load the values
+               ADDS    R0,R0,#0                ;Clear the carry flag
+               TEQ     R3,#0                   ;Sanity check
+               MOV     R14,PC                  ;Set up the return address
+               MOVNE   PC,R3                   ;Call the handler
+               LDMFD   R13!,{R10,R12}          ;Get my registers back
+
+               BL      tms_recreate            ;Recreate the existing menus
+
+               ; --- Return to the user ---
+
+90tms__buttons ADD     R13,R13,#36             ;Reclaim my stack
+99tms__buttons LDMFD   R13!,{R0-R9,PC}^        ;And return to caller
+
+               LTORG
+
+; --- tms__cleanUp ---
+;
+; On entry:    R0 == handle idle handler is called with (the menu)
+;
+; On exit:     --
+;
+; Use:         Called to clean up the system when the pointer has left
+;              a menu.
+
+               EXPORT  tms__cleanUp
+tms__cleanUp   ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+               MOV     R2,R0                   ;The R10 value
+               ADRL    R1,tms__idleHandler     ;The routine that is called
+               MOV     R0,#0                   ;How frequently it was called
+               MOV     R3,R12                  ;The R12 value passed
+               BL      idle_removeHandler      ;Remove the handler
+               MOV     R0,#0                   ;No handler set up
+               STR     R0,tms__oldHandle       ;Store that fact
+               ADRL    R0,tms__alarm1          ;Remove alarms with this hnd
+               BL      idle_removeAllAlarms    ;Do it then
+               MOV     R0,#-1                  ;No alarm set
+               STR     R0,tms__alarmItem       ;So say that
+               BL      tms__alarm2             ;Allow item selection
+
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+
+; --- tms__updateBar ---
+;
+; On entry:    R10 == pointer to the menu
+;
+; On exit:     --
+;
+; Use:         Update the tearoff bar of the given menu
+
+tms__updateBar ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+
+               SUB     R13,R13,#44             ;Get me a block
+               LDR     R0,[R10,#hHandle]       ;Get the window handle
+               MOV     R1,#0                   ;x0
+               LDR     R3,[R10,#hTotWidth]     ;Get the total width
+               ADD     R3,R3,#48               ;x1
+               MOV     R2,#-tms__barHeight     ;y0
+               MOV     R4,#0                   ;y1
+               STMIA   R13,{R0-R4}             ;Fill in the block
+               MOV     R1,R13                  ;Point to it
+               MOV     R4,R2                   ;The y coordinate
+               SUB     R13,R13,#32             ;Get another block
+               SWI     Wimp_UpdateWindow       ;Start the redraw
+00             CMP     R0,#0                   ;More to do?
+               BEQ     %10tms__updateBar       ;No -- return
+               BL      tms__redrawBar          ;Perform the redrawing
+               SWI     Wimp_GetRectangle       ;Get another rectangle
+               B       %00tms__updateBar       ;And keep redrawing
+
+10             ADD     R13,R13,#(44+32)        ;Get the stack back
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- tms__tearMenu ---
+;
+; On entry:    R10 == pointer to menu to tear off
+;
+; On exit:     --
+;
+; Use:         Called when the user clicks on the tear icon
+
+tms__tearMenu  ROUT
+
+               STMFD   R13!,{R0-R2,R4,R14}     ;Stack some registers
+               LDR     R0,[R10,#hFlags]        ;Get the menu flags
+               ORR     R0,R0,#hFlag__torn      ;The menu is now torn
+               STR     R0,[R10,#hFlags]        ;Store back the flags
+               LDR     R0,[R10,#hPrevMenu]     ;Get the previous menu
+               CMP     R0,#0                   ;Is there one?
+               BLNE    tms__deselect           ;Yes -- deselect it
+
+               ; --- Start the drag operaton ---
+
+               SUB     R13,R13,#28             ;Get me a block
+               LDR     R0,[R10,#hHandle]       ;Get the window handle
+               MOV     R1,#1                   ;Drag window position
+               STMIA   R13,{R0,R1}             ;Store them in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_DragBox            ;Start the drag
+               ADD     R13,R13,#28             ;Get the stack back
+
+               ; --- Alter the icons on the bar ---
+
+               BL      tms__updateBar          ;Update the bar
+
+               ; --- Add the menu to the list of torn menus ---
+
+10tms__tearMenu        LDR     R0,tms__tornoffs        ;Get the list head
+               STR     R0,[R10,#hNextTorn]     ;Put pointer in menu header
+               STR     R10,tms__tornoffs       ;Store this as the head
+               LDR     R0,tms__current         ;Get the current transient
+               CMP     R0,R10                  ;Are we tearing it?
+               BNE     %15tms__tearMenu        ;No -- jump ahead
+               MOV     R0,#0                   ;A NULL pointer
+               STR     R0,tms__current         ;No current transient
+               BL      tearSupport_closed      ;TearoffSupt_Closed
+
+               ; --- Close the transient if we need to ---
+
+15tms__tearMenu        LDR     R0,tms__flags           ;Get the program flags
+               TST     R0,#tFlag__close        ;Do we close transients?
+               LDRNE   R2,tms__current         ;Point to current transient
+               BLNE    tms__closeMenu          ;And close the transient
+
+               ; --- Return to the caller ---
+
+               LDMFD   R13!,{R0-R2,R4,PC}^     ;Return to caller
+
+               LTORG
+
+; --- tms__unTearMenu ---
+;
+; On entry:    R10 == pointer to menu to untear
+;
+; On exit:     --
+;
+; Use:         'Un-tears' the give menu. Note that the bar is NOT redrawn
+
+tms__unTearMenu        ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack some registers
+               LDR     R0,tms__tornoffs        ;Get the torn off list
+               MOV     R1,#0                   ;The previous menu
+00             CMP     R0,R10                  ;Is this the menu
+               BEQ     %10tms__unTearMenu      ;Yes -- deal with it
+               MOV     R1,R0                   ;This is now the previous
+               LDR     R0,[R0,#hNextTorn]      ;Get the next in the list
+               CMP     R0,#0                   ;Is there one?
+               BNE     %00tms__unTearMenu      ;Yes -- deal with it
+
+               ; --- Cant find it, werg! ---
+
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               ; -- Right, we've found it now ---
+
+10             LDR     R2,[R0,#hNextTorn]      ;Get the pointer to next
+               CMP     R1,#0                   ;Is it the first in list?
+               STREQ   R2,tms__tornoffs        ;Yes -- store next as head
+               STRNE   R2,[R1,#hNextTorn]      ;No -- store in prev ptr
+               LDR     R0,[R10,#hFlags]        ;Get the menu flags
+               BIC     R0,R0,#hFlag__torn      ;We are not torn now
+               STR     R0,[R10,#hFlags]        ;Store the flags back
+               TST     R0,#hFlag__warned       ;Have we been warned?
+               BEQ     %15tms__unTearMenu      ;No -- jump ahead
+               LDR     R2,[R10,#hSubMenu]      ;Get the sub menu
+               BL      tms__closeMenu          ;Close it
+               MOV     R0,R10                  ;Point to my menu
+               BL      tms__deselect           ;Deselect it
+
+               ; --- Unfold the menu if we need to ---
+
+15             LDR     R0,[R10,#hFlags]        ;Get the menu flags
+               TST     R0,#hFlag__folded       ;Is the menu folded
+               BLNE    tms__foldMenu           ;Yes -- unfold it
+
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- tms__closeTornMenu ---
+;
+; On entry:    R10 == pointer to torn off menu to close
+;
+; On exit:     --
+;
+; Use:         Closes a torn off menu.
+
+tms__closeTornMenu ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack some registers
+
+               BL      tms__unTearMenu         ;'Un-tear' the menu
+               MOV     R2,R10                  ;Close this menu
+               BL      tms__closeMenu          ;Now close the menu
+               LDR     R0,tms__flags           ;Get the program flags
+               TST     R0,#tFlag__close        ;Do we close transients?
+               LDRNE   R2,tms__current         ;Point to current transient
+               BLNE    tms__closeMenu          ;And close the transient
+
+               ; --- Return to the caller ---
+
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- tms__locateMenu ---
+;
+; On entry:    R4 == pointer to menu to find
+;
+; On exit:     R4 preserved if it exists, 0 otherwise
+;
+; Use:         Attempt to find the given menu in the torn off
+;              list. It is returned in R4 if it is found
+
+tms__locateMenu        ROUT
+
+               STMFD   R13!,{R14}              ;Stack some registers
+               LDR     R14,tms__tornoffs       ;Get the torn off list
+               CMP     R14,#0                  ;Are there any
+               BEQ     %99tms__locateMenu      ;No -- return failure
+00             CMP     R14,R4                  ;Have we found it?
+               LDMEQFD R13!,{PC}^              ;Yes -- return
+               LDR     R14,[R14,#hNextTorn]    ;Get the next in the list
+               CMP     R14,#0                  ;Is there one
+               BNE     %00tms__locateMenu      ;Yes -- try it
+
+               ; --- We didn't find it ---
+
+99             MOV     R4,#0                   ;Return failure
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- tms__searchForMenu ---
+;
+; On entry:    R0 == pointer to packed definition
+;              R1 == pointer to event handler
+;              R2 == R10 value passed to handler
+;              R3 == R12 value passed to handler
+;
+; On exit:     C set and R4 points to menu if found, C clear otherwise
+;
+; Use:         Searches the tornoff menus for a menu with characteristics
+;              matching the search required
+
+tms__searchForMenu ROUT
+
+               BIC     R14,R14,#C_flag         ;We haven't found it
+               STMFD   R13!,{R5-R7,R12,R14}    ;Stack some registers
+               WSPACE  tms__wSpace             ;Locate my workspace
+               LDR     R14,tms__tornoffs       ;Get the torn off list
+               CMP     R14,#0                  ;Are there any
+               BEQ     %99tms__searchForMenu   ;No -- return failure
+00             ADD     R4,R14,#hHandler        ;Point to useful values
+               LDMIA   R4,{R4-R7}              ;Get them out
+               CMP     R0,R7                   ;Packed definition the same?
+               CMPEQ   R1,R4                   ;...and the handler?
+               CMPEQ   R2,R5                   ;...and R10 value?
+               CMPEQ   R3,R6                   ;...and R12 value?
+               MOVEQ   R4,R14                  ;We've found it
+               LDMEQFD R13!,{R5-R7,R12,R14}    ;Get back registers
+               ORREQS  PC,R14,#C_flag          ;And return happy
+               LDR     R14,[R14,#hNextTorn]    ;Get the next in the list
+               CMP     R14,#0                  ;Is there one
+               BNE     %00tms__searchForMenu   ;Yes -- try it
+
+               ; --- We didn't find it ---
+
+99             MOV     R4,#0                   ;Return failure
+               LDMFD   R13!,{R5-R7,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- tms_closeMenu ---
+;
+; On entry:    R0 == pointer to menu definition
+;              R1 == pointer to event handler
+;              R2 == R10 value to look for
+;              R3 == R12 value to look for
+;
+; On exit:     --
+;
+; Use:         Searches through the menus which have been torn off for a
+;              menu which matches the specifications given, and closes
+;              it if it is found.
+
+               EXPORT  tms_closeMenu
+tms_closeMenu  ROUT
+
+               STMFD   R13!,{R4,R10,R12,R14}   ;Stack registers
+               WSPACE  tms__wSpace             ;Locate my workspace
+               BL      tms__searchForMenu      ;Try to find the menu
+               MOVCS   R10,R4                  ;Found it -- put in R10
+               BLCS    tms__closeTornMenu      ;And close it
+               LDMFD   R13!,{R4,R10,R12,PC}^   ;Return to caller
+               
+               LTORG
+
+; --- tms_closeAll ---
+;
+; On entry:    R0 == R10 value to search for
+;
+; On exit:     --
+;
+; Use:         Closes all the torn off menus with the given r10
+;              value.
+
+               EXPORT  tms_closeAll
+tms_closeAll   ROUT
+
+               STMFD   R13!,{R10,R12,R14}      ;Stack registers
+               WSPACE  tms__wSpace             ;Locate my workspace
+               LDR     R10,tms__tornoffs       ;Get the torn off list
+               CMP     R10,#0                  ;Are there any
+               BEQ     %90tms_closeAll         ;No -- return
+00             LDR     R14,[R10,#hR10]         ;Get the R10 value
+               CMP     R0,R14                  ;Is R10 value the same?
+               BLEQ    tms__closeTornMenu      ;Yes -- close that menu
+               LDR     R10,[R10,#hNextTorn]    ;Get the next in the list
+               CMP     R10,#0                  ;Is there one
+               BNE     %00tms_closeAll         ;Yes -- try it
+
+90tms_closeAll LDMFD   R13!,{R10,R12,PC}^      ;Return to caller
+
+               LTORG   
+
+; --- tms__foldMenu ---
+;
+; On entry:    R10 == pointer to menu to fold
+;
+; On exit:     --
+;
+; Use:         Folds or unfolds the menu, as appropriate
+
+tms__foldMenu  ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Stack some registers
+
+               ; --- Get the window state ---
+
+               SUB     R13,R13,#88             ;Get me a block
+               LDR     R0,[R10,#hHandle]       ;Get the window handle
+               STR     R0,[R13,#0]             ;Store it in the block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetWindowState     ;Get the window state
+
+               ; --- First, close the current transient menu ---
+
+               LDR     R0,tms__flags           ;Get the program flags
+               TST     R0,#tFlag__close        ;Do we close transients?
+               LDRNE   R2,tms__current         ;Point to current transient
+               BLNE    tms__closeMenu          ;And close the transient
+
+               LDR     R0,[R10,#hFlags]        ;Get the menu flags
+               EOR     R0,R0,#hFlag__folded    ;Toggle the foldedness
+               STR     R0,[R10,#hFlags]        ;Store back modified flags
+               TST     R0,#hFlag__folded       ;Test that bit now
+               BEQ     %50tms__foldMenu        ;No longer folded -- jump
+
+               ; --- We must now fold up the menu ---
+
+               TST     R0,#hFlag__scrBar       ;Is there a scroll bar?
+               BEQ     %25tms__foldMenu        ;No -- do quick fold
+
+               ADD     R1,R10,#hHandle         ;Point to the window handle
+               SWI     Wimp_CloseWindow        ;Close the window
+               SWI     Wimp_DeleteWindow       ;And then delete it
+               LDR     R0,[R10,#hHandle]       ;The window handle
+               ADRL    R1,tms__eventHandler    ;Point to the handler
+               MOV     R2,R10                  ;The handle passed
+               MOV     R3,R12                  ;Workspace passed in R3
+               BL      win_removeEventHandler  ;Remove the event handler
+               LDR     R1,tms__oldHandle       ;Get the old handle
+               CMP     R0,R1                   ;Are they the same?
+               BLEQ    tms__cleanUp            ;Yes -- clean up a bit
+               LDR     R0,[R10,#hHeight]       ;Get the menu height
+               BL      tms__createWindow       ;Create the window
+               MOVVS   R1,#1                   ;On error -- show 1 icon
+               BLVS    errorBox                ;...display the error
+               BVS     %99tms__foldMenu        ;...and return to caller
+               ADRL    R1,tms__eventHandler    ;Point to the handler
+               MOV     R2,R10                  ;The handle passed
+               MOV     R3,R12                  ;Workspace passed in R3
+               BL      win_eventHandler        ;Remove the event handler
+               MOV     R1,R13                  ;Point to window state
+               STR     R0,[R1,#0]              ;Store in the block
+               LDR     R4,[R1,#16]             ;Get y1
+               SUB     R0,R4,#24               ;No -- y0-y1-actual height
+               STR     R0,[R1,#8]              ;Store new y0
+               BL      tspr_adjustBox          ;Mangle to fit on the screen
+               SWI     Wimp_OpenWindow         ;Open the window
+               B       %99tms__foldMenu        ;Return to caller
+
+               ; --- The menu has no scrollbar ---
+
+25tms__foldMenu        MOV     R1,R13                  ;Point to state
+               LDR     R0,[R1,#16]             ;Get y1
+               SUB     R0,R0,#24               ;New y0 value
+               STR     R0,[R1,#8]              ;Store it in the block
+               SWI     Wimp_OpenWindow         ;Open the window
+               B       %99tms__foldMenu        ;And return
+
+               ; --- The menu must be 'un-folded' ---
+
+50tms__foldMenu        BL      screen_getInfo          ;Get the screen information
+               LDR     R1,[R0,#screen_height]  ;Get the screen height
+               LDR     R2,[R10,#hMaxHeight]    ;Get the maximum menu height
+               LDR     R3,[R10,#hHeight]       ;And the actual menu height
+
+               ; --- We add a scroll bar if h>maxH or h+50>screen height ---
+
+               CMP     R2,#0                   ;Is there a maximum height?
+               BEQ     %55tms__foldMenu        ;No try next condition
+               CMP     R3,R2                   ;Is height > maxHeight?
+               BGT     %60tms__foldMenu        ;Yes -- unfold with scrll bar
+55tms__foldMenu        ADD     R3,R3,#50               ;Add a little to the height
+               CMP     R3,R1                   ;Compare to the screen height
+               BLE     %75tms__foldMenu        ;Unfold without scroll bar
+
+               ; --- Unfold with a scroll bar ---
+
+60tms__foldMenu        ADD     R1,R10,#hHandle         ;Point to the window handle
+               SWI     Wimp_CloseWindow        ;Close the window
+               SWI     Wimp_DeleteWindow       ;And then delete it
+               LDR     R0,[R10,#hHandle]       ;The window handle
+               ADRL    R1,tms__eventHandler    ;Point to the handler
+               MOV     R2,R10                  ;The handle passed
+               MOV     R3,R12                  ;Workspace passed in R3
+               BL      win_removeEventHandler  ;Remove the event handler
+               LDR     R1,tms__oldHandle       ;Get the old handle
+               CMP     R0,R1                   ;Are they the same?
+               BLEQ    tms__cleanUp            ;Yes -- clean up a bit
+               LDR     R0,[R10,#hHeight]       ;Get the menu height
+               BL      tms__createWindow       ;Create the window
+               MOVVS   R1,#1                   ;On error -- show 1 icon
+               BLVS    errorBox                ;...display the error
+               BVS     %99tms__foldMenu        ;...and return to caller
+               ADRL    R1,tms__eventHandler    ;Point to the handler
+               MOV     R2,R10                  ;The handle passed
+               MOV     R3,R12                  ;Workspace passed in R3
+               BL      win_eventHandler        ;Remove the event handler
+               MOV     R1,R13                  ;Point to window state
+               STR     R0,[R1,#0]              ;Store in the block
+               LDR     R4,[R1,#16]             ;Get y1
+               LDR     R3,[R10,#hHeight]       ;And actual height
+               LDR     R2,[R10,#hMaxHeight]    ;Get the maximum height
+               CMP     R2,#0                   ;Is there one?
+               SUBNE   R0,R4,R2                ;Yes -- y0=y1-maxHeight
+               SUBEQ   R0,R4,R3                ;No -- y0-y1-actual height
+               STR     R0,[R1,#8]              ;Store new y0
+               BL      tspr_adjustBox          ;Mangle to fit on the screen
+               MOV     R14,#-1                 ;To open at the front
+               STR     R14,[R1,#28]            ;We alter the behind value
+               SWI     Wimp_OpenWindow         ;Open the window
+               B       %99tms__foldMenu        ;Return to caller
+
+               ; --- We must unfold without a scroll bar ---
+
+75tms__foldMenu        MOV     R1,R13                  ;Point to state
+               LDR     R0,[R1,#16]             ;Get y1
+               LDR     R2,[R10,#hHeight]       ;Get actual height
+               SUB     R0,R0,R2                ;New y0 value
+               STR     R0,[R1,#8]              ;Store it in the block  
+               MOV     R14,#-1                 ;To open at the front
+               STR     R14,[R1,#28]            ;We alter the behind value
+               SWI     Wimp_OpenWindow         ;Open the window
+
+99tms__foldMenu        ADD     R13,R13,#88             ;Get the block back
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+; --- tms__ensureWindowOK ---
+;
+; On entry:    R1 == pointer to window state
+;              R10 == ponter to the menu
+;
+; On exit:     --
+;
+; Use:         Called after a mode change, to make sure that the menu still
+;              fits on the screen, and to make appropriate changes
+;              if the font has changed, etc.
+
+tms__ensureWindowOK ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+
+               LDR     R0,[R10,#hFlags]        ;Get the menu flags
+               TST     R0,#hFlag__folded       ;Is the menu folded
+               BNE     %98tms__ensureWindowOK  ;Yes -- return
+               BL      screen_getInfo          ;Get the screen info
+               LDR     R4,[R0,#screen_height]  ;Get screen height
+               LDR     R3,[R10,#hHeight]       ;Get menu height
+               ADD     R3,R3,#50               ;Add 50 for luck
+               LDR     R2,[R10,#hFlags]        ;Get the menu flags
+
+               ; --- Check to see if we should remove scroll bar ---
+
+               TST     R2,#hFlag__scrBar       ;Is there a scroll bar
+               BEQ     %40tms__ensureWindowOK  ;No -- jump ahead
+               CMP     R3,R4                   ;Is actual < screen height?
+               BGT     %40tms__ensureWindowOK  ;No -- jump ahead
+               LDR     R14,[R10,#hMaxHeight]   ;Get max height
+               CMP     R14,#0                  ;Is there one?
+               BEQ     %10tms__ensureWindowOK  ;No -- remove scroll bar
+               CMP     R3,R14                  ;Is actual < max height?
+               BGT     %40tms__ensureWindowOK  ;No -- jump ahead
+
+               ; --- Remove the scroll bar then ---
+
+10             BL      %80tms__ensureWindowOK  ;Create a new window
+               LDR     R0,[R1,#8]              ;Get y0
+               ADD     R0,R0,R3                ;Calculate y1
+               STR     R0,[R1,#16]             ;Store it in the block
+               SWI     Wimp_OpenWindow         ;Open the window
+               B       %99tms__ensureWindowOK  ;And return to caller
+
+               ; --- Check if we should add a scroll bar ---
+
+40             TST     R2,#hFlag__scrBar       ;Is there a scroll bar
+               BNE     %98tms__ensureWindowOK  ;Yes -- return
+               CMP     R3,R4                   ;Is actual > screen height?
+               BLT     %98tms__ensureWindowOK  ;No -- return
+
+               ; --- Rebuild the window ---
+
+50             BL      %80tms__ensureWindowOK  ;Create a new window
+               LDR     R0,[R1,#4]              ;Get old x0
+               LDR     R2,[R10,#hTotWidth]     ;Get the menu width
+               ADD     R0,R0,R2                ;Calculate x1
+               STR     R0,[R1,#12]             ;Store it in the block
+               SWI     Wimp_OpenWindow         ;Open the window
+               BL      tms__width              ;Check the width
+               B       %99tms__ensureWindowOK  ;And return to caller
+
+               ; --- Create a new window ---
+
+80             STMFD   R13!,{R1-R3,R14}        ;Save some registers
+
+               ADD     R1,R10,#hHandle         ;Point to the window handle
+               SWI     Wimp_CloseWindow        ;Close the window
+               SWI     Wimp_DeleteWindow       ;And then delete it
+               LDR     R0,[R10,#hHandle]       ;The window handle
+               ADRL    R1,tms__eventHandler    ;Point to the handler
+               MOV     R2,R10                  ;The handle passed
+               MOV     R3,R12                  ;Workspace passed in R3
+               BL      win_removeEventHandler  ;Remove the event handler
+               LDR     R1,tms__oldHandle       ;Get the old handle
+               CMP     R0,R1                   ;Are they the same?
+               BLEQ    tms__cleanUp            ;Yes -- clean up a bit
+               LDR     R0,[R10,#hHeight]       ;Get the menu height
+               BL      tms__createWindow       ;Create the window
+               MOVVS   R1,#1                   ;On error -- show 1 icon
+               BLVS    errorBox                ;...display the error
+               BVS     %99tms__ensureWindowOK  ;...and return to caller
+               ADRL    R1,tms__eventHandler    ;Point to the handler
+               MOV     R2,R10                  ;The handle passed
+               MOV     R3,R12                  ;Workspace passed in R3
+               BL      win_eventHandler        ;Remove the event handler
+               LDMFD   R13!,{R1-R3,R14}        ;Get registers back
+               STR     R0,[R1,#0]              ;Store in the block
+               MOV     R0,#-1                  ;The behind value
+               STR     R0,[R1,#28]             ;Store in the block
+
+               MOVS    PC,R14                  ;Return to caller
+
+               ; --- Return to caller ---
+
+98             MOV     R0,#-1                  ;Open in front
+               STR     R0,[R1,#28]             ;Store this fact
+               SWI     Wimp_OpenWindow         ;Open the window
+               LDR     R14,tms__flags          ;Get the main flags word
+               TST     R14,#tFlag__newFont     ;Has the font changed?
+               BL      tms__width              ;Yes -- check the width
+
+99             LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- tms__idleHandler ---
+;
+; On entry:    R10 == pointer to menu
+;
+; On exit:     --
+;
+; Use:         Called on NULL events. R10 points to the menu that the
+;              pointer is currently over
+
+tms__idleHandler ROUT
+
+               STMFD   R13!,{R1,R14}           ;Stack some registers
+               LDR     R1,tms__flags           ;Get the flags word
+               TST     R1,#tFlag__doFake       ;Are we about to fake a NULL?
+               LDMNEFD R13!,{R1,PC}^           ;Yes -- return then
+               TST     R1,#tFlag__faking       ;Are we fakingone now?
+               BNE     %10tms__idleHandler     ;Yes -- jump ahead then
+               SUB     R13,R13,#20             ;Get a block
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_GetPointerInfo     ;Get the pointer position
+               MOV     R14,#0                  ;Clear the button state
+               STR     R14,[R1,#8]             ;Put value in the bbits
+               BL      tms__buttons            ;Call the buttons routine
+               ADD     R13,R13,#20             ;Get the stack back
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               ; --- Clear the 'faking' bit ---
+
+10             BIC     R1,R1,#tFlag__faking    ;Clear the flag
+               STR     R1,tms__flags           ;Store the new flags
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- tms__makeDashPattern ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Programs the VDU dot pattern, for sheer prettiness.
+
+tms__makeDashPattern ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack some registers
+               MOV     R0,#163                 ;General OS_Byte
+               MOV     R1,#242                 ;242 is the only valid value
+               MOV     R2,#8                   ;Repeat length
+               SWI     OS_Byte                 ;Set dash pattern length
+
+               ADR     R0,tms__dashPtn         ;Point to the pattern spec
+               MOV     R1,#?tms__dashPtn       ;Size of the string
+               SWI     OS_WriteN               ;Write 'em all to VDU drivers
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+tms__dashPtn   DCB     23,6,&f0,&f0,&f0,&f0,&f0,&f0,&f0,&f0
+
+               LTORG
+
+; --- tms__redrawTick ---
+;
+; On entry:    R4 == the y coordinate
+;              R11 == item flags
+;              R13 == pointer to a block to use
+;
+; On exit:     --
+;
+; Use:         Redraw the tick/splodge on the left hand side of a menu
+
+tms__redrawTick        ROUT
+
+               STMFD   R13!,{R0-R3,R5,R14}     ;Stack the link
+               ADD     R5,R13,#24              ;Point to the block
+               MOV     R0,#0                   ;x0
+               MOV     R2,#24                  ;x1
+               SUB     R1,R4,#44               ;y0
+               MOV     R3,R4                   ;y1
+               STMIA   R5!,{R0-R3}             ;Store this in the block
+               LDR     R0,=&07000038           ;Icon flags so far
+
+               TST     R11,#iFlag__ticked      ;Is there a tick
+               TSTEQ   R11,#iFlag__radio       ;Or a splodge?
+               MOVEQ   R1,#&20                 ;Neither -- plot nothing
+               BEQ     %00tms__redrawTick      ;And plot it
+
+               TST     R11,#iFlag__shaded      ;Is the item shaded?
+               ORRNE   R0,R0,#&00400000        ;Yes -- shade icon
+               TST     R11,#iFlag__ticked      ;Are we plotting a tick?
+               MOVEQ   R1,#&8F                 ;Nope -- must be a splodge
+               BEQ     %00tms__redrawTick      ;And plot it
+               LDR     R1,tms__flags           ;Get the flags word
+               TST     R1,#tFlag__riscos3      ;Is this RISC OS 3?
+               BNE     %01tms__redrawTick      ;Yes -- jump a bit
+               MOV     R1,#&80                 ;No -- plot a tick
+
+00             ORR     R0,R0,#1                ;Text icon
+               STMIA   R5,{R0,R1}              ;Fill in the rest of block
+               B       %02tms__redrawTick      ;And jump this bit
+
+               ; --- Plot tick RISCOS 3 style ---
+
+01             MOV     R2,#1                   ;Point R2 at it
+               ORR     R0,R0,#&100             ;Indirected icon
+               ORR     R0,R0,#&2               ;Sprite icon
+               ADR     R1,tms__sprTickName     ;Point to the sprite name
+               MOV     R3,#2                   ;The buffer length
+               STMIA   R5,{R0-R3}              ;Fill in the rest of block
+
+02             ADD     R1,R13,#24              ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+
+               LDMFD   R13!,{R0-R3,R5,PC}^     ;Return to caller
+
+               LTORG
+
+tms__sprTickName DCB   &80,0
+
+               EXPORT  tms__wSpace
+tms__wSpace    DCD     0
+
+; --- tms__redrawSprite ---
+;
+; On entry:    R4 == the y coordinate
+;              R11 == item flags
+;              R13 == pointer to a block to use
+;
+; On exit:     --
+;
+; Use:         Redraw the tick/splodge on the left hand side of a menu
+
+tms__redrawSprite ROUT
+
+               STMFD   R13!,{R0-R3,R5,R14}     ;Stack the link
+               ADD     R5,R13,#24              ;Point to the block
+               MOV     R0,#24+8                ;x0
+               LDR     R2,[R10,#hSprWidth]     ;Get maximum sprite width
+               ADD     R2,R2,R0                ;Add on to get x1
+               SUB     R1,R4,#44               ;y0
+               MOV     R3,R4                   ;y1
+               STMIA   R5!,{R0-R3}             ;Store this in the block
+               LDR     R0,=&07000112           ;Icon flags so far
+               TST     R11,#iFlag__sprite      ;Is there a sprite?
+               BICEQ   R0,R0,#2                ;No -- plot no sprite then
+
+               TST     R11,#iFlag__shaded      ;Is the item shaded?
+               ORRNE   R0,R0,#&00400000        ;Yes -- shade icon
+               TST     R11,#iFlag__halfSize    ;Is it a small one?
+               ORRNE   R0,R0,#&00000800        ;Yes -- set the half-size bit
+               STR     R0,[R5],#4              ;Stash the flags away
+
+               LDR     R0,[R7,#iSprName]       ;Find the sprite name string
+               LDR     R1,[R7,#iSprArea]       ;Get the sprite area too
+               MOV     R2,#1                   ;Not a number, it's a name
+               STMIA   R5!,{R0-R2}             ;Stash the data away too
+
+02             ADD     R1,R13,#24              ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+
+               LDMFD   R13!,{R0-R3,R5,PC}^     ;Return to caller
+
+               LTORG
+
+; --- tms__redrawText ---
+;
+; On entry:    R4 == the y coordinate
+;              R7 == pointer to the icon
+;              R10 == the menu pointer
+;              R11 == item flags
+;              R13 == pointer to a block to use
+;
+; On exit:     --
+;
+; Use:         Redraw the text part of the menu
+
+tms__redrawText        ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack the link
+
+               ADD     R14,R13,#20             ;Point to the block
+
+               ; --- Plot a dirty great bar across the item ---
+
+               MOV     R0,#24                  ;x0
+               LDR     R2,[R10,#hTotWidth]     ;The menu width
+               SUB     R2,R2,#24               ;Calculate x1
+               SUB     R1,R4,#44               ;y0
+               MOV     R3,R4                   ;y1
+               STMIA   R14!,{R0-R3}            ;Store this in the block
+               LDR     R0,=&07000030           ;Get some base flags
+               TST     R11,#iFlag__shaded      ;Is the item shaded?
+               ORRNE   R0,R0,#&00400000        ;Yes -- set the shaded bitty
+               LDREQ   R2,[R10,#hSelected]     ;Get the selected item
+               CMPEQ   R7,R2                   ;Is it this item?
+               EOREQ   R0,R0,#&77000000        ;Yes -- invert it then
+               STR     R0,[R14],#4             ;Save these flags away
+               ADD     R1,R13,#20              ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+
+               ; --- Now plot the text transparently over this ---
+
+               LDR     R14,[R10,#hSprWidth]    ;Load sprite column width
+               ADD     R14,R14,#24             ;Bump in a little
+               STR     R14,[R1,#0]             ;Save as the x0 position
+               LDR     R0,=&07000131           ;The icon flags
+               TST     R11,#iFlag__shaded      ;Is the item shaded?
+               ORRNE   R0,R0,#&00400000        ;Yes -- shade icon
+               LDREQ   R2,[R10,#hSelected]     ;Get the selected item
+               CMPEQ   R7,R2                   ;Is it this item?
+               EOREQ   R0,R0,#&77000000        ;No -- use these colours
+               LDR     R1,[R7,#iText]          ;Point to the text
+               MOV     R2,#-1                  ;No validation string
+               MOV     R3,#&ff                 ;Buffer length
+               ADD     R14,R13,#36             ;Point to the right bit
+               STMIA   R14,{R0-R3}             ;Fill in the rest of block
+               ADD     R1,R13,#20              ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- tms__redrawKey ---
+;
+; On entry:    R4 == the y coordinate
+;              R7 == pointer to the icon
+;              R10 == the menu pointer
+;              R11 == item flags
+;              R13 == pointer to a block to use
+;
+; On exit:     --
+;
+; Use:         Redraw the text part of the menu
+
+tms__redrawKey ROUT
+
+               STMFD   R13!,{R0-R3,R5,R11,R14} ;Stack the link
+
+               ADD     R5,R13,#28              ;Point to the block
+               LDR     R2,[R7,#iKeyCode]       ;Get the string to print
+               CMP     R2,#-1                  ;Is there one?
+               BEQ     %99tms__redrawKey       ;No -- return
+               LDR     R2,[R10,#hTotWidth]     ;The menu width
+               LDR     R0,[R10,#hKeyWidth]     ;Get the shortcut width
+               SUB     R2,R2,#24               ;Calculate x1
+               SUB     R0,R2,R0                ;And then x0
+               SUB     R1,R4,#44               ;y0
+               MOV     R3,R4                   ;y1
+               STMIA   R5!,{R0-R3}             ;Store this in the block
+               LDR     R3,=&00000131           ;The icon flags
+               TST     R11,#iFlag__shaded      ;Is the item shaded?
+               ORRNE   R3,R3,#&007400000       ;Yes -- shade icon
+               BNE     %00tms__redrawKey       ;...forget this next bit
+               LDR     R2,[R10,#hSelected]     ;Get the selected item
+               CMP     R7,R2                   ;Is it this item?
+               ORRNE   R3,R3,#&07000000        ;No -- use these colours
+               ORREQ   R3,R3,#&70000000        ;Yep -- use these colours
+00             LDR     R0,[R7,#iKeyCode]       ;Point to the text
+               MOV     R1,#1                   ;Covert to a short string
+               LDR     R11,tms__R11            ;Get scratchpad address
+               BL      keyString               ;Do the conversion
+               MOV     R1,R0                   ;Put string in R1
+               MOV     R0,R3                   ;And flags in R0
+               MOV     R2,#-1                  ;No validation string
+               MOV     R3,#&ff                 ;Buffer length
+               STMIA   R5,{R0-R3}              ;Fill in the rest of block
+               ADD     R1,R13,#28              ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+
+99             LDMFD   R13!,{R0-R3,R5,R11,PC}^ ;Return to caller
+
+               LTORG
+
+; --- tms__redrawArrow ---
+;
+; On entry:    R4 == the y coordinate
+;              R10 == pointer to the menu
+;              R11 == item flags
+;              R13 == pointer to a block to use
+;
+; On exit:     --
+;
+; Use:         Redraw the arrow on the right hand side of a menu
+
+tms__redrawArrow ROUT
+
+               TST     R11,#iFlag__arrow       ;Is there an arrow?
+               MOVEQS  PC,R14                  ;No -- return
+
+               STMFD   R13!,{R0-R3,R5,R14}     ;Stack the link
+               ADD     R5,R13,#24              ;Point to the block
+               LDR     R2,[R10,#hTotWidth]     ;x1
+               SUB     R0,R2,#24               ;x0
+               SUB     R1,R4,#44               ;y0
+               MOV     R3,R4                   ;y1
+               STMIA   R5!,{R0-R3}             ;Store this in the block
+               LDR     R0,=&07000038           ;Icon flags so far
+               TST     R11,#iFlag__shaded      ;Is the item shaded?
+               ORRNE   R0,R0,#&00400000        ;Yes -- shade icon
+               LDR     R1,tms__flags           ;Get the flags word
+               TST     R1,#tFlag__riscos3      ;Is this RISC OS 3?
+               BNE     %01tms__redrawArrow     ;Yes -- jump a bit
+               MOV     R1,#&89                 ;No -- plot a tick
+               ORR     R0,R0,#1                ;Text icon
+               STMIA   R5,{R0,R1}              ;Fill in the rest of block
+               B       %02tms__redrawArrow     ;And jump this bit
+
+               ; --- Plot tick RISCOS 3 style ---
+
+01             MOV     R2,#1                   ;The WIMP area
+               ORR     R0,R0,#&100             ;Indirected icon
+               ORR     R0,R0,#&2               ;Sprite icon
+               ADR     R1,tms__sprArrowName    ;Point to the sprite name
+               MOV     R3,#2                   ;The buffer length
+               STMIA   R5,{R0-R3}              ;Fill in the rest of block
+
+02             ADD     R1,R13,#24              ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+
+               LDMFD   R13!,{R0-R3,R5,PC}^     ;Return to caller
+
+               LTORG
+
+tms__sprArrowName DCB &89,0
+
+; --- tms__redrawBar ---
+;
+; On entry:    R4 == the y coordinate
+;              R10 == the menu pointer
+;              R13 == pointer to a block to use
+;
+; On exit:     --
+;
+; Use:         Redraw the tearoff bar in a menu. Notice that this is
+;              different to the steel version, which uses icons here
+
+tms__redrawBar ROUT
+
+               STMFD   R13!,{R0-R3,R5,R14}     ;Stack the link
+
+               ADD     R5,R13,#24              ;Point to the block
+               MOV     R0,#0                   ;x0
+               LDR     R2,[R10,#hTotWidth]     ;x1
+               MOV     R1,R4                   ;y0
+               MOV     R3,#0                   ;y1
+               STMIA   R5!,{R0-R3}             ;Store this in the block
+               LDR     R14,[R10,#hFlags]       ;Get the menu flags
+               LDR     R0,=&07000031           ;The icon flags
+               TST     R14,#hFlag__global      ;Is this a `global' menu?
+               ORREQ   R0,R0,#&30000000        ;No -- grey bar then
+               ORRNE   R0,R0,#&80000000        ;Yes -- blie bar then
+               MOV     R1,#0                   ;No text
+               STMIA   R5,{R0-R1}              ;Fill in the rest of block
+               ADD     R1,R13,#24              ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+               LDR     R5,[R10,#hFlags]        ;Get the menu flags
+               TST     R5,#hFlag__torn         ;Has menu been torn?
+               BNE     %50tms__redrawBar       ;Yes -- draw that bit
+
+               ; --- Draw just the tear icon ---
+
+               ADD     R5,R13,#24              ;Point to the block
+               MOV     R0,#4                   ;x0
+               MOV     R2,#68                  ;x1
+               MOV     R1,#-20                 ;y0
+               MOV     R3,#-4                  ;y1
+               STMIA   R5!,{R0-R3}             ;Store this in the block
+               LDR     R0,=&00000112           ;The icon flags
+               MOV     R1,R0                   ;Hark -- R0 to be corrupted
+               BL      resspr_area             ;Get the sprite area
+               MOV     R2,R0                   ;Point R2 at it
+               MOV     R0,R1                   ;Get flags back in R0
+               ADR     R1,tms__sprTearName     ;Point to the sprite name
+               MOV     R3,#5                   ;The buffer length
+               STMIA   R5,{R0-R3}              ;Fill in the rest of block
+
+               ADD     R1,R13,#24              ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+               LDMFD   R13!,{R0-R3,R5,PC}^     ;Return to caller
+
+               ; --- Plot the icons in a torn menu ---
+
+50             ADD     R5,R13,#24              ;Point to the block
+               MOV     R0,#4                   ;x0
+               MOV     R2,#70                  ;x1
+               MOV     R1,#-20                 ;y0
+               MOV     R3,#-4                  ;y1
+               STMIA   R5!,{R0-R3}             ;Store this in the block
+               LDR     R0,=&00000112           ;The icon flags
+               MOV     R1,R0                   ;Hark -- R0 to be corrupted
+               BL      resspr_area             ;Get the sprite area
+               MOV     R2,R0                   ;Point R2 at it
+               MOV     R0,R1                   ;Get flags back in R0
+               ADR     R1,tms__sprCloseName    ;Point to the sprite name
+               MOV     R3,#6                   ;The buffer length
+               STMIA   R5,{R0-R3}              ;Fill in the rest of block
+
+               ADD     R1,R13,#24              ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+
+               ADD     R5,R13,#24              ;Point to the block
+               LDR     R2,[R10,#hTotWidth]     ;Get the width
+               SUB     R0,R2,#60               ;x0
+               SUB     R2,R2,#4                ;x1
+               MOV     R1,#-20                 ;y0
+               MOV     R3,#-4                  ;y1
+               STMIA   R5!,{R0-R3}             ;Store this in the block
+               LDR     R0,=&00000112           ;The icon flags
+               MOV     R1,R0                   ;Hark -- R0 to be corrupted
+               BL      resspr_area             ;Get the sprite area
+               MOV     R2,R0                   ;Point R2 at it
+               MOV     R0,R1                   ;Get flags back in R0
+               ADR     R1,tms__sprFoldName     ;Point to the sprite name
+               MOV     R3,#6                   ;The buffer length
+               STMIA   R5,{R0-R3}              ;Fill in the rest of block
+
+               ADD     R1,R13,#24              ;Point to the block
+               SWI     Wimp_PlotIcon           ;Plot the icon
+
+               LDMFD   R13!,{R0-R3,R5,PC}^     ;Return to caller
+
+               LTORG
+
+tms__sprTearName DCB   "tear",0
+tms__sprCloseName DCB  "close",0
+tms__sprFoldName DCB   "fold",0
+
+; --- tms__doRedraw ---
+;
+; On entry:    R0 == flags:
+;                    bit 0 == don't only plot queued items
+;              R1 == pointer to the redraw block
+;
+; On exit:     --
+;
+; Use:         Actually redraws a menu, given the redraw block
+
+tms__doRedraw  ROUT
+
+               STMFD   R13!,{R0-R11,R14}       ;Stack some registers
+               MOV     R3,R0                   ;Keep flags safe nicely
+
+               ; --- Set up some pointers ---
+
+               SUB     R13,R13,#32             ;Get a nice block
+               MOV     R6,R1                   ;Remember the redraw block
+               LDR     R5,[R10,#hFlags]        ;Get the flags word
+               MOV     R4,#0                   ;The y coordinate
+               TST     R5,#hFlag__tearable     ;Is there a tearoff bar?
+               SUBNE   R4,R4,#tms__barHeight   ;Yes -- Allow for it
+
+               ; --- Draw the tearoff bar ---
+
+               TSTNE   R3,#1                   ;Does it need redrawing?
+               BLNE    tms__redrawBar          ;Yeap...
+
+               ; --- Now deal with items ---
+
+               LDR     R9,[R10,#hItems]        ;Point to the first item
+00tms__doRedraw        LDR     R8,[R9,#iNumber]        ;Get the number of items
+               ADD     R7,R9,#iHdrSize         ;And point to the first item
+
+               ; --- Now redraw each item ---
+
+01tms__doRedraw        LDR     R11,[R7,#iFlags]        ;Get the item flags
+               TST     R3,#1                   ;Are we only doing queued?
+               ORRNE   R11,R11,#&FF000000      ;No -- pretend it wa queued
+
+               ; --- Redraw the tick/splodge on the left ---
+
+               TST     R11,#iFlag__newTick     ;Has the tick changed?
+               BLNE    tms__redrawTick         ;Yes -- plot the tick thing
+
+               ; --- Plot the main text part ---
+
+09tms__doRedraw        TST     R11,#iFlag__newText     ;Has the text changed?
+               BLNE    tms__redrawText         ;Yes -- redraw the text bit
+
+               ; --- Now the sprite, if there is one ---
+
+08tms__doRedraw        TST     R11,#iFlag__newSpr      ;Does sprite need rendering?
+               BLNE    tms__redrawSprite       ;Yes -- render it then
+
+               ; --- The keyboard shortcut ---
+
+               TST     R11,#iFlag__newKey      ;Has shortcut changed?
+               BLNE    tms__redrawKey          ;Yes -- redraw it then
+
+               ; --- The arrow ---
+
+               TST     R11,#iFlag__newArrow    ;Has the arrow changed?
+               BLNE    tms__redrawArrow        ;Yes -- draw it then
+
+               ; --- And finally, plot the dotted line ---
+
+               TST     R11,#iFlag__dotted      ;Is there a dotted line here?
+               BEQ     %90tms__doRedraw        ;No -- jump this code then
+               MOV     R0,#4                   ;Move cursor
+               LDR     R1,[R6,#4]              ;To r.box->x0
+               LDR     R2,[R6,#16]             ;r.box->y1
+               ADD     R2,R2,R4                ;r.box->y1+y
+               SUB     R2,R2,#56               ;r.box->y1+y-(44+12)
+               LDR     R14,[R6,#24]            ;Don't neglect scroll offset
+               SUB     R2,R2,R14               ;No way bob...
+               SWI     OS_Plot                 ;Do the move
+               BL      tms__makeDashPattern    ;Program the dash pattern
+               MOV     R0,#7                   ;Colour 7
+               SWI     Wimp_SetColour          ;Thus let it be
+               MOV     R0,#17                  ;Dotted line -- both ends
+               LDR     R1,[R10,#hTotWidth]     ;Get the width to draw
+               MOV     R2,#0                   ;Relative y offset
+               SWI     OS_Plot                 ;Plot the line
+
+               ; --- Alter the y coordinate ---
+
+90tms__doRedraw        TST     R11,#iFlag__dotted      ;Is there a dotted line
+               SUBNE   R4,R4,#68               ;Yes -- take into account
+               SUBEQ   R4,R4,#44               ;No -- just sub item height
+
+               ; --- Do next item ---
+
+               SUBS    R8,R8,#1                ;Decrement item count
+               ADDNE   R7,R7,#iItemSize        ;Point to the next item
+               BNE     %01tms__doRedraw        ;...and redraw it
+               LDR     R9,[R9,#iItems]         ;If at end -- point to next
+               CMP     R9,#0                   ;Any more items?
+               BNE     %00tms__doRedraw        ;Yes -- redraw them
+               ADD     R13,R13,#32             ;Get my block back
+               LDMFD   R13!,{R0-R11,PC}^       ;Return to caller
+
+               LTORG
+
+; --- tms__redraw ---
+;
+; On entry:    R0 == event from wimp
+;              R1 == pointer to the wimp block
+;              R10 == pointer to the menu
+;
+; On exit:     --
+;
+; Use:         Called to perform the redraw loop when redrawing a menu
+
+tms__redraw    ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Stack some registers
+               SWI     Wimp_RedrawWindow       ;Start the redraw
+00tms__redraw  CMP     R0,#0                   ;More to do?
+               LDMEQFD R13!,{R0,R1,PC}^        ;No -- return
+               MOV     R0,#1                   ;Redraw everything please
+               BL      tms__doRedraw           ;Perform the redrawing
+               SWI     Wimp_GetRectangle       ;Get another rectangle
+               B       %00tms__redraw          ;And keep redrawing
+
+               LTORG
+
+; --- tms__update ---
+;
+; On entry:    R0 == flags (as for doRedraw)
+;              R10 == pointer to the menu
+;
+; On exit:     --
+;
+; Use:         Updates the entire menu.
+
+               EXPORT  tms__update
+tms__update    ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+
+               LDR     R14,[R10,#hHandle]      ;Load the window handle
+               STR     R14,[R13,#-44]!         ;Create a block
+               MOV     R0,#0                   ;Minimum x coord
+               LDR     R1,[R10,#hHeight]       ;Load out the height
+               RSB     R1,R1,#0                ;Minimum y coordinate
+               LDR     R2,[R10,#hTotWidth]     ;Get the total width
+               MOV     R3,#0                   ;Maximum y coordinate
+               STMIB   R13,{R0-R3}             ;Store in the block
+               MOV     R1,R13                  ;Point to the block
+
+               SWI     Wimp_UpdateWindow       ;Start the redraw
+00tms__update  CMP     R0,#0                   ;More to do?
+               ADDEQ   R13,R13,#44             ;No -- get stack back
+               LDMEQFD R13!,{R0-R3,PC}^        ;...and return
+               LDR     R0,[R13,#44]            ;Load the caller's flags
+               BL      tms__doRedraw           ;Perform the redrawing
+               SWI     Wimp_GetRectangle       ;Get another rectangle
+               B       %00tms__update          ;And keep redrawing
+
+               LTORG
+
+; --- tms__eventHandler ---
+;
+; On entry:    R0 == event, as returned from Wimp_Poll
+;              R1 == pointer to the event block
+;              R10 == pointer to the menu
+;
+; On exit:     --
+;
+; Use:         Deals with the event that has been sent to my window
+
+               EXPORT tms__eventHandler
+tms__eventHandler ROUT
+
+               ORR     R14,R14,#C_flag         ;Set carry flag on return
+               CMP     R0,#8                   ;Is it a low-numbered event?
+               ADDLE   PC,PC,R0,LSL #2         ;Yes -- dispatch
+               B       %00tms__eventHandler    ;No -- handle specially
+
+               ; --- The event dispatch table ---
+
+               BICS    PC,R14,#C_flag          ;Null events are ignored
+               B       tms__redraw             ;Call this to redraw menu
+               B       %10tms__eventHandler    ;Open unopened windows
+               B       %20tms__eventHandler    ;Close unclosed windows
+               B       %30tms__eventHandler    ;Pointer's left a window
+               B       %40tms__eventHandler    ;Gone back inside again
+               B       tms__buttons            ;Call the button handler
+               BICS    PC,R14,#C_flag          ;Drag returned -- so what
+               BICS    PC,R14,#C_flag          ;Key press
+
+               ; --- Handle high-numbered events ---
+
+00             CMP     R0,#17                  ;Is it a message?
+               CMPNE   R0,#18                  ;Or another message?
+               BICNES  PC,R14,#C_flag          ;No -- nothing we can do
+
+               ; --- Deal with a help message ---
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack registers
+               LDR     R14,[R1,#16]            ;Get the message number
+               LDR     R2,=&502                ;Load the constant number
+               CMP     R14,R2                  ;Is it a help message
+               LDMNEFD R13!,{R0-R3,R14}        ;No -- load registers
+               BICNES  PC,R14,#C_flag          ;...couldn't understand
+
+               ; --- Find the item that we are over ---
+
+               ADD     R4,R1,#20               ;Point to the coordinates
+               SUB     R13,R13,#36             ;Get a small block
+               MOV     R1,R13                  ;Point to the block
+               LDR     R2,[R10,#hHandle]       ;Get the window handle
+               STR     R2,[R1,#0]              ;Store the window handle
+               SWI     Wimp_GetWindowState     ;Get the window state
+               LDR     R0,[R4,#0]              ;Get the mouse x coord
+               LDR     R2,[R13,#20]            ;Get the scroll x position
+               LDR     R3,[R13,#4]             ;Get the x0 position
+               ADD     R0,R0,R2                ;Calculate workarea relative
+               SUB     R0,R0,R3                ;...x position
+               LDR     R1,[R4,#4]              ;Get the mouse y coord
+               LDR     R2,[R13,#24]            ;Get the scroll y position
+               LDR     R3,[R13,#16]            ;Get the y1 position
+               ADD     R1,R1,R2                ;Calculate workarea relative
+               SUB     R1,R1,R3                ;...y position
+               ADD     R13,R13,#36             ;Get the block back
+               STMFD   R13!,{R0,R1}            ;Stack the coordinates
+               BL      tms__findItem           ;Find the associated icon
+
+               CMP     R8,#0                   ;Were we over an item?
+               BEQ     %05tms__eventHandler    ;No -- try the tearoff bar
+
+               ; --- Send the help event to the users handler ---
+
+               STMFD   R13!,{R10,R12}          ;Save these registers
+               MOV     R0,#mEvent_help         ;Help on item required
+               LDR     R1,tms__itemIndex       ;The items index
+               LDR     R2,tms__itemOver        ;Point to packed item def.
+               ADD     R3,R8,#iHandler         ;Point to the handler
+               LDMIA   R3,{R3,R10,R12}         ;Load the values
+               TEQ     R3,#0                   ;Sanity check
+               MOV     R14,PC                  ;Set up the return address
+               MOVNE   PC,R3                   ;Call the handler
+               LDMFD   R13!,{R10,R12}          ;Get my registers back
+               ADD     R13,R13,#8              ;Skip over the coordinates
+               B       %09tms__eventHandler    ;And return
+
+               ; --- Was the click on the tearoff bar? ---
+
+05             LDR     R0,tms__flags           ;Get the flags word
+               LDMFD   R13!,{R0,R1}            ;Get the coordiantes
+               LDR     R2,[R10,#hFlags]        ;Get the menu flags
+               TST     R2,#hFlag__tearable     ;Is there a bar?
+               BEQ     %09tms__eventHandler    ;No -- branch ahead
+               CMP     R1,#-tms__barHeight     ;Did we click in the bar?
+               BLT     %09tms__eventHandler    ;No -- branch ahead
+               CMP     R1,#-4                  ;The top of the icon
+               BGT     %09tms__eventHandler    ;Not in icon -- return
+               CMP     R1,#-(tms__barHeight-4) ;The bottom level
+               BLT     %09tms__eventHandler    ;Not in icon -- return
+               TST     R2,#hFlag__torn         ;Has the menu been torn off
+               BNE     %06tms__eventHandler    ;Yes -- deal with that
+
+               ; --- Was the click in the tear icon? ---
+
+               CMP     R0,#4                   ;The left hand side
+               BLT     %09tms__eventHandler    ;Not in icon -- return
+               CMP     R0,#68                  ;The right hand side
+               BGT     %09tms__eventHandler    ;Not in icon -- return
+               ADRL    R0,tms__helpTear        ;Point to the tear message
+               BL      msgs_lookup             ;Look it up in messages file
+               BL      help_add                ;And send it to help
+               B       %09tms__eventHandler    ;Return to caller
+
+               ; --- The menu is torn off -- what did we click in? ---
+
+06             CMP     R0,#4                   ;The left hand side
+               BLT     %09tms__eventHandler    ;Not in icon -- return
+               CMP     R0,#70                  ;The right hand side
+               ADRLEL  R0,tms__helpClose       ;Point to the close message
+               BLLE    msgs_lookup             ;Look it up in messages file
+               BLLE    help_add                ;And send it to help
+               BLE     %09tms__eventHandler    ;Return to caller
+
+               ; --- Was it in the fold icon ---
+
+07             LDR     R2,[R10,#hTotWidth]     ;The total menu width
+               SUB     R2,R2,#60               ;LHS of tear icon
+               CMP     R0,R2                   ;Where did we click?
+               BLT     %09tms__eventHandler    ;Not in it, that's for sure
+               ADD     R2,R2,#56               ;RHS of tear icon
+               CMP     R0,R2                   ;Where did we click?
+               ADRLEL  R0,tms__helpFold        ;Point to the fold message
+               BLLE    msgs_lookup             ;Look it up in messages file
+               BLLE    help_add                ;And send it to help
+
+09             LDMFD   R13!,{R0-R4,R14}        ;Load back registers
+               ORRS    PC,R14,#C_flag          ;Return with carry set
+
+               ; --- OpenWindow request ---
+
+10             STMFD   R13!,{R14}              ;Stack some registers
+               BL      screen_justChangedMode  ;Has there been a mode change
+               SWICC   Wimp_OpenWindow         ;No -- open the window
+               LDMCCFD R13!,{PC}^              ;...and return to caller
+               STMFD   R13!,{R0-R3}            ;Stack some more registers
+               BL      tms__ensureWindowOK     ;Ensure window is OK
+               SUB     R13,R13,#20             ;Get me a block
+               MOV     R1,R13                  ;Point to it
+               SWI     Wimp_GetPointerInfo     ;Get the pointer information
+               LDR     R0,[R1,#12]             ;Get the window ptr is over
+               LDR     R1,[R10,#hHandle]       ;And window handle of menu
+               CMP     R0,R1                   ;Are they the same?
+               BNE     %15tms__eventHandler    ;No -- return
+               LDR     R0,tms__oldHandle       ;Get the idle handler handle
+               CMP     R0,#0                   ;Is there one?
+               BNE     %15tms__eventHandler    ;Yes -- return
+               MOV     R0,#0                   ;Frequency -- quick please
+               ADRL    R1,tms__idleHandler     ;Point to the handler
+               MOV     R2,R10                  ;Pass menu in R10
+               MOV     R3,R12                  ;And workspace in R12
+               BL      idle_handler            ;Add in the handler
+               STR     R10,tms__oldHandle      ;And store away new handle
+
+15             ADD     R13,R13,#20             ;Get the stack back
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               ; --- CloseWindow request ---
+
+20             SWI     Wimp_CloseWindow        ;Close the window
+               MOVS    PC,R14                  ;And return
+
+               ; --- Pointer leaving ---
+
+30             STMFD   R13!,{R0,R2,R10,R14}    ;Stack some registers
+               LDR     R0,tms__oldHandle       ;Is there an idle handle hnd
+               CMP     R0,#0                   ;Is there one?
+               LDMEQFD R13!,{R0,R2,R10,PC}^    ;No -- return
+               BL      tms__cleanUp            ;Yes -- clean up a bit
+               MOV     R10,R0                  ;Point to the menu
+               LDR     R2,[R10,#hFlags]        ;Get the flags for the menu
+               TST     R2,#hFlag__warned       ;Have we be warned?
+               LDMNEFD R13!,{R0,R2,R10,PC}^    ;Yes -- return
+               LDR     R2,[R0,#hSelected]      ;Point to the selected item
+               CMP     R2,#0                   ;Is there one?
+               BLNE    tms__unHighlight        ;Un-highlight the item
+               LDMFD   R13!,{R0,R2,R10,PC}^    ;And return to caller
+
+               ; --- Pointer entering ---
+
+40             STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+               LDR     R0,tms__oldHandle       ;Is there an idle handle hnd
+               CMP     R0,#0                   ;Is there one?
+               BLNE    tms__cleanUp            ;Yes -- clean up a bit
+               MOV     R0,#0                   ;Frequency -- quick please
+               ADRL    R1,tms__idleHandler     ;Point to the handler
+               MOV     R2,R10                  ;Pass menu in R10
+               MOV     R3,R12                  ;And workspace in R12
+               BL      idle_handler            ;Add in the handler
+               STR     R2,tms__oldHandle       ;We have an idle handler
+               BL      tms__alarm2             ;Allow item selection
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+tms__helpTear  DCB     "TMST",0
+tms__helpClose DCB     "TMSC",0
+tms__helpFold  DCB     "TMSF",0
+
+               LTORG
+
+; --- tms_help ---
+;
+; On entry:    R0 == pointer to base message tag
+;              R1 == index of menu item
+;
+; On exit:     --
+;
+; Use:         Adds a string to the help message found by adding the menu
+;              item number to the base message tag.
+
+               EXPORT  tms_help
+tms_help       ROUT
+
+               CMP     R1,#0                   ;Is the menu item sane?
+               MOVLTS  PC,R14                  ;No -- don't trust Tim
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R1,R0                   ;Point to base message tag
+               MOV     R0,R11                  ;Point to scratchpad
+               BL      str_cpy                 ;Add the string in there
+               MOV     R1,R0                   ;Point to terminating null
+               MOV     R2,#25                  ;Should be 25 bytes left over
+               LDR     R0,[R13,#4]             ;Get his item number
+               SWI     OS_ConvertInteger4      ;Tack it on the end
+               MOV     R0,R11                  ;Point to the message tag
+               BL      msgs_lookup             ;Translate it nicely
+               BL      help_add                ;Add it to the help string
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     tms__wSize              ;Workspace size
+               DCD     tms__wSpace             ;Workspace pointer
+               DCD     0                       ;Scratchpad size
+               DCD     tms_init                ;Initialisation
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/xfer/s/load b/StraySrc/Libraries/Sapphire/xfer/s/load
new file mode 100644 (file)
index 0000000..e8a9c5e
--- /dev/null
@@ -0,0 +1,790 @@
+;
+; xfer.load.s
+;
+; Loading and importing of files (MDW)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:event
+               GET     sapphire:fastMove
+               GET     sapphire:flex
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:string
+               GET     sapphire:wimp
+               GET     sapphire:win
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- load ---
+;
+; On entry:    R0 == pointer to entry point block
+;              R1 == value of R10 to pass to entry points
+;              R2 == value of R12 to pass to entry points
+;
+; On exit:     --
+;
+; Use:         Attempts to load a file after receipt of a Message_DataSave,
+;              Message_DataLoad or Message_DataOpen.  If user entries for
+;              RAM transfer are provided, this is attempted, although the
+;              entries must also be aware that file transfer may be
+;              required.
+
+               EXPORT  load
+load           ROUT
+
+               STMFD   R13!,{R0-R6,R10,R12,R14} ;Save a load of registers
+               WSPACE  load__wSpace            ;Locate my workspace address
+
+               ; --- Save the handler information ---
+
+               ADR     R14,load__entries       ;Point to my entry info
+               STMIA   R14,{R0-R2}             ;And save the handler info
+
+               ; --- Read the current message ---
+
+               BL      event_last              ;Read the actual last event
+               CMP     R0,#17                  ;Is it a normal message?
+               CMPNE   R0,#18                  ;Or a bouncy one?
+               BNE     %90load                 ;Neither -- ignore it then
+
+               LDR     R0,[R1,#16]             ;Load the message action
+               CMP     R0,#1                   ;Is it a Message_DataSave?
+               BEQ     %20load                 ;Yes -- handle it then
+               CMP     R0,#3                   ;Is it a Message_DataLoad?
+               BEQ     %50load                 ;Yes -- deal with that
+               CMP     R0,#5                   ;Is it a Message_DataOpen?
+               BEQ     %60load                 ;Yes -- deal with that too
+               B       %90load                 ;Otherwise ignore it
+
+               ; --- Deal with a Message_DataSave ---
+                ;
+               ; First, set up all the data in my workspace.
+
+20load         MOV     R6,R1                   ;Keep the message pointer
+               ADR     R0,load__message        ;Point to my message buffer
+               LDR     R2,[R6,#0]              ;Get the message block size
+               BL      fastMove                ;Copy it over nicely
+
+               ; --- Find out if he can do RAM transfer ---
+
+               LDR     R5,load__entries        ;Find his handler block
+               LDR     R14,[R5,#lEntry__initBuf] ;Point to his initBuf entry
+               CMP     R14,#0                  ;Is it defined?
+               BEQ     %40load                 ;No -- just do scrap xfer
+
+               ; --- Set up for RAM transfer ---
+
+               ADR     R0,load__name           ;Point to the leafname
+               LDR     R1,[R6,#36]             ;Load the estimated size
+               MOV     R2,#0                   ;Pass a zero buffer handle
+               ADR     R14,load__R10           ;Point to his R10/R12 values
+               LDMIA   R14,{R10,R12}           ;Load them out ready
+               ADDS    R0,R0,#0                ;Clear lots of flags
+               MOV     R14,PC                  ;Set up a return address
+               ADD     PC,R5,#lEntry__initBuf  ;Make him give me a buffer
+               WSPACE  load__wSpace            ;Get my workspace back again
+               STR     R10,load__R10           ;Save his returned R10 value
+               BLVS    load__finish            ;If it failed, tidy it up
+               BVS     %90load                 ;And return right now
+               ADR     R14,load__buffStart     ;Point to the buffer info
+               STMIA   R14,{R0-R2}             ;And save the buffer stuff
+               MOV     R14,#0                  ;We've not read any data yet
+               STR     R14,load__totalSize     ;So zero the total size
+
+               ; --- Build the Message_RAMFetch ---
+
+               MOV     R14,#28                 ;Size of a RAMFetch message
+               STR     R14,[R11,#0]            ;Store it in the scratchpad
+               ADD     R14,R11,#12             ;Point to your_ref word
+               MOV     R2,R0                   ;Point to the buffer start
+               MOV     R3,R1                   ;And get the buffer size
+               LDR     R0,[R6,#8]              ;Load his reference number
+               MOV     R1,#6                   ;The RAMFetch message code
+               STMIA   R14,{R0-R3}             ;Save all that lot away
+               MOV     R0,#18                  ;Make it bounce if ignored
+               MOV     R1,R11                  ;Point to my message block
+               LDR     R2,[R6,#4]              ;Load his task handle
+               SWI     Wimp_SendMessage        ;And send along his message
+
+               ; --- Set everything up for the acknowledgement ---
+
+               MOV     R14,#lState__test       ;We're seeing if he'll cope
+               STR     R14,load__state         ;So save this state info
+
+               ADR     R0,load__unknown        ;Point to my unknown handler
+               MOV     R1,#0                   ;Nothing interesting in R4
+               MOV     R2,#0                   ;Nothing interesting in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_unknownHandler      ;Register my unknown handler
+               B       %90load                 ;And finish everything off
+
+               ; --- Set up scrap transfer ---
+
+40load         BL      load__doScrap           ;Start scrap transfer going
+               B       %90load                 ;And finish everything off
+
+               ; --- Handle a Message_DataLoad ---
+               ;
+               ; If this is *not* a reply to a Message_DataSaveAck then we
+               ; should clear all the associated data from out message
+               ; cache.
+
+50load         LDR     R14,[R1,#12]            ;Load message's your_ref
+               CMP     R14,#0                  ;Is this a new message?
+               BNE     %70load                 ;No -- don't do setting up
+
+               ; --- Handle a new Message_DataLoad or Message_DataOpen ---
+               ;
+               ; First, copy all the message data over
+
+60load         ADR     R0,load__message        ;Point to my message buffer
+               LDR     R2,[R1,#0]              ;Get the message block size
+               BL      fastMove                ;Copy it over nicely
+
+               ; --- Remember we're doing file transfer ---
+
+               MOV     R14,#lState__file       ;This is file transfer
+               STR     R14,load__state         ;Save this state value
+
+               ; --- Send an immediate acknowledgement ---
+               ;
+               ; For a Message_DataOpen, this is very important -- if we
+               ; don't, and the application dies, we then get started all
+               ; over again from the command line, and probably die again
+               ; if it's a duff file.  For a Message_DataLoad it doesn't
+               ; matter too much, although I suspect we should really send
+               ; the acknowledgement after we loaded the file.
+
+70load         MOV     R6,R1                   ;Keep the message pointer
+               ADD     R0,R11,#20              ;Copy to the scratchpad
+               ADD     R1,R6,#20               ;Point to the message data
+               LDR     R2,[R6,#0]              ;Get the message block size
+               SUB     R2,R2,#20               ;Subtract the bit not copied
+               BL      fastMove                ;Copy it over nicely
+
+               LDR     R14,[R6,#0]             ;Load the message size word
+               STR     R14,[R11,#0]            ;Save it in my dummy message
+               LDR     R0,[R6,#8]              ;Load his my_ref field
+               MOV     R1,#4                   ;This is Message_DataLoadAck
+               ADD     R14,R11,#12             ;Point to the your_ref field
+               STMIA   R14,{R0,R1}             ;Save them in there
+
+               MOV     R0,#17                  ;Don't want acknowledgement
+               MOV     R1,R11                  ;Point to the message block
+               LDR     R2,[R6,#4]              ;Get his task handle ready
+               SWI     Wimp_SendMessage        ;And acknowledge his message
+
+               ; --- Tell the client to load the file ---
+
+               ADR     R0,load__name           ;Point to apparent filename
+               ADD     R1,R6,#44               ;Point to filename to load
+               LDR     R2,load__state          ;Load state (safeness flag)
+               ADR     R14,load__entries       ;Point to the entry data
+               LDMIA   R14,{R5,R10,R12}        ;Load the important stuff
+               ADDS    R0,R0,#0                ;Clear C and V flags
+               MOV     R14,PC                  ;Set up his return address
+               ADD     PC,R5,#lEntry__file     ;Tell him to load the file
+               WSPACE  load__wSpace            ;Find my workspace again
+               STR     R10,load__R10           ;Save the new R10 value
+               BL      load__finish            ;Send a completed message
+
+               ; --- Now delete the Wimp$Scrap file if we need to ---
+
+               CMP     R2,#0                   ;Is the file `safe'?
+               BNE     %90load                 ;Yes -- then do nothing
+               MOV     R0,#27                  ;Wipe files please
+               ADD     R1,R6,#44               ;Point to the filename
+               MOV     R3,#&3                  ;No confirm, recurse
+               SWI     XOS_FSControl           ;Do the Wipe job
+
+               ; --- We finished at last! ---
+
+90load         LDMFD   R13!,{R0-R6,R10,R12,PC}^ ;Return to caller
+
+               LTORG
+
+; --- load__doScrap ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets everything up for Wimp$Scrap-type data transfer.
+
+load__doScrap  ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+
+               ; --- First, ensure the variable <Wimp$Scrap> exists ---
+
+               ADR     R0,load__wimpScrap      ;Point to my variable name
+               MOV     R1,R11                  ;Point to a convenient buffer
+               MOV     R2,#256                 ;Get the buffer size
+               MOV     R3,#0                   ;This is the first call
+               MOV     R4,#0                   ;Don't expand or anything
+               SWI     XOS_ReadVarVal          ;Read the variable value
+               BLVS    load__finish            ;If it failed, abort now
+               BVS     %90load__doScrap        ;And return to caller
+
+               ; --- Build the message and send it ---
+
+               ADD     R0,R11,#20              ;Point at scratch msg data
+               ADR     R1,load__message+20     ;And the saved bits of data
+               MOV     R2,#24                  ;All up to the filename
+               BL      fastMove                ;Copy all that lot over
+
+               MOV     R14,#60                 ;The size of this message
+               STR     R14,[R11,#0]            ;Store it in the right place
+               LDR     R0,load__message+8      ;Load the message's my_ref
+               MOV     R1,#2                   ;This is Message_DataSaveAck
+               ADD     R14,R11,#12             ;Point to your_ref
+               STMIA   R14,{R0,R1}             ;Save your_ref and action
+
+               ADD     R0,R11,#44              ;Point to the filename area
+               ADR     R1,load__scrapVar       ;Point to the variable name
+               BL      str_cpy                 ;Copy the string over
+
+               MOV     R14,#-1                 ;Say that the data's not safe
+               STR     R14,[R11,#36]           ;Save -1 as estimated size
+               MOV     R0,#17                  ;This should be send normal
+               MOV     R1,R11                  ;Point at my message
+               LDR     R2,load__message+4      ;Load his task handle
+               SWI     Wimp_SendMessage        ;Send the message back
+
+               ; --- Now remember we're doing scrap transfer ---
+
+               MOV     R14,#lState__scrap      ;Get the right state number
+               STR     R14,load__state         ;And save it away nicely
+
+               ; --- That's it -- we're done ---
+
+90load__doScrap        LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+load__wimpScrap        DCB     "Wimp$Scrap",0
+load__scrapVar DCB     "<Wimp$Scrap>",0
+
+               LTORG
+
+; --- load__unknown ---
+;
+; On entry:    R0 == an event code
+;              R1 == pointer to event data
+;
+; On exit:     CS if we handled the event, CC otherwise
+;
+; Use:         Handles unknown events (i.e. user messages) during a RAM
+;              transfer.
+
+load__unknown  ROUT
+
+               CMP     R0,#17                  ;Is it a user message?
+               CMPNE   R0,#18                  ;Or a bouncy user message?
+               BEQ     %00load__unknown        ;Yes -- handle it then
+               CMP     R0,#19                  ;Is it a bounced message?
+               BEQ     %60load__unknown        ;Yes -- deal with that
+               MOVS    PC,R14                  ;Nothing we could do about it
+
+               ; --- Deal with a message ---
+
+00load__unknown        STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,[R1,#16]            ;Load the message code
+               CMP     R14,#7                  ;Is it a Message_RAMTransmit?
+               LDMNEFD R13!,{PC}^              ;No -- ignore it then
+
+               ; --- Data transfer is go ---
+
+               STMFD   R13!,{R0-R6,R10}        ;Save loads of registers
+               MOV     R6,R1                   ;Look after the message ptr
+               MOV     R14,#lState__ram        ;We're doing RAM transfer now
+               STR     R14,load__state         ;So save this state away
+
+               ; --- Have we finished data transfer yet? ---
+
+               ADR     R14,load__buffStart     ;Point to the buffer info
+               LDMIA   R14,{R0-R2}             ;Load all the buffer stuff
+               LDR     R3,[R6,#24]             ;How much has he sent?
+               LDR     R4,load__totalSize      ;Load the total so far
+               ADD     R4,R4,R3                ;Add on this new size
+               STR     R4,load__totalSize      ;And save back the new total
+               CMP     R1,R3                   ;Has he sent enough data?
+               BNE     %30load__unknown        ;No -- then it's all over
+
+               ; --- Get some more buffer space ---
+
+               ADR     R14,load__entries       ;Point at his entry info
+               LDMIA   R14,{R5,R10,R12}        ;Load all his info out
+               ADDS    R0,R0,#0                ;Clear C and V flags
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R5,#lEntry__extend   ;Extend your buffer please
+               WSPACE  load__wSpace            ;Find my workspace again
+               BVS     %40load__unknown        ;If it failed, kill buffer
+               ADR     R14,load__buffStart     ;Point to the buffer info
+               STMIA   R14,{R0-R2}             ;Save the buffer info again
+
+               ; --- Send another RAMFetch along ---
+
+               MOV     R14,#28                 ;Size of a RAMFetch message
+               STR     R14,[R11,#0]            ;Store it in the scratchpad
+               ADD     R14,R11,#12             ;Point to your_ref word
+               MOV     R2,R0                   ;Point to the buffer start
+               MOV     R3,R1                   ;And get the buffer size
+               LDR     R0,[R6,#8]              ;Load his reference number
+               MOV     R1,#6                   ;The RAMFetch message code
+               STMIA   R14,{R0-R3}             ;Save all that lot away
+               MOV     R0,#18                  ;Make it bounce if ignored
+               MOV     R1,R11                  ;Point to my message block
+               LDR     R2,[R6,#4]              ;Load his task handle
+               SWI     Wimp_SendMessage        ;And send along his message
+               B       %50load__unknown        ;Finish off everything
+
+               ; --- Tell the client to wrap things up ---
+
+30load__unknown        ADR     R0,load__name           ;Point to the `filename'
+               MOV     R1,R4                   ;Get the total data size
+               ADR     R14,load__entries       ;Point at his entry info
+               LDMIA   R14,{R5,R10,R12}        ;Load all his info out
+               ADDS    R0,R0,#0                ;Clear C and V flags
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R5,#lEntry__doneBuf  ;Tidy up your buffer please
+               WSPACE  load__wSpace            ;Find my workspace again
+               BVS     %40load__unknown        ;If it failed, tidy up
+               BL      load__finish            ;It's all over now
+
+               ; --- Unattach this unknown handler ---
+
+               ADR     R0,load__unknown        ;Point to my unknown handler
+               MOV     R1,#0                   ;Nothing interesting in R4
+               MOV     R2,#0                   ;Nothing interesting in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_removeUnknownHandler ;Unattach the handler
+               B       %50load__unknown        ;And return nicely
+
+               ; --- Tidy up after buffer extension failed ---
+
+40load__unknown        MOV     R4,R0                   ;Look after the error pointer
+               ADR     R14,load__buffStart     ;Point to the buffer info
+               LDMIA   R14,{R0-R2}             ;Load it all out
+               LDR     R12,load__R12           ;Find the client's R12
+               MOV     R14,PC                  ;Set up a return address
+               ADD     PC,R5,#lEntry__killBuf  ;Destroy the buffer
+               WSPACE  load__wSpace            ;Find my workspace again
+               MOV     R14,#V_flag             ;Get the V bit position
+               TEQVCP  R14,PC                  ;If clear, set it again
+               MOV     R0,R4                   ;Point at the error again
+               BL      load__finish            ;Report the error
+
+               ; --- We don't need the unknown handler any more ---
+
+               ADR     R0,load__unknown        ;Point to my unknown handler
+               MOV     R1,#0                   ;Nothing interesting in R4
+               MOV     R2,#0                   ;Nothing interesting in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_removeUnknownHandler ;Unattach the handler
+
+               ; --- Return to caller ---
+
+50load__unknown        LDMFD   R13!,{R0-R6,R10,R14}    ;Unstack all the registers
+               ORRS    PC,R14,#C_flag          ;And claim the event
+
+               ; --- Handle a bounced message ---
+
+60load__unknown        STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,[R1,#16]            ;Load the message action
+               CMP     R14,#6                  ;Is it one of my RAMFetches?
+               LDMNEFD R13!,{PC}^              ;No -- ignore it then
+
+               ; --- My RAMFetch bounced! ---
+
+               LDR     R14,load__state         ;Get my current state?
+               CMP     R14,#lState__test       ;Was I just testing the water
+               BLEQ    load__doScrap           ;Yes -- set up for scrap xfer
+
+               ; --- Shut down the data transfer ---
+
+               STMFD   R13!,{R0-R3,R10}        ;Save some more registers
+               ADR     R14,load__buffStart     ;Point to the buffer info
+               LDMIA   R14,{R0-R2}             ;Load it all out
+               ADR     R14,load__entries       ;Point to entry information
+               LDMIA   R14,{R3,R10,R12}        ;Load all the stuff out
+               MOV     R14,PC                  ;Set up a return address
+               ADD     PC,R3,#lEntry__killBuf  ;Destroy the buffer
+               WSPACE  load__wSpace            ;Find my workspace again
+               MOV     R14,#V_flag             ;Get the V bit position
+               TEQVCP  R14,PC                  ;If clear, set it again
+               MOV     R0,#0                   ;Don't report any errors
+               BL      load__finish            ;Report the error
+
+               ; --- We don't need the unknown handler any more ---
+
+               ADR     R0,load__unknown        ;Point to my unknown handler
+               MOV     R1,#0                   ;Nothing interesting in R4
+               MOV     R2,#0                   ;Nothing interesting in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_removeUnknownHandler ;Unattach the handler
+
+               LDMFD   R13!,{R0-R3,R10,R14}    ;Unstack all the registers
+               ORRS    PC,R14,#C_flag          ;And return with C set
+
+               LTORG
+
+; --- load__finish ---
+;
+; On entry:    VS and R0 points to error, or VC
+;
+; On exit:     R10 corrupted
+;
+; Use:         Calls the appropriate client routine for finishing off
+;              a load operation.
+
+load__finish   ROUT
+
+               STMFD   R13!,{R0-R2,R12,R14}    ;Save some registers
+               MOVVS   R1,#1                   ;If error, set button count
+               ADRVC   R0,load__name           ;Point to apparent name
+               LDRVC   R1,load__state          ;And load my state
+               AND     R1,R1,#1                ;Leave only safeness flag
+               ADR     R14,load__entries       ;Point to the entry points
+               LDMIA   R14,{R2,R10,R12}        ;Load the entry info
+               ADDVS   R2,R2,#4                ;If error, call fail entry
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R2,#lEntry__done     ;Call the correct entry pt
+               LDMFD   R13!,{R0-R2,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- load_initBuf ---
+;
+; On entry:    R1 == estimated file size
+;              R2 == pointer to flex anchor (unallocated)
+;
+; On exit:     R0 == pointer to buffer start
+;              R1 == buffer size
+;              May return an error
+;
+; Use:         Initialises a flex block for use as a RAM transfer buffer.
+;              This routine is suitable for use as the initBuf routine for
+;              RAM transfer loading.
+
+               EXPORT  load_initBuf
+load_initBuf   ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+               MOV     R0,R2                   ;Point to caller's anchor
+               BL      flex_alloc              ;Try to allocate the buffer
+               MOVCS   R1,#4096                ;Otherwise assume 4K size
+               BLCS    flex_alloc              ;And try again...
+               BLCS    alloc_error             ;If it failed, get an error
+               LDRCC   R0,[R0,#0]              ;Otherwise load buffer start
+               LDMFD   R13!,{R14}              ;Restore the link register
+               BICCCS  PC,R14,#V_flag          ;If no error, clear V on exit
+               ORRCSS  PC,R14,#V_flag          ;Otherwise set it
+
+               LTORG
+
+; --- load_killBuf ---
+;
+; On entry:    R2 == pointer to flex anchor
+;
+; On exit:     --
+;
+; Use:         Frees a flex block.  This routine should be used to free
+;              the buffer used for RAM transfer.
+
+               EXPORT  load_killBuf
+load_killBuf   ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R2                   ;Point to the flex anchor
+               BL      flex_free               ;Free the block
+               MOV     R14,#0                  ;Get a zero word
+               STR     R14,[R2,#0]             ;Write this over the anchor
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+; --- load_extendBuf ---
+;
+; On entry:    R0 == pointer to previous buffer
+;              R1 == size of previous buffer
+;              R2 == pointer to flex anchor
+;
+; On exit:     R0 == pointer to a new buffer
+;              R1 == size of the new buffer
+;              May return an error
+;
+; Use:         Extends the flex block if it was initially too small.
+;              This routine is designed to be used as the extend routine
+;              during RAM transfer.
+
+               EXPORT  load_extendBuf
+load_extendBuf ROUT
+
+               STMFD   R13!,{R3,R14}           ;Save some registers
+               MOV     R0,R2                   ;Point to the flex anchor
+               BL      flex_size               ;Read the block's size
+               MOV     R3,R0                   ;Look after the size
+               MOV     R0,R2                   ;Point to the flex anchor
+               ADD     R1,R3,#&1000            ;Extend buffer by 4K
+               BL      flex_extend             ;Make more space for loading
+               BLCS    alloc_error             ;If it failed, get an error
+               LDRCC   R0,[R2,#0]              ;Otherwise load the anchor
+               ADDCC   R0,R0,R3                ;And add the old size
+               MOVCC   R1,#&1000               ;Get the buffer size
+               LDMFD   R13!,{R3,R14}           ;Restore the registers
+               BICCCS  PC,R14,#V_flag          ;If no error, clear V on exit
+               ORRCSS  PC,R14,#V_flag          ;Otherwise set it
+
+               LTORG
+
+; --- load_doneBuf ---
+;
+; On entry:    R1 == actual size of data
+;              R2 == pointer to flex anchor
+;
+; On exit:     --
+;
+; Use:         Sets the block into which the data has been loaded to the
+;              correct exact size.
+
+               EXPORT  load_doneBuf
+load_doneBuf   ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R2                   ;Point to the anchor
+               BL      flex_extend             ;Set the block's correct size
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+; --- load_file ---
+;
+; On entry:    R1 == pointer to filename to load
+;              R2 == pointer to flex anchor
+;
+; On exit:     R0 == size of file loaded
+;              May return an error
+;
+; Use:         Loads a named file into a flex block for your delectation.
+
+               EXPORT  load_file
+load_file      ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Save some registers
+               MOV     R6,R2                   ;Keep the flex anchor safe
+
+               ; --- Find the file information ---
+
+               MOV     R0,#17                  ;Read file information
+               SWI     XOS_File                ;Find the file's size
+               BVS     %90load_file            ;If it failed, handle error
+               TST     R0,#1                   ;Is the object a file?
+               BEQ     %80load_file            ;No -- get an error for it
+               STR     R4,[R13,#0]             ;Save the file size in R0
+
+               ; --- Allocate the flex block ---
+
+               MOV     R1,R4                   ;Get the object size in R1
+               MOV     R0,R6                   ;Point to caller's anchor
+               BL      flex_alloc              ;Try to allocate the block
+               BLCS    alloc_error             ;No memory -- get the message
+               BCS     %90load_file            ;If it failed, handle error
+
+               ; --- Load file into the flex block ---
+
+               MOV     R0,#16                  ;Load the file
+               LDR     R1,[R13,#4]             ;Load the filename address
+               LDR     R2,[R6,#0]              ;Load the flex anchor
+               MOV     R3,#0                   ;Load into my buffer please
+               SWI     XOS_File                ;Try to do the load op
+               BVS     %85load_file            ;If it failed, tidy up
+               LDMFD   R13!,{R0-R6,R14}        ;Unstack registers
+               BICS    PC,R14,#V_flag          ;And return with no error
+
+               ; --- We found a bad object type ---
+
+80load_file    MOV     R2,R0                   ;Get object type in R2
+               MOV     R0,#19                  ;Get the error message
+               SWI     XOS_File                ;Return pointer in R0
+               B       %90load_file            ;Handle error in usual way
+
+               ; --- Tidy up after various errors ---
+
+85load_file    MOV     R1,R0                   ;Look after the error pointer
+               MOV     R0,R6                   ;Point to the flex anchor
+               BL      flex_free               ;Free up all tht memory
+               MOV     R14,#0                  ;Get a zero word
+               STR     R14,[R6,#0]             ;And zero out the anchor
+               MOV     R0,R1                   ;Restore the error pointer
+
+90load_file    ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R6,R14}        ;Unstack registers
+               ORRS    PC,R14,#V_flag          ;And return with the error
+
+               LTORG
+
+load__wSpace   DCD     0
+
+;----- User entry points ----------------------------------------------------
+
+               ^       0
+
+lEntry__initBuf        #       4                       ;Create a load buffer
+                                               ;On entry:
+                                               ;  R0 == ptr to `filename'
+                                               ;  R1 == estimated file size
+                                               ;  R2 == 0
+                                               ;On exit:
+                                               ;  R0 == ptr to buffer start
+                                               ;  R1 == ptr to buffer end
+                                               ;  R2 == buffer `handle'
+                                               ;  R10 may be updated
+
+lEntry__killBuf        #       4                       ;Destroy the load buffer
+                                               ;On entry:
+                                               ;  R0 == ptr to buffer start
+                                               ;  R1 == ptr to buffer end
+                                               ;  R2 == buffer `handle'
+                                               ;On exit:
+                                               ;  --
+
+lEntry__extend #       4                       ;Extend the load buffer
+                                               ;On entry:
+                                               ;  R0 == ptr to buffer start
+                                               ;  R1 == ptr to buffer end
+                                               ;  R2 == buffer `handle'
+                                               ;On exit:
+                                               ;  R0-R2 updated
+
+lEntry__doneBuf        #       4                       ;All data is now loaded
+                                               ;On entry:
+                                               ;  R0 == ptr to `filename'
+                                               ;  R1 == total size of data
+                                               ;  R2 == buffer `handle'
+                                               ;On exit:
+                                               ;  --
+
+lEntry__file   #       4                       ;Load data from a file
+                                               ;On entry:
+                                               ;  R0 == ptr to `filename'
+                                               ;  R1 == file to load
+                                               ;  R2 == 0 if file unsafe
+                                               ;On exit:
+                                               ;  R10 may be updated
+
+lEntry__done   #       4                       ;Completed loading
+                                               ;On entry:
+                                               ;  R0 == ptr to `filename'
+                                               ;  R1 == safeness indicator
+                                               ;On exit:
+                                               ;  --
+
+lEntry__failed #       4                       ;Failed to load file
+                                               ;On entry:
+                                               ;  R0 == pointer to error
+                                               ;  R1 == 1
+                                               ;On exit:
+                                               ;  --
+
+; --- Explanation ---
+;
+; Loading is several orders of magnitude harder than saving, at a guess.
+; I've tried to make it fairly straightforward here -- there are a few
+; standard routines provided for simple things like loading into a flex
+; block, and a coroutine-based system for unified RAM/file transfer is
+; available.
+;
+; Like saving, loading is based around a table of branch instructions which
+; perform application-specific actions during the load operation.  All the
+; message passing protocol is hidden away, and all you have to do is write
+; the entries for the table.
+;
+; If you want to support RAM-transfer, you must provide three buffer
+; handling routines:
+;
+; * initBuf is called when load is attempting to start a RAM transfer with
+;   the saving application.  It should create a buffer of appropriate size
+;   (possibly based on the estimated file size already given).  You can
+;   declare a buffer handle at this point, which is passed to all other
+;   routines that need to deal with the buffer.  It may return an error.
+;
+;   If you can't handle RAM transfer, you should replace the branch
+;   instruction here with a null word.
+;
+; * extend is called if the previous buffer was filled and there is more
+;   data to come.  The address of the previous buffer is returned to you,
+;   so either you can process it there and then, or extend the buffer in
+;   some way.  You just have to return a new area of memory to fill with
+;   data.  It may return an error.
+;
+; * doneBuf is called when all the data has been loaded, so that the buffer
+;   can be set to the exact right size.
+;
+; * killBuf is called if the attempt to load via RAM transfer failed and
+;   the buffer has to be destroyed.  It is always called whenever there is
+;   a fault during RAM transfer, even if one of your other entry points
+;   raised the error.
+;
+; * file is called if you have to load a file from the filing system, either
+;   because RAM transfer failed or because you received a direct load from
+;   the Filer.  It may return an error.
+;
+; * done is called when the data transfer is successfully completed.
+;
+; * failed is called when the data transfer fails due to an error.
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+load__wStart   #       0
+
+load__state    #       4                       ;The current state (1 byte)
+
+load__entries  #       4                       ;Pointer to entry pt block
+load__R10      #       4                       ;Client's R10 value
+load__R12      #       4                       ;Client's R12 value
+
+load__buffStart        #       4                       ;The buffer's start address
+load__buffSize #       4                       ;And its size
+load__buffHnd  #       4                       ;Client's buffer handle
+
+load__totalSize        #       4                       ;How much data we've received
+
+load__message  #       44                      ;The original load/save msg
+load__name     #       212                     ;The file's apparent name
+
+load__wSize    EQU     {VAR}-load__wStart
+
+               ; --- States ---
+               ;
+               ; These have been carefully arranged so that we can return
+               ; the safeness flag to various routines.  If we only
+               ; consider files, then the state /is/ the safeness flag.
+               ; Otherwise we only use the bottom bit of the state.
+
+lState__scrap  EQU     0                       ;We're doing scrap transfer
+lState__file   EQU     1                       ;We're loading from a file
+lState__test   EQU     2                       ;We're testing RAM transfer
+lState__ram    EQU     4                       ;We're doing RAM transfer
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     load__wSize
+               DCD     load__wSpace
+               DCD     256
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/xfer/s/save b/StraySrc/Libraries/Sapphire/xfer/s/save
new file mode 100644 (file)
index 0000000..7d69459
--- /dev/null
@@ -0,0 +1,470 @@
+;
+; xfer.save.s
+;
+; Saving data to other applications (MDW)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:fastMove
+               GET     sapphire:msgs
+               GET     sapphire:sapphire
+               GET     sapphire:string
+               GET     sapphire:wimp
+               GET     sapphire:win
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- save ---
+;
+; On entry:    R0 == window handle to send to
+;              R1 == icon handle to send to
+;              R2 == estimated size of the data
+;              R3 == file type of data to send and flag:
+;                    bit 31: use R8 as below
+;              R4 == pointer to name of file (may be full path)
+;              R5 == address of handler block
+;              R6 == value to pass handlers in R10
+;              R7 == value to pass handlers in R12
+;              R8 == pointer to extra handler block (only if bit 31 of R3)
+;
+; On exit:     --
+;
+; Use:         Starts a save operation to another application.  The extra
+;              handler is used by systems like saveas which need to be
+;              aware of data transfer start/end conditions without
+;              interfering with the normal entry table.  This will not
+;              normally concern applications however.
+
+               EXPORT  save
+save           ROUT
+
+               STMFD   R13!,{R0-R8,R12,R14}    ;Save a load of registers
+               WSPACE  save__wSpace            ;Find my workspace pointer
+
+               ; --- Save some information in workspace ---
+
+               TST     R3,#&80000000           ;Is there an extra handler?
+               MOVEQ   R8,#0                   ;No -- then clear pointer
+               SUBNE   R8,R8,#sEntry__success  ;Otherwise, pad it out a bit
+               BIC     R3,R3,#&FF000000        ;Clear the flag bits
+               ADR     R14,save__handler       ;Save the handler information
+               STMIA   R14,{R5-R8}             ;Save them for later
+
+               MOV     R14,#0                  ;No buffer to send yet
+               STR     R14,save__srcSize       ;So clear out its size
+               STR     R14,save__acc           ;And clear RAM transfer acc
+               MOV     R14,#sState__safe       ;Data is safe at the moment
+               STR     R14,save__state         ;Clear out any old state info
+
+               ; --- Get the leafname of the file ---
+
+               MOV     R5,R4                   ;Point to the name start
+00save         LDRB    R14,[R5],#1             ;Get a character from it
+               CMP     R14,#'.'                ;Is it a directory separator?
+               MOVEQ   R4,R5                   ;Yes -- update pointer
+               CMP     R14,#32                 ;Is this the name end?
+               BGE     %00save                 ;No -- go round for more
+
+               ; --- Find the mouse position ---
+
+               SUB     R13,R13,#36             ;Make way for a pointer block
+               MOV     R1,R13                  ;Point to the new space
+               SWI     Wimp_GetPointerInfo     ;Read the mouse position
+               LDMIA   R1,{R7,R14}             ;Load the mouse coordinates
+               ADD     R13,R13,#36             ;Reclaim the stack space
+               LDMIA   R13,{R5,R6}             ;Load the window and icon
+
+               ; --- Build the message at last ---
+
+               ADD     R0,R11,#20              ;Start building msg body
+               STMIA   R0!,{R5-R7,R14}         ;Save coords and window hnd
+               STMIA   R0!,{R2,R3}             ;Save estimated size and type
+               MOV     R1,R4                   ;Point to the filename
+               BL      str_cpy                 ;Copy the name over
+               ADD     R0,R0,#4                ;Include the null terminator
+               SUB     R0,R0,R11               ;Get the final offset
+               BIC     R0,R0,#3                ;Round off to word size
+               STR     R0,[R11,#0]             ;Save the message size
+               ADD     R0,R11,#12              ;Point into message header
+               MOV     R1,#0                   ;This isn't a reply
+               MOV     R2,#1                   ;The message code for save
+               STMIA   R0,{R1,R2}              ;Store them in the message
+
+               ; --- Send the message over ---
+
+               MOV     R0,#18                  ;I want a bounce if it fails
+               MOV     R1,R11                  ;Point to message in scratch
+               LDMIA   R13,{R2,R3}             ;Load the window to send to
+               SWI     Wimp_SendMessage        ;Send the message to it then
+
+               ; --- Register the unknown handler to fix it all ---
+
+               ADR     R0,save__unknown        ;Point to my handler
+               MOV     R1,#0                   ;Nothing interesting in R4
+               MOV     R2,#0                   ;Nothing interesting in R10
+               MOV     R3,R12                  ;Pass my workspace pointer
+               BL      win_unknownHandler      ;Add in the handler nicely
+               LDMFD   R13!,{R0-R8,R12,PC}^    ;Restore registers and return
+
+               LTORG
+
+; --- save__unknown ---
+;
+; On entry:    R0 == event code
+;              R1 == pointer to event data
+;
+; On exit:     --
+;
+; Use:         Handles unknown events during a save operation.
+
+save__unknown  ROUT
+
+               CMP     R0,#19                  ;Is this a message bounce?
+               BEQ     %60save__unknown        ;Yes -- skip to handle it
+               CMP     R0,#17                  ;Is this any sort of message?
+               CMPNE   R0,#18                  ;Check both types
+               MOVNE   PC,R14                  ;No -- return to caller
+
+               ; --- Check the message codes ---
+
+               STMFD   R13!,{R14}              ;Save the link to check it
+               LDR     R14,[R1,#16]            ;Load the message code
+               CMP     R14,#6                  ;Is it a RamFetch message?
+               BEQ     %20save__unknown        ;Yes -- get a buffer to send
+               CMP     R14,#4                  ;Is it a DataLoadAck?
+               BEQ     %40save__unknown        ;Yes -- wrap scrap xfer up
+               CMP     R14,#2                  ;Is it a DataSaveAck?
+               LDMNEFD R13!,{PC}^              ;No -- return to caller
+
+               ; --- It's a normal acknowledgement ---
+
+               STMFD   R13!,{R0-R2,R10,R12}    ;Save some more registers
+               ADD     R0,R1,#44               ;Point to the filename
+               LDR     R1,[R1,#36]             ;Load the estimated size
+               CMP     R1,#-1                  ;Is it an unsafe file?
+               MOVLE   R1,#0                   ;Yes if est size < 0
+               MOVGT   R1,#1                   ;No if est size >= 0
+               STRLE   R1,save__state          ;Store the state away
+               ADR     R14,save__handler       ;Point to the handler block
+               LDMIA   R14,{R2,R10,R12}        ;Load the registers out
+               ADDS    R0,R0,#0                ;Clear carry and overflow
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R2,#sEntry__save     ;Call the save routine
+               WSPACE  save__wSpace            ;Load workspace pointer again
+               BLVS    save__finish            ;Wrap everything up here
+               BVS     %10save__unknown        ;It failed -- skip to the end
+
+               ; --- Send the DataLoad message ---
+
+               MOV     R0,R11                  ;Copy it to the scratchpad
+               LDR     R1,[R13,#4]             ;Read from the message block
+               LDR     R2,[R1,#0]              ;Message size, conveniently
+               BL      fastMove                ;Copy it over quickly
+               LDR     R14,[R1,#8]             ;Get his reference number
+               STR     R14,[R1,#12]            ;Store it so I can reply
+               MOV     R14,#3                  ;Send a DataLoad message
+               STR     R14,[R1,#16]            ;Save it in the message code
+               LDR     R2,[R1,#4]              ;Get his task handle out
+               MOV     R0,#18                  ;Make sure I get a bounce
+               SWI     Wimp_SendMessage        ;Send the message to him
+
+10save__unknown        LDMFD   R13!,{R0-R2,R10,R12,R14} ;Restore all the registers
+               ORRS    PC,R14,#C_flag          ;Return with carry set
+
+               ; --- It's a request for memory transfer ---
+
+20save__unknown        STMFD   R13!,{R0-R7,R10,R12}    ;Save some more registers
+               LDR     R14,save__handler       ;Load the handlers block
+               LDR     R14,[R14,#sEntry__send] ;Get the send entry
+               CMP     R14,#0                  ;Is it defined properly?
+               BEQ     %35save__unknown        ;No -- skip to the end
+
+               ; --- Set things up for the main loop ---
+
+               MOV     R6,#0                   ;No data sent yet
+               LDR     R2,[R1,#4]              ;Load his task handle
+               ADD     R3,R1,#20               ;Point to dest buffer info
+               LDMIA   R3,{R3,R5}              ;Load his buffer info
+               ADR     R1,save__srcBuff        ;Point to source buffer info
+               LDMIA   R1,{R1,R7}              ;Load the information out
+
+               ; --- Now for the main loop then ---
+
+25save__unknown        LDR     R14,save__state         ;Get the current state
+               CMP     R14,#sState__xferred    ;Have we finished?
+               BEQ     %30save__unknown        ;Yes -- skip to the end
+
+               CMP     R7,#0                   ;Is there any data waiting?
+               BNE     %30save__unknown        ;Yes -- skip the next bit
+
+               ; --- Find some data from the client ---
+
+               ADR     R14,save__handler       ;Point to the handler
+               STMFD   R13!,{R2}               ;Save the old R2 value away
+               LDR     R2,save__acc            ;Load caller's accumulator
+               LDMIA   R14,{R0,R10,R12}        ;Get ready to call it
+               ADDS    R0,R0,#0                ;Clear lots of flags
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R0,#sEntry__send     ;Get some data to send
+               WSPACE  save__wSpace            ;Load my workspace again
+               BLVS    save__finish            ;It failed -- wrap things up
+               ADDVS   R13,R13,#4              ;Don't bother with acc.
+               BVS     %35save__unknown        ;And skip to the end
+               STRCC   R2,save__acc            ;Save accumulator back
+               LDMFD   R13!,{R2}               ;Reload saved R2 value
+               MOVCS   R14,#sState__xferred    ;If that's the last one...
+               STRCS   R14,save__state         ;Save the state flag away
+               MOV     R7,R1                   ;Copy the size and the...
+               MOV     R1,R0                   ;... buffer pointers away
+
+               ; --- Send another bufferfull ---
+
+30save__unknown        CMP     R5,R7                   ;Which one is bigger?
+               MOVLT   R4,R5                   ;Choose the smaller as the...
+               MOVGE   R4,R7                   ;... buffer size to send
+               BL      wimp_taskHandle         ;Get my task handle ready
+               SWI     Wimp_TransferBlock      ;Transfer the data across
+
+               ; --- Set things up for the next go round ---
+
+               ADD     R6,R6,R4                ;Bump the amount we've sent
+               SUB     R7,R7,R4                ;Decrement the amount to send
+               SUB     R5,R5,R4                ;And the destination buffer
+               ADD     R1,R1,R4                ;But bump the buffer pointer
+               ADD     R3,R3,R4                ;For both sides of the xfer
+
+               ; --- Find out if we need to go again ---
+
+               LDR     R14,save__state         ;Get my state variable again
+               CMP     R14,#sState__xferred    ;Is the transfer proceeding?
+               CMPNE   R5,#0                   ;And is he waiting for more?
+               BNE     %25save__unknown        ;Yes -- loop back round then
+
+               ; --- Update all the variables ---
+
+               ADR     R14,save__srcBuff       ;Point to source buff address
+               STMIA   R14,{R1,R7}             ;Save the updated values back
+
+               ; --- Send the RamTransmit to the other task ---
+
+               MOV     R0,#28                  ;Size of my message block
+               LDR     R1,[R13,#4]             ;Get the address of original
+               LDR     R3,[R1,#8]              ;Get his reference number
+               MOV     R4,#7                   ;This is a RamTransmit
+               LDR     R5,[R1,#20]             ;Get his buffer address
+               STMIA   R11,{R0-R6}             ;Save all the information
+               LDR     R7,[R1,#24]             ;Get the amount he expected
+               CMP     R6,R7                   ;Have we filled his buffer?
+               MOVLT   R0,#17                  ;No -- send as normal message
+               MOVEQ   R0,#18                  ;Otherwise get bounces nicely
+               LDR     R2,[R1,#4]              ;Get his task handle ready
+               MOV     R1,R11                  ;Point to the scratch message
+               SWI     Wimp_SendMessage        ;Send the message over
+
+               ; --- Now tidy everthing up and leave ---
+
+               CMP     R6,R7                   ;Did we fill his buffer?
+               BEQ     %35save__unknown        ;Yes -- skip this next bit
+               CMP     R0,#0                   ;Clear overflow flag
+               BL      save__finish            ;Tidy everything up nicely
+
+35save__unknown        LDMFD   R13!,{R0-R7,R10,R12,R14} ;Load massive chunk of regs
+               ORRS    PC,R14,#C_flag          ;I handled the event
+
+               ; --- Handle a DataLoadAck message ---
+
+40save__unknown        CMP     R14,#0                  ;Clear the overflow flag
+               LDMFD   R13!,{R14}              ;Load the return address
+               ORR     R14,R14,#C_flag         ;Set C on eventual exit
+               B       save__finish            ;Tidy everything up and leave
+
+               ; --- Handle message bounces ---
+
+60save__unknown        STMFD   R13!,{R14}              ;Save a single register
+               LDR     R14,[R1,#16]            ;Load the message code
+               CMP     R14,#3                  ;Is it a bounced DataLoad?
+               BEQ     %70save__unknown        ;Yes -- handle that properly
+               CMP     R14,#7                  ;Is it a bounced RamTransit?
+               CMPNE   R14,#1                  ;Or a bounced DataSave?
+               LDMNEFD R13!,{PC}^              ;No -- return to caller then
+
+               ; --- Receiver failed to reply to RamTransmit or DataSave ---
+               ;
+               ; There's probably a good reason for this, such as it ran
+               ; out of memory, so we'd better just ignore it and tidy up.
+
+               STMFD   R13!,{R0}               ;Save another register
+               MOV     R14,#V_flag             ;Get the V flag's bit
+               TEQVCP  R14,PC                  ;If V not set, toggle it!
+               MOV     R0,#0                   ;Don't pass an error block
+               BL      save__finish            ;Bring it all to a stop
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               ; --- Failed to reply to a DataLoad ---
+               ;
+               ; There could be a loose temporary file lying around, so
+               ; we'd better nobble it quickly.  It also seems to be
+               ; traditional to moan if the DataLoadAck is not received.
+
+70save__unknown        STMFD   R13!,{R0-R2}            ;Save a few registers
+               ADR     R0,save__delScrap       ;Point to the command skel
+               ADD     R2,R1,#44               ;Point to the filename
+               MOV     R1,R11                  ;Build it up in the scratch
+               BL      str_subst               ;Build the command string
+               SWI     XOS_CLI                 ;Perform the command and hope
+               ADR     R0,save__dtDead         ;Point to an error message
+               BL      msgs_error              ;Translate it cunningly
+               MOV     R14,#V_flag             ;Get the V flag's bit
+               TEQVCP  R14,PC                  ;If V not set, toggle it!
+               BL      save__finish            ;Wrap everything up then
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+save__delScrap DCB     "%%Wipe %0 ~c~vfr",0
+save__dtDead   DCD     1
+               DCB     "saveDTDEAD",0
+
+               LTORG
+
+; --- save__finish ---
+;
+; On entry:    R0 == pointer to error, or 0 if V set
+;
+; On exit:     --
+;
+; Use:         Finishes off a data transfer job nicely
+
+save__finish   ROUT
+
+               STMFD   R13!,{R0-R4,R10,R12,R14} ;Save some registers
+
+               ; --- We need to remove the unknown handler first ---
+
+               MOV     R10,PC                  ;Look after entry flags
+               ADR     R0,save__unknown        ;Point to my handler
+               MOV     R1,#0                   ;Nothing interesting in R4
+               MOV     R2,#0                   ;Nothing interesting in R10
+               MOV     R3,R12                  ;Pass my workspace pointer
+               BL      win_removeUnknownHandler ;Kill off the handler
+               TEQP    R10,#0                  ;Restore the saved flags
+               MOVVS   R4,#4                   ;If so, offset handlers by 4
+               MOVVC   R4,#0                   ;Otherwise, don't do it
+
+               LDRVS   R0,[R13,#0]             ;Yes -- load error pointer
+               MOVVS   R1,#1                   ;And pass 1 as button count
+               LDRVC   R1,save__state          ;Load the state value
+               ANDVC   R1,R1,#1                ;Leave the safeness flag
+               LDRVC   R0,[R13,#4]             ;Load the message address
+               ADDVC   R0,R0,#44               ;Point to the filename
+
+               ; --- Now call the user routine ---
+
+               ADR     R14,save__handler       ;Point to the handlers
+               LDMIA   R14,{R2,R10,R12,R14}    ;Load all the stuff out
+
+               MOVS    R3,R14                  ;Keep the extra handler
+               ADD     R2,R2,R4                ;Offset the handler properly
+               ADDNE   R3,R3,R4                ;And offset extra one too
+
+10save__finish MOV     R14,PC                  ;Set up return address
+               ADD     PC,R2,#sEntry__success  ;Call the handler as required
+               MOVS    R2,R3                   ;Copy the real handler over
+               MOVNE   R3,#0                   ;If it was nonzero, zero it
+               BNE     %10save__finish         ;And go round again for it
+
+               LDMFD   R13!,{R0-R4,R10,R12,PC}^ ;Return to caller
+
+               LTORG
+
+save__wSpace   DCD     0
+
+;----- The save handler -----------------------------------------------------
+
+               ^       0
+sEntry__save   #       4                       ;Write to a file
+                                               ;Entry:
+                                               ;  R0 == pointer to file name
+                                               ;  R1 == 0 if file unsafe,
+                                               ;        non-0 if safe
+                                               ;Exit:
+                                               ;  --
+
+sEntry__send   #       4                       ;Send a block of data
+                                               ;Entry:
+                                               ;  R2 == 0 for first call,
+                                               ;        or R2 from previous
+                                               ;Exit:
+                                               ;  R0 == pointer to block
+                                               ;  R1 == size of block
+                                               ;  R2 == value to pass to
+                                               ;        next call
+                                               ;  CS if this is the last one
+
+sEntry__success        #       4                       ;Data transfer has finished
+                                               ;Entry:
+                                               ;  R0 == pointer to filename
+                                               ;  R1 == safeness flag
+                                               ;Exit:
+                                               ;  --
+
+sEntry__failed #       4                       ;Data transfer failed
+                                               ;Entry:
+                                               ;  R0 == 0 or ptr to error
+                                               ;  R1 == 1
+                                               ;Exit:
+                                               ;  --
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+save__wStart   #       0
+
+               ; --- Miscellaneous variables ---
+
+save__state    #       4                       ;My current saving state
+
+               ; --- The handler ---
+
+save__handler  #       4                       ;Pointer to handler code
+save__R10      #       4                       ;The R10 to pass to it
+save__R12      #       4                       ;The R12 to pass to it
+save__extra    #       4                       ;Special extra handler
+
+               ; --- Variables for dealing with RAM transfer ---
+
+save__srcBuff  #       4                       ;The source buffer to read
+save__srcSize  #       4                       ;The source buffer size
+save__acc      #       4                       ;The sender's counter thing
+
+save__wSize    EQU     {VAR}-save__wStart
+
+               ; --- Various state indicators ---
+               ;
+               ; These have been carefully arranged so that the safeness
+               ; flag is the bottom bit of the state.  The state is changed
+               ; from the default sState__safe when we detect that the file
+               ; is not safe.
+
+sState__unsafe EQU     0                       ;File is unsafe as it is
+sState__safe   EQU     1                       ;File is safe
+sState__xferred        EQU     2                       ;We've finished all that now
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     save__wSize
+               DCD     save__wSpace
+               DCD     256
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/xfer/s/saveAs b/StraySrc/Libraries/Sapphire/xfer/s/saveAs
new file mode 100644 (file)
index 0000000..17f826e
--- /dev/null
@@ -0,0 +1,383 @@
+;
+; xfer.saveAs.s
+;
+; Implementation of a save as dialogue box (MDW)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:help
+               GET     sapphire:msgs
+               GET     sapphire:note
+               GET     sapphire:sapphire
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx.fileIcon
+
+               GET     sapphire:xfer.save
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- saveAs ---
+;
+; On entry:    R0 == estimated size of data
+;              R1 == file type of the data
+;              R2 == pointer to name of the file
+;              R3 == pointer to handler block
+;              R4 == value to pass to handlers in R10
+;              R5 == value to pass to handlers in R12
+;
+; On exit:     May return an error
+;
+; Use:         Displays a save as dialogue box for you to save some data.
+
+               EXPORT  saveAs
+saveAs         ROUT
+
+               STMFD   R13!,{R0-R6,R12,R14}    ;Save some registers
+               WSPACE  sa__wSpace              ;Find my workspace address
+
+               ; --- Find the end of the string ---
+
+               MOV     R6,R3                   ;Take a copy of the title tag
+00saveAs       LDRB    R14,[R3],#1             ;Load a byte from the table
+               CMP     R14,#32                 ;Is it the end yet?
+               BGE     %00saveAs               ;No -- go round again then
+               ADD     R3,R3,#3                ;Add on a little bit
+               BIC     R3,R3,#3                ;And word align the result
+
+               ; --- Save the fixed information away ---
+
+               STMIA   R12,{R0-R5}             ;Save the stuff in workspace
+
+               ; --- Now create a dialogue box ---
+
+               ADR     R0,sa__dbName           ;Point to my dialogue name
+               BL      dbox_create             ;Try to create the dialogue
+               BVS     %99saveAs               ;If it failed, tidy up
+               STR     R0,sa__dbox             ;Save the dialogue handle
+
+               ADR     R1,sa__dbHandler        ;Point to my handler routine
+               MOV     R2,R0                   ;Pass dialogue handle in R10
+               MOV     R3,R12                  ;And workspace in R12 please
+               BL      dbox_eventHandler       ;Set up the event handler
+
+               ADR     R1,sa__dbxDef           ;Point to my dialogue def
+               BL      dbx_declare             ;Let dbx handle the dialogue
+
+               ; --- Set up the dialogue ---
+
+               MOV     R1,#saIcon__write       ;Get the writable icon handle
+               LDR     R2,[R13,#8]             ;Get the default filename
+               BL      dbox_setField           ;Write it into the icon
+
+               MOV     R3,R0                   ;Save the dialogue handle
+               MOV     R0,R6                   ;Get the title string tag
+               BL      msgs_lookup             ;Translate it nicely
+               MOV     R2,R0                   ;Copy it into R2 now
+               MOV     R0,R3                   ;Restore the dialogue handle
+               MOV     R1,#-1                  ;Fill in the title bar
+               BL      dbox_setField           ;And fill in the title
+
+               ; --- Now display it and return ---
+
+               MOV     R1,#dbOpen_trans :OR: dbOpen_pointer
+               BL      dbox_open               ;Open the dialogue box
+               LDMFD   R13!,{R0-R6,R12,R14}    ;Restore all the registers
+               BICS    PC,R14,#V_flag          ;And don't return any errors
+
+               ; --- Couldn't create the dialogue box ---
+
+99saveAs       ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R6,R12,R14}    ;Restore the other registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+sa__dbName     DCB     "save",0
+
+sa__dbxDef     FILEICN saIcon__file,R12,:INDEX: sa__fileType
+               DBXEND
+
+               LTORG
+
+; --- sa__dbHandler ---
+;
+; On entry:    R0 == dialogue box event code
+;              R1-R9 == event-dependent information
+;
+; On exit:     --
+;
+; Use:         Handles events for the save dialogue box.
+
+sa__dbHandler  ROUT
+
+               CMP     R0,#saIcon__ok          ;Is it the OK button clicked?
+               CMPNE   R0,#dbEvent_OK          ;Or maybe a return key?
+               BEQ     %10sa__dbHandler        ;Either -- handle it
+
+               CMP     R0,#dbEvent_close       ;Has the window been closed?
+               BEQ     %20sa__dbHandler        ;Yes -- deal with this then
+
+               CMP     R0,#fIcon_event         ;Or is it the fileicon drag?
+               BEQ     %30sa__dbHandler        ;Yes -- deal with that
+
+               CMP     R0,#dbEvent_help        ;Is it a help request?
+               BEQ     %40sa__dbHandler        ;Yes -- send some help along
+
+               MOVS    PC,R14                  ;Return -- unknown event
+
+               ; --- Deal with a click on the OK button ---
+
+10sa__dbHandler        STMFD   R13!,{R0-R3,R10,R12,R14} ;Save some registers
+               MOV     R3,R1                   ;Keep the button status safe
+
+               ; --- Slab the OK button ---
+
+               MOV     R0,R10                  ;Get my dialogue handle
+               MOV     R1,#saIcon__ok          ;And the OK button handle
+               BL      dbox_slab               ;Slab the icon in nicely
+
+               ; --- Try to find a `.' character ---
+
+               MOV     R1,#saIcon__write       ;Find the writable icon
+               BL      dbox_getField           ;Read the string value
+               MOV     R0,R2                   ;Keep pointer to string
+13sa__dbHandler        LDRB    R14,[R2],#1             ;Load a byte from it
+               CMP     R14,#32                 ;Is it a control character?
+               BLO     %17sa__dbHandler        ;Yes -- tell user he's silly
+               CMP     R14,#'.'                ;Is it a dot character?
+               BNE     %13sa__dbHandler        ;No -- loop round again
+
+               ; --- Tell the client to save the file ---
+
+               MOV     R1,#1                   ;Say that the file's safe
+               ADR     R2,sa__entries          ;Find the entry point block
+               LDMIA   R2,{R2,R10,R12}         ;Load all the client stuff
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R2,#saEntry__save    ;Try to send the file
+               BVC     %19sa__dbHandler        ;If it worked, skip to end
+
+               ; --- Handle an error from the client ---
+
+               MOV     R1,#1                   ;Set icon count for errorBox
+               MOV     R14,PC                  ;Set up the return address
+               ADD     PC,R2,#saEntry__failed  ;Tell client it failed
+               MOV     R3,#1                   ;Don't close the dialogue
+               B       %19sa__dbHandler        ;And skip to the end
+
+               ; --- Display a note about dragging the icon ---
+
+17sa__dbHandler        MOV     R3,#1                   ;Don't close the dialogue
+               ADR     R0,sa__noteMsg          ;Point to the note message
+               BL      msgs_lookup             ;Translate the note string
+               BL      note                    ;And display it in a window
+
+               ; --- Wrap everything up nice and tight ---
+
+19sa__dbHandler        CMP     R3,#1                   ;Was it an Adjust click?
+               LDR     R0,[R13,#16]            ;Load my dialogue handle
+               BLNE    dbox_close              ;No -- close the dialogue
+               BL      dbox_unslab             ;Unslab the OK button
+               BLNE    sa__close               ;And close the dialogue box
+               LDMFD   R13!,{R0-R3,R10,R12,PC}^ ;Return to caller
+
+sa__noteMsg    DCB     "saDRAGICN",0
+
+               ; --- Handle a close event for the window ---
+
+20sa__dbHandler        B       sa__close               ;Just close the window
+
+               ; --- Handle an icon drag for the window ---
+
+30sa__dbHandler        STMFD   R13!,{R0-R8,R14}        ;Save a load of registers
+
+               ; --- Find the filename string ---
+
+               MOV     R0,R10                  ;Get the dialogue box handle
+               MOV     R1,#saIcon__write       ;Get the writable icon handle
+               BL      dbox_getField           ;Read the text string
+               MOV     R8,R2                   ;Keep a pointer to it
+
+               ; --- Set up the other arguments ---
+
+               ADD     R14,R13,#8              ;Point to saved window/icon
+               LDMIA   R14,{R0,R1}             ;Load them into registers
+               LDMIA   R12,{R2-R7}             ;Load the other arguments
+               ORR     R3,R3,#&80000000        ;Set the extended args flag
+               MOV     R4,R8                   ;Point to new file name
+               ADD     R5,R5,#saEntry__save    ;Point at save handlers
+               ADR     R8,sa__extraHnd         ;Point to my extra handlers
+               BL      save                    ;Start the save operation
+               LDMFD   R13!,{R0-R8,PC}^        ;Return to caller
+
+sa__extraHnd   B       sa__success             ;The save attempt succeeded
+               B       sa__failed              ;The save attempt failed
+
+40sa__dbHandler        STMFD   R13!,{R0,R14}           ;Save some registers
+               ADR     R0,sa__dbHelp           ;Point to the message string
+               BL      msgs_lookup             ;Translate the message
+               BL      help_add                ;Add it to the help text
+               BL      dbox_help               ;Read help from the icon
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+sa__dbHelp     DCB     "sahDB",0
+
+               LTORG
+
+; --- sa__close ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Closes the save as dialogue box
+
+sa__close      ROUT
+
+               STMFD   R13!,{R0,R10,R12,R14}   ;Save some registers away
+
+               ; --- Close the dialogue box ---
+
+               WSPACE  sa__wSpace              ;Locate my workspace
+               LDR     R0,sa__dbox             ;Load the dialogue box handle
+               BL      dbox_destroy            ;Destroy the dialogue
+               BL      fileIcon_closed         ;Tell fileIcon it's closed
+
+               ; --- Tell the client we've done this thing ---
+
+               ADR     R14,sa__entries         ;Point to the entry table
+               LDMIA   R14,{R0,R10,R12}        ;Load the client data
+               LDR     R14,[R0,#saEntry__closed] ;Find the closed entry word
+               CMP     R14,#0                  ;Is there an entry defined?
+               MOV     R14,PC                  ;Set up the return address
+               ADDNE   PC,R0,#saEntry__closed  ;If defined, call the entry
+               LDMFD   R13!,{R0,R10,R12,PC}^   ;Return to caller
+
+               LTORG
+
+; --- sa__success ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Handles a successful icon drag-save operation.
+
+sa__success    ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Save a few registers
+
+               ; --- Send a close event to the dialogue ---
+
+               WSPACE  sa__wSpace              ;Find my workspace pointer
+               LDR     R0,sa__dbox             ;Get the dialogue box handle
+               BL      dbox_window             ;Get its window handle
+               STR     R0,[R13,#-4]!           ;Store it on the stack
+               MOV     R2,R0                   ;Get the window handle in R2
+               MOV     R1,R13                  ;Point to the close block
+               MOV     R0,#3                   ;And send a close event
+               SWI     Wimp_SendMessage        ;Add it to my event queue
+               ADD     R13,R13,#4              ;Reclaim that microblock
+               LDMFD   R13!,{R0-R3,R12,PC}^    ;Return to caller
+
+               LTORG
+
+; --- sa__failed ---
+;
+; On entry:    R0 == pointer to an error, or 0
+;              R1 == 1
+;
+; On exit:     --
+;
+; Use:         Deals with an abortive to save data.
+
+sa__failed     ROUT
+
+               B       fileIcon_reAppear       ;Make the file icon reappear
+
+               LTORG
+
+sa__wSpace     DCD     0
+
+;----- The SaveAs handler block ---------------------------------------------
+;
+; The block begins with the message tag for the dialogue title, followed by
+; an align to word boundary and then branch instructions or 0 for:
+
+               ^       0
+saEntry__closed        #       4                       ;Save dialogue has closed
+                                               ;Entry:
+                                               ;  --
+                                               ;Exit:
+                                               ;  --
+
+saEntry__save  #       4                       ;Write to a file
+                                               ;Entry:
+                                               ;  R0 == pointer to file name
+                                               ;  R1 == 0 if file unsafe,
+                                               ;        non-0 if safe
+                                               ;Exit:
+                                               ;  --
+
+saEntry__send  #       4                       ;Send a block of data
+                                               ;Entry:
+                                               ;  --
+                                               ;Exit:
+                                               ;  R0 == pointer to block
+                                               ;  R1 == size of block
+                                               ;  CS if this is the last one
+
+saEntry__success       #       4               ;Data transfer has finished
+                                               ;Entry:
+                                               ;  --
+                                               ;Exit:
+                                               ;  --
+
+saEntry__failed        #       4                       ;Data transfer failed
+                                               ;Entry:
+                                               ;  R0 == 0 or ptr to error
+                                               ;  R1 == 1
+                                               ;Exit:
+                                               ;  --
+
+;----- Icon numbers ---------------------------------------------------------
+
+saIcon__write  EQU     1
+saIcon__file   EQU     2
+saIcon__ok     EQU     3
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+sa__wStart     #       0
+
+sa__estSize    #       4                       ;Estimated size of data
+sa__fileType   #       4                       ;Filetype of data to save
+sa__fileName   #       4                       ;Pointer to default name
+sa__entries    #       4                       ;Pointer to branch table
+sa__R10                #       4                       ;Caller's value of R10
+sa__R12                #       4                       ;Caller's value of R12
+
+sa__dbox       #       4                       ;My dialogue box handle
+
+sa__wSize      EQU     {VAR}-sa__wStart
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     sa__wSize
+               DCD     sa__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/xfer/s/xload b/StraySrc/Libraries/Sapphire/xfer/s/xload
new file mode 100644 (file)
index 0000000..f714eae
--- /dev/null
@@ -0,0 +1,760 @@
+;
+; xfer.xload.s
+;
+; Simplified loading with coroutines (MDW)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:coRoutine
+               GET     sapphire:fastMove
+               GET     sapphire:sapphire
+
+;----- How it all works -----------------------------------------------------
+;
+; xload attempts to unify the various loading routines you have to supply,
+; by providing a single interface.
+;
+; There are several main routines, xload_file, xload_initBuf,
+; xload_killBuf, xload_extend and xload_doneBuf, which are called from
+; the main load branch table.
+;
+; Loading of data is done with the call xload_block.  This just reads
+; a block of data somehow.  All the other routines are special interfaces to
+; xload_block.
+
+;----- How the error handling works -----------------------------------------
+;
+; The really tricky bit is passing of errors during a RAM transfer.
+; Errors can be returned at two places -- in the user code (e.g. running out
+; of memory) and by load's message handling if the receiver dies.  All
+; errors must be handled by user code, to release claimed memory etc.
+;
+; The error gets passed along a path like this:
+;
+; Error created by user code
+;
+; user code --> xload__startCo --> xload_failed
+;
+; Error created by remote receiver
+;
+; xload_failed --> xload__read --> user code --> xload__startCo
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- xload_file ---
+;
+; On entry:    R0 == pointer to loader routine
+;              R1 == R10 value to pass to loader
+;              R2 == R12 value to pass to loader
+;              R3 == pointer to leafname of file (passed to loader in R0)
+;              R4 == pointer to filename to load from
+;              R5 == whether the file is safe (passed to loader in R1)
+;
+; On exit:     May return an error
+;
+; Use:         Calls a generalised loader routine to read data from a file.
+
+               EXPORT  xload_file
+xload_file     ROUT
+
+               STMFD   R13!,{R0-R5,R10,R12,R14} ;Save lots of registers
+               WSPACE  xload__wSpace           ;Find my workspace address
+
+               ; --- First, try to allocate a buffer ---
+
+               BL      xload__setBuff          ;Allocate the buffer nicely
+               BVS     %99xload_file           ;If we couldn't, tidy up
+
+               ; --- Set up the file for writing ---
+
+               MOV     R1,R4                   ;Point at the file name
+               MOV     R0,#&4F                 ;Lots of errors, no path
+               SWI     XOS_Find                ;Try to open the file
+               BVS     %98xload_file           ;Tidy up if it wouldn't open
+               STR     R0,xload__file          ;Save the file handle away
+
+               ; --- Set up flags and let rip ---
+
+               LDR     R14,xload__flags        ;Load my current flags word
+               AND     R14,R14,#xlFlag__inited ;Only leave inited flag
+               STR     R14,xload__flags        ;Save the flags back again
+
+               MOV     R14,#0                  ;Nothing read yet
+               STR     R14,xload__buffUsed     ;So clear buffer size
+
+               LDMIA   R13,{R2,R10,R12,R14}    ;Load the arguments out
+               MOV     R0,R14                  ;Get the leafname in R0
+               ADDS    R1,R1,#0                ;Clear overflow and carry
+               LDR     R1,[R13,#16]            ;Load the safeness flag
+               MOV     R14,PC                  ;Set up the return address
+               MOV     PC,R2                   ;And call the saver routine
+               WSPACE  xload__wSpace           ;Restore my workspace ptr
+               BVS     %97xload_file           ;Tidy up if it failed
+
+               ; --- Close the file ---
+
+               MOV     R0,#0                   ;Close an open file
+               LDR     R1,xload__file          ;Get the file handle ready
+               SWI     OS_Find                 ;Close it
+
+               ; --- Get rid of the buffer and return ---
+
+               BL      xload__loseBuff         ;Free up the buffer space
+               LDMFD   R13!,{R0-R5,R10,R12,R14} ;Unstack all the registers
+               BICS    PC,R14,#V_flag          ;And return to caller
+
+               ; --- Tidy up after various catastrophes ---
+
+97xload_file   MOV     R10,R0                  ;Keep the error pointer
+               MOV     R0,#0                   ;Close an open file
+               LDR     R1,xload__file          ;Get the file handle ready
+               SWI     OS_Find                 ;Close it
+               MOV     R0,R10                  ;Restore the error pointer
+
+98xload_file   BL      xload__loseBuff         ;Free up the buffer space
+
+99xload_file   ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R5,R10,R12,R14} ;Unstack all the registers
+               ORRS    PC,R14,#V_flag          ;And return to caller
+
+; --- xload_initBuf ---
+;
+; On entry:    R0 == pointer to loader routine
+;              R1 == R10 value to pass to loader
+;              R2 == R12 value to pass to loader
+;              R3 == pointer to leafname of file (passed to loader in R0)
+;
+; On exit:     R0 == pointer to load buffer
+;              R1 == size of load buffer
+;              May return an error
+;
+; Use:         Starts a RAM transfer and starts up a generalised load
+;              routine.
+
+               EXPORT  xload_initBuf
+xload_initBuf  ROUT
+
+               STMFD   R13!,{R0-R3,R12,R14}    ;Save some registers
+               WSPACE  xload__wSpace           ;Load my workspace address
+
+               ; --- Firstly, allocate the buffer ---
+
+               BL      xload__setBuff          ;Create the load buffer
+               ADDVS   R13,R13,#8              ;If failed, unstack R0,R1
+               BVS     %99xload_initBuf        ;And then return error
+
+               ; --- Now create the coroutine ---
+
+               ADR     R0,xload__startCo       ;Point to the coroutine
+               MOV     R1,R13                  ;Point to saved corout info
+               MOV     R2,R12                  ;Pass my workspace in R12
+               MOV     R3,#0                   ;Default stack size please
+               BL      coRout_create           ;Try to create the coroutine
+               ADDVS   R13,R13,#8              ;Don't return R0,R1
+               BVS     %98xload_initBuf        ;If it failed, tidy up
+               STR     R0,xload__coRout        ;Save the couroutine handle
+
+               ; --- Let xload__startCo save coroutine info ---
+
+               BL      coRout_switch           ;Switch to it quickly
+               ADD     R13,R13,#8              ;Don't return R0,R1
+
+               ; --- Set up flags and bits of workspace ---
+
+               LDR     R14,xload__flags        ;Load my flags word
+               AND     R14,R14,#xlFlag__inited ;Clear all but initialised
+               ORR     R14,R14,#xlFlag__ramTran ;We're doing RAM transfer
+               STR     R14,xload__flags        ;Save the flags back
+               MOV     R14,#0                  ;No data RAMmed in yet
+               STR     R14,xload__rammed       ;So save this information
+
+               ; --- Return the buffer information ---
+
+               ADR     R14,xload__buffer       ;Find my buffer info
+               LDMIA   R14,{R0,R1}             ;Load address and size
+               LDMFD   R13!,{R2,R3,R12,R14}    ;Unstack my registers
+               BICS    PC,R14,#V_flag          ;And return no error
+
+               ; --- Things went wrong ---
+
+98xload_initBuf        BL      xload__loseBuff         ;Get rid of transfer buffer
+99xload_initBuf        LDMFD   R13!,{R2,R3,R12,R14}    ;Unstack my registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- xload__startCo ---
+;
+; On entry:    R0 == my coroutine handle
+;              R10 == pointer to block containing (routine,R10,R12,leafname)
+;              R12 == my workspace
+;
+; On exit:     Returns through coRout_end
+;
+; Use:         Starts the coroutine for sending data by RAM transfer.  It
+;              handles errors reported by it, and terminates the transfer
+;              properly.
+;
+;              The information about the real client is stored on the
+;              main routine's stack.  Before it returns, therefore, we
+;              need to load it from there and save it somewhere so that
+;              it will be safe when we start the coroutine properly from
+;              xload_extend.  Therefore we actually start from xload_initBuf
+;              and save the information on the coroutine's stack, and
+;              switch back quickly.
+
+xload__startCo ROUT
+
+               LDMIA   R10,{R0-R3}             ;Load the caller's registers
+               STMFD   R13!,{R0-R3}            ;Save them on our stack
+               MOV     R0,#0                   ;Return to main routine
+               BL      coRout_switch           ;Switch back please
+
+               LDR     R14,xload__flags        ;Load my flags word
+               ORR     R14,R14,#xlFlag__started ;Coroutine has started now
+               STR     R14,xload__flags        ;Save flags back again
+
+               LDMFD   R13!,{R2,R10,R12,R14}   ;Load client's workspace
+               MOV     R0,R14                  ;Pass leafname in R0
+               MOV     R1,#0                   ;File is not safe
+               MOV     R14,PC                  ;Set up a return address
+               MOV     PC,R2                   ;And call the saver routine
+               BVS     %90xload__startCo       ;If it failed, report error
+
+               MOV     R14,#0                  ;A nice zero value
+               WSPACE  xload__wSpace           ;Load my workspace pointer
+               STR     R14,xload__coRout       ;Write over the coroutine
+               LDR     R0,xload__buffer        ;Load the buffer address
+               MOV     R1,#xload__buffSize     ;Get the current buffer size
+               ADR     R14,xload__start        ;Point to load area
+               STMIA   R14,{R0,R1}             ;Save the data in there
+               B       coRout_end              ;Terminate coroutine
+
+               ; --- Handle its return values ---
+
+90
+               WSPACE  xload__wSpace           ;Locate my workspace address
+               LDR     R14,xload__flags        ;Load the flags word
+
+               ORR     R14,R14,#xlFlag__error  ;Set the main error flag
+               STR     R14,xload__flags        ;Save the flags back again
+               STR     R0,xload__error         ;And save the error pointer
+               B       coRout_end              ;And finish the coroutine
+
+               LTORG
+
+; --- xload_killBuf ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Does a buffer destroy for a failed load operation.
+
+               EXPORT  xload_killBuf
+xload_killBuf  ROUT
+
+               STMFD   R13!,{R0,R12,R14}       ;Save some registers
+               WSPACE  xload__wSpace           ;Find my workspace address
+               LDR     R14,xload__flags        ;Load my flags word
+               TST     R14,#xlFlag__started    ;Has the coroutine started?
+               LDMNEFD R13!,{R0,R12,PC}^       ;Yes -- this is an error then
+
+               ; --- Destroy the buffer and the coroutine ---
+
+               BL      xload__loseBuff         ;Get rid of the load buffer
+               LDR     R0,xload__coRout        ;Load the coroutine handle
+               BL      coRout_destroy          ;Destroy the coroutine
+               LDMFD   R13!,{R0,R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- xload_extend ---
+;
+; On entry:    R1 == size of last buffer used for receiving
+;
+; On exit:     R0 == pointer to new buffer
+;              R1 == size of new buffer
+;              May return an error
+;
+; Use:         Performs a buffer extent operation during an xload RAM
+;              transfer.
+
+               EXPORT  xload_extend
+xload_extend   ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  xload__wSpace           ;Find my workspace address
+
+               ; --- Bump the amount of data received ---
+
+               LDR     R14,xload__rammed       ;Find how much was sent
+               ADD     R14,R14,R1              ;Add size of last buffer
+               STR     R14,xload__rammed       ;And save the size back
+
+               ; --- Let the coroutine do some loading ---
+
+               BL      xload__resume           ;Let the coroutine run a bit
+               LDR     R14,xload__flags        ;Load the coroutine's flags
+               TST     R14,#xlFlag__error      ;Has it returned an error?
+               BNE     %90xload_extend         ;Yes -- then return it
+
+               ; --- Get the next buffer to send from xload__read ---
+
+               ADR     R14,xload__start        ;Point to buffer data
+               LDMIA   R14,{R0,R1}             ;Load the buffer data
+               LDMFD   R13!,{R12,R14}          ;Unstack the registers
+               BICS    PC,R14,#V_flag          ;And don't return an error
+
+               ; --- Client had a wee problem ---
+
+90xload_extend LDR     R0,xload__error         ;Load the error pointer
+               LDMFD   R13!,{R12,R14}          ;Unstack the registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- xload_doneBuf ---
+;
+; On entry:    R1 == total size of data received
+;
+; On exit:     R0 corrupted
+;              May return an error
+;
+; Use:         Handles the last bufferful of a RAM load.
+
+               EXPORT  xload_doneBuf
+xload_doneBuf  ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  xload__wSpace           ;Find my workspace address
+
+               ; --- Work out how much of the last buffer was sent ---
+
+               LDR     R14,xload__rammed       ;Find how much was sent
+               SUB     R0,R1,R14               ;How much of last buffer?
+               STR     R0,xload__length        ;And save the size back
+               LDR     R14,xload__flags        ;Load the flags word
+               ORR     R14,R14,#xlFlag__finish ;Set the finished flag
+               STR     R14,xload__flags        ;Save the flags back again
+               TST     R14,#xlFlag__started    ;Has the coroutine started?
+               STREQ   R0,xload__buffUsed      ;No -- set buffer size
+
+               ; --- Now let the coroutine finish off ---
+
+               BL      xload__resume           ;Let the coroutine run a bit
+               LDR     R14,xload__flags        ;Load the coroutine's flags
+               TST     R14,#xlFlag__error      ;Has it returned an error?
+               BNE     %90xload_doneBuf        ;Yes -- then return it
+
+               ; --- Return to caller ---
+
+               BL      xload__loseBuff         ;Don't want this any more
+               LDMFD   R13!,{R12,R14}          ;Unstack the registers
+               BICS    PC,R14,#V_flag          ;Don't return an error
+
+               ; --- Coroutine hit a wee problem ---
+
+90xload_doneBuf        LDR     R0,xload__error         ;Load the error pointer
+               LDMFD   R13!,{R12,R14}          ;Unstack the registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- xload_done ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Tidies up after a successful load job.
+
+               EXPORT  xload_done
+xload_done     ROUT
+
+               MOVS    PC,R14                  ;Nothing to do here
+
+; --- xload_failed ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     --
+;
+; Use:         Tidies up a RAM transfer after an error.
+
+               EXPORT  xload_failed
+xload_failed   ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  xload__wSpace           ;Find my workspace
+               LDR     R14,xload__flags        ;Load my flags word
+               TST     R14,#xlFlag__ramTran    ;Are we using RAM transfer?
+               LDMEQFD R13!,{R12,PC}^          ;No -- return right now then
+
+               ; --- Find out if the user has seen the error yet ---
+
+               STMFD   R13!,{R0}               ;Save some more registers
+               TST     R14,#xlFlag__error      ;Has he seen the error?
+               BNE     %30xload_failed         ;Yes -- then don't switch
+
+               ; --- Get xload__write to return an error ---
+
+               ORR     R14,R14,#xlFlag__error  ;Set the error flag
+               STR     R0,xload__error         ;And save the error pointer
+               BL      xload__resume           ;Let the coroutine run a bit
+
+               ; --- Now tidy everything up ---
+               ;
+               ; The coroutine should have killed itself by now
+
+30xload_failed BL      xload__loseBuff         ;Kill off the data buffer
+               LDMFD   R13!,{R0,R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- xload__resume ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Lets the coroutine run for a bit.
+
+xload__resume  ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R0,xload__coRout        ;Load the coroutine handle
+               CMP     R0,#0                   ;Has it finished yet?
+               BLNE    coRout_switch           ;No -- run it a bit more then
+               LDMNEFD R13!,{R0,R1,PC}^        ;And return to caller
+
+               LDR     R0,xload__buffer        ;Load the buffer address
+               MOV     R1,#xload__buffSize     ;Get the current buffer size
+               ADR     R14,xload__start        ;Point to load area
+               STMIA   R14,{R0,R1}             ;Save the data in there
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- xload__setBuff ---
+;
+; On entry:    --
+;
+; On exit:     May return an error
+;
+; Use:         Sets up the buffer for a data transfer.
+
+xload__setBuff ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Allocate the buffer memory ---
+
+               MOV     R0,#xload__buffSize     ;Get the buffer size
+               BL      alloc                   ;Try to allocate the buffer
+               BLCS    alloc_error             ;Get an error if it failed
+               BCS     %90xload__setBuff       ;And tidy things up
+
+               ; --- Set up los of variables ---
+
+               ADR     R14,xload__buffer       ;Point at the buffer info
+               MOV     R1,#xload__buffSize     ;No buffer used yet
+               MOV     R2,#0                   ;Start buffer from beginning
+               MOV     R3,#0                   ;No data sent yet either
+               STMIA   R14,{R0-R3}             ;Save these values away
+               LDMFD   R13!,{R0-R3,R14}        ;Restore all the registers
+               BICS    PC,R14,#V_flag          ;And return with V clear
+
+               ; --- Report an error ---
+
+90             ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R3,R14}        ;Restore all the registers
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+; --- xload__loseBuff ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Kills off the buffer.
+
+xload__loseBuff        ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               LDR     R0,xload__buffer        ;Load the buffer address
+               BL      free                    ;Free the buffer
+               LDR     R14,xload__flags        ;Load my current flags word
+               AND     R14,R14,#xlFlag__inited ;Only leave inited flag
+               STR     R14,xload__flags        ;Save the flags back again
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               LTORG
+
+; --- xload_byte ---
+;
+; On entry:    --
+;
+; On exit:     CC if data read OK, and
+;                R0 == byte read
+;              else CC if end-of-file, and
+;                R0 corrupted
+;              May return an error
+;
+; Use:         Reads a byte from the current input.
+
+               EXPORT  xload_byte
+xload_byte     ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R0,R13                  ;Overwrite saved R0
+               MOV     R1,#1                   ;Just read one byte
+               BL      xload_block             ;Read it onto the stack
+               STRVS   R0,[R13,#0]             ;If error, store pointer
+               LDR     R0,[R13],#4             ;Load the byte/error pointer
+               ANDVC   R0,R0,#&FF              ;If byte/EOF, kill other bits
+               LDMFD   R13!,{R1,R2,PC}         ;And return to caller
+
+               LTORG
+
+; --- xload_word ---
+;
+; On entry:    --
+;
+; On exit:     CC if data read OK, and
+;                R0 == word read
+;              else CS if end-of-file and
+;                R0 corrupted
+;              May return an error
+;
+; Use:         Reads a word from the current input.
+
+               EXPORT  xload_word
+xload_word     ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R0,R13                  ;Overwrite saved R0
+               MOV     R1,#4                   ;Just read one word
+               BL      xload_block             ;Read it onto the stack
+               STRVS   R0,[R13,#0]             ;If error, store pointer
+               LDR     R0,[R13],#4             ;Load the byte/error pointer
+               LDMFD   R13!,{R1,R2,PC}         ;And return to caller
+
+               LTORG
+
+; --- xload_block ---
+;
+; On entry:    R0 == pointer to buffer to read
+;              R1 == size of buffer to read
+;
+; On exit:     R0, R1 preserved
+;              R2 == number of bytes read
+;              CC if more data available, CS for end-of-file
+;              May return an error
+;
+; Use:         Reads in a block of data.  Data is buffered, so this is
+;              fairly quick for reading small objects.  Large data blocks
+;              are read directly to avoid buffering overhead.
+
+               EXPORT  xload_block
+xload_block    ROUT
+
+               CMP     R1,#0                   ;Is there anything there?
+               MOVEQ   R2,#0                   ;Nothing read yet
+               BICEQS  PC,R14,#V_flag          ;No -- return with no error
+
+               STMFD   R13!,{R0,R1,R3-R8,R12,R14} ;Save a load of registers
+               WSPACE  xload__wSpace           ;Load my workspace address
+               MOV     R6,R0                   ;Keep his buffer address
+               MOV     R7,R1                   ;Look after his buffer size
+               MOV     R8,#0                   ;No data copied yet
+
+               ; --- First, try to read from the buffer ---
+
+               ADR     R14,xload__buffer       ;Point to the buff info
+               LDMIA   R14,{R3-R5}             ;Load the buffer stuff
+00xload_block  SUBS    R14,R4,R5               ;Find out how much there is
+               BEQ     %20xload_block          ;No -- skip ahead then
+
+               ; --- Read as much as we need from buffer ---
+
+               CMP     R7,R14                  ;Is there enough there?
+               MOVLT   R2,R7                   ;Yes -- get as much as we can
+               MOVGE   R2,R14                  ;Otherwise empty the buffer
+               ADD     R1,R3,R5                ;Get the correct address
+               MOV     R0,R6                   ;Point at his buffer
+               BL      fastMove                ;Copy the data across nicely
+
+               ; --- Reset the buffer arguments ---
+
+               ADD     R5,R5,R2                ;Add on the offset now
+               ADD     R6,R6,R2                ;Bump up his buffer address
+               SUBS    R7,R7,R2                ;And decrease the size
+               ADD     R8,R8,R2                ;Bump amount of data read
+               BEQ     %90xload_block          ;If no more to do, return
+
+               ; --- Buffer was empty ---
+               ;
+               ; If he wants more than a buffer full, we should just read
+               ; directly into his buffer.  Otherwise we fill the buffer
+               ; and loop back again to copy data.
+
+20xload_block  CMP     R7,#xload__buffSize     ;Does he want more?
+               BGE     %50xload_block          ;Yes -- skip ahead then
+
+               MOV     R0,R3                   ;Point to the buffer
+               MOV     R1,#xload__buffSize     ;Get the buffer size
+               BL      xload__read             ;Read data into the buffer
+               BVS     %95xload_block          ;If it failed, return error
+               MOVS    R4,R2                   ;Get the new buffer size
+               MOV     R5,#0                   ;Haven't started on it yet
+               BNE     %00xload_block          ;If anything read, go round
+               B       %90xload_block          ;Otherwise we'd better stop
+
+               ; --- Read data into his big buffer ---
+
+50xload_block  MOV     R0,R6                   ;Point to his buffer
+               MOV     R1,R7                   ;And get his buffer size
+               BL      xload__read             ;Read data into the buffer
+               BVS     %95xload_block          ;If it failed, return error
+               ADD     R8,R8,R2                ;Bump by amount read
+
+               ; --- Everything went OK ---
+
+90xload_block  ADR     R14,xload__buffUsed     ;Point to the buff info
+               STMIA   R14,{R4,R5}             ;Store new offsets
+               MOV     R2,R8                   ;Get amount of data read
+
+               LDR     R14,xload__total        ;Load the total data read
+               ADD     R14,R14,R8              ;Add new amount read
+               STR     R14,xload__total        ;And save back the new total
+
+               LDR     R14,xload__flags        ;Load the flags word
+               LDR     R1,[R13,#4]             ;Load amount he wanted
+               CMP     R1,R2                   ;Did we read it all?
+               ORRGT   R14,R14,#xlFlag__finish ;No -- set eof flag then
+               STRGT   R14,xload__flags        ;Save the flags back
+
+               LDMFD   R13!,{R0,R1,R3-R8,R12,R14} ;Unstack loads of regs
+               BIC     R14,R14,#V_flag         ;Clear error indicator
+               ORRGTS  PC,R14,#C_flag          ;Set Carry on exit if EOF
+               BICLES  PC,R14,#C_flag          ;Otherwise clear it
+
+               ; --- We had an error ---
+
+95xload_block  ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1,R3-R8,R12,R14} ;Unstack loads of regs
+               ORRS    PC,R14,#V_flag          ;Return the error condition
+
+               LTORG
+
+; --- xload__read ---
+;
+; On entry:    R0 == pointer to buffer to read
+;              R1 == size of buffer to read
+;
+; On exit:     May return an error
+;              R2 == actual amount of data read
+;
+; Use:         Reads a block of data from the input stream.
+
+xload__read    ROUT
+
+               BIC     R14,R14,#V_flag         ;Clear error indicator
+               MOV     R2,#0                   ;Nothing read yet
+               CMP     R1,#0                   ;Is there anything there?
+               MOVEQS  PC,R14                  ;No -- return with no error
+
+               STMFD   R13!,{R14}              ;Save some registers
+               LDR     R14,xload__flags        ;Find my flags word
+               TST     R14,#xlFlag__finish     ;Is the transfer over?
+               LDMNEFD R13!,{PC}^              ;Yes -- return right now
+               TST     R14,#xlFlag__ramTran    ;Am I using RAM transfer?
+               BNE     %50xload__read          ;Yes -- do that then
+
+               ; --- Use OS_HeebieJeebie to read the data ---
+
+               STMFD   R13!,{R0,R1,R3,R4}      ;Save some more registers
+               MOV     R2,R0                   ;Point to the user's buffer
+               MOV     R3,R1                   ;And get the buffer size
+               LDR     R1,xload__file          ;Get the file's handle
+               MOV     R0,#4                   ;Read at current position
+               SWI     XOS_GBPB                ;Read the data in nicely
+               STRVS   R0,[R13,#0]             ;If error, save error ptr
+               LDRVC   R1,[R13,#4]             ;Load number of bytes wanted
+               SUBVC   R2,R1,R3                ;Get number actually read
+               LDMFD   R13!,{R0,R1,R3,R4,R14}  ;Unstack the registers
+               ORRVSS  PC,R14,#V_flag          ;Return V set as required
+               BICVCS  PC,R14,#V_flag
+
+               ; --- Get the main coroutine to read the buffer ---
+
+50xload__read  STMFD   R13!,{R0}               ;Save another register
+               ADR     R14,xload__start        ;Point to the buffer info
+               STMIA   R14,{R0,R1}             ;Save for main coroutine
+               MOV     R0,#0                   ;Get magic coroutine handle
+               BL      coRout_switch           ;And switch to main code
+               LDR     R2,xload__length        ;Read data size read
+               LDR     R14,xload__flags        ;Reload the flags
+               TST     R14,#xlFlag__error      ;Was there a problem?
+               LDMFD   R13!,{R0,R14}           ;Restore the registers
+               BICEQS  PC,R14,#V_flag          ;No -- just clear V then
+               LDRNE   R0,xload__error         ;Otherwise load error pointer
+               ORRNES  PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+xload__wSpace  DCD     0
+
+;----- Constants ------------------------------------------------------------
+
+xload__buffSize        EQU     1024                    ;1K buffer should be enough
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+xload__wStart  #       0
+
+xload__flags   #       4                       ;Various run-time flags
+xload__coRout  #       0                       ;The load coroutine handle
+xload__file    #       4                       ;The load file handle
+xload__buffer  #       4                       ;Pointer to my 1K buffer
+xload__buffUsed        #       4                       ;Amount of data in buffer
+xload__buffOff #       4                       ;Offset reading from buffer
+xload__total   #       4                       ;How much data read so far
+xload__error   #       0                       ;Error pointer from corout
+xload__start   #       4                       ;Start of buffer to send
+xload__length  #       4                       ;Size of next buffer to send
+xload__rammed  #       4                       ;Data RAMFetched so far
+
+xload__wSize   EQU     {VAR}-xload__wStart
+
+xlFlag__inited EQU     (1<<0)                  ;Are we initialised already?
+xlFlag__ramTran        EQU     (1<<1)                  ;Are we doing RAM transfer?
+xlFlag__finish EQU     (1<<2)                  ;This is the very last block
+xlFlag__error  EQU     (1<<3)                  ;Should return an error
+xlFlag__started        EQU     (1<<4)                  ;Coroutine has started
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     xload__wSize
+               DCD     xload__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Sapphire/xfer/s/xsave b/StraySrc/Libraries/Sapphire/xfer/s/xsave
new file mode 100644 (file)
index 0000000..f6571c6
--- /dev/null
@@ -0,0 +1,628 @@
+;
+; xfer.xsave.s
+;
+; Simplified saving with coroutines (MDW)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:coRoutine
+               GET     sapphire:fastMove
+               GET     sapphire:sapphire
+
+;----- How it all works -----------------------------------------------------
+;
+; xsave attempts to unify the two saving routines you have to give (the saver
+; and the sender) and provide the same interface to both.  For data sending
+; through RAM transfer, this has to be done using coroutines, but this is
+; fairly invisible to you.
+;
+; There are two main routines, xsave_save and xsave_send which start save
+; jobs.  They take a pointer to a save routine with R10 and R12 pointers.
+; xsave_save also takes a pointer to a filename.  The actual save routine
+; should be the same for both.
+;
+; Saving of data is done with the call xsave_block.  This just writes out
+; a block of data somehow.  All the other routines are special interfaces to
+; xsave_block.
+
+;----- How the error handling works -----------------------------------------
+;
+; The really tricky bit is passing of errors during a RAM transfer.
+; Errors can be returned at two places -- in the user code (e.g. running out
+; of memory) and by save's cunning message handling if the receiver dies.
+; All errors must be handled by user code, to release claimed memory etc.
+;
+; The error gets passed along a path like this:
+;
+; Error created by user code
+;
+; user code --> xsave__startCo --> xsave_failed
+;
+; Error created by remote receiver
+;
+; xsave_failed --> xsave__write --> user code --> xsave__startCo
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- xsave_save ---
+;
+; On entry:    R0 == pointer to saver routine
+;              R1 == R10 value to pass to saver
+;              R2 == R12 value to pass to saver
+;              R3 == pointer to filename to save to
+;              R4 == filetype of file to save
+;
+; On exit:     May return an error
+;
+; Use:         Calls a generalised saver routine to write data to a file.
+
+               EXPORT  xsave_save
+xsave_save     ROUT
+
+               STMFD   R13!,{R0-R5,R10,R12,R14} ;Save lots of registers
+               WSPACE  xsave__wSpace           ;Find my workspace address
+
+               ; --- First, try to allocate a buffer ---
+
+               BL      xsave__setBuff          ;Allocate the buffer nicely
+               BVS     %99xsave_save           ;If we couldn't, tidy up
+
+               ; --- Set up the file for writing ---
+
+               MOV     R1,R3                   ;Point at the file name
+               MOV     R0,#&8F                 ;Lots of errors, no path
+               SWI     XOS_Find                ;Try to open the file
+               BVS     %98xsave_save           ;Tidy up if it wouldn't open
+               STR     R0,xsave__file          ;Save the file handle away
+
+               ; --- Set up flags and let rip ---
+
+               LDR     R14,xsave__flags        ;Load my current flags word
+               AND     R14,R14,#xsFlag__inited ;Only leave inited flag
+               STR     R14,xsave__flags        ;Save the flags back again
+
+               LDMIA   R13,{R0,R10,R12}        ;Load the arguments out
+               ADDS    R0,R0,#0                ;Clear overflow and carry
+               MOV     R14,PC                  ;Set up the return address
+               MOV     PC,R0                   ;And call the saver routine
+               WSPACE  xsave__wSpace           ;Restore my workspace ptr
+               BVS     %97xsave_save           ;Tidy up if it failed
+
+               ; --- Write the remainder of the file ---
+
+               ADR     R14,xsave__buffer       ;Point to the buffer info
+               LDMIA   R14,{R0,R1}             ;Load buffer addr and size
+               BL      xsave__write            ;Write it out to the file
+               BVS     %97xsave_save           ;Tidy up if it failed
+
+               ; --- Close the file and set the filetype ---
+
+               MOV     R0,#0                   ;Close an open file
+               LDR     R1,xsave__file          ;Get the file handle ready
+               SWI     OS_Find                 ;Close it
+
+               MOV     R0,#18                  ;Set file type
+               MOV     R1,R3                   ;Point to the filename
+               MOV     R2,R4                   ;And get the filetype
+               SWI     OS_File                 ;And set the filetype
+
+               ; --- Get rid of the buffer and return ---
+
+               BL      xsave__loseBuff         ;Free up the buffer space
+               LDMFD   R13!,{R0-R5,R10,R12,R14} ;Unstack all the registers
+               BICS    PC,R14,#V_flag          ;And return to caller
+
+               ; --- Tidy up after various catastrophes ---
+
+97xsave_save   MOV     R10,R0                  ;Keep the error pointer
+               MOV     R0,#0                   ;Close an open file
+               LDR     R1,xsave__file          ;Get the file handle ready
+               SWI     OS_Find                 ;Close it
+               MOV     R0,#6                   ;Delete the file now
+               MOV     R1,R3                   ;Point to the filename
+               SWI     XOS_File                ;Delete it as much as we can
+               MOV     R0,R10                  ;Restore the error pointer
+
+98xsave_save   BL      xsave__loseBuff         ;Free up the buffer space
+
+99xsave_save   ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R5,R10,R12,R14} ;Unstack all the registers
+               ORRS    PC,R14,#V_flag          ;And return to caller
+
+; --- xsave_send ---
+;
+; On entry:    R0 == pointer to saver routine
+;              R1 == R10 value to pass to saver
+;              R2 == R12 value to pass to saver
+;
+; On exit:     R0 == pointer to block to send
+;              R1 == size of block
+;              CS if this is the last block, else CC
+;              May return an error
+;
+; Use:         Calls a generalised saver routine to write data to another
+;              application, using RAM transfer.  Note that you must call
+;              this routine from your send entry point throughout the
+;              save operation.
+
+               EXPORT  xsave_send
+xsave_send     ROUT
+
+               STMFD   R13!,{R0-R4,R12,R14}    ;Save some registers away
+               WSPACE  xsave__wSpace           ;Find my workspace address
+
+               ; --- Find out if we need to set anything up ---
+
+               LDR     R14,xsave__flags        ;Load my flags word
+               TST     R14,#xsFlag__ramTran    ;Are we doing RAM transfer?
+               BNE     %50xsave_send           ;Yes -- continue te job then
+
+               ; --- Clear all the flags for now ---
+
+               AND     R4,R14,#xsFlag__inited  ;Leave only `initialised'
+               STR     R4,xsave__flags         ;And save these flags back
+
+               ; --- Set things up for RAM transfer ---
+
+               BL      xsave__setBuff          ;Set up my buffer nicely
+               BVS     %99xsave_send           ;If it failed, tidy up
+
+               ADR     R0,xsave__startCo       ;Point to my coroutine
+               MOV     R1,R13                  ;Point R10 at the stack
+               MOV     R2,R12                  ;Pass workspace in R12
+               MOV     R3,#0                   ;Use a default stack
+               BL      coRout_create           ;Create a coroutine
+               BVS     %98xsave_send           ;If it failed, tidy up
+               STR     R0,xsave__coRout        ;Save the coroutine handle
+
+               ; --- Set up the flags properly now ---
+
+               ORR     R4,R4,#xsFlag__ramTran  ;Say we're RAM transfering
+               STR     R4,xsave__flags         ;And save these flags back
+
+               ; --- Get some more data to send ---
+
+50xsave_send   LDR     R0,xsave__coRout        ;Get the coroutine handle
+               BL      coRout_switch           ;Switch to it for a bit
+
+               LDR     R14,xsave__flags        ;Get the newly updated flags
+               TST     R14,#xsFlag__error      ;Was there an error?
+               LDRNE   R0,xsave__error         ;Yes -- load the error ptr
+               BNE     %99xsave_send           ;And tidy everything up
+
+               ; --- Get the returned block ---
+
+               ADR     R0,xsave__start         ;Point to the block info
+               LDMIA   R0,{R0,R1}              ;Load the start and length
+               TST     R14,#xsFlag__finish     ;Has the transfer finished?
+               ADD     R13,R13,#8              ;Don't restore R0,R1
+               LDMFD   R13!,{R2-R4,R12,R14}    ;Unstack lots of registers
+               ORRNES  PC,R14,#C_flag          ;If finished, set C flag
+               BICEQS  PC,R14,#C_flag          ;Otherwise say more to come
+
+               ; --- Handle errors from various things ---
+
+98xsave_send   BL      xsave__loseBuff         ;Close the buffer
+
+99xsave_send   ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R4,R12,R14}    ;Unstack lots of registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- xsave__startCo ---
+;
+; On entry:    R0 == my coroutine handle
+;              R10 == pointer to block containing (routine,R10,R12)
+;              R12 == my workspace
+;
+; On exit:     Returns through coRout_end
+;
+; Use:         Starts the coroutine for sending data by RAM transfer.  It
+;              handles errors reported by it, and terminates the transfer
+;              properly.
+
+xsave__startCo ROUT
+
+               LDMIA   R10,{R0,R10,R12}        ;Load the caller's registers
+               MOV     R14,PC                  ;Set up a return address
+               MOV     PC,R0                   ;And call the saver routine
+
+               ; --- Handle its return values ---
+
+               WSPACE  xsave__wSpace           ;Locate my workspace address
+               LDR     R14,xsave__flags        ;Load the flags word
+               BVS     %90xsave__startCo       ;If error, handle it nicely
+
+               ; --- Just return the current buffer state ---
+
+               ORR     R14,R14,#xsFlag__finish ;Set the finished flag
+               STR     R14,xsave__flags        ;Save the flags back again
+               ADR     R14,xsave__buffer       ;Point to the buffer info
+               LDMIA   R14,{R0,R1}             ;Load the start and size info
+               ADR     R14,xsave__start        ;Point to return information
+               STMIA   R14,{R0,R1}             ;Save this to be sent next
+               B       coRout_end              ;And terminate the coroutine
+
+90             ORR     R14,R14,#xsFlag__error  ;Set the main error flag
+               STR     R14,xsave__flags        ;Save the flags back again
+               STR     R0,xsave__error         ;And save the error pointer
+               B       coRout_end              ;And finish the coroutine
+
+               LTORG
+
+; --- xsave_done ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Tidies up after a successful save job.
+
+               EXPORT  xsave_done
+xsave_done     ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  xsave__wSpace           ;Find my workspace
+               LDR     R14,xsave__flags        ;Load my flags word
+               TST     R14,#xsFlag__ramTran    ;Are we using RAM transfer?
+               BLNE    xsave__loseBuff         ;Yes -- destroy the buffer
+               LDMFD   R13!,{R12,PC}^          ;Return to caller
+
+               LTORG
+
+; --- xsave_failed ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     --
+;
+; Use:         Tidies up a RAM transfer after an error.
+
+               EXPORT  xsave_failed
+xsave_failed   ROUT
+
+               STMFD   R13!,{R12,R14}          ;Save some registers
+               WSPACE  xsave__wSpace           ;Find my workspace
+               LDR     R14,xsave__flags        ;Load my flags word
+               TST     R14,#xsFlag__ramTran    ;Are we using RAM transfer?
+               LDMEQFD R13!,{R12,PC}^          ;No -- return right now then
+
+               ; --- Find out if the user has seen the error yet ---
+               ;
+               ; We also don't want to inform the user if the save is
+               ; complete -- his coroutine will already be destroyed.
+
+               STMFD   R13!,{R0}               ;Save some more registers
+               TST     R14,#xsFlag__finish :OR: xsFlag__error
+               BNE     %30xsave_failed         ;Yes -- then don't switch
+
+               ; --- Get xsave__write to return an error ---
+
+               ORR     R14,R14,#xsFlag__error  ;Set the error flag
+               STR     R0,xsave__error         ;And save the error pointer
+               LDR     R0,xsave__coRout        ;Load the coroutine handle
+               BL      coRout_switch           ;And switch to it
+
+               ; --- Now tidy everything up ---
+               ;
+               ; The coroutine should have killed itself by now
+
+30xsave_failed BL      xsave__loseBuff         ;Kill off the data buffer
+               LDMFD   R13!,{R0,R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- xsave__setBuff ---
+;
+; On entry:    --
+;
+; On exit:     May return an error
+;
+; Use:         Sets up the buffer for a data transfer.
+
+xsave__setBuff ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Allocate the buffer memory ---
+
+               MOV     R0,#xsave__buffSize     ;Get the buffer size
+               BL      alloc                   ;Try to allocate the buffer
+               BLCS    alloc_error             ;Get an error if it failed
+               BCS     %90xsave__setBuff       ;And tidy things up
+
+               ; --- Set up los of variables ---
+
+               ADR     R14,xsave__buffer       ;Point at the buffer info
+               MOV     R1,#0                   ;No buffer used yet
+               MOV     R2,#0                   ;No data sent yet either
+               STMIA   R14,{R0-R2}             ;Save these values away
+               LDMFD   R13!,{R0-R2,R14}        ;Restore all the registers
+               BICS    PC,R14,#V_flag          ;And return with V clear
+
+               ; --- Report an error ---
+
+90             ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1,R2,R14}        ;Restore all the registers
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+; --- xsave__loseBuff ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Kills off the buffer.
+
+xsave__loseBuff        ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               LDR     R0,xsave__buffer        ;Load the buffer address
+               BL      free                    ;Free the buffer
+               LDR     R14,xsave__flags        ;Load my current flags word
+               AND     R14,R14,#xsFlag__inited ;Only leave inited flag
+               STR     R14,xsave__flags        ;Save the flags back again
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               LTORG
+
+; --- xsave_byte ---
+;
+; On entry:    R0 == byte to write in lowest 8 bits
+;
+; On exit:     May return an error
+;
+; Use:         Writes a single byte to the current output.
+
+               EXPORT  xsave_byte
+xsave_byte     ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               MOV     R0,R13                  ;Point to saved byte
+               MOV     R1,#1                   ;Just write one byte
+               BL      xsave_block             ;Send it to the output
+               STRVS   R0,[R13,#0]             ;Save any error pointers
+               LDMFD   R13!,{R0,R1,PC}         ;And return to caller
+
+               LTORG
+
+; --- xsave_word ---
+;
+; On entry:    R0 == word to write
+;
+; On exit:     May return an error
+;
+; Use:         Writes a single word to the current output.
+
+               EXPORT  xsave_word
+xsave_word     ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               MOV     R0,R13                  ;Point to saved word
+               MOV     R1,#4                   ;Just write one word
+               BL      xsave_block             ;Send it to the output
+               STRVS   R0,[R13,#0]             ;Save any error pointers
+               LDMFD   R13!,{R0,R1,PC}         ;And return to caller
+
+               LTORG
+
+; --- xsave_string ---
+;
+; On entry:    R0 == pointer to a control-terminated string
+;
+; On exit:     May return an error
+;
+; Use:         Writes a control-terminated string to the current output.
+;              The string is null terminated in the output file.
+
+               EXPORT  xsave_string
+xsave_string   ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+00xsave_string LDRB    R14,[R0],#1             ;Load a byte from the string
+               CMP     R14,#32                 ;Is it a control character?
+               MOVLO   R14,#0                  ;Yes -- make it a zero then
+               BL      xsave_byte              ;Write it out
+               BVS     %90xsave_string         ;If it failed, return error
+               BHS     %00xsave_string         ;Otherwise go round again
+               LDMFD   R13!,{R0,R14}           ;Restore the registers
+               BICS    PC,R14,#V_flag          ;And don't return an error
+
+90xsave_string ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R14}              ;Restore the link register
+               ORRS    PC,R14,#V_flag          ;And return an error
+
+               LTORG
+
+; --- xsave_block ---
+;
+; On entry:    R0 == pointer to buffer to write
+;              R1 == size of buffer to write
+;
+; On exit:     May return an error
+;
+; Use:         Writes out a block of data.  Data is buffered, so this is
+;              fairly quick for reading small objects.  Large data blocks
+;              are sent directly to avoid buffering overhead.
+
+               EXPORT  xsave_block
+xsave_block    ROUT
+
+               CMP     R1,#0                   ;Is there anything there?
+               BICEQS  PC,R14,#V_flag          ;No -- return with no error
+
+               STMFD   R13!,{R0-R4,R12,R14}    ;Save a load of registers
+               WSPACE  xsave__wSpace           ;Load my workspace address
+
+               ; --- Fix up the total data sent ---
+
+               LDR     R14,xsave__total        ;Load the total sent so far
+               ADD     R14,R14,R1              ;Add on the size of this one
+               STR     R14,xsave__total        ;And save the total back
+
+               ; --- Work out what we have to do ---
+
+               CMP     R1,#xsave__buffSize     ;Is the block really big?
+               BGE     %50xsave_block          ;Yes -- then deal with that
+
+               ; --- Write as much as possible to the buffer ---
+
+               ADR     R14,xsave__buffer       ;Point to buffer data
+               LDMIA   R14,{R2,R3}             ;Load address and size
+               RSB     R4,R3,#xsave__buffSize  ;How much is free in there?
+               CMP     R1,R4                   ;Is there enough space?
+               BLT     %30xsave_block          ;Yes -- just add some more
+
+               ; --- Fill the buffer right up now ---
+
+               MOV     R1,R0                   ;Point to the new block
+               ADD     R0,R2,R3                ;Point to free part of buffer
+               MOV     R2,R4                   ;And get the size to copy
+               BL      fastMove                ;Copy it all over then
+               LDR     R0,xsave__buffer        ;Point to the buffer
+               MOV     R1,#xsave__buffSize     ;And get its full size
+               BL      xsave__write            ;Write a bufferfull out
+               BVS     %99xsave_block          ;Handle an error from this
+
+               ; --- Fix up all the pointers ---
+
+               LDMIA   R13,{R0,R1}             ;Reload the buffer addresses
+               ADD     R0,R0,R2                ;Move on the block pointer
+               SUB     R1,R1,R2                ;And chop off correctly
+               LDR     R2,xsave__buffer        ;Point to the buffer start
+               MOV     R3,#0                   ;And now it's empty
+
+               ; --- Just top up the buffer then ---
+
+30xsave_block  MOV     R14,R0                  ;Point to client's buffer
+               ADD     R0,R2,R3                ;Point to free part of buff
+               MOVS    R2,R1                   ;Get the block size to copy
+               MOV     R1,R14                  ;Set up source pointer now
+               BLNE    fastMove                ;Do the copy job now
+               ADD     R3,R3,R2                ;Add on the block size
+               STR     R3,xsave__buffUsed      ;Save the new buffer size
+               B       %90xsave_block          ;And finish it all up
+
+               ; --- Send a really big block ---
+
+50xsave_block  ADR     R14,xsave__buffer       ;Point to buffer info
+               LDMIA   R14,{R0,R1}             ;Load the buffer stuff
+               BL      xsave__write            ;Write it all out
+               BVS     %99xsave_block          ;Handle an error from this
+               MOV     R14,#0                  ;Nothing left there now
+               STR     R14,xsave__buffUsed     ;So clear the buffer size
+               LDMIA   R13,{R0,R1}             ;Get caller's block size
+               BL      xsave__write            ;Write it out nicely
+               BVS     %99xsave_block          ;Handle an error from this
+
+90xsave_block  LDMFD   R13!,{R0-R4,R12,R14}    ;Restore all the registers
+               BICS    PC,R14,#V_flag          ;And return no errors
+
+99xsave_block  ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R4,R12,R14}    ;Restore all the registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- xsave__write ---
+;
+; On entry:    R0 == pointer to buffer to write
+;              R1 == size of buffer to write
+;
+; On exit:     May return an error
+;
+; Use:         Writes a block of data to the file or application.  This is
+;              one of the few bits of save/send dependent code in the
+;              module.
+
+xsave__write   ROUT
+
+               CMP     R1,#0                   ;Is there anything there?
+               BICEQS  PC,R14,#V_flag          ;No -- return with no error
+
+               STMFD   R13!,{R14}              ;Save some registers
+               LDR     R14,xsave__flags        ;Find my flags word
+               TST     R14,#xsFlag__ramTran    ;Am I using RAM transfer?
+               BNE     %50xsave__write         ;Yes -- do that then
+
+               ; --- Use OS_HeebieJeebie to send the data ---
+
+               STMFD   R13!,{R0-R4}            ;Save some more registers
+               MOV     R2,R0                   ;Point to the user's buffer
+               MOV     R3,R1                   ;And get the buffer size
+               LDR     R1,xsave__file          ;Get the file's handle
+               MOV     R0,#2                   ;Write at current position
+               SWI     XOS_GBPB                ;Write the data out nicely
+               STRVS   R0,[R13,#0]             ;If error, save error pointer
+               LDMFD   R13!,{R0-R4,R14}        ;Unstack the registers
+               ORRVSS  PC,R14,#V_flag          ;Return V set as required
+               BICVCS  PC,R14,#V_flag
+
+               ; --- Get the main coroutine to send the buffer ---
+
+50xsave__write STMFD   R13!,{R0}               ;Save another register
+               ADR     R14,xsave__start        ;Point to the buffer info
+               STMIA   R14,{R0,R1}             ;Save for main coroutine
+               MOV     R0,#0                   ;Get magic coroutine handle
+               BL      coRout_switch           ;And switch to main code
+               LDR     R14,xsave__flags        ;Reload the flags
+               TST     R14,#xsFlag__error      ;Was there a problem?
+               LDMFD   R13!,{R0,R14}           ;Restore the registers
+               BICEQS  PC,R14,#V_flag          ;No -- just clear V then
+               LDRNE   R0,xsave__error         ;Otherwise load error pointer
+               ORRNES  PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+xsave__wSpace  DCD     0
+
+;----- Constants ------------------------------------------------------------
+
+xsave__buffSize        EQU     1024                    ;1K buffer should be enough
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+xsave__wStart  #       0
+
+xsave__flags   #       4                       ;Various run-time flags
+xsave__coRout  #       0                       ;The send coroutine handle
+xsave__file    #       4                       ;The save file handle
+xsave__buffer  #       4                       ;Pointer to my 1K buffer
+xsave__buffUsed        #       4                       ;Amount of data in buffer
+xsave__total   #       4                       ;How much data sent so far
+xsave__error   #       0                       ;Error pointer from corout
+xsave__start   #       4                       ;Start of buffer to send
+xsave__length  #       4                       ;Size of next buffer to send
+
+xsave__wSize   EQU     {VAR}-xsave__wStart
+
+xsFlag__inited EQU     (1<<0)                  ;Are we initialised already?
+xsFlag__ramTran        EQU     (1<<1)                  ;Are we doing RAM transfer?
+xsFlag__finish EQU     (1<<2)                  ;This is the very last block
+xsFlag__error  EQU     (1<<3)                  ;Should return an error
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     xsave__wSize
+               DCD     xsave__wSpace
+               DCD     0
+               DCD     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Steel/Makefile,fe1 b/StraySrc/Libraries/Steel/Makefile,fe1
new file mode 100644 (file)
index 0000000..b8a7f88
--- /dev/null
@@ -0,0 +1,1853 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Jlibs: -JC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .do .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.c.do:
+       $(COMPILE) -zM -D_DLL $<
+.s.do:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+# --- Maintenance note ---
+#
+# The list of object files is duplicated.  I don't really care, because I'm
+# not expecting to have to fiddle with anything here.  If you want anything
+# changing, do it yourself.  That's what Free software is about.
+
+# --- Dynamic library components ---
+
+DLLOBJ = \
+       do.bbc do.colourtran do.font do.interface do.os do.print \
+               do.sculptrix do.sprite do.wimpext do.wimp_dll \
+       do.buffer do.calltrace do.exception do.utils do.vsscanf \
+       do.akbd do.coords do.keystring \
+       do.alarm do.blinkc do.caretptr do.pointer do.visdelay \
+       do.event do.help do.pane do.wimpt do.win \
+       do.baricon do.ibicon do.listbox do.viewer \
+       do.buttons do.dbox do.fileicon do.nopoll do.saveas \
+               do.stddbox do.tcol do.werr \
+       do.choices do.prefs \
+       do.creator do.fontmenu do.menu do.tearoff libs:tearsupt.o.tearsupt \
+       do.msgs do.res do.resspr do.template \
+       do.fastMove do.flex_dll do.heap_dll do.mem \
+       do.xferrecv do.xfersend
+
+# --- Static library components ---
+
+STATOBJ = \
+       o.bbc o.colourtran o.font o.interface o.os o.print \
+               o.sculptrix o.sprite o.wimpext o.wimp_stat \
+       o.buffer o.calltrace o.exception o.utils o.vsscanf \
+       o.akbd o.coords o.keystring \
+       o.alarm o.blinkc o.caretptr o.pointer o.visdelay \
+       o.event o.help o.pane o.wimpt o.win \
+       o.baricon o.ibicon o.listbox o.viewer \
+       o.buttons o.dbox o.fileicon o.nopoll o.saveas \
+               o.stddbox o.tcol o.werr \
+       o.choices o.prefs \
+       o.crc o.crc32 \
+       o.creator o.fontmenu o.menu o.tearoff libs:tearsupt.o.tearsupt \
+       o.scroller o.xproginfo \
+       o.msgs o.res o.resspr o.template \
+       o.fastMove o.flex_stat o.heap_stat o.mem \
+       o.xferrecv o.xfersend
+
+#----- Interface targets ----------------------------------------------------
+
+# --- Main target ---
+
+all: dll.Steel lib.steel lib.steeldll
+
+# --- Installing the libraries ---
+
+install: dll.Steel
+       cdir <SSR$DLLDir>.Straylight
+       $(INSTALL) dll.Steel <SSR$DLLDir>.Straylight
+
+# --- Cleansing the build tree ---
+
+clean:
+       -$(RM) o.* do.* lib.* dll.* dl.* ds.*
+
+#----- Building the libraries -----------------------------------------------
+
+# --- Static library ---
+
+lib.steel: $(STATOBJ)
+       test -file lib.steel -exists -else "$(AR) -c lib.steel"
+       $(AR) -i lib.steel $?
+
+# --- Dynamic library ---
+
+do.steel: $(DLLOBJ)
+       test -file do.steel -exists -else "$(AR) -c do.steel"
+       $(AR) -i do.steel $?
+
+lib.steeldll: ds.steel
+       $(AR) -c lib.steeldll ds.steel
+
+dh.steel ds.steel: def.steel do.steel
+       $(CDLL) def.steel ds.steel dh.steel
+
+DLL_LDADD = libs:o.swiv libs:o.dstubs libs:o.dlllib
+dll.steel: dh.steel do.steel $(DLL_LDADD)
+       $(LD_DLL) dh.steel do.steel $(DLL_LDADD)
+       $(SET_DLL)
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.bbc: s.bbc
+o.bbc: libs:header
+o.bbc: libs:swis
+o.colourtran: s.colourtran
+o.colourtran: libs:header
+o.colourtran: libs:swis
+o.font:        c.font
+o.font:        C:h.stddef
+o.font:        h.os
+o.font:        C:h.kernel
+o.font:        C:h.trace
+o.font:        h.font
+o.font:        C:h.drawmod
+o.interface:   c.interface
+o.interface:   libs:h.stdio
+o.interface:   libs:h.swiv
+o.interface:   C:h.kernel
+o.interface:   h.os
+o.interface:   h.wimp
+o.interface:   h.wimpstruct
+o.interface:   h.sprite
+o.interface:   libs:h.swis
+o.interface:   h.pointer
+o.interface:   h.interface
+o.interface:   h.visdelay
+o.os: s.os
+o.os: libs:header
+o.os: libs:swis
+o.os: libs:s.swihack
+o.print:       c.print
+o.print:       h.os
+o.print:       C:h.kernel
+o.print:       C:h.print
+o.sculptrix: s.sculptrix
+o.sculptrix: libs:header
+o.sculptrix: libs:swis
+o.sprite:      c.sprite
+o.sprite:      C:h.stddef
+o.sprite:      h.os
+o.sprite:      C:h.kernel
+o.sprite:      h.sprite
+o.wimpext: s.wimpext
+o.wimp_stat: s.wimp_stat
+o.wimp_stat: libs:header
+o.wimp_stat: libs:SWIs
+o.wimp_stat: s.wimp_main
+o.buffer:      c.buffer
+o.buffer:      h.buffer
+o.calltrace: s.calltrace
+o.calltrace: libs:header
+o.calltrace: libs:swis
+o.exception:   c.exception
+o.exception:   C:h.stdarg
+o.exception:   libs:h.stdio
+o.exception:   C:h.stdlib
+o.exception:   h.msgs
+o.exception:   h.exception
+o.exception:   C:h.setjmp
+o.exception:   libs:h.dll
+o.exception:   libs:h.os
+o.exception:   C:h.kernel
+o.exception:   libs:h.wimp
+o.exception:   libs:h.wimpstruct
+o.exception:   libs:h.sprite
+o.exception:   h.wimpt
+o.exception:   h.werr
+o.exception:   h.visdelay
+o.utils:       c.utils
+o.utils:       libs:h.stdio
+o.utils:       C:h.string
+o.utils:       libs:h.ctype
+o.utils:       h.utils
+o.utils:       h.os
+o.utils:       C:h.kernel
+o.utils:       h.os
+o.utils:       h.werr
+o.utils:       h.wimpt
+o.utils:       h.wimp
+o.utils:       h.wimpstruct
+o.utils:       h.sprite
+o.utils:       libs:h.swiv
+o.utils:       libs:h.swis
+o.utils:       h.buffer
+o.vsscanf:     c.vsscanf
+o.vsscanf:     libs:h.stdio
+o.vsscanf:     C:h.stdarg
+o.vsscanf:     C:h.stdlib
+o.vsscanf:     libs:h.ctype
+o.vsscanf:     h.vsscanf
+o.akbd:        c.akbd
+o.akbd:        h.os
+o.akbd:        C:h.kernel
+o.akbd:        h.akbd
+o.akbd:        h.bbc
+o.coords: s.coords
+o.coords: libs:header
+o.keystring:   c.keystring
+o.keystring:   h.akbd
+o.keystring:   h.msgs
+o.keystring:   h.keyString
+o.keystring:   h.buffer
+o.keystring:   C:h.string
+o.keystring:   libs:h.stdio
+o.alarm:       c.alarm
+o.alarm:       h.alarm
+o.alarm:       h.mem
+o.alarm:       h.werr
+o.alarm:       h.msgs
+o.alarm:       h.os
+o.alarm:       C:h.kernel
+o.alarm:       libs:h.swiv
+o.alarm:       libs:h.swis
+o.blinkc:      c.blinkc
+o.blinkc:      h.wimp
+o.blinkc:      h.wimpstruct
+o.blinkc:      h.os
+o.blinkc:      C:h.kernel
+o.blinkc:      h.sprite
+o.blinkc:      h.wimpt
+o.blinkc:      h.os
+o.blinkc:      h.blinkC
+o.blinkc:      h.alarm
+o.blinkc:      libs:h.swiv
+o.blinkc:      C:h.stdlib
+o.blinkc:      libs:h.dll
+o.caretptr:    c.caretptr
+o.caretptr:    libs:h.ctype
+o.caretptr:    h.pointer
+o.caretptr:    h.os
+o.caretptr:    C:h.kernel
+o.caretptr:    h.sprite
+o.caretptr:    h.win
+o.caretptr:    h.wimp
+o.caretptr:    h.wimpstruct
+o.caretptr:    h.wimpt
+o.caretptr:    h.wimp
+o.caretptr:    h.os
+o.caretptr:    h.caretptr
+o.caretptr:    h.resspr
+o.pointer:     c.pointer
+o.pointer:     libs:h.stdio
+o.pointer:     h.os
+o.pointer:     C:h.kernel
+o.pointer:     h.sprite
+o.pointer:     libs:h.swis
+o.pointer:     h.wimpt
+o.pointer:     h.wimp
+o.pointer:     h.wimpstruct
+o.pointer:     h.pointer
+o.visdelay:    c.visdelay
+o.visdelay:    h.visdelay
+o.visdelay:    h.os
+o.visdelay:    C:h.kernel
+o.visdelay:    libs:h.swiv
+o.visdelay:    libs:h.swis
+o.visdelay:    h.wimpt
+o.visdelay:    h.wimp
+o.visdelay:    h.wimpstruct
+o.visdelay:    h.sprite
+o.visdelay:    C:h.stdlib
+o.visdelay:    libs:h.dll
+o.event:       c.event
+o.event:       C:h.stdlib
+o.event:       C:h.string
+o.event:       h.event
+o.event:       h.wimp
+o.event:       h.wimpstruct
+o.event:       h.os
+o.event:       C:h.kernel
+o.event:       h.sprite
+o.event:       h.menu
+o.event:       h.wimpt
+o.event:       h.win
+o.event:       h.menu
+o.event:       h.msgs
+o.event:       h.werr
+o.event:       h.alarm
+o.event:       h.mem
+o.event:       libs:h.swis
+o.event:       h.dbox
+o.help:        c.help
+o.help:        h.wimp
+o.help:        h.wimpstruct
+o.help:        h.os
+o.help:        C:h.kernel
+o.help:        h.sprite
+o.help:        h.wimpt
+o.help:        h.help
+o.help:        h.msgs
+o.help:        h.werr
+o.help:        C:h.string
+o.help:        C:h.stdarg
+o.help:        libs:h.stdio
+o.pane:        c.pane
+o.pane:        h.wimp
+o.pane:        h.wimpstruct
+o.pane:        h.os
+o.pane:        C:h.kernel
+o.pane:        h.sprite
+o.pane:        h.wimpt
+o.pane:        h.pane
+o.pane:        h.listbox
+o.pane:        h.werr
+o.pane:        h.msgs
+o.pane:        h.mem
+o.pane:        h.win
+o.pane:        C:h.stdlib
+o.wimpt:       c.wimpt
+o.wimpt:       libs:h.stdio
+o.wimpt:       C:h.stdlib
+o.wimpt:       C:h.stdarg
+o.wimpt:       C:h.signal
+o.wimpt:       C:h.string
+o.wimpt:       libs:h.dll
+o.wimpt:       libs:h.os
+o.wimpt:       C:h.kernel
+o.wimpt:       libs:h.wimp
+o.wimpt:       libs:h.wimpstruct
+o.wimpt:       libs:h.sprite
+o.wimpt:       libs:h.swis
+o.wimpt:       C:h.kernel
+o.wimpt:       h.os
+o.wimpt:       h.bbc
+o.wimpt:       h.wimp
+o.wimpt:       h.font
+o.wimpt:       C:h.drawmod
+o.wimpt:       h.wimpt
+o.wimpt:       h.wimpt
+o.wimpt:       h.werr
+o.wimpt:       h.alarm
+o.wimpt:       h.event
+o.wimpt:       h.menu
+o.wimpt:       h.flex
+o.wimpt:       h.msgs
+o.wimpt:       h.interface
+o.wimpt:       h.exception
+o.wimpt:       C:h.setjmp
+o.wimpt:       h.mem
+o.wimpt:       h.visdelay
+o.wimpt:       h.caretptr
+o.wimpt:       h.pointer
+o.wimpt:       h.sculptrix
+o.wimpt:       h.resspr
+o.win: c.win
+o.win: C:h.stdarg
+o.win: C:h.stdlib
+o.win: C:h.string
+o.win: libs:h.stdio
+o.win: C:h.trace
+o.win: h.os
+o.win: C:h.kernel
+o.win: h.wimp
+o.win: h.wimpstruct
+o.win: h.sprite
+o.win: h.werr
+o.win: h.wimpt
+o.win: h.event
+o.win: h.menu
+o.win: h.msgs
+o.win: h.mem
+o.win: h.bbc
+o.win: libs:h.swis
+o.win: h.menu
+o.win: h.win
+o.baricon:     c.baricon
+o.baricon:     h.baricon
+o.baricon:     h.ibicon
+o.baricon:     h.sprite
+o.baricon:     h.os
+o.baricon:     C:h.kernel
+o.baricon:     h.wimp
+o.baricon:     h.wimpstruct
+o.baricon:     h.event
+o.baricon:     h.menu
+o.ibicon:      c.ibicon
+o.ibicon:      h.wimp
+o.ibicon:      h.wimpstruct
+o.ibicon:      h.os
+o.ibicon:      C:h.kernel
+o.ibicon:      h.sprite
+o.ibicon:      h.wimpt
+o.ibicon:      h.os
+o.ibicon:      libs:h.swis
+o.ibicon:      h.bbc
+o.ibicon:      h.win
+o.ibicon:      h.werr
+o.ibicon:      h.ibicon
+o.ibicon:      h.event
+o.ibicon:      h.menu
+o.ibicon:      h.msgs
+o.ibicon:      h.event
+o.ibicon:      h.mem
+o.ibicon:      libs:h.swiv
+o.ibicon:      C:h.string
+o.ibicon:      libs:h.stdio
+o.ibicon:      libs:h.dll
+o.listbox:     c.listbox
+o.listbox:     libs:h.stdio
+o.listbox:     C:h.stdlib
+o.listbox:     C:h.string
+o.listbox:     h.wimp
+o.listbox:     h.wimpstruct
+o.listbox:     h.os
+o.listbox:     C:h.kernel
+o.listbox:     h.sprite
+o.listbox:     h.wimpt
+o.listbox:     h.event
+o.listbox:     h.menu
+o.listbox:     h.win
+o.listbox:     h.template
+o.listbox:     h.listbox
+o.listbox:     h.pane
+o.listbox:     h.werr
+o.listbox:     h.msgs
+o.listbox:     h.bbc
+o.listbox:     h.mem
+o.listbox:     h.utils
+o.listbox:     h.help
+o.listbox:     h.visdelay
+o.listbox:     libs:h.dll
+o.viewer:      c.viewer
+o.viewer:      h.wimp
+o.viewer:      h.wimpstruct
+o.viewer:      h.os
+o.viewer:      C:h.kernel
+o.viewer:      h.sprite
+o.viewer:      h.wimpt
+o.viewer:      h.win
+o.viewer:      h.viewer
+o.viewer:      h.menu
+o.viewer:      h.event
+o.viewer:      h.msgs
+o.viewer:      h.bbc
+o.viewer:      h.werr
+o.viewer:      h.os
+o.viewer:      h.xfersend
+o.viewer:      h.mem
+o.viewer:      h.coords
+o.viewer:      h.wimp
+o.viewer:      h.utils
+o.viewer:      h.help
+o.viewer:      h.fileicon
+o.viewer:      h.buffer
+o.viewer:      libs:h.swis
+o.viewer:      C:h.stdlib
+o.viewer:      C:h.string
+o.viewer:      libs:h.stdio
+o.viewer:      libs:h.dll
+o.buttons:     c.buttons
+o.buttons:     h.wimp
+o.buttons:     h.wimpstruct
+o.buttons:     h.os
+o.buttons:     C:h.kernel
+o.buttons:     h.sprite
+o.buttons:     h.wimpt
+o.buttons:     h.buttons
+o.buttons:     h.dbox
+o.buttons:     h.event
+o.buttons:     h.menu
+o.buttons:     h.bbc
+o.buttons:     h.win
+o.buttons:     h.werr
+o.buttons:     libs:h.stdio
+o.buttons:     C:h.colourtran
+o.buttons:     C:h.font
+o.buttons:     C:h.drawmod
+o.buttons:     h.msgs
+o.buttons:     h.mem
+o.buttons:     h.alarm
+o.buttons:     C:h.stdlib
+o.buttons:     C:h.string
+o.fileicon:    c.fileicon
+o.fileicon:    h.fileicon
+o.fileicon:    h.wimp
+o.fileicon:    h.wimpstruct
+o.fileicon:    h.os
+o.fileicon:    C:h.kernel
+o.fileicon:    h.sprite
+o.fileicon:    h.wimp
+o.fileicon:    h.wimpt
+o.fileicon:    h.werr
+o.fileicon:    h.msgs
+o.fileicon:    h.buffer
+o.fileicon:    libs:h.stdio
+o.fileicon:    C:h.string
+o.nopoll:      c.nopoll
+o.nopoll:      h.dbox
+o.nopoll:      h.wimp
+o.nopoll:      h.wimpstruct
+o.nopoll:      h.os
+o.nopoll:      C:h.kernel
+o.nopoll:      h.sprite
+o.nopoll:      h.event
+o.nopoll:      h.menu
+o.nopoll:      h.wimpt
+o.nopoll:      h.coords
+o.nopoll:      h.wimp
+o.nopoll:      h.bbc
+o.nopoll:      h.os
+o.nopoll:      h.nopoll
+o.nopoll:      h.interface
+o.nopoll:      h.sculptrix
+o.nopoll:      h.visdelay
+o.nopoll:      h.resspr
+o.nopoll:      libs:h.swiv
+o.saveas:      c.saveas
+o.saveas:      h.wimp
+o.saveas:      h.wimpstruct
+o.saveas:      h.os
+o.saveas:      C:h.kernel
+o.saveas:      h.sprite
+o.saveas:      h.wimpt
+o.saveas:      h.win
+o.saveas:      h.dbox
+o.saveas:      h.event
+o.saveas:      h.menu
+o.saveas:      h.help
+o.saveas:      h.saveas
+o.saveas:      h.xfersend
+o.saveas:      h.fileicon
+o.saveas:      h.stddbox
+o.saveas:      h.msgs
+o.saveas:      h.template
+o.saveas:      h.werr
+o.stddbox:     c.stddbox
+o.stddbox:     h.dbox
+o.stddbox:     h.wimp
+o.stddbox:     h.wimpstruct
+o.stddbox:     h.os
+o.stddbox:     C:h.kernel
+o.stddbox:     h.sprite
+o.stddbox:     h.event
+o.stddbox:     h.menu
+o.stddbox:     h.nopoll
+o.stddbox:     h.bbc
+o.stddbox:     h.stddbox
+o.stddbox:     h.xfersend
+o.stddbox:     h.werr
+o.stddbox:     h.win
+o.stddbox:     h.wimpt
+o.stddbox:     h.msgs
+o.stddbox:     h.saveas
+o.stddbox:     h.help
+o.stddbox:     C:h.stdarg
+o.stddbox:     libs:h.stdio
+o.stddbox:     C:h.string
+o.tcol:        c.tcol
+o.tcol:        h.dbox
+o.tcol:        h.wimp
+o.tcol:        h.wimpstruct
+o.tcol:        h.os
+o.tcol:        C:h.kernel
+o.tcol:        h.sprite
+o.tcol:        h.event
+o.tcol:        h.menu
+o.tcol:        h.buttons
+o.tcol:        h.wimp
+o.tcol:        h.wimpt
+o.tcol:        h.werr
+o.tcol:        h.tcol
+o.tcol:        h.help
+o.tcol:        h.msgs
+o.tcol:        h.mem
+o.tcol:        h.akbd
+o.tcol:        libs:h.stdio
+o.tcol:        C:h.string
+o.tcol:        C:h.stdlib
+o.werr:        c.werr
+o.werr:        h.werr
+o.werr:        h.dbox
+o.werr:        h.wimp
+o.werr:        h.wimpstruct
+o.werr:        h.os
+o.werr:        C:h.kernel
+o.werr:        h.sprite
+o.werr:        h.event
+o.werr:        h.menu
+o.werr:        h.template
+o.werr:        h.nopoll
+o.werr:        h.bbc
+o.werr:        h.wimp
+o.werr:        h.wimpt
+o.werr:        h.win
+o.werr:        h.msgs
+o.werr:        C:h.kernel
+o.werr:        libs:h.swiv
+o.werr:        libs:h.swis
+o.werr:        h.exception
+o.werr:        C:h.setjmp
+o.werr:        libs:h.dll
+o.werr:        h.calltrace
+o.werr:        C:h.stdlib
+o.werr:        C:h.stdarg
+o.werr:        C:h.string
+o.werr:        libs:h.stdio
+o.choices:     c.choices
+o.choices:     C:h.stdlib
+o.choices:     C:h.string
+o.choices:     h.res
+o.choices:     libs:h.stdio
+o.choices:     h.wimpt
+o.choices:     h.wimp
+o.choices:     h.wimpstruct
+o.choices:     h.os
+o.choices:     C:h.kernel
+o.choices:     h.sprite
+o.choices:     h.buffer
+o.choices:     h.choices
+o.prefs:       c.prefs
+o.prefs:       h.prefs
+o.prefs:       libs:h.stdio
+o.prefs:       h.os
+o.prefs:       C:h.kernel
+o.prefs:       h.utils
+o.prefs:       h.msgs
+o.prefs:       h.choices
+o.prefs:       h.res
+o.prefs:       C:h.kernel
+o.prefs:       h.werr
+o.prefs:       libs:h.stdio
+o.prefs:       C:h.string
+o.prefs:       libs:h.ctype
+o.crc: c.crc
+o.crc: h.crc
+o.crc: h.crc32
+o.crc: C:h.stddef
+o.crc: h.os
+o.crc: C:h.kernel
+o.crc: h.res
+o.crc: libs:h.stdio
+o.crc: h.msgs
+o.crc: h.werr
+o.crc: h.wimpt
+o.crc: h.wimp
+o.crc: h.wimpstruct
+o.crc: h.sprite
+o.crc: libs:h.stdio
+o.crc: C:h.stdlib
+o.crc32: s.crc32
+o.crc32: libs:header
+o.crc32: libs:swis
+o.creator:     c.creator
+o.creator:     C:h.stdlib
+o.creator:     C:h.stdarg
+o.creator:     h.steel
+o.creator:     h.wimp
+o.creator:     h.wimpstruct
+o.creator:     h.os
+o.creator:     C:h.kernel
+o.creator:     h.sprite
+o.creator:     h.wimpt
+o.creator:     h.win
+o.creator:     h.event
+o.creator:     h.menu
+o.creator:     h.ibicon
+o.creator:     h.res
+o.creator:     libs:h.stdio
+o.creator:     h.resspr
+o.creator:     h.template
+o.creator:     h.dbox
+o.creator:     h.mem
+o.creator:     h.visdelay
+o.creator:     h.help
+o.creator:     h.exception
+o.creator:     C:h.setjmp
+o.creator:     libs:h.dll
+o.creator:     h.msgs
+o.creator:     h.utils
+o.creator:     h.stddbox
+o.creator:     h.xfersend
+o.creator:     h.werr
+o.creator:     C:h.string
+o.creator:     h.xtearoff
+o.creator:     h.tearoff
+o.fontmenu:    c.fontmenu
+o.fontmenu:    h.wimp
+o.fontmenu:    h.wimpstruct
+o.fontmenu:    h.os
+o.fontmenu:    C:h.kernel
+o.fontmenu:    h.sprite
+o.fontmenu:    h.fontMenu
+o.fontmenu:    h.menu
+o.fontmenu:    h.event
+o.fontmenu:    h.msgs
+o.fontmenu:    h.werr
+o.fontmenu:    h.wimpt
+o.fontmenu:    h.menuExt
+o.fontmenu:    h.buffer
+o.fontmenu:    libs:h.stdio
+o.fontmenu:    h.font
+o.fontmenu:    C:h.drawmod
+o.fontmenu:    h.visdelay
+o.fontmenu:    h.win
+o.fontmenu:    h.utils
+o.fontmenu:    C:h.string
+o.fontmenu:    C:h.stdlib
+o.menu:        c.menu
+o.menu:        h.menu
+o.menu:        h.wimp
+o.menu:        h.wimpstruct
+o.menu:        h.os
+o.menu:        C:h.kernel
+o.menu:        h.sprite
+o.menu:        h.event
+o.menu:        h.mem
+o.menu:        h.wimp
+o.menu:        h.werr
+o.menu:        h.msgs
+o.menu:        h.resspr
+o.menu:        h.event
+o.menu:        h.wimpt
+o.menu:        h.os
+o.menu:        libs:h.swis
+o.menu:        C:h.stdlib
+o.menu:        libs:h.stdio
+o.menu:        C:h.string
+o.menu:        libs:h.dll
+o.tearoff:     c.tearoff
+o.tearoff:     C:h.stdlib
+o.tearoff:     C:h.stdarg
+o.tearoff:     h.steel
+o.tearoff:     h.wimp
+o.tearoff:     h.wimpstruct
+o.tearoff:     h.os
+o.tearoff:     C:h.kernel
+o.tearoff:     h.sprite
+o.tearoff:     h.wimpt
+o.tearoff:     h.win
+o.tearoff:     h.event
+o.tearoff:     h.menu
+o.tearoff:     h.ibicon
+o.tearoff:     h.res
+o.tearoff:     libs:h.stdio
+o.tearoff:     h.resspr
+o.tearoff:     h.template
+o.tearoff:     h.dbox
+o.tearoff:     h.mem
+o.tearoff:     h.visdelay
+o.tearoff:     h.help
+o.tearoff:     h.exception
+o.tearoff:     C:h.setjmp
+o.tearoff:     libs:h.dll
+o.tearoff:     h.msgs
+o.tearoff:     h.utils
+o.tearoff:     h.stddbox
+o.tearoff:     h.xfersend
+o.tearoff:     h.werr
+o.tearoff:     C:h.string
+o.tearoff:     h.os
+o.tearoff:     h.bbc
+o.tearoff:     h.xtearoff
+o.tearoff:     h.tearoff
+o.tearoff:     h.font
+o.tearoff:     C:h.drawmod
+o.tearoff:     libs:h.swis
+o.tearoff:     h.alarm
+o.tearoff:     libs:tearSupt.h.tearSupt
+o.scroller:    c.scroller
+o.scroller:    libs:h.stdio
+o.scroller:    C:h.string
+o.scroller:    C:h.stdlib
+o.scroller:    h.scroller
+o.scroller:    h.wimp
+o.scroller:    h.wimpstruct
+o.scroller:    h.os
+o.scroller:    C:h.kernel
+o.scroller:    h.sprite
+o.scroller:    h.dbox
+o.scroller:    h.event
+o.scroller:    h.menu
+o.scroller:    h.steel
+o.scroller:    h.wimpt
+o.scroller:    h.win
+o.scroller:    h.ibicon
+o.scroller:    h.res
+o.scroller:    h.resspr
+o.scroller:    h.template
+o.scroller:    h.mem
+o.scroller:    h.visdelay
+o.scroller:    h.bbc
+o.scroller:    h.msgs
+o.scroller:    h.werr
+o.xproginfo:   c.xproginfo
+o.xproginfo:   h.steel
+o.xproginfo:   h.wimp
+o.xproginfo:   h.wimpstruct
+o.xproginfo:   h.os
+o.xproginfo:   C:h.kernel
+o.xproginfo:   h.sprite
+o.xproginfo:   h.wimpt
+o.xproginfo:   h.win
+o.xproginfo:   h.event
+o.xproginfo:   h.menu
+o.xproginfo:   h.ibicon
+o.xproginfo:   h.res
+o.xproginfo:   libs:h.stdio
+o.xproginfo:   h.resspr
+o.xproginfo:   h.template
+o.xproginfo:   h.dbox
+o.xproginfo:   h.mem
+o.xproginfo:   h.visdelay
+o.xproginfo:   h.help
+o.xproginfo:   h.exception
+o.xproginfo:   C:h.setjmp
+o.xproginfo:   libs:h.dll
+o.xproginfo:   h.msgs
+o.xproginfo:   h.utils
+o.xproginfo:   h.stddbox
+o.xproginfo:   h.xfersend
+o.xproginfo:   h.werr
+o.xproginfo:   h.scroller
+o.xproginfo:   h.xproginfo
+o.msgs:        c.msgs
+o.msgs:        libs:h.stdio
+o.msgs:        C:h.stdlib
+o.msgs:        C:h.string
+o.msgs:        libs:h.ctype
+o.msgs:        h.os
+o.msgs:        C:h.kernel
+o.msgs:        h.mem
+o.msgs:        h.werr
+o.msgs:        h.res
+o.msgs:        h.msgs
+o.res: c.res
+o.res: C:h.string
+o.res: libs:h.stdio
+o.res: h.os
+o.res: C:h.kernel
+o.res: libs:h.swiv
+o.res: libs:h.swis
+o.res: h.wimpt
+o.res: h.wimp
+o.res: h.wimpstruct
+o.res: h.sprite
+o.res: h.res
+o.res: h.buffer
+o.resspr:      c.resspr
+o.resspr:      C:h.stdlib
+o.resspr:      h.os
+o.resspr:      C:h.kernel
+o.resspr:      h.resspr
+o.resspr:      h.sprite
+o.resspr:      h.mem
+o.resspr:      h.msgs
+o.resspr:      h.werr
+o.resspr:      h.res
+o.resspr:      libs:h.stdio
+o.template:    c.template
+o.template:    C:h.string
+o.template:    C:h.stdlib
+o.template:    libs:h.stdio
+o.template:    h.os
+o.template:    C:h.kernel
+o.template:    h.wimp
+o.template:    h.wimpstruct
+o.template:    h.sprite
+o.template:    h.utils
+o.template:    h.template
+o.template:    libs:h.dll
+o.template:    h.mem
+o.template:    h.font
+o.template:    C:h.drawmod
+o.template:    h.msgs
+o.template:    h.werr
+o.template:    h.res
+o.template:    h.resspr
+o.fastMove: s.fastMove
+o.fastMove: libs:s.fastMove
+o.fastMove: libs:header
+o.fastMove: libs:swis
+o.flex_stat: s.flex_stat
+o.flex_stat: libs:s.flex
+o.flex_stat: libs:header
+o.flex_stat: libs:swis
+o.flex_stat: libs:sh.flexws
+o.heap_stat: s.heap_stat
+o.heap_stat: libs:s.heap
+o.heap_stat: libs:header
+o.heap_stat: libs:swis
+o.heap_stat: libs:sh.heapws
+o.mem: c.mem
+o.mem: h.flex
+o.mem: h.heap
+o.mem: h.wimpt
+o.mem: h.wimp
+o.mem: h.wimpstruct
+o.mem: h.os
+o.mem: C:h.kernel
+o.mem: h.sprite
+o.mem: h.mem
+o.mem: C:h.kernel
+o.mem: h.bbc
+o.mem: C:h.stdlib
+o.mem: C:h.string
+o.mem: libs:h.stdio
+o.xferrecv:    c.xferrecv
+o.xferrecv:    C:h.string
+o.xferrecv:    libs:h.stdio
+o.xferrecv:    C:h.trace
+o.xferrecv:    h.os
+o.xferrecv:    C:h.kernel
+o.xferrecv:    h.bbc
+o.xferrecv:    h.wimp
+o.xferrecv:    h.wimpstruct
+o.xferrecv:    h.sprite
+o.xferrecv:    h.wimpt
+o.xferrecv:    h.win
+o.xferrecv:    h.dbox
+o.xferrecv:    h.event
+o.xferrecv:    h.menu
+o.xferrecv:    C:h.typdat
+o.xferrecv:    h.xfersend
+o.xferrecv:    h.fileicon
+o.xferrecv:    h.werr
+o.xferrecv:    h.menu
+o.xferrecv:    h.event
+o.xferrecv:    h.xferrecv
+o.xferrecv:    h.flex
+o.xferrecv:    h.msgs
+o.xfersend:    c.xfersend
+o.xfersend:    C:h.string
+o.xfersend:    libs:h.stdio
+o.xfersend:    C:h.stdlib
+o.xfersend:    C:h.trace
+o.xfersend:    h.os
+o.xfersend:    C:h.kernel
+o.xfersend:    h.bbc
+o.xfersend:    h.wimp
+o.xfersend:    h.wimpstruct
+o.xfersend:    h.sprite
+o.xfersend:    h.wimpt
+o.xfersend:    h.win
+o.xfersend:    h.dbox
+o.xfersend:    h.event
+o.xfersend:    h.menu
+o.xfersend:    h.xfersend
+o.xfersend:    h.fileicon
+o.xfersend:    h.werr
+o.xfersend:    h.menu
+o.xfersend:    h.event
+o.xfersend:    h.msgs
+o.xfersend:    libs:h.swis
+do.bbc: s.bbc
+do.bbc: libs:header
+do.bbc: libs:swis
+do.colourtran: s.colourtran
+do.colourtran: libs:header
+do.colourtran: libs:swis
+do.font:       c.font
+do.font:       C:h.stddef
+do.font:       h.os
+do.font:       C:h.kernel
+do.font:       C:h.trace
+do.font:       h.font
+do.font:       C:h.drawmod
+do.interface:  c.interface
+do.interface:  libs:h.stdio
+do.interface:  libs:h.swiv
+do.interface:  C:h.kernel
+do.interface:  h.os
+do.interface:  h.wimp
+do.interface:  h.wimpstruct
+do.interface:  h.sprite
+do.interface:  libs:h.swis
+do.interface:  h.pointer
+do.interface:  h.interface
+do.interface:  h.visdelay
+do.os: s.os
+do.os: libs:header
+do.os: libs:swis
+do.os: libs:s.swihack
+do.print:      c.print
+do.print:      h.os
+do.print:      C:h.kernel
+do.print:      C:h.print
+do.sculptrix: s.sculptrix
+do.sculptrix: libs:header
+do.sculptrix: libs:swis
+do.sprite:     c.sprite
+do.sprite:     C:h.stddef
+do.sprite:     h.os
+do.sprite:     C:h.kernel
+do.sprite:     h.sprite
+do.wimpext: s.wimpext
+do.wimp_dll: s.wimp_dll
+do.wimp_dll: libs:header
+do.wimp_dll: libs:SWIs
+do.wimp_dll: s.wimp_main
+do.buffer:     c.buffer
+do.buffer:     h.buffer
+do.calltrace: s.calltrace
+do.calltrace: libs:header
+do.calltrace: libs:swis
+do.exception:  c.exception
+do.exception:  C:h.stdarg
+do.exception:  libs:h.stdio
+do.exception:  C:h.stdlib
+do.exception:  h.msgs
+do.exception:  h.exception
+do.exception:  C:h.setjmp
+do.exception:  libs:h.dll
+do.exception:  libs:h.os
+do.exception:  C:h.kernel
+do.exception:  libs:h.wimp
+do.exception:  libs:h.wimpstruct
+do.exception:  libs:h.sprite
+do.exception:  h.wimpt
+do.exception:  h.werr
+do.exception:  h.visdelay
+do.utils:      c.utils
+do.utils:      libs:h.stdio
+do.utils:      C:h.string
+do.utils:      libs:h.ctype
+do.utils:      h.utils
+do.utils:      h.os
+do.utils:      C:h.kernel
+do.utils:      h.os
+do.utils:      h.werr
+do.utils:      h.wimpt
+do.utils:      h.wimp
+do.utils:      h.wimpstruct
+do.utils:      h.sprite
+do.utils:      libs:h.swiv
+do.utils:      libs:h.swis
+do.utils:      h.buffer
+do.vsscanf:    c.vsscanf
+do.vsscanf:    libs:h.stdio
+do.vsscanf:    C:h.stdarg
+do.vsscanf:    C:h.stdlib
+do.vsscanf:    libs:h.ctype
+do.vsscanf:    h.vsscanf
+do.akbd:       c.akbd
+do.akbd:       h.os
+do.akbd:       C:h.kernel
+do.akbd:       h.akbd
+do.akbd:       h.bbc
+do.coords: s.coords
+do.coords: libs:header
+do.keystring:  c.keystring
+do.keystring:  h.akbd
+do.keystring:  h.msgs
+do.keystring:  h.keyString
+do.keystring:  h.buffer
+do.keystring:  C:h.string
+do.keystring:  libs:h.stdio
+do.alarm:      c.alarm
+do.alarm:      h.alarm
+do.alarm:      h.mem
+do.alarm:      h.werr
+do.alarm:      h.msgs
+do.alarm:      h.os
+do.alarm:      C:h.kernel
+do.alarm:      libs:h.swiv
+do.alarm:      libs:h.swis
+do.blinkc:     c.blinkc
+do.blinkc:     h.wimp
+do.blinkc:     h.wimpstruct
+do.blinkc:     h.os
+do.blinkc:     C:h.kernel
+do.blinkc:     h.sprite
+do.blinkc:     h.wimpt
+do.blinkc:     h.os
+do.blinkc:     h.blinkC
+do.blinkc:     h.alarm
+do.blinkc:     libs:h.swiv
+do.blinkc:     C:h.stdlib
+do.blinkc:     libs:h.dll
+do.caretptr:   c.caretptr
+do.caretptr:   libs:h.ctype
+do.caretptr:   h.pointer
+do.caretptr:   h.os
+do.caretptr:   C:h.kernel
+do.caretptr:   h.sprite
+do.caretptr:   h.win
+do.caretptr:   h.wimp
+do.caretptr:   h.wimpstruct
+do.caretptr:   h.wimpt
+do.caretptr:   h.wimp
+do.caretptr:   h.os
+do.caretptr:   h.caretptr
+do.caretptr:   h.resspr
+do.pointer:    c.pointer
+do.pointer:    libs:h.stdio
+do.pointer:    h.os
+do.pointer:    C:h.kernel
+do.pointer:    h.sprite
+do.pointer:    libs:h.swis
+do.pointer:    h.wimpt
+do.pointer:    h.wimp
+do.pointer:    h.wimpstruct
+do.pointer:    h.pointer
+do.visdelay:   c.visdelay
+do.visdelay:   h.visdelay
+do.visdelay:   h.os
+do.visdelay:   C:h.kernel
+do.visdelay:   libs:h.swiv
+do.visdelay:   libs:h.swis
+do.visdelay:   h.wimpt
+do.visdelay:   h.wimp
+do.visdelay:   h.wimpstruct
+do.visdelay:   h.sprite
+do.visdelay:   C:h.stdlib
+do.visdelay:   libs:h.dll
+do.event:      c.event
+do.event:      C:h.stdlib
+do.event:      C:h.string
+do.event:      h.event
+do.event:      h.wimp
+do.event:      h.wimpstruct
+do.event:      h.os
+do.event:      C:h.kernel
+do.event:      h.sprite
+do.event:      h.menu
+do.event:      h.wimpt
+do.event:      h.win
+do.event:      h.menu
+do.event:      h.msgs
+do.event:      h.werr
+do.event:      h.alarm
+do.event:      h.mem
+do.event:      libs:h.swis
+do.event:      h.dbox
+do.help:       c.help
+do.help:       h.wimp
+do.help:       h.wimpstruct
+do.help:       h.os
+do.help:       C:h.kernel
+do.help:       h.sprite
+do.help:       h.wimpt
+do.help:       h.help
+do.help:       h.msgs
+do.help:       h.werr
+do.help:       C:h.string
+do.help:       C:h.stdarg
+do.help:       libs:h.stdio
+do.pane:       c.pane
+do.pane:       h.wimp
+do.pane:       h.wimpstruct
+do.pane:       h.os
+do.pane:       C:h.kernel
+do.pane:       h.sprite
+do.pane:       h.wimpt
+do.pane:       h.pane
+do.pane:       h.listbox
+do.pane:       h.werr
+do.pane:       h.msgs
+do.pane:       h.mem
+do.pane:       h.win
+do.pane:       C:h.stdlib
+do.wimpt:      c.wimpt
+do.wimpt:      libs:h.stdio
+do.wimpt:      C:h.stdlib
+do.wimpt:      C:h.stdarg
+do.wimpt:      C:h.signal
+do.wimpt:      C:h.string
+do.wimpt:      libs:h.dll
+do.wimpt:      libs:h.os
+do.wimpt:      C:h.kernel
+do.wimpt:      libs:h.wimp
+do.wimpt:      libs:h.wimpstruct
+do.wimpt:      libs:h.sprite
+do.wimpt:      libs:h.swis
+do.wimpt:      C:h.kernel
+do.wimpt:      h.os
+do.wimpt:      h.bbc
+do.wimpt:      h.wimp
+do.wimpt:      h.font
+do.wimpt:      C:h.drawmod
+do.wimpt:      h.wimpt
+do.wimpt:      h.wimpt
+do.wimpt:      h.werr
+do.wimpt:      h.alarm
+do.wimpt:      h.event
+do.wimpt:      h.menu
+do.wimpt:      h.flex
+do.wimpt:      h.msgs
+do.wimpt:      h.interface
+do.wimpt:      h.exception
+do.wimpt:      C:h.setjmp
+do.wimpt:      h.mem
+do.wimpt:      h.visdelay
+do.wimpt:      h.caretptr
+do.wimpt:      h.pointer
+do.wimpt:      h.sculptrix
+do.wimpt:      h.resspr
+do.win:        c.win
+do.win:        C:h.stdarg
+do.win:        C:h.stdlib
+do.win:        C:h.string
+do.win:        libs:h.stdio
+do.win:        C:h.trace
+do.win:        h.os
+do.win:        C:h.kernel
+do.win:        h.wimp
+do.win:        h.wimpstruct
+do.win:        h.sprite
+do.win:        h.werr
+do.win:        h.wimpt
+do.win:        h.event
+do.win:        h.menu
+do.win:        h.msgs
+do.win:        h.mem
+do.win:        h.bbc
+do.win:        libs:h.swis
+do.win:        h.menu
+do.win:        h.win
+do.baricon:    c.baricon
+do.baricon:    h.baricon
+do.baricon:    h.ibicon
+do.baricon:    h.sprite
+do.baricon:    h.os
+do.baricon:    C:h.kernel
+do.baricon:    h.wimp
+do.baricon:    h.wimpstruct
+do.baricon:    h.event
+do.baricon:    h.menu
+do.ibicon:     c.ibicon
+do.ibicon:     h.wimp
+do.ibicon:     h.wimpstruct
+do.ibicon:     h.os
+do.ibicon:     C:h.kernel
+do.ibicon:     h.sprite
+do.ibicon:     h.wimpt
+do.ibicon:     h.os
+do.ibicon:     libs:h.swis
+do.ibicon:     h.bbc
+do.ibicon:     h.win
+do.ibicon:     h.werr
+do.ibicon:     h.ibicon
+do.ibicon:     h.event
+do.ibicon:     h.menu
+do.ibicon:     h.msgs
+do.ibicon:     h.event
+do.ibicon:     h.mem
+do.ibicon:     libs:h.swiv
+do.ibicon:     C:h.string
+do.ibicon:     libs:h.stdio
+do.ibicon:     libs:h.dll
+do.listbox:    c.listbox
+do.listbox:    libs:h.stdio
+do.listbox:    C:h.stdlib
+do.listbox:    C:h.string
+do.listbox:    h.wimp
+do.listbox:    h.wimpstruct
+do.listbox:    h.os
+do.listbox:    C:h.kernel
+do.listbox:    h.sprite
+do.listbox:    h.wimpt
+do.listbox:    h.event
+do.listbox:    h.menu
+do.listbox:    h.win
+do.listbox:    h.template
+do.listbox:    h.listbox
+do.listbox:    h.pane
+do.listbox:    h.werr
+do.listbox:    h.msgs
+do.listbox:    h.bbc
+do.listbox:    h.mem
+do.listbox:    h.utils
+do.listbox:    h.help
+do.listbox:    h.visdelay
+do.listbox:    libs:h.dll
+do.viewer:     c.viewer
+do.viewer:     h.wimp
+do.viewer:     h.wimpstruct
+do.viewer:     h.os
+do.viewer:     C:h.kernel
+do.viewer:     h.sprite
+do.viewer:     h.wimpt
+do.viewer:     h.win
+do.viewer:     h.viewer
+do.viewer:     h.menu
+do.viewer:     h.event
+do.viewer:     h.msgs
+do.viewer:     h.bbc
+do.viewer:     h.werr
+do.viewer:     h.os
+do.viewer:     h.xfersend
+do.viewer:     h.mem
+do.viewer:     h.coords
+do.viewer:     h.wimp
+do.viewer:     h.utils
+do.viewer:     h.help
+do.viewer:     h.fileicon
+do.viewer:     h.buffer
+do.viewer:     libs:h.swis
+do.viewer:     C:h.stdlib
+do.viewer:     C:h.string
+do.viewer:     libs:h.stdio
+do.viewer:     libs:h.dll
+do.buttons:    c.buttons
+do.buttons:    h.wimp
+do.buttons:    h.wimpstruct
+do.buttons:    h.os
+do.buttons:    C:h.kernel
+do.buttons:    h.sprite
+do.buttons:    h.wimpt
+do.buttons:    h.buttons
+do.buttons:    h.dbox
+do.buttons:    h.event
+do.buttons:    h.menu
+do.buttons:    h.bbc
+do.buttons:    h.win
+do.buttons:    h.werr
+do.buttons:    libs:h.stdio
+do.buttons:    h.colourtran
+do.buttons:    h.font
+do.buttons:    C:h.drawmod
+do.buttons:    h.msgs
+do.buttons:    h.mem
+do.buttons:    h.alarm
+do.buttons:    C:h.stdlib
+do.buttons:    C:h.string
+do.fileicon:   c.fileicon
+do.fileicon:   h.fileicon
+do.fileicon:   h.wimp
+do.fileicon:   h.wimpstruct
+do.fileicon:   h.os
+do.fileicon:   C:h.kernel
+do.fileicon:   h.sprite
+do.fileicon:   h.wimp
+do.fileicon:   h.wimpt
+do.fileicon:   h.werr
+do.fileicon:   h.msgs
+do.fileicon:   h.buffer
+do.fileicon:   libs:h.stdio
+do.fileicon:   C:h.string
+do.nopoll:     c.nopoll
+do.nopoll:     h.dbox
+do.nopoll:     h.wimp
+do.nopoll:     h.wimpstruct
+do.nopoll:     h.os
+do.nopoll:     C:h.kernel
+do.nopoll:     h.sprite
+do.nopoll:     h.event
+do.nopoll:     h.menu
+do.nopoll:     h.wimpt
+do.nopoll:     h.coords
+do.nopoll:     h.wimp
+do.nopoll:     h.bbc
+do.nopoll:     h.os
+do.nopoll:     h.nopoll
+do.nopoll:     h.interface
+do.nopoll:     h.sculptrix
+do.nopoll:     h.visdelay
+do.nopoll:     h.resspr
+do.nopoll:     libs:h.swiv
+do.saveas:     c.saveas
+do.saveas:     h.wimp
+do.saveas:     h.wimpstruct
+do.saveas:     h.os
+do.saveas:     C:h.kernel
+do.saveas:     h.sprite
+do.saveas:     h.wimpt
+do.saveas:     h.win
+do.saveas:     h.dbox
+do.saveas:     h.event
+do.saveas:     h.menu
+do.saveas:     h.help
+do.saveas:     h.saveas
+do.saveas:     h.xfersend
+do.saveas:     h.fileicon
+do.saveas:     h.stddbox
+do.saveas:     h.msgs
+do.saveas:     h.template
+do.saveas:     h.werr
+do.stddbox:    c.stddbox
+do.stddbox:    h.dbox
+do.stddbox:    h.wimp
+do.stddbox:    h.wimpstruct
+do.stddbox:    h.os
+do.stddbox:    C:h.kernel
+do.stddbox:    h.sprite
+do.stddbox:    h.event
+do.stddbox:    h.menu
+do.stddbox:    h.nopoll
+do.stddbox:    h.bbc
+do.stddbox:    h.stddbox
+do.stddbox:    h.xfersend
+do.stddbox:    h.werr
+do.stddbox:    h.win
+do.stddbox:    h.wimpt
+do.stddbox:    h.msgs
+do.stddbox:    h.saveas
+do.stddbox:    h.help
+do.stddbox:    C:h.stdarg
+do.stddbox:    libs:h.stdio
+do.stddbox:    C:h.string
+do.tcol:       c.tcol
+do.tcol:       h.dbox
+do.tcol:       h.wimp
+do.tcol:       h.wimpstruct
+do.tcol:       h.os
+do.tcol:       C:h.kernel
+do.tcol:       h.sprite
+do.tcol:       h.event
+do.tcol:       h.menu
+do.tcol:       h.buttons
+do.tcol:       h.wimp
+do.tcol:       h.wimpt
+do.tcol:       h.werr
+do.tcol:       h.tcol
+do.tcol:       h.help
+do.tcol:       h.msgs
+do.tcol:       h.mem
+do.tcol:       h.akbd
+do.tcol:       libs:h.stdio
+do.tcol:       C:h.string
+do.tcol:       C:h.stdlib
+do.werr:       c.werr
+do.werr:       h.werr
+do.werr:       h.dbox
+do.werr:       h.wimp
+do.werr:       h.wimpstruct
+do.werr:       h.os
+do.werr:       C:h.kernel
+do.werr:       h.sprite
+do.werr:       h.event
+do.werr:       h.menu
+do.werr:       h.template
+do.werr:       h.nopoll
+do.werr:       h.bbc
+do.werr:       h.wimp
+do.werr:       h.wimpt
+do.werr:       h.win
+do.werr:       h.msgs
+do.werr:       C:h.kernel
+do.werr:       libs:h.swiv
+do.werr:       libs:h.swis
+do.werr:       h.exception
+do.werr:       C:h.setjmp
+do.werr:       libs:h.dll
+do.werr:       h.calltrace
+do.werr:       C:h.stdlib
+do.werr:       C:h.stdarg
+do.werr:       C:h.string
+do.werr:       libs:h.stdio
+do.choices:    c.choices
+do.choices:    C:h.stdlib
+do.choices:    C:h.string
+do.choices:    h.res
+do.choices:    libs:h.stdio
+do.choices:    h.wimpt
+do.choices:    h.wimp
+do.choices:    h.wimpstruct
+do.choices:    h.os
+do.choices:    C:h.kernel
+do.choices:    h.sprite
+do.choices:    h.buffer
+do.choices:    h.choices
+do.prefs:      c.prefs
+do.prefs:      h.prefs
+do.prefs:      libs:h.stdio
+do.prefs:      h.os
+do.prefs:      C:h.kernel
+do.prefs:      h.utils
+do.prefs:      h.msgs
+do.prefs:      h.choices
+do.prefs:      h.res
+do.prefs:      C:h.kernel
+do.prefs:      h.werr
+do.prefs:      libs:h.stdio
+do.prefs:      C:h.string
+do.prefs:      libs:h.ctype
+do.creator:    c.creator
+do.creator:    C:h.stdlib
+do.creator:    C:h.stdarg
+do.creator:    h.steel
+do.creator:    h.wimp
+do.creator:    h.wimpstruct
+do.creator:    h.os
+do.creator:    C:h.kernel
+do.creator:    h.sprite
+do.creator:    h.wimpt
+do.creator:    h.win
+do.creator:    h.event
+do.creator:    h.menu
+do.creator:    h.ibicon
+do.creator:    h.res
+do.creator:    libs:h.stdio
+do.creator:    h.resspr
+do.creator:    h.template
+do.creator:    h.dbox
+do.creator:    h.mem
+do.creator:    h.visdelay
+do.creator:    h.help
+do.creator:    h.exception
+do.creator:    C:h.setjmp
+do.creator:    libs:h.dll
+do.creator:    h.msgs
+do.creator:    h.utils
+do.creator:    h.stddbox
+do.creator:    h.xfersend
+do.creator:    h.werr
+do.creator:    C:h.string
+do.creator:    h.xtearoff
+do.creator:    h.tearoff
+do.fontmenu:   c.fontmenu
+do.fontmenu:   h.wimp
+do.fontmenu:   h.wimpstruct
+do.fontmenu:   h.os
+do.fontmenu:   C:h.kernel
+do.fontmenu:   h.sprite
+do.fontmenu:   h.fontMenu
+do.fontmenu:   h.menu
+do.fontmenu:   h.event
+do.fontmenu:   h.msgs
+do.fontmenu:   h.werr
+do.fontmenu:   h.wimpt
+do.fontmenu:   h.menuExt
+do.fontmenu:   h.buffer
+do.fontmenu:   libs:h.stdio
+do.fontmenu:   h.font
+do.fontmenu:   C:h.drawmod
+do.fontmenu:   h.visdelay
+do.fontmenu:   h.win
+do.fontmenu:   h.utils
+do.fontmenu:   C:h.string
+do.fontmenu:   C:h.stdlib
+do.menu:       c.menu
+do.menu:       h.menu
+do.menu:       h.wimp
+do.menu:       h.wimpstruct
+do.menu:       h.os
+do.menu:       C:h.kernel
+do.menu:       h.sprite
+do.menu:       h.event
+do.menu:       h.mem
+do.menu:       h.wimp
+do.menu:       h.werr
+do.menu:       h.msgs
+do.menu:       h.resspr
+do.menu:       h.event
+do.menu:       h.wimpt
+do.menu:       h.os
+do.menu:       libs:h.swis
+do.menu:       C:h.stdlib
+do.menu:       libs:h.stdio
+do.menu:       C:h.string
+do.menu:       libs:h.dll
+do.tearoff:    c.tearoff
+do.tearoff:    C:h.stdlib
+do.tearoff:    C:h.stdarg
+do.tearoff:    h.steel
+do.tearoff:    h.wimp
+do.tearoff:    h.wimpstruct
+do.tearoff:    h.os
+do.tearoff:    C:h.kernel
+do.tearoff:    h.sprite
+do.tearoff:    h.wimpt
+do.tearoff:    h.win
+do.tearoff:    h.event
+do.tearoff:    h.menu
+do.tearoff:    h.ibicon
+do.tearoff:    h.res
+do.tearoff:    libs:h.stdio
+do.tearoff:    h.resspr
+do.tearoff:    h.template
+do.tearoff:    h.dbox
+do.tearoff:    h.mem
+do.tearoff:    h.visdelay
+do.tearoff:    h.help
+do.tearoff:    h.exception
+do.tearoff:    C:h.setjmp
+do.tearoff:    libs:h.dll
+do.tearoff:    h.msgs
+do.tearoff:    h.utils
+do.tearoff:    h.stddbox
+do.tearoff:    h.xfersend
+do.tearoff:    h.werr
+do.tearoff:    C:h.string
+do.tearoff:    h.os
+do.tearoff:    h.bbc
+do.tearoff:    h.xtearoff
+do.tearoff:    h.tearoff
+do.tearoff:    h.font
+do.tearoff:    C:h.drawmod
+do.tearoff:    libs:h.swis
+do.tearoff:    h.alarm
+do.tearoff:    libs:tearSupt.h.tearSupt
+do.msgs:       c.msgs
+do.msgs:       libs:h.stdio
+do.msgs:       C:h.stdlib
+do.msgs:       C:h.string
+do.msgs:       libs:h.ctype
+do.msgs:       h.os
+do.msgs:       C:h.kernel
+do.msgs:       h.mem
+do.msgs:       h.werr
+do.msgs:       h.res
+do.msgs:       h.msgs
+do.res:        c.res
+do.res:        C:h.string
+do.res:        libs:h.stdio
+do.res:        h.os
+do.res:        C:h.kernel
+do.res:        libs:h.swiv
+do.res:        libs:h.swis
+do.res:        h.wimpt
+do.res:        h.wimp
+do.res:        h.wimpstruct
+do.res:        h.sprite
+do.res:        h.res
+do.res:        h.buffer
+do.resspr:     c.resspr
+do.resspr:     C:h.stdlib
+do.resspr:     h.os
+do.resspr:     C:h.kernel
+do.resspr:     h.resspr
+do.resspr:     h.sprite
+do.resspr:     h.mem
+do.resspr:     h.msgs
+do.resspr:     h.werr
+do.resspr:     h.res
+do.resspr:     libs:h.stdio
+do.template:   c.template
+do.template:   C:h.string
+do.template:   C:h.stdlib
+do.template:   libs:h.stdio
+do.template:   h.os
+do.template:   C:h.kernel
+do.template:   h.wimp
+do.template:   h.wimpstruct
+do.template:   h.sprite
+do.template:   h.utils
+do.template:   h.template
+do.template:   libs:h.dll
+do.template:   h.mem
+do.template:   h.font
+do.template:   C:h.drawmod
+do.template:   h.msgs
+do.template:   h.werr
+do.template:   h.res
+do.template:   h.resspr
+do.fastMove: s.fastMove
+do.fastMove: libs:s.fastMove
+do.fastMove: libs:header
+do.fastMove: libs:swis
+do.flex_dll: s.flex_dll
+do.flex_dll: libs:s.flex
+do.flex_dll: libs:header
+do.flex_dll: libs:swis
+do.flex_dll: libs:sh.flexws
+do.heap_dll: s.heap_dll
+do.heap_dll: libs:s.heap
+do.heap_dll: libs:header
+do.heap_dll: libs:swis
+do.heap_dll: libs:sh.heapws
+do.mem:        c.mem
+do.mem:        h.flex
+do.mem:        h.heap
+do.mem:        h.wimpt
+do.mem:        h.wimp
+do.mem:        h.wimpstruct
+do.mem:        h.os
+do.mem:        C:h.kernel
+do.mem:        h.sprite
+do.mem:        h.mem
+do.mem:        C:h.kernel
+do.mem:        h.bbc
+do.mem:        C:h.stdlib
+do.mem:        C:h.string
+do.mem:        libs:h.stdio
+do.xferrecv:   c.xferrecv
+do.xferrecv:   C:h.string
+do.xferrecv:   libs:h.stdio
+do.xferrecv:   C:h.trace
+do.xferrecv:   h.os
+do.xferrecv:   C:h.kernel
+do.xferrecv:   h.bbc
+do.xferrecv:   h.wimp
+do.xferrecv:   h.wimpstruct
+do.xferrecv:   h.sprite
+do.xferrecv:   h.wimpt
+do.xferrecv:   h.win
+do.xferrecv:   h.dbox
+do.xferrecv:   h.event
+do.xferrecv:   h.menu
+do.xferrecv:   C:h.typdat
+do.xferrecv:   h.xfersend
+do.xferrecv:   h.fileicon
+do.xferrecv:   h.werr
+do.xferrecv:   h.menu
+do.xferrecv:   h.event
+do.xferrecv:   h.xferrecv
+do.xferrecv:   h.flex
+do.xferrecv:   h.msgs
+do.xfersend:   c.xfersend
+do.xfersend:   C:h.string
+do.xfersend:   libs:h.stdio
+do.xfersend:   C:h.stdlib
+do.xfersend:   C:h.trace
+do.xfersend:   h.os
+do.xfersend:   C:h.kernel
+do.xfersend:   h.bbc
+do.xfersend:   h.wimp
+do.xfersend:   h.wimpstruct
+do.xfersend:   h.sprite
+do.xfersend:   h.wimpt
+do.xfersend:   h.win
+do.xfersend:   h.dbox
+do.xfersend:   h.event
+do.xfersend:   h.menu
+do.xfersend:   h.xfersend
+do.xfersend:   h.fileicon
+do.xfersend:   h.werr
+do.xfersend:   h.menu
+do.xfersend:   h.event
+do.xfersend:   h.msgs
+do.xfersend:   libs:h.swis
+o.dbox:        c.dbox
+o.dbox:        h.event
+o.dbox:        h.wimp
+o.dbox:        h.wimpstruct
+o.dbox:        h.os
+o.dbox:        C:h.kernel
+o.dbox:        h.sprite
+o.dbox:        h.menu
+o.dbox:        h.wimpt
+o.dbox:        h.wimp
+o.dbox:        h.interface
+o.dbox:        h.sculptrix
+o.dbox:        h.werr
+o.dbox:        h.template
+o.dbox:        h.win
+o.dbox:        h.dbox
+o.dbox:        h.msgs
+o.dbox:        h.bbc
+o.dbox:        h.mem
+o.dbox:        h.akbd
+o.dbox:        h.os
+o.dbox:        libs:h.swiv
+o.dbox:        libs:h.swis
+o.dbox:        h.help
+o.dbox:        h.vsscanf
+o.dbox:        C:h.stdarg
+o.dbox:        C:h.string
+o.dbox:        C:h.stdlib
+o.dbox:        libs:h.stdio
+o.dbox:        C:h.stdarg
+o.dbox:        libs:h.dll
+do.dbox:       c.dbox
+do.dbox:       h.event
+do.dbox:       h.wimp
+do.dbox:       h.wimpstruct
+do.dbox:       h.os
+do.dbox:       C:h.kernel
+do.dbox:       h.sprite
+do.dbox:       h.menu
+do.dbox:       h.wimpt
+do.dbox:       h.wimp
+do.dbox:       h.interface
+do.dbox:       h.sculptrix
+do.dbox:       h.werr
+do.dbox:       h.template
+do.dbox:       h.win
+do.dbox:       h.dbox
+do.dbox:       h.msgs
+do.dbox:       h.bbc
+do.dbox:       h.mem
+do.dbox:       h.akbd
+do.dbox:       h.os
+do.dbox:       libs:h.swiv
+do.dbox:       libs:h.swis
+do.dbox:       h.help
+do.dbox:       h.vsscanf
+do.dbox:       C:h.stdarg
+do.dbox:       C:h.string
+do.dbox:       C:h.stdlib
+do.dbox:       libs:h.stdio
+do.dbox:       C:h.stdarg
+do.dbox:       libs:h.dll
diff --git a/StraySrc/Libraries/Steel/Messages b/StraySrc/Libraries/Steel/Messages
new file mode 100644 (file)
index 0000000..29085d1
--- /dev/null
@@ -0,0 +1,260 @@
+# /-------------------------------------------------------------------------\
+# |                                                                         |
+# |                            STEEL messages                               |
+# |                                                                         |
+# +-------------------------------------------------------------------------+
+# |                                                                         |
+# | This messages file is organised into two parts:                         |
+# |                                                                         |
+# | 1. RISC_OSlib messages from the old message  file.  These have been     |
+# |    separated out  according to their RISC_OSlib segments.               |
+# |                                                                         |
+# | 2. STEEL  messages.  These have names indicative of their function      |
+# |    instead of just numeric ones.                                        |
+# |                                                                         |# \-------------------------------------------------------------------------/
+
+
+#====[ RISC_OSlib messages ]=================================================
+
+#----- alarm ----------------------------------------------------------------
+
+alarm1:Unable to read monotonic time
+alarm2:Not enough memory to set alarm -- increase wimpslot
+
+#----- resspr ---------------------------------------------------------------
+
+resspr1:Not enough memory to load sprite file '%s' -- increase wimpslot
+resspr2:Unable to load sprite file '%s'
+
+#----- template -------------------------------------------------------------
+
+template1:Template '%s' not found
+template2:Template load failed: %s
+template3:Not enough memory to load templates -- increase wimpslot
+template4:Cannot open file: %s
+template5:Read failed for %s
+template6:Template file not found
+template7:Not enough memory to load templates -- increase wimpslot
+template8:Template load failed
+
+#----- txt ------------------------------------------------------------------
+
+txt1:Not enough memory (txt) -- free some application memory
+txt2:Bad line separation in font
+txt3:Could not save file '%s'
+txt4:Not enough memory to import data -- free some application memory
+txt5:Cannot save a file into itself
+txt6:Too many windows
+txt7:File '%s' not found
+txt8:Not enough memory (find) -- increase wimpslot
+txt9:1 file edited but not saved in Edit: are you sure you want to Quit?
+txt10:%i files edited but not saved in Edit: are you sure you want to Quit?
+txt11:<untitled>
+txt12:Edit
+txt13:Misc,>Save,Select,Edit,Display
+txt14:Misc
+txt15:>Info,>File,New view
+txt16:Select
+txt17:>Save          ,Copy   (ctl-C),Move   (ctl-V),Delete (ctl-X),Clear  (ctl-Z),>Indent
+txt18:Edit
+txt19:>Find   (f4),>Goto   (f5),Undo   (f8),Redo   (f9),CR<->LF,Expand tabs,Format text
+txt20:Format Width
+txt21:Fonts
+txt22:System Font
+txt23:Colour
+txt24:Display
+txt25:Font,Font size,Font height,Line spacing,Margin,Invert,Wrap,Foreground,Background
+txt26:Font size
+txt27:Font height
+txt28:Line spacing
+txt29:Left margin
+txt30:Counting...
+txt31:%i Found
+txt32:Searching...
+txt33:Not Found
+txt34:Found
+txt35:Replace ?
+txt36:Last Replace ?
+txt37:%i replaced
+txt38:Nothing to Undo
+txt39:Undone
+txt40:Redone
+txt41:Nothing to redo
+txt42:Name of new file:
+txt43:Insert file:
+txt44:TextFile
+txt45:DataFile
+txt46:ExecFile
+txt47:ObeyFile
+txt48:EditFile
+txt49:Selection
+txt50:YES
+txt51:NO
+txt52:load/exec
+txt53:Click/Drag SELECT to set the caret.|M
+txt54:Drag SELECT to set a selection.|M
+txt55:Click/Drag ADJUST to adjust the selection.
+txt56:Click ADJUST to set a selection.
+txt57:Do you want to save edited file '%s'?
+txt58:Do you want to save your edited file?
+txt59:File not found
+
+#----- win ------------------------------------------------------------------
+
+win2:Not enough memory to change window title.
+
+#----- xferrecv -------------------------------------------------------------
+
+xferrecv1:Can't transfer file (use *Set Wimp$Scrap <filename>)
+xferrecv2:Data transfer failed
+
+#----- xfersend -------------------------------------------------------------
+
+xfersend1:Bad data transfer, receiver dead
+xfersend2:Selection
+
+#====[ STEEL messages ]======================================================
+
+#----- buttons --------------------------------------------------------------
+
+buttonsNM:Not enough memory for slider.
+
+#---- crc -------------------------------------------------------------------
+
+crcFNF:Couldn't open file '%s'.
+crcFC:%s resource file '%s' has been corrupted.  Please restore this file from the distribution disk.
+
+#----- dbox -----------------------------------------------------------------
+
+dboxTMW:Too many windows - %s could not create window/dialogue box.
+dboxNEM:Not enough memory for new dialogue box.
+dboxFRE:(dbox_fillin, caller fault): dbox_fillin only works with menu dboxes.
+dboxCOD:(dbox_openDisplaced): failed - dbox already open.
+dboxSTK:Only enough stack space for %i icons.
+dboxCSU:(dbox_unclick): Click stack underflow.
+dboxHFE:(dbox_helpField, caller fault): Not called on HELPREQUEST event.
+
+#----- event ----------------------------------------------------------------
+
+eventTMWS:Too many windows - %s could not create submenu.
+eventTMWM:Too many windows - %s could not create new menu.
+
+#----- exception ------------------------------------------------------------
+
+excFATAL:Fatal internal error: '%s'
+excSEV:Internal error: '%s'.  Click OK to continue, or Cancel to quit %s.
+excAYS:Are you sure you want to quit %s?  Click OK to continue, or Cancel to quit.
+
+#----- fileicon -------------------------------------------------------------
+
+ficnNII:(fileicon, caller fault): Icon must be indirected.
+ficnIHD:(fileicon): Icon handle has changed.
+
+#----- fontmenu -------------------------------------------------------------
+
+fontmNF:Couldn't find any fonts.  Double-click on a !Fonts application and reload.
+fontmFT:Fonts
+fontmSF:System font
+fontmNEM:Not enough memory to create font menu.
+fontmRF:(Regular)
+fontmTMWS:Too many windows - %s could not create submenu.
+
+#----- keyString ------------------------------------------------------------
+
+kstrPRT:<Print>
+kstrFKEY:F
+kstrSH:<Shift> 
+kstrCTL:<Ctrl> 
+
+#----- ibicon ---------------------------------------------------------------
+
+ibicnICF:(ibicon__events): Event for non-existant icon.
+ibicnNEM:Not enough memory for icon.
+ibicnCCT:(ibicon_changeText, caller fault): Attempt to write text to sprite-only ibicon.
+
+#----- list -----------------------------------------------------------------
+
+listNEM:Not enough room to create list box.
+listNEMI:Not enough room to add new item.
+listTMW:Too many windows - %s could not create list box.
+listHIE:(list_helpItem, caller fault): Not called on HELPREQUEST event.
+
+#----- menu -----------------------------------------------------------------
+
+menuNEM:Not enough memory to construct menu.
+menuICOU:(menu_new): Menu item undercount.
+menuICOO:(menu_new): Menu item overcount.
+menuIMSC:(menu_new): Menu item count mismatch.
+menuNEME:Not enough memory to extend menu.
+menuUKNME:(menu__menuproc): Unknown menu event type.
+
+#----- pane -----------------------------------------------------------------
+
+paneNEM:Not enough memory to register pane.
+paneIPH:(pane_moved, caller fault): not a wimp_EOPEN event or with wrong pane handle.
+
+#----- prefs ----------------------------------------------------------------
+
+prefsERP:Error reading preferences.  Assuming defaults.
+prefsRBB:Bad boolean variable '%s' at line %i (must be 'true' or 'false')
+prefsEWP:Error writing preferences: '%s'
+
+#----- saveas ---------------------------------------------------------------
+
+saveasHM:This is the %s dialogue box.
+saveasFIH:Drag this icon to a Filer window or another application to save the file.
+saveasDI:To save, drag icon to a directory viewer.
+saveasWRT:Type the name you want to use for your file in here.
+saveasHOK:Click here to save the file using the name given.
+
+#----- stddbox --------------------------------------------------------------
+
+stddbWARN:Warning from %s
+stddbNOTE:Note from %s
+stddbPIH:This window gives you information about this version of %s.
+stddbREFN:File '%s' has been modified, but not saved.  Do you want to discard these changes, save and then close the file, or cancel?"
+stddbREF:This file has been modified, but not saved.  Do you want to discard these changes, save and then close the file, or cancel?"
+#----- tcol -----------------------------------------------------------------
+
+tcolHM:This is the Colour Selector.
+tcolNEM:Not enough memory to create dbox.
+tcolHTIT:This shows you what colour you are selecting.
+tcolHRU:Click SELECT to increase the amount of red.|mClick ADJUST to decrease.
+tcolHRD:Click SELECT to decrease the amount of red.|mClick ADJUST to increase.
+tcolHRW:Type the amount of red desired in here.
+tcolHRS:Drag this bar to change the amount of red.
+tcolHGU:Click SELECT to increase the amount of green.|mClick ADJUST to decrease.
+tcolHGD:Click SELECT to decrease the amount of green.|mClick ADJUST to increase.
+tcolHGW:Type the amount of green desired in here.
+tcolHGS:Drag this bar to change the amount of green.
+tcolHBU:Click SELECT to increase the amount of blue.|mClick ADJUST to decrease.
+tcolHBD:Click SELECT to decrease the amount of blue.|mClick ADJUST to increase.
+tcolHBW:Type the amount of blue desired in here.
+tcolHBS:Drag this bar to change the amount of blue.
+tcolHCOL:This shows you an approximation of the colour you have chosen.
+tcolHOK:Click SELECT to confirm your choice of colour.|mClicking ADJUST keeps the dialogue on-screen.
+tcolHCAN:Click SELECT to abort selection of the colour.
+
+#----- viewer ---------------------------------------------------------------
+
+viewerNEM:Not enough room to create viewer.
+viewerTMW:Too many windows - %s could not create viewer.
+viewerCCI:Not enough room to create new icon.
+viewerMIS:Selection
+viewerVIE:(viewer_helpIcon, caller fault): Not called on HELPREQUEST event.
+
+#----- werr -----------------------------------------------------------------
+
+werrSEM:Could not initialise.
+
+#----- wimpt ----------------------------------------------------------------
+
+wimptSIGC:%s - code=%s
+wimptNEMI:Not enough memory to initialise.
+wimptFTI:Failed to initialise: '%s'
+
+#----- win ------------------------------------------------------------------
+
+winNEM:Not enough memory for new event handler.
+
+#============================================================================
diff --git a/StraySrc/Libraries/Steel/c/akbd b/StraySrc/Libraries/Steel/c/akbd
new file mode 100644 (file)
index 0000000..ce11fc1
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * akbd.c
+ *
+ * Really good keyboard handling
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "os.h"
+#include "akbd.h"
+#include "bbc.h"
+
+/*
+ * BOOL akbd_checkInternalKey(int ikey)
+ *
+ * Use
+ *  Checks whether a given key is being pressed at the moment.
+ *
+ * Parameters
+ *  int ikey == the internal key number of the key to check, as shown on page
+ *    1-849 of the RISC OS 3 Programmer's Reference Manual.
+ */
+
+BOOL akbd_checkInternalKey(int ikey)
+{
+  return (bbc_inkey(0xFF00 | (ikey ^ 0xFF)));
+}
+
+/*
+ * int akbd_translate(int chcode)
+ *
+ * Use
+ *  Translates the given WIMP-type key number, as returned in a Key_Pressed
+ *  (wimp_EKEY) event into a STEEL extended key number, which should
+ *  distinguish almost every keypress available.
+ *
+ * Parameters
+ *  int chcode == a WIMP-type keypress number
+ *
+ * Returns
+ *  An extended keycode
+ */
+
+#define akbd__WEIRDCTRL 0x000003BB
+
+#define akbd__modify(a,b,c,d) \
+  switch (modifiers) \
+  { \
+    case 0: \
+      return (a); \
+    case 1: \
+      return (b); \
+    case 2: \
+      return (c); \
+    case 3: \
+      return (d); \
+  }
+
+int akbd_translate(int chcode)
+{
+  int modifiers;
+  int icode=0;
+  int base=0;
+
+  /* --- If it's a function key, the WIMP has translated it for us --- */
+
+  if ((chcode>=0x1CA) ||
+      (chcode>=0x180 && chcode<=0x1BF) ||
+      (chcode>='a' && chcode<='z') ||
+      (chcode>='A' && chcode<='Z') ||
+      (chcode>='[' && chcode<=']'))
+    return (chcode);
+
+  /* --- Work out the modifier status --- */
+
+  modifiers=0;
+  if (akbd_checkInternalKey(0))
+    modifiers|=1;
+  if (akbd_checkInternalKey(1))
+    modifiers|=2;
+
+  /* --- How many ways can you press Delete? --- */
+
+  if (chcode==0x7F)
+  {
+    switch (modifiers)
+    {
+      case 0:
+        return (0x7F);
+      case 1:
+        return (0x17F);
+      case 2:
+        return (0x01F);
+      case 3:
+        return (0x11F);
+    }
+  }
+
+  /* --- Check for variants of space --- */
+
+  if (chcode==' ')
+    akbd__modify(0x020,0x120,0x000,0x100);
+
+  /* --- The many faces of the Return key --- */
+
+  if (chcode==0x0D)
+  {
+    /* --- He pressed return (or maybe ^M, or even Enter...) --- */
+
+    if (akbd_checkInternalKey(60))
+    {
+      /* --- It was Enter, so return a variant of that --- */
+
+      akbd__modify(0x166,0x176,0x126,0x146);
+    }
+    else if (!akbd_checkInternalKey(101))
+    {
+      /* --- It *wasn't* ^M, so it must have been Return --- */
+
+      akbd__modify(0x01D,0x11D,0x13D,0x15D);
+    }
+    /* --- If it was ^M, the control key mashing will catch it --- */
+  }
+
+  /* --- Check for control keys --- */
+
+  if (chcode<0x1B)
+  {
+    if (akbd__WEIRDCTRL & (1<<chcode))
+    {
+      /* --- It's a control key, Jim, but not as we know it... --- */
+
+      static char intCodes[]={0,48,0,17,18,19,0,36,21,38};
+
+      if (chcode==0x008)
+      {
+        /* --- It's backspace, though it may be ^H --- */
+
+        if (!akbd_checkInternalKey(84) &&
+            !akbd_checkInternalKey(21))
+        {
+          /* --- It really is backspace, or a variant thereof --- */
+
+          akbd__modify(0x01C,0x11C,0x13C,0x15C);
+        }
+      }
+      if (chcode)
+      {
+        /* --- It's not a *really* weird key at least --- */
+
+        if (akbd_checkInternalKey(intCodes[chcode]))
+        {
+          /* --- It was a strange ^digit key press --- */
+
+          if (modifiers & 1)
+            return (chcode+0x150);
+          else
+            return (chcode+0x130);
+        }
+      }
+      else
+      {
+        /* --- The many things that return 0 --- */
+
+        if (akbd_checkInternalKey(39))
+          base=0;
+        else
+          base=2;
+        if (modifiers & 1)
+          return (0x150+base);
+        else
+          return (0x130+base);
+      }
+    }
+
+    /* --- Ok -- it's fairly sane then --- */
+
+    if (modifiers & 1)
+      return (chcode+0x100);
+    else
+      return (chcode);
+  }
+
+  /* --- Check for number key presses --- */
+
+  if (chcode>='0' && chcode<='9')
+  {
+    static char keypadTable[]={106,107,124,108,122,123,26,27,42,43};
+
+    if (akbd_checkInternalKey(keypadTable[chcode-'0']))
+    {
+      /* --- It was the keypad version, so we have to modify it --- */
+
+      return (chcode+(0x1C0-'0')+(modifiers<<4));
+    }
+    else
+      return (chcode);
+  }
+
+  /* --- Test for the rest of the keypad --- */
+
+  switch (chcode)
+  {
+    case '/': icode=74; base=0x161; break;
+    case '*': icode=91; base=0x162; break;
+    case '#': icode=90; base=0x163; break;
+    case '-': icode=59; base=0x164; break;
+    case '+': icode=58; base=0x165; break;
+    case '.': icode=76; base=0x167; break;
+  }
+  if (icode)
+  {
+    /* --- It could be a keypad key here, so check --- */
+
+    if (akbd_checkInternalKey(icode))
+    {
+      /* --- It is one of the other keypad keys, so return it modified --- */
+
+      akbd__modify(base,base+16,base-64,base-32);
+    }
+  }
+
+  /* --- The revolting gross (US-ism -- yuk) keys that are left --- */
+
+  switch (chcode)
+  {
+    case 0x01E:
+      /* --- Home, or maybe ^6 :-/ --- */
+
+      if (akbd_checkInternalKey(24))
+      {
+        if (modifiers & 1)
+          return (0x156);
+        else
+          return (0x136);
+      }
+      else
+        akbd__modify(0x01E,0x11E,0x13E,0x15E);
+      break;
+
+    case 0x01B:
+      /* --- Escape, or maybe ^[ :-/ --- */
+
+      if (akbd_checkInternalKey(56))
+      {
+        if (modifiers & 1)
+          return (0x14B);
+        else
+          return (0x12B);
+      }
+      else
+        akbd__modify(0x01B,0x11B,0x13B,0x15B);
+      break;
+
+    case 0x01C:
+    case 0x01D:
+    case 0x01F:
+      if (modifiers & 1)
+        return (chcode+0x130);
+      else
+        return (chcode+0x110);
+      break;
+  }
+
+  /* --- Hmm -- it seems sensible after all --- */
+
+  return (chcode);
+}
+
+/*
+ * BOOL akbd_pollsh(void)
+ *
+ * Use
+ *  Returns whether the Shift key is pressed
+ */
+
+BOOL akbd_pollsh(void)
+{
+  return (akbd_checkInternalKey(0));
+}
+
+/*
+ * BOOL akbd_pollctl(void)
+ *
+ * Use
+ *  Returns whether the Control key is pressed
+ */
+
+BOOL akbd_pollctl(void)
+{
+  return (akbd_checkInternalKey(1));
+}
+
+/*
+ * BOOL akbd_pollkey(int *code)
+ *
+ * Use
+ *  Reports whether the user has typed ahead, and if so what the keypress
+ *  was.  Note that the keypresses returned are WIMP-type, not STEEL extended
+ *  ones so you will have to use akbd_translate if you need the extended
+ *  type.
+ *
+ *  This call could be used to allow buffering of keypresses: on a
+ *  Key_Pressed event you would call this routine until it returns FALSE
+ *  and store the codes it returns in a buffer along with the code from the
+ *  event.
+ */
+
+BOOL akbd_pollkey(int *code)
+{
+  int key;
+
+  /* --- Find out if there is a key waiting --- */
+
+  key=bbc_inkey(0);
+  if (key==-1)
+    return (FALSE);
+
+  /* --- Check for extended codes --- */
+
+  if (!key)
+  {
+    key=bbc_inkey(0);
+    if (key)
+      *code=key+0x100;
+    else
+      *code=0;
+  }
+  else
+    *code=key;
+
+  /* --- We found one --- */
+
+  return (TRUE);
+}
diff --git a/StraySrc/Libraries/Steel/c/alarm b/StraySrc/Libraries/Steel/c/alarm
new file mode 100644 (file)
index 0000000..71e14aa
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * alarm.c
+ *
+ * Calling routines at set times
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "alarm.h"
+#include "mem.h"
+#include "werr.h"
+#include "msgs.h"
+#include "os.h"
+#include "swiv.h"
+#include "swis.h"
+
+typedef struct alarm__str
+{
+  struct alarm__str *next;
+  alarm_handler proc;
+  void *handle;
+  int time;
+}
+alarm__str;
+
+static alarm__str *alarm__all;
+
+/*
+ * void alarm_init(void)
+ *
+ * Use
+ *  None at all
+ */
+
+void alarm_init(void)
+{
+  /* Hmmm.... this *is* an interesting function */
+}
+
+/*
+ * int alarm_timenow(void)
+ *
+ * Use
+ *  Reports the time right now
+ */
+
+int alarm_timenow(void)
+{
+  return (_swi(OS_ReadMonotonicTime,_return(0)));
+}
+
+/*
+ * int alarm_timedifference(int t1,int t2)
+ *
+ * Use
+ *  Tells you the difference between two times.  t2 is considered to be later
+ *  than t1.
+ */
+
+int alarm_timedifference(int t1,int t2)
+{
+  /* --- Humm.... How to deal with wraparound --- *
+   *
+   * Answer: Ignore it and subtract -- mod 2^32 arithmetic + 2s complement
+   * sorts it all out for you.
+   */
+
+  return (t2-t1);
+}
+
+/*
+ * void alarm_set(int at,alarm_handler proc,void *handle)
+ *
+ * Use
+ *  Sets up `proc' to be called at time `at', being passed `handle'.
+ */
+
+void alarm_set(int at,alarm_handler proc,void *handle)
+{
+  alarm__str *a=mem_alloc(sizeof(alarm__str));
+  alarm__str *p;
+  if (!a)
+    werr(FALSE,msgs_lookup("alarmNEM:Not enough memory for alarm"));
+  else
+  {
+    /* --- Fill in the structure --- */
+
+    a->time=at;
+    a->proc=proc;
+    a->handle=handle;
+
+    /* --- Scan the list and put the new node in the right place --- *
+     *
+     * Is this the right condition for the times?
+     */
+
+    p=(alarm__str *)&alarm__all;
+    while (p->next && p->next->time<at)
+      p=p->next;
+    a->next=p->next;
+    p->next=a;
+  }
+}
+
+/*
+ * void alarm_remove(int at,void *handle)
+ *
+ * Use
+ *  Removes an alarm identified by a time and a handle
+ */
+
+void alarm_remove(int at,void *handle)
+{
+  alarm__str *p;
+  alarm__str *q;
+
+  p=(alarm__str *)&alarm__all;
+  while (p->next)
+  {
+    if (p->next->time==at && p->next->handle==handle)
+    {
+      q=p->next;
+      p->next=q->next;
+      mem_free(q);
+      return;
+    }
+    p=p->next;
+  }
+}
+
+/*
+ * void alarm_removeall(void *handle)
+ *
+ * Use
+ *  Removes all alarms for the given handle
+ */
+
+void alarm_removeall(void *handle)
+{
+  alarm__str *p;
+  alarm__str *q;
+
+  p=(alarm__str *)&alarm__all;
+  while (p->next)
+  {
+    if (p->next->handle==handle)
+    {
+      q=p->next;
+      p->next=q->next;
+      mem_free(q);
+    }
+    else
+      p=p->next;
+  }
+}
+
+/*
+ * BOOL alarm_anypending(void *handle)
+ *
+ * Use
+ *  Returns TRUE if there are alarms for the given handle
+ */
+
+BOOL alarm_anypending(void *handle)
+{
+  alarm__str *p=alarm__all;
+
+  while (p)
+  {
+    if (p->handle==handle)
+      return (TRUE);
+    p=p->next;
+  }
+  return (FALSE);
+}
+
+/*
+ * BOOL alarm_next(int *when)
+ *
+ * Use
+ *  Informs the caller (a) if there are any alarms waiting, and (b) when
+ *  the next one is.
+ *
+ * Parameters
+ *  int *when == where to put the next time for an alarm (unchanged if no
+ *    alarm is set)
+ *
+ * Returns
+ *  TRUE if there are any alarms left
+ */
+
+BOOL alarm_next(int *when)
+{
+  if (alarm__all)
+  {
+    *when=alarm__all->time;
+    return (TRUE);
+  }
+  else
+    return (FALSE);
+}
+
+/*
+ * void alarm_callnext(void)
+ *
+ * Use
+ *  Calls the next alarm and removes it from the list
+ */
+
+void alarm_callnext(void)
+{
+  alarm__str a;
+
+  if (!alarm__all)
+    return;
+
+  a=*alarm__all;
+  mem_free(alarm__all);
+  alarm__all=a.next;
+  a.proc(a.time,a.handle);
+}
diff --git a/StraySrc/Libraries/Steel/c/baricon b/StraySrc/Libraries/Steel/c/baricon
new file mode 100644 (file)
index 0000000..46790ed
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * baricon
+ *  stripped down version (uses ibicon)
+ *
+ * © 1993-1998 Straylight
+ *
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "baricon.h"
+
+static ibicon baricon__icon;
+static baricon_clickproc baricon__proc;
+
+static void baricon__events(ibicon i,ibicon_eventType t,void *handle)
+{
+  handle=handle;
+  i=i;
+  if (t==ibicon_LEFTCLICK)
+    baricon__proc(ibicon_syshandle(baricon__icon));
+}
+
+wimp_i baricon(char *spritename,int spritearea,baricon_clickproc p)
+{
+  baricon__icon=ibicon_create
+  (
+    ibicon_RIGHT,
+    spritename,
+    (sprite_area *)spritearea,
+    0,
+    0
+  );
+  ibicon_eventHandler(baricon__icon,baricon__events,0);
+  baricon__proc=p;
+  return (ibicon_syshandle(baricon__icon));
+}
+
+wimp_i baricon_left(char *spritename,int spritearea,baricon_clickproc p)
+{
+  baricon__icon=ibicon_create
+  (
+    ibicon_LEFT,
+    spritename,
+    (sprite_area *)spritearea,
+    0,
+    0
+  );
+  ibicon_eventHandler(baricon__icon,baricon__events,0);
+  baricon__proc=p;
+  return (ibicon_syshandle(baricon__icon));
+}
+
+wimp_i baricon_textandsprite
+(
+  char *spritename,
+  char *text,
+  int bufflen,
+  int spritearea,
+  baricon_clickproc p
+)
+{
+  baricon__icon=ibicon_create
+  (
+    ibicon_RIGHT,
+    spritename,
+    (sprite_area *)spritearea,
+    text,
+    bufflen-1
+  );
+  ibicon_eventHandler(baricon__icon,baricon__events,0);
+  baricon__proc=p;
+  return (ibicon_syshandle(baricon__icon));
+}  
+
+wimp_i baricon_textandsprite_left
+(
+  char *spritename,
+  char *text,
+  int bufflen,
+  int spritearea,
+  baricon_clickproc p
+)
+{
+  baricon__icon=ibicon_create
+  (
+    ibicon_LEFT,
+    spritename,
+    (sprite_area *)spritearea,
+    text,
+    bufflen-1
+  );
+  ibicon_eventHandler(baricon__icon,baricon__events,0);
+  baricon__proc=p;
+  return (ibicon_syshandle(baricon__icon));  
+}  
+
+wimp_i baricon_newsprite(char *newsprite)
+{
+  ibicon_changeSprite(baricon__icon,newsprite);
+  return (ibicon_syshandle(baricon__icon));  
+}
+
+wimp_i baricon_newtext(char *newtext)
+{
+  ibicon_changeText(baricon__icon,newtext);
+  return (ibicon_syshandle(baricon__icon));  
+}
diff --git a/StraySrc/Libraries/Steel/c/blinkC b/StraySrc/Libraries/Steel/c/blinkC
new file mode 100644 (file)
index 0000000..61e980d
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * BlinkCursor
+ *  A nice blinky caret routine for your progs
+ *
+ * v. 1.00 (23 July 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wimp.h"
+#include "wimpt.h"
+#include "os.h"
+#include "blinkC.h"
+#include "alarm.h"
+#include "swiv.h"
+#include <stdlib.h>
+
+#include "dll.h"
+
+#ifndef _dll_NODLL
+  extern void _dllEntry(blink__exit)(void);
+  extern void _dllEntry(blink__doBlink)(int at,void *handle);
+#endif
+
+/*
+ * A handle thing for alarm.  It's not used by the routine, but it helps
+ * identify the alarm routine to be removed.
+ */
+#define blink__MYHANDLE (void *)&blink__onAlready
+
+/*
+ * The SWI number for Wimp_SendMessage.
+ */
+#define Wimp_SendMessage 0x600E7
+
+/*
+ * Due to circular definitions, I am forced to add in a prototype for this
+ * function.
+ */
+static void blink__setupAlarm(void);
+
+/*
+ * A flag to say whether we are on already or not.
+ */
+static BOOL blink__onAlready;
+
+/*
+ * A flag to say whether the caret is visible or not.
+ */
+static BOOL blink__caretVisible;
+
+/*
+ * void blink__onCaret(void)
+ *
+ * Use
+ *  Makes the caret visible.
+ */
+
+static void blink__onCaret(void)
+{
+  wimp_caretstr c;
+  wimpt_noerr(wimp_get_caret_pos(&c));
+  c.height &= ~(1<<25);
+  wimpt_noerr(wimp_set_caret_pos(&c));
+  blink__caretVisible=TRUE;
+}
+
+/*
+ * void blink__offCaret(void)
+ *
+ * Use
+ *  Makes the caret invisible.
+ */
+
+static void blink__offCaret(void)
+{
+  wimp_caretstr c;
+  wimpt_noerr(wimp_get_caret_pos(&c));
+  c.height |= 1<<25;
+  wimpt_noerr(wimp_set_caret_pos(&c));
+  blink__caretVisible=FALSE;
+}
+
+/*
+ * BOOL blink__ownCaret(void)
+ *
+ * Use
+ *  Returns whether the task owns the caret or not!
+ *
+ * Returns
+ *  TRUE if it does.
+ */
+
+static BOOL blink__ownCaret(void)
+{
+  wimp_caretstr c;
+  wimp_msgstr m;
+  int task;
+  wimpt_noerr(wimp_get_caret_pos(&c));
+  if (c.w<=0)
+    return (FALSE);
+  m.hdr.size=20;
+  m.hdr.your_ref=0;
+  _swix(Wimp_SendMessage, _inr(0,2)+_out(2), 19,&m,c.w, &task);
+  return (task==wimpt_task());
+}
+
+_dll_static void blink__doBlink(int at,void *handle)
+{
+  handle=handle;
+  at=at;
+  if (blink__ownCaret())
+  {
+    switch (blink__caretVisible)
+    {
+      case TRUE:
+        blink__offCaret();
+        break;
+      case FALSE:
+        blink__onCaret();
+        break;
+    }
+  }
+  blink__setupAlarm();
+}
+
+/*
+ * void blink__setupAlarm(void)
+ *
+ * Use
+ *  Sets up next alarm ready.
+ */
+
+static void blink__setupAlarm(void)
+{
+  int nextTime=((alarm_timenow()/25)*25)+25;
+  alarm_set(nextTime,_dllEntry(blink__doBlink),blink__MYHANDLE);
+}
+
+/*
+ * void blinkCursor(BOOL onOrOff)
+ *
+ * Use
+ *  Turns the blinkingness of the cursor on or off.  You must call
+ *  alarm_init() before this function, or all hell breaks loose.
+ *
+ * Parameters
+ *  BOOL onOrOff == whether you want to turn blinking cursor on or off
+ */
+
+void blinkCursor(BOOL onOrOff)
+{
+  if (onOrOff==blink__onAlready)
+    return;
+  switch (onOrOff)
+  {
+    case TRUE:
+      blink__setupAlarm();
+      blink__onAlready=TRUE;
+      break;
+    case FALSE:
+      if (blink__ownCaret())
+        blink__onCaret();
+      alarm_removeall(blink__MYHANDLE);
+      blink__onAlready=FALSE;
+      break;
+  }
+}
+
+/*
+ * void blink__exit(void)
+ *
+ * Use
+ *  Turns off the caret blinking.
+ */
+
+_dll_static void blink__exit(void)
+{
+  blinkCursor(FALSE);
+}
+
+/*
+ * void blink_init(void)
+ *
+ * Use
+ *  Sets everything up nicely.
+ */
+
+void blink_init(void)
+{
+  atexit(_dllEntry(blink__exit));
+}
diff --git a/StraySrc/Libraries/Steel/c/buffer b/StraySrc/Libraries/Steel/c/buffer
new file mode 100644 (file)
index 0000000..24e4bab
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * buffer.c
+ *
+ * Two buffers for building strings in
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "buffer.h"
+
+/*
+ * char *buffer_find(void)
+ *
+ * Use
+ *  Returns a pointer to a 256-byte buffer.  There are two buffers, which are
+ *  returned alternately.
+ */
+
+char *buffer_find(void)
+{
+  static int which;
+  static char buffers[512];
+  which^=256;
+  return (buffers+which);
+}
diff --git a/StraySrc/Libraries/Steel/c/buttons b/StraySrc/Libraries/Steel/c/buttons
new file mode 100644 (file)
index 0000000..395b38d
--- /dev/null
@@ -0,0 +1,808 @@
+/*
+ * Buttons
+ *  provides handling for clever buttons and things.
+ *
+ * v. 1.00 (23 July 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wimp.h"
+#include "wimpt.h"
+#include "buttons.h"
+#include "bbc.h"
+#include "win.h"
+#include "werr.h"
+#include <stdio.h>
+#include "colourtran.h"
+#include "msgs.h"
+#include "mem.h"
+#include "alarm.h"
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct
+{
+  /* --- Information from the caller --- */
+
+  dbox d;
+  dbox_field f;
+  dbox wd;
+  dbox_field wf;
+  int diff;
+  buttons_arrowProc p;
+  void *handle;
+
+  /* --- Other information about the arrow --- */
+
+  int rate;
+  BOOL done;
+}
+buttons__arrowstr;
+
+/*
+ * A structure that says everything necessary about a slider
+ */
+
+typedef struct
+{
+  dbox d;
+  wimp_i i;
+  int max;
+  int *val;
+  int colour;
+  BOOL isVertical;
+  int slideMax;
+  int iwidth;
+  int o;
+  buttons_sliderHandler proc;
+  void *handle;
+  BOOL dragOver;
+  int lastLen;
+}
+buttons__sliderstr;
+
+static BOOL buttons__testMouse=TRUE;
+
+/*
+ * void buttons_arrowClick
+ * (
+ *   dbox d,
+ *   dbox_field f,
+ *   int min,
+ *   int max,
+ *   int increment,
+ *   BOOL wrap
+ * )
+ *
+ * Use
+ *  Increases (or decreases) the value in a writable box.  If the last event
+ *  was a click with the adjust button, the increment is made negative (i.e.
+ *  1 becomes -1, and -1 becomes 1), following the standard convention.  The
+ *  value will not be allowed to exceed the limits passed.  If you don't
+ *  want limits, make max and min the same.  Optionally, you can make the
+ *  field's value 'wrap around' if it goes out of range.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field number
+ *  int min == the lowest allowable value for the field
+ *  int max == the highest allowable value for the field
+ *  int increment == what to add to the value.  This may be negative.
+ *  BOOL wrap == wrap around or not
+ */
+
+void buttons_arrowClick
+(
+  dbox d,
+  dbox_field f,
+  int min,
+  int max,
+  int increment,
+  BOOL wrap
+)
+{
+  int value=dbox_getNumeric(d,f);
+
+  if (buttons__testMouse && dbox_wasAdjustClick())
+    increment=-increment;
+  value+=increment;
+  if (max>min)
+  {
+    if (value>max)
+      value=wrap ? min : max;
+    if (value<min)
+      value=wrap ? max : min;
+  }
+  dbox_setNumeric(d,f,value);
+}
+
+/*
+ * void buttons__simpleArrows(dbox d,dbox_field f,int diff,void *handle)
+ *
+ * Use
+ *  Handles a simple arrow click event on an arrow button
+ *
+ * Parameters
+ *  dbox d == the dbox containing the writable bitty to bump
+ *  dbox_field == the field to bump
+ *  int diff == how much to bump it by
+ *  void *handle == pointer to more information about the bump op
+ */
+
+static void buttons__simpleArrows(dbox d,dbox_field f,int diff,void *handle)
+{
+  buttons_simpleArrow *sa=handle;
+
+  buttons_arrowClick(d,f,sa->min,sa->max,diff,sa->wrap);
+}
+
+/*
+ * void buttons__arrowAlarm(int at,void *handle)
+ *
+ * Use
+ *  Handles an alarm for the arrow handlers: we use alarms to handle the
+ *  auto-repeat on the arrows more easily.
+ *
+ * Parameters
+ *  int at == when this alarm was meant to happen
+ *  void *handle == information about the arrow handling
+ */
+
+static void buttons__arrowAlarm(int at,void *handle)
+{
+  buttons__arrowstr *a=handle;
+  int missed;
+
+  /* --- Call the user function, and get a call-back --- *
+   *
+   * We resynch to the original time, to try to make up for any major
+   * problems, in case the repeat rate is very slow.
+   */
+
+  (a->p)(a->wd,a->wf,a->diff,a->handle);
+  missed=(alarm_timenow()-at)/a->rate;
+  alarm_set(at+(missed+1)*a->rate,buttons__arrowAlarm,a);
+}
+
+/*
+ * BOOL buttons__arrowUnknowns(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Picks up unknown events for the duration of an arrow operation.  It is
+ *  used to detect the raising of the mouse buttons by picking up the
+ *  WIMP drag event
+ */
+
+static BOOL buttons__arrowUnknowns(wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  buttons__arrowstr *a=handle;
+
+  switch (e->e)
+  {
+    case wimp_EUSERDRAG:
+      a->done=TRUE;
+      win_remove_unknown_event_processor(buttons__arrowUnknowns,a);
+      handled=TRUE;
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void buttons_arrow(dbox d,
+ *                    dbox_field f,
+ *                    dbox wd,
+ *                    dbox_field wf,
+ *                    buttons_arrowProc p,
+ *                    int diff,
+ *                    void *handle)
+ *
+ * Use
+ *  Handles a click on an arrow button.  It constrains the mouse pointer
+ *  so it doesn't drift away annoyingly, and presses the icon in (by
+ *  selecting it, so set up the sprites properly) while it's being clicked,
+ *  with nary a flicker in sight.  It simulates auto-repeat on the button,
+ *  so don't use real auto-repeat buttons.
+ *
+ * Parameters
+ *  dbox d,dbox_field f == the icon that was clicked
+ *  dbox wd,dbox_field wf == the (writable) icon that is passed to p
+ *  buttons_arrowProc p == a procedure to call for each `click' on the
+ *   button.  It may call buttons_arrowClick to bump the field.  If you pass
+ *   0, a default function is called which just bumps the icon.  handle must
+ *   point to a buttons_simpleArrow structure filled in correctly.
+ *  int diff == the difference to add to the icon (passed to p).  The sign
+ *   is toggled if the click was with the adjust button.
+ *  void *handle == a handle to pass to p
+ */
+
+void buttons_arrow(dbox d,
+                   dbox_field f,
+                   dbox wd,
+                   dbox_field wf,
+                   buttons_arrowProc p,
+                   int diff,
+                   void *handle)
+{
+  buttons__arrowstr ar;
+  wimp_mousestr m;
+  int rate=0,delay=0;
+  int read_osbyte;
+  wimp_dragstr drag;
+
+  /* --- Handle adjust-clicks in time-honoured fashion --- */
+
+  if (dbox_wasAdjustClick())
+    diff=-diff;
+
+  /* --- Start a drag to constrain the mouse --- */
+
+  wimpt_noerr(wimp_get_point_info(&m));
+  drag.window=dbox_syshandle(d);
+  drag.type=wimp_USER_HIDDEN;
+  drag.parent.x0=drag.parent.x1=m.x;
+  drag.parent.y0=drag.parent.y1=m.y;
+  wimpt_noerr(wimp_drag_box(&drag));
+
+  /* --- Read auto-repeat information --- */
+
+  read_osbyte=255;
+  os_byte(196,&delay,&read_osbyte);
+
+  read_osbyte=255;
+  os_byte(197,&rate,&read_osbyte);
+
+  /* --- Fill in the structure --- */
+
+  ar.d=d;
+  ar.f=f;
+  ar.wd=wd;
+  ar.wf=wf;
+  ar.p=p ? p : buttons__simpleArrows;
+  ar.diff=diff;
+  ar.handle=handle;
+  ar.rate=rate;
+  ar.done=FALSE;
+
+  /* --- Perform an initial `click' --- */
+
+  dbox_selecticon(d,f,TRUE);
+  buttons__testMouse=FALSE;
+  ar.p(wd,wf,diff,handle);
+
+  /* --- Set the alarm up to do the next one --- */
+
+  alarm_set(alarm_timenow()+delay,buttons__arrowAlarm,&ar);
+  win_add_unknown_event_processor(buttons__arrowUnknowns,&ar);
+
+  /* --- Wait until the user stops clicking --- */
+
+  while (!ar.done)
+    event_process();
+
+  /* --- Tidy everything away again --- */
+
+  dbox_selecticon(d,f,FALSE);
+  buttons__testMouse=TRUE;
+  alarm_removeall(&ar);
+}
+
+/*
+ * BOOL buttons_insertChar(dbox d,int chcode,char min,char max)
+ *
+ * Use
+ *  This function inserts the character specified into the writable field
+ *  containing the caret.  Useful if you want to handle input yourself so
+ *  you can update things (such as sliders) in deending on the input.  It
+ *  will insure that the character is within the limits given (invalid
+ *  limits will cause a default of 32-255 to be used).
+ *
+ * Parameters
+ *  dbox d == dbox handle
+ *  int chcode == the character, as returned from event_process().
+ *  char min == minimum character allowable.
+ *  char max == maximum character allowable.
+ *
+ * Returns
+ *  Whether it inserted the character or not.
+ */
+
+BOOL buttons_insertChar(dbox d,int chcode,char min,char max)
+{
+  wimp_caretstr c;
+  char field[255];
+  int i;
+  int len;
+  if (min>=max)
+  {
+    min=32;
+    max=255;
+  }
+  if (chcode<min || chcode>max)
+    return (FALSE);
+  wimpt_noerr(wimp_get_caret_pos(&c));
+  c.height=-1;
+  dbox_getfield(d,c.i,field,254);
+  len=strlen(field);
+  for (i=len;i>=c.index;i--)
+    field[i+1]=field[i];
+  field[c.index]=chcode;
+  c.index++;
+  dbox_setfield(d,c.i,field);
+  wimpt_noerr(wimp_set_caret_pos(&c));
+  return (TRUE);
+}
+
+/*
+ * void buttons__rect(int x1,int y1,int x2,int y2,int colour)
+ *
+ * Use
+ *  Gagdy veneer for bbc_rectanglefill
+ *
+ * Parameters
+ *  int x1 == left side
+ *  int y1 == bottom
+ *  int x2 == right side
+ *  int y2 == top
+ *  int colour == the colour to use
+ */
+
+static void buttons__rect(int x1,int y1,int x2,int y2,int colour)
+{
+  int w,h;
+  wimpt_noerr(wimp_setcolour(colour));
+  w=x2-x1;
+  h=y2-y1;
+  if (w && h)
+    wimpt_noerr(bbc_rectanglefill(x1,y1,w,h));
+}
+
+/*
+ * void buttons__doRdrSlider
+ * (
+ *   wimp_w w,
+ *   wimp_icon *icn,
+ *   int slideLen,
+ *   int colour,
+ *   BOOL isVertical
+ * )
+ *
+ * Use
+ *  Redraws a slider with the specified length.
+ *
+ * Parameters
+ *  wimp_w w == the window handle
+ *  wimp_icon *icn == pointer to the icon definition
+ *  int slideLen == the length to draw the slider
+ *  int colour ==  colour of the slider
+ *  BOOL isVertical == whether the slider is vertical
+ */
+
+static void buttons__doRdrSlider
+(
+  wimp_w w,
+  wimp_icon *icn,
+  int slideLen,
+  int colour,
+  BOOL isVertical
+)
+{
+  wimp_wstate state;
+  int bordCol;
+  int backg;
+  int ox,oy;
+  wimpt_noerr(wimp_get_wind_state(w,&state));
+  bordCol=(((int)icn->flags)>>24) & 15;
+  backg=(((int)icn->flags)>>28) & 15;
+  ox=state.o.box.x0-state.o.x;
+  oy=state.o.box.y1-state.o.y;
+  if (isVertical)
+  {
+    buttons__rect
+    (
+      icn->box.x0+ox , icn->box.y0+oy ,
+      icn->box.x1+ox , slideLen+icn->box.y0+oy ,
+      colour
+    );
+    buttons__rect
+    (
+      icn->box.x0+ox , icn->box.y0+oy+slideLen ,
+      icn->box.x1+ox , icn->box.y1+oy ,
+      backg
+    );
+    wimpt_noerr(wimp_setcolour(bordCol));
+    wimpt_noerr(bbc_move(ox+icn->box.x0,oy+icn->box.y0+slideLen));
+    wimpt_noerr(bbc_draw(ox+icn->box.x1,oy+icn->box.y0+slideLen));
+  }
+  else
+  {
+    buttons__rect
+    (
+      icn->box.x0+ox , icn->box.y0+oy ,
+      slideLen+icn->box.x0+ox , icn->box.y1+oy ,
+      colour
+    );
+    buttons__rect
+    (
+      icn->box.x0+ox+slideLen , icn->box.y0+oy ,
+      icn->box.x1+ox , icn->box.y1+oy ,
+      backg
+    );
+    wimpt_noerr(wimp_setcolour(bordCol));
+    wimpt_noerr(bbc_move(ox+icn->box.x0+slideLen,oy+icn->box.y0));
+    wimpt_noerr(bbc_draw(ox+icn->box.x0+slideLen,oy+icn->box.y1));
+  }
+}
+
+/*
+ * void buttons_redrawSlider
+ * (
+ *   dbox d,
+ *   wimp_i i,
+ *   int max,
+ *   int val,
+ *   int colour,
+ *   BOOL isVertical
+ * )
+ *
+ * Use
+ *  Draws a slider in the specified icon
+ *
+ * Parameters
+ *  dbox d == dbox handle
+ *  wimp_i icon == the icon we're dealing with
+ *  int max == the maximum value you want
+ *  int val == the current value of the slider
+ *  int colour == the WIMP colour for the slider
+ *  BOOL isVertical == TRUE if the slider is vertical
+ */
+
+void buttons_redrawSlider
+(
+  dbox d,
+  wimp_i i,
+  int max,
+  int val,
+  int colour,
+  BOOL isVertical
+)
+{
+  wimp_w w=dbox_syshandle(d);
+  wimp_icon icn;
+  int slideLen,slideMax;
+  wimpt_noerr(wimp_get_icon_info(w,i,&icn));
+  icn.box.x0+=wimpt_dx();
+  icn.box.y0+=wimpt_dy();
+  icn.box.x1-=2*wimpt_dx();
+  icn.box.y1-=2*wimpt_dy();
+  slideMax=isVertical ? icn.box.y1-icn.box.y0 : icn.box.x1-icn.box.x0;
+  slideLen=(val*slideMax)/max;
+  if (slideLen>slideMax)
+    slideLen=slideMax;
+  buttons__doRdrSlider(w,&icn,slideLen,colour,isVertical);
+}
+
+/*
+ * void buttons_updateSlider
+ * (
+ *   dbox d,
+ *   wimp_i i,
+ *   int max,
+ *   int val,
+ *   int colour,
+ *   BOOL isVertical
+ * )
+ *
+ * Use
+ *  Redraws a slider in the specified icon
+ *
+ * Parameters
+ *  dbox d == dbox handle
+ *  wimp_i icon == the icon we're dealing with
+ *  int max == the maximum value you want
+ *  int val == the current value of the slider
+ *  int colour == the WIMP colour for the slider
+ *  BOOL isVertical == TRUE if the slider is vertical
+ */
+
+void buttons_updateSlider
+(
+  dbox d,
+  wimp_i i,
+  int max,
+  int val,
+  int colour,
+  BOOL isVertical
+)
+{
+  wimp_w w=dbox_syshandle(d);
+  wimp_icon icn;
+  wimp_redrawstr r;
+  BOOL more;
+  wimpt_noerr(wimp_get_icon_info(w,i,&icn));
+  r.w=w;
+  r.box.x0=icn.box.x0;
+  r.box.y0=icn.box.y0;
+  r.box.x1=icn.box.x1;
+  r.box.y1=icn.box.y1;
+  wimpt_noerr(wimp_update_wind(&r,&more));
+  while (more)
+  {
+    buttons_redrawSlider(d,i,max,val,colour,isVertical);
+    wimpt_noerr(wimp_get_rectangle(&r,&more));
+  }
+}
+
+/*
+ * void buttons__doSlide(void *handle)
+ *
+ * Use
+ *  This is the routine wot keeps everything going during the drag.
+ *
+ * Parameters
+ *  void *handle == pointer to the buttons__sliderstr running the show
+ */
+
+static void buttons__doSlide(void *handle)
+{
+  wimp_mousestr m;
+  int nVal;
+  buttons__sliderstr *s=(buttons__sliderstr *)handle;
+  int dist,half;
+  wimp_w w=dbox_syshandle(s->d);
+  wimp_icon icn;
+  wimp_redrawstr r;
+  BOOL more;
+  int len;
+  wimpt_noerr(wimp_get_point_info(&m));
+  half=s->slideMax/s->max/2;
+  len=s->isVertical ? m.y-s->o : m.x-s->o;
+  dist=len+half;
+  nVal=dist*s->max/s->slideMax;
+  if ((s->slideMax)>=(s->max)*2*(s->isVertical ? wimpt_dy() : wimpt_dx()))
+    len=nVal*s->slideMax/s->max;
+  if (nVal>s->max)
+    nVal=s->max;
+  if (nVal<0)
+    nVal=0;
+  if (len!=s->lastLen)
+  {
+    *(s->val)=nVal;
+    s->lastLen=len;
+    wimpt_noerr(wimp_get_icon_info(w,s->i,&icn));
+    icn.box.x0+=wimpt_dx();
+    icn.box.y0+=wimpt_dy();
+    icn.box.x1-=wimpt_dx();
+    icn.box.y1-=wimpt_dy();
+    r.w=w;
+    r.box.x0=icn.box.x0;
+    r.box.y0=icn.box.y0;
+    r.box.x1=icn.box.x1;
+    r.box.y1=icn.box.y1;
+    wimpt_noerr(wimp_update_wind(&r,&more));
+    icn.box.x1-=wimpt_dx();
+    icn.box.y1-=wimpt_dy();
+    while (more)
+    {
+      buttons__doRdrSlider(w,&icn,len,s->colour,s->isVertical);
+      wimpt_noerr(wimp_get_rectangle(&r,&more));
+    }
+    if (s->proc)
+      (s->proc)(s->d,s->i,nVal,s->handle);
+  }
+}
+
+/*
+ * BOOL buttons__ukEvents(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  This routine just grabs the drag event and closes off the drag if it's
+ *  over.
+ *
+ * Parameters
+ *  wimp_eventstr *e == a pointer to the event
+ *  void *handle == pointer to the current slider
+ *
+ * Returns
+ *  Whether it handled the event or not.
+ */
+
+static BOOL buttons__ukEvents(wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  buttons__sliderstr *s=(buttons__sliderstr *)handle;
+  switch (e->e)
+  {
+    case wimp_EUSERDRAG:
+      s->dragOver=TRUE;
+      win_remove_idle_claimer(buttons__doSlide,handle);
+      handled=TRUE;
+      win_remove_unknown_event_processor(buttons__ukEvents,handle);
+      mem_free(s);
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void buttons_slideSlider
+ * (
+ *   dbox d,
+ *   wimp_i i,
+ *   int max,
+ *   int *val,
+ *   int colour,
+ *   BOOL isVertical,
+ *   buttons_sliderHandler proc,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  This routine just neatly handles the slider totally.  Just pass it the
+ *  parameters it needs, and let it get on with it.
+ *
+ * Parameters
+ *  dbox d == the dbox
+ *  wimp_i i == the icon number
+ *  int max == the maximum slider value
+ *  int *val == a pointer to the slider value (updated as we go along)
+ *  int colour == the colour for the slider
+ *  BOOL isVertical == whether the slider is vertical
+ *  buttons_sliderHandler proc == a slider handler, which can update, say a
+ *   a writable field as the drag takes place
+ *  void *handle == a handle to pass the routine
+ */
+
+void buttons_slideSlider
+(
+  dbox d,
+  wimp_i i,
+  int max,
+  int *val,
+  int colour,
+  BOOL isVertical,
+  buttons_sliderHandler proc,
+  void *handle
+)
+{
+  wimp_w w=dbox_syshandle(d);
+  wimp_wstate state;
+  wimp_icon icn;
+  int ox,oy;
+  buttons__sliderstr *s;
+  wimp_dragstr drag;
+  wimp_mousestr m;
+  s=(buttons__sliderstr *)mem_alloc(sizeof(buttons__sliderstr));
+  if (!s)
+  {
+    werr(FALSE,msgs_lookup("buttonsNM:Not enough memory for slider."));
+    return;
+  }
+  wimpt_noerr(wimp_get_wind_state(w,&state));
+  wimpt_noerr(wimp_get_icon_info(w,i,&icn));
+  icn.box.x0+=wimpt_dx();
+  icn.box.y0+=wimpt_dy();
+  icn.box.x1-=2*wimpt_dx();
+  icn.box.y1-=2*wimpt_dy();
+  ox=state.o.box.x0-state.o.x;
+  oy=state.o.box.y1-state.o.y;
+  s->slideMax=isVertical ? icn.box.y1-icn.box.y0 : icn.box.x1-icn.box.x0;
+  s->d=d;
+  s->i=i;
+  s->max=max;
+  s->val=val;
+  s->colour=colour;
+  s->isVertical=isVertical;
+  s->o=isVertical ? oy+icn.box.y0 : ox+icn.box.x0;
+  s->iwidth=isVertical ? icn.box.x1-icn.box.x0 : icn.box.y1-icn.box.y0;
+  s->proc=proc;
+  s->handle=handle;
+  s->dragOver=FALSE;
+  s->lastLen=-1;
+  wimpt_noerr(wimp_get_point_info(&m));
+  drag.window=0;
+  drag.type=wimp_USER_HIDDEN;
+  if (isVertical)
+  {
+    drag.parent.x0=m.x;
+    drag.parent.y0=icn.box.y0+oy;
+    drag.parent.x1=m.x;
+    drag.parent.y1=icn.box.y1+oy;
+  }
+  else
+  {
+    drag.parent.x0=icn.box.x0+ox;
+    drag.parent.y0=m.y;
+    drag.parent.x1=icn.box.x1+ox;
+    drag.parent.y1=m.y;
+  }
+  wimpt_noerr(wimp_drag_box(&drag));
+  win_add_unknown_event_processor(buttons__ukEvents,s);
+  win_addIdleClaimer(buttons__doSlide,2,s);
+}
+
+/*
+ * void buttons_redrawColourButton(dbox d,wimp_i i,buttons_colourstr *c)
+ *
+ * Use
+ *  Redraws a true-colour button.
+ *
+ * Parameters
+ *  dbox d == the dbox
+ *  wimp_i i == icon number
+ *  buttons_colourstr == the colour we're intersted in
+ */
+
+void buttons_redrawColourButton(dbox d,wimp_i i,wimp_paletteword c)
+{
+  wimp_w w=dbox_syshandle(d);
+  wimp_wstate state;
+  wimp_icon icn;
+  int ox,oy;
+  int dummy;
+  wimpt_noerr(wimp_get_wind_state(w,&state));
+  wimpt_noerr(wimp_get_icon_info(w,i,&icn));
+  ox=state.o.box.x0-state.o.x;
+  oy=state.o.box.y1-state.o.y;
+  if (wimpt_getVersion()>=300)
+    colourtran_setGCOL(c,256,0,&dummy); /* Dither if you can               */
+  else
+    colourtran_setGCOL(c,0,0,&dummy);
+  bbc_rectanglefill(
+    ox+icn.box.x0 , oy+icn.box.y0 ,
+    icn.box.x1-icn.box.x0-1 , icn.box.y1-icn.box.y0-1
+  );
+}
+
+/*
+ * buttons_updateColourButton(dbox d,wimp_i i,wimp_paletteword c)
+ *
+ * Use
+ *  This routine redraws a colour button.
+ *
+ * Parameters
+ *  dbox d ==  the dbox
+ *  wimp_i == the icon number
+ *  wimp_paletteword c == the colour number
+ */
+
+void buttons_updateColourButton(dbox d,wimp_i i,wimp_paletteword c)
+{
+  wimp_w w=dbox_syshandle(d);
+  wimp_icon icn;
+  wimp_redrawstr r;
+  BOOL more;
+  wimpt_noerr(wimp_get_icon_info(w,i,&icn));
+  r.w=w;
+  r.box.x0=icn.box.x0;
+  r.box.y0=icn.box.y0;
+  r.box.x1=icn.box.x1;
+  r.box.y1=icn.box.y1;
+  wimpt_noerr(wimp_update_wind(&r,&more));
+  while (more)
+  {
+    buttons_redrawColourButton(d,i,c);
+    wimpt_noerr(wimp_get_rectangle(&r,&more));
+  }
+}
diff --git a/StraySrc/Libraries/Steel/c/caretptr b/StraySrc/Libraries/Steel/c/caretptr
new file mode 100644 (file)
index 0000000..c0fb50d
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * CaretPtr
+ *  handles a 'caret pointer' - one that changes to a 'I' shape if over a
+ *  writable icon.
+ *
+ *  Also (as of 05-Apr-1994), changes pointer according to `xp<name>,<x>,<y>'
+ *  validation string commands.
+ *
+ * v. 1.00 (25 July 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <ctype.h>
+
+#include "pointer.h"
+#include "win.h"
+#include "wimpt.h"
+#include "wimp.h"
+#include "os.h"
+#include "caretptr.h"
+#include "resspr.h"
+
+/*
+ * The SWI number for Wimp_SendMessage.
+ */
+#define Wimp_SendMessage 0x600E7
+
+static BOOL caretptr__onOrOff;
+static sprite_id caretptr__name;
+static sprite_area *caretptr__area;
+static int caretptr__x;
+static int caretptr__y;
+static wimp_i caretptr__icon=-20;
+static BOOL caretptr__stdptr=TRUE;
+
+/*
+ * void caretptr__idles(void *handle)
+ *
+ * Use
+ *  Called every null event to update the pointer.
+ *
+ * Parameters
+ *  void *handle == handle from win segment, not used.
+ */
+
+static void caretptr__idles(void *handle)
+{
+  wimp_mousestr mse;
+  wimp_icon i;
+  int bt;
+  handle=handle;
+
+  wimpt_noerr(wimp_get_point_info(&mse));
+  if (caretptr__icon!=mse.i)
+  {
+    wimpt_noerr(wimp_get_icon_info(mse.w,mse.i,&i));
+    bt=(((int)i.flags)>>12)&15;
+    if ((i.flags & wimp_INDIRECT) &&
+             (i.flags & wimp_ITEXT) &&
+             !((wimpt_options() & wimpt_ONOWIMPSHADE) &&
+               (i.flags & 0x001f0000)==0x001f0000) &&
+             (i.data.indirecttext.validstring!=(char *)-1))
+    {
+      char name[15];
+      int x=0;
+      int y=0;
+      int state=1;
+      char *p=i.data.indirecttext.validstring;
+      char *q=name;
+      sprite_id sid;
+
+      for (;*p>31 && state!=5;p++)
+      {
+        switch (*p)
+        {
+          case '\\':
+            if (p[1]>31)
+              p++;
+            if (state==1)
+              state=0;
+            else if (state==2)
+              *q++=*p;
+            break;
+          case ';':
+            if (state>1)
+              state=5;
+            else
+              state=1;
+            break;
+          case 'X':
+          case 'x':
+            if (state==1)
+            {
+              if (p[1]=='p' || p[1]=='P')
+              {
+                p++;
+                state=2;
+              }
+            }
+            else if (state==2)
+              *q++=*p;
+            break;
+          case ',':
+            switch (state)
+            {
+              case 2:
+                *q++=0;
+                /* Drop through */
+              case 3:
+              case 4:
+                state++;
+            }
+            break;
+          default:
+            switch (state)
+            {
+              case 1:
+                state=0;
+                break;
+              case 2:
+                *q++=*p;
+                break;
+              case 3:
+                if (isdigit(*p))
+                  x=(x*10)+(*p-'0');
+                break;
+              case 4:
+                if (isdigit(*p))
+                  y=(y*10)+(*p-'0');
+                break;
+            }
+            break;
+        }
+      }
+
+      if (state>1)
+      {
+        sid.s.name=name;
+        sid.tag=sprite_id_name;
+        pointer_set_shape(resspr_area(),&sid,x,y);
+        caretptr__stdptr=FALSE;
+        caretptr__icon=mse.i;
+        return;
+      }
+    }
+
+    if (bt==14 || bt==15)
+    {
+      wimpt_noerr(pointer_set_shape(caretptr__area,
+                                    &caretptr__name,
+                                    caretptr__x,
+                                    caretptr__y));
+      caretptr__stdptr=FALSE;
+    }
+    else if (!caretptr__stdptr)
+    {
+      pointer_reset_shape();
+      caretptr__stdptr=TRUE;
+    }
+    caretptr__icon=mse.i;
+  }
+}
+
+/*
+ * void caretPtr(char *name,sprite_area *area,int x,int y)
+ *
+ * Use
+ *  Turns the caret pointer on
+ *
+ * Parameters
+ *  char *name == the name of the sprite to use
+ *  sprite_area *area == pointer to sprite area
+ *  int x == x position of hotspot
+ *  int y == y position of hotspot
+ */
+
+void caretPtr(char *name,sprite_area *area,int x,int y)
+{
+  if (caretptr__onOrOff)
+    return;
+  caretptr__name.s.name=name;
+  caretptr__name.tag=sprite_id_name;
+  caretptr__area=area;
+  caretptr__x=x;
+  caretptr__y=y;
+  caretptr__onOrOff=TRUE;
+  caretptr__icon=-20;
+}
+
+void caretPtr__pointer(BOOL ownIt)
+{
+  if (caretptr__onOrOff)
+  {
+    if (ownIt)
+    {
+      win_addIdleClaimer(caretptr__idles,win_DONTCARE,0);
+      caretptr__icon=-20;
+    }
+    else
+    {
+      win_remove_idle_claimer(caretptr__idles,0);
+      if (!caretptr__stdptr)
+        pointer_reset_shape();
+      caretptr__stdptr=TRUE;
+      caretptr__icon=-1;
+    }
+  }
+}
+
+/*
+ * void caretPtrOff(void)
+ *
+ * Use
+ *  Turns the caretPtr off.
+ */
+
+void caretPtrOff(void)
+{
+  if (!caretptr__onOrOff)
+    return;
+  if (caretptr__icon>-20)
+  {
+    win_remove_idle_claimer(caretptr__idles,0);
+    pointer_reset_shape();
+  }
+}
diff --git a/StraySrc/Libraries/Steel/c/choices b/StraySrc/Libraries/Steel/c/choices
new file mode 100644 (file)
index 0000000..28ff129
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * choices.c
+ *
+ * Handling the global choices repository
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "res.h"
+#include "wimpt.h"
+#include "buffer.h"
+
+#include "choices.h"
+
+static char choices__root[15];
+
+/*
+ * void choices_setName(char *progname)
+ *
+ * Use
+ *  Sets the name of the application as used by choices.  The name is
+ *  truncated to 10 characters if necessary.  If no name is specified (i.e.
+ *  you don't call this routine) then the name of the application (as passed
+ *  to wimpt_init) is assumed.
+ */
+
+void choices_setName(char *progname)
+{
+  memcpy(choices__root,progname,10);
+  choices__root[10]=0;
+}
+
+/*
+ * char *choices_name(char *leaf,BOOL writable)
+ *
+ * Use
+ *  Locates the name of the specified resource.  If you want to open a file
+ *  for writing, you should set the writable flag.  Otherwise, this routine
+ *  will try to find the name of a file which already exists.
+ *
+ *  If you only want to read a file, this routine will first look at
+ *  <Choices$Dir>.leaf, and then at <resPrefix>.leaf, and return whichever
+ *  is found first.  If neither exists, a name is returned as for the
+ *  writable case.
+ *
+ *  If you want to write a file, then <Choices$Dir>.leaf is returned, unless
+ *  Choices$Dir is unset, in which case <resPrefix>.leaf is returned.
+ *
+ *  resPrefix is the prefix passed to res through res_init or res_setPrefix.
+ */
+
+char *choices_name(char *leaf,BOOL writable)
+{
+  char *name=buffer_find();
+  char *choices=getenv("Choices$Write");
+
+  /* --- Ensure choices__root is set up properly --- */
+
+  if (!choices__root[0])
+    choices_setName(wimpt_programname());
+
+  /* --- Just find one of the cases -- we're only reading --- */
+
+  if (!writable)
+  {
+    if (choices)
+    {
+      sprintf(name,"Choices:%s.%s",choices__root,leaf);
+      if (res_fileExists(name))
+        return (name);
+    }
+    strcpy(name,res_name(leaf));
+    if (res_fileExists(name))
+      return (name);
+  }
+
+  /* --- Find whichever is more appropriate --- */
+
+  if (choices)
+  {
+    if (writable)
+    {
+      /* --- To avoid hassle, create the directory here --- */
+
+      sprintf(name,"CDir %s.%s",choices,choices__root);
+      os_cli(name);
+    }
+    sprintf(name,"%s.%s.%s",choices,choices__root,leaf);
+  }
+  else
+    strcpy(name,res_name(leaf));
+
+  return (name);
+}
diff --git a/StraySrc/Libraries/Steel/c/crc b/StraySrc/Libraries/Steel/c/crc
new file mode 100644 (file)
index 0000000..2789c9e
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * crc
+ *  Checks CRC values for resource files
+ *
+ * v. 1.00 (24 August 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "crc.h"
+#include "crc32.h"
+#include "os.h"
+#include "res.h"
+#include "msgs.h"
+#include "werr.h"
+#include "wimpt.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+/*
+ * long crc__doCRC(char *filename,int offset)
+ *
+ * Use
+ *  Returns the CRC value for a file starting from a certain offset.
+ *
+ * Parameters
+ *  char *filename == the resource filename to use
+ *  int offset == the offset to start from
+ *
+ * Returns
+ *  A 4-byte CRC value.
+ */ 
+
+static long crc__doCRC(char *filename,int offset)
+{
+  FILE *fp;
+  char buffer[1024];
+  int read;
+  long c=0;
+  fp=res_openfile(filename,"rb");
+  if (!fp)
+  {
+    werr(FALSE,msgs_lookup("crcFNF:Couldn't open file '%s'."),filename);
+    exit(0);
+  }
+  fseek(fp,offset,SEEK_SET);
+  do
+  {
+    read=fread(buffer,1,1024,fp);
+    c=crc32(c,buffer,read,1);
+  }
+  while (read==1024);
+  fclose(fp);
+  return (c);
+}
+
+/*
+ * long crc(char *filename)
+ *
+ * Use
+ *  Calculates the CRC value for the file specified.  Uses the same method
+ *  as WindowEd etc.
+ *
+ * Parameters
+ *  char *filename == the filename of the file to check (leaf only - it's
+ *    passed through res_findname()).  Note that CRC-checking the
+ *    '!RunImage' file is rather silly.
+ *
+ * Returns
+ *  A 4-byte CRC value
+ */
+
+long crc(char *filename)
+{
+  return (crc__doCRC(filename,0));
+}
+
+/*
+ * void crc_check(char *filename,int check)
+ *
+ * Use
+ *  Checks a CRC value for a file and reports a fatal error if the check
+ *  fails.
+ *
+ * Parameters
+ *  char *filename == the leafname of the file
+ *  long check == the CRC number to check with
+ */
+
+void crc_check(char *filename,long check)
+{
+  if (check==-1)
+    return;
+  if (crc__doCRC(filename,0)!=check)
+  {
+    werr
+    (
+      FALSE,
+      msgs_lookup("crcFC:%s resource file '%s' has been corrupted.  "
+                  "Please restore this file from the distribution disk."),
+      wimpt_programname(),
+      filename
+    );
+    exit(0);
+  }
+}
+
+/*
+ * void crc_checkRunImage(void)
+ *
+ * Use
+ *  Corruption-checks the main !RunImage file.  It must have been passed
+ *  through CodeScr first, to install the CRC into the code.
+ */
+
+void crc_checkRunImage(void)
+{
+  FILE *fp=res_openfile("!RunImage","r");
+  long c;
+  if (!fp)
+    werr(TRUE,msgs_lookup("crcFNF:Couldn't open file '%s'."),"!RunImage");
+  fseek(fp,8,SEEK_SET);
+  fread(&c,4,1,fp);
+  fclose(fp);
+  if (c!=crc__doCRC("!RunImage",12))
+  {
+    werr
+    (
+      FALSE,
+      msgs_lookup("crcFC:%s resource file '%s' has been corrupted.  "
+                  "Please restore this file from the distribution disk."),
+      wimpt_programname(),
+      "!RunImage"
+    );
+    exit(0);
+  }
+}
diff --git a/StraySrc/Libraries/Steel/c/creator b/StraySrc/Libraries/Steel/c/creator
new file mode 100644 (file)
index 0000000..0bf8bdf
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ * creator.c
+ *
+ * Tearoff menu generating routines
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define _CORE
+#define _STDAPP
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "steel.h"
+#include "string.h"
+
+#include "xtearoff.h"
+
+/*---------------------------------------------------------------------------
+
+  The syntax of menu strings is a subset of the system used by the
+  RISC_OSlib menu segment:
+
+    menu_description ::= <flags> <item> <sep> { <flags> <item> <sep> }
+    flags ::= '!' | '~' | '>' | ' ' | '@'
+    sep ::= ','
+    item ::= <a bunch of other characters>[#<Short-cut string>]
+
+  flags have meanings as follows:
+
+    ' ' has no effect
+    '~' shades the item
+    '>' item has a menu dbox attached
+    '!' item is ticked
+    '@' item is 'radioed'
+
+---------------------------------------------------------------------------*/
+
+static BOOL tearoff__parse(tearoff t,char **p,tearoff__item *item,int *y)
+{
+  char *ind;
+  int len=0;
+  int hash=0;
+
+  BOOL done=FALSE;
+  tearoff__item *itm;
+  char *eptr;
+  item->sub=(tearoff)-1;
+  item->subMenuWarning = FALSE;
+  item->selType = 0;
+  item->shaded = FALSE;
+  item->subMenu = FALSE;
+  item->subShaded = FALSE;
+  item->dotted = FALSE;
+  item->text = NULL;
+  item->keys = NULL;
+  item->y=*y;
+  while (!done)
+  {
+    switch (**p)
+    {
+      case '!':
+        item->selType=1;
+        (*p)++;
+        break;
+      case '@':
+        item->selType=2;
+        (*p)++;
+        break;
+      case ' ':
+        (*p)++;
+        break;
+      case '>':
+        item->subMenuWarning=TRUE;
+        (*p)++;
+        break;
+      case '~':
+        item->shaded=TRUE;
+        (*p)++;
+        break;
+      default:
+        done=TRUE;
+        break;
+    }
+  }
+  done=FALSE;
+  for (eptr=*p;*eptr!=0 && *eptr!='|' && *eptr!=',';eptr++,len++)
+    if (*eptr=='#') hash=len;
+  if (ind=mem_alloc(len+1),!ind)
+  {
+    werr(FALSE,msgs_lookup("menuNEM:Not enough memory to construct menu."));
+    return (FALSE);
+  }
+  itm=(tearoff__item *)(t+1);
+  item->text=ind;
+  if (hash) item->keys=ind+hash+1;
+  while (**p!=0 && **p!='|' && **p!=',')
+  {
+    *ind=**p;
+    if (*ind=='#') *ind=0;
+    ind++;
+    (*p)++;
+  }
+  if (**p == '|')
+  {
+    item->dotted = TRUE;
+    t->dotted += 24;
+    t->redraw=TRUE;
+    *y-=24;
+  }
+  *(ind++)=0;
+  if (!**p)
+    *p=0;
+  else
+    (*p)++;
+  t->numberOfItems+=1;
+  *y-=44;
+  return (TRUE);
+}
+
+static int tearoff__itemCount(char *s)
+{
+  int count=1;
+  if (*s=='|')
+    s++;
+  while (*s)
+  {
+    switch (*s)
+    {
+      case '|':
+      case ',':
+        count++;
+        break;
+    }
+    s++;
+  }
+  return (count);
+}
+
+tearoff tearoff_create(char *title,char *items,BOOL tearable,
+                    tearoff_selectProc proc, int max, void *handle)
+{
+  int i,y;
+  tearoff__item *itm;
+  tearoff t;
+  int ino=tearoff__itemCount(items);
+
+  if (t=mem_alloc(sizeof(tearoff__str) + ino*sizeof(tearoff__item)),!t)
+  {
+    werr(FALSE,msgs_lookup("Not enough memory to construct menu."));
+    return (0);
+  }
+  t->menuTitle=malloc(strlen(title)+1);
+  if (!t->menuTitle)
+  {
+    werr(FALSE,msgs_lookup("Not enough memory to construct menu."));
+    return (0);
+  }
+  strcpy(t->menuTitle,title);
+  t->numberOfItems=0;
+  t->maxHeight=max;
+  t->selected=0;
+  t->tearoff=tearable;
+  t->tornoff=FALSE;
+  t->warned=FALSE;
+  t->folded=FALSE;
+  t->open=FALSE;
+  t->redraw=FALSE;
+  t->scrollBar=FALSE;
+  t->selectProc=proc;
+  t->userHandle=handle;
+  t->w=NULL;
+  t->sub=NULL;
+  t->prev=NULL;
+  t->dotted=0;
+  t->nextTornoff=NULL;
+  itm=((tearoff__item *)(t+1))-1;
+  y=-44;
+  if (t->tearoff) y-=tearoff__HEIGHT;
+  for (i=0;i<ino;i++)
+  {
+    itm++;
+    if (!items)
+      werr(TRUE,msgs_lookup("(tearoff_create): Menu item undercount."));
+    if (!tearoff__parse(t,&items,itm,&y))
+    {
+      if (t->indirected)
+        mem_free(t->indirected);
+      mem_free(t);
+      return (0);
+    }
+  }
+  if (items)
+    werr(TRUE,msgs_lookup("(tearoff_create): Menu item overcount."));
+  if (ino!=t->numberOfItems)
+    werr(TRUE,msgs_lookup("(tearoff_create): Menu item count mismatch."));
+  return (t);
+}
+
+void tearoff_attachSubMenu(tearoff to,int itm,tearoff sub)
+{
+  tearoff__item *item;
+
+  if (to->numberOfItems < itm)
+  {
+    werr(TRUE,"(tearoff_attachSubMenu): Item does not exist");
+    return;
+  }
+  item = (tearoff__item *)(to+1);
+  item += (itm-1);
+  item->sub = sub;
+  item->subMenu = TRUE;
+}
+
+void tearoff_destroy(tearoff t)
+{
+  tearoff__item *i;
+  int c;
+
+  if (!t) return;
+  i=(tearoff__item *)(t+1);
+  for (c=1;c<=t->numberOfItems;c++,i++)
+    mem_free(i->text);
+  mem_free(t->menuTitle);
+  mem_free(t);
+}
+
+void tearoff_selectItem(tearoff t, int item, tearoff_selectType type)
+{
+  tearoff__item *i;
+  int more;
+  wimp_redrawstr r;
+  wimp_icon icon;
+  BOOL riscos3=(wimpt_getVersion()>=300);
+
+  i = (tearoff__item *)(t + 1);
+  i += (item-1);
+  if (i->selType == type) return;
+  i->selType = type;
+
+  if (t->open && !t->folded)
+  {
+    r.w=t->w;
+    r.box.x0=0;
+    r.box.x1=24;
+    r.box.y0=i->y;
+    r.box.y1=i->y+44;
+    wimp_update_wind(&r,&more);
+    while (more)
+    {
+      icon.box.y1=i->y+44;
+      icon.box.y0=i->y;
+      icon.box.x0=0;
+      icon.box.x1=24;
+
+      icon.flags=wimp_IVCENTRE |
+                 wimp_IHCENTRE |
+                 wimp_IFILLED |
+                 wimp_IBACKCOL * 0 |
+                 wimp_IFORECOL * 7;
+
+      if (i->shaded) icon.flags |= wimp_INOSELECT;
+      if (!riscos3 && i->selType == tearoff_TICKED)
+      {
+        icon.flags |= wimp_ITEXT;
+        strcpy(icon.data.text, "\x80");
+      }
+      if (riscos3 && i->selType == tearoff_TICKED)
+      {
+        icon.flags |= wimp_ISPRITE | wimp_INDIRECT;
+        icon.data.indirectsprite.name = "\x80";
+        icon.data.indirectsprite.spritearea = (sprite_area *)1;
+        icon.data.indirectsprite.nameisname = 4;
+      }
+      if (i->selType == tearoff_RADIOED)
+      {
+        icon.flags |= wimp_ITEXT;
+        strcpy(icon.data.text, "\x8F");
+      }
+      if (i->selType == tearoff_NONE)
+      {
+        icon.flags |= wimp_ITEXT;
+        strcpy(icon.data.text, "");
+      }
+      wimpt_noerr(wimp_ploticon(&icon));
+
+      wimp_get_rectangle(&r,&more);
+    }
+  }
+}
+
+void tearoff_shadeItem(tearoff t, int item, BOOL shaded)
+{
+  tearoff__item *i;
+  wimp_redrawstr r;
+  int more;
+
+  i = (tearoff__item *)(t + 1);
+  i += (item-1);
+  if (i->shaded == shaded) return;
+  i->shaded = shaded;
+
+  if (t->open && !t->folded)
+  {
+    if (t->selected==item)
+    {
+      /* Close menu structure here */
+
+      t->selected=0;
+    }
+    r.w=t->w;
+    r.box.x0=0;
+    r.box.x1=t->width;
+    r.box.y0=i->y;
+    r.box.y1=i->y+44;
+    wimp_update_wind(&r,&more);
+    while (more)
+    {
+      tearoff__doRedraw(t, &r);
+      wimp_get_rectangle(&r,&more);
+    }
+  }
+}
+
+void tearoff_changeItemText(tearoff t,int item,char *text)
+{
+  tearoff__item *i;
+  char *ind,*eptr;
+  int len=0,hash=0,oldWidth;
+
+  i=(tearoff__item *)(t+1);
+  i+=(item-1);
+
+  mem_free(i->text);
+  i->text=i->keys=NULL;
+  for (eptr=text;*eptr!=0;eptr++,len++)
+    if (*eptr=='#') hash=len;
+  if (ind=mem_alloc(len+1),!ind)
+  {
+    werr(FALSE,msgs_lookup("menuNEM:Not enough memory to construct menu."));
+    return;
+  }
+  i->text=ind;
+  if (hash) i->keys=ind+hash+1;
+  while (*text)
+  {
+    *ind=*text;
+    if (*ind=='#') *ind=0;
+    ind++;
+    text++;
+  }
+  *ind=0;
+  if (t->open)
+  {
+    oldWidth=t->width;
+    tearoff_calculateMenuWidth(t);
+    if (oldWidth!=t->width)
+      tearoff_rebuildMenu(t);
+    else
+    {
+      if (t->selected)
+        tearoff_highlightItem(t->selected,t,FALSE);
+      t->selected=item;
+      tearoff_highlightItem(item,t,FALSE);
+      t->selected=0;
+    }
+  }
+}
+
+void tearoff_changeTitle(tearoff t,char *title)
+{
+  int oldWidth;
+  mem_free(t->menuTitle);
+  t->menuTitle=NULL;
+  t->menuTitle=mem_alloc(strlen(title)+1);
+  if (!t->menuTitle)
+    return;
+  strcpy(t->menuTitle,title);
+  if (t->open)
+  {
+    oldWidth=t->width;
+    tearoff_calculateMenuWidth(t);
+    if (t->width!=oldWidth)
+      tearoff_rebuildMenu(t);
+    else
+      win_settitle(t->w,title);
+  }
+}
+
+tearoff tearoff_extendMenu(tearoff t,char *items)
+{
+  tearoff__item *itm;
+  int ino=tearoff__itemCount(items),i,y;
+
+  if (!ino) return t;
+
+  if (t=mem_reAlloc(t, sizeof(tearoff__str) +
+                       (ino+t->numberOfItems)*sizeof(tearoff__item)),!t)
+  {
+    werr(FALSE,msgs_lookup("Not enough memory to construct menu."));
+    return NULL;
+  }
+  itm=((tearoff__item *)(t+1));
+  itm+=(t->numberOfItems-1);
+  y=itm->y-44;
+  if (itm->dotted) y-=24;
+  for (i=0;i<ino;i++)
+  {
+    itm++;
+    if (!items)
+      werr(TRUE,msgs_lookup("(tearoff_create): Menu item undercount."));
+    if (!tearoff__parse(t,&items,itm,&y))
+      return t;
+  }
+  return t;
+}
+
+BOOL tearoff_isShaded(tearoff t,int item)
+{
+  tearoff__item *i;
+
+  i=(tearoff__item *)(t+1);
+  i+=(item-1);
+
+   return i->shaded;
+}
+
+tearoff_selectType tearoff_howSelected(tearoff t,int item)
+{
+  tearoff__item *i;
+
+  i=(tearoff__item *)(t+1);
+  i+=(item-1);
+
+   return i->selType;
+}
diff --git a/StraySrc/Libraries/Steel/c/dbox b/StraySrc/Libraries/Steel/c/dbox
new file mode 100644 (file)
index 0000000..c12ff7c
--- /dev/null
@@ -0,0 +1,1664 @@
+/*
+ * dbox
+ *  further dialogue box routines for Straylight apps
+ *
+ * v. 1.02 (10 August 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define dbox__INTERNALS
+
+#include "event.h"
+#include "wimpt.h"
+#include "wimp.h"
+#include "interface.h"
+#include "sculptrix.h"
+#include "werr.h"
+#include "template.h"
+#include "win.h"
+#include "dbox.h"
+#include "msgs.h"
+#include "bbc.h"
+#include "mem.h"
+#include "akbd.h"
+#include "os.h"
+#include "swiv.h"
+#include "swis.h"
+#include "help.h"
+#include "vsscanf.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "dll.h"
+
+#ifndef _dll_NODLL
+  extern void _dllEntry(dbox__eventhandler)(wimp_eventstr *e,void *handle);
+#endif
+
+wimp_w dbox_menuDboxWindow(void);
+
+/*
+ * The big one - the data needed to manage the dbox system.  This IS a dbox.
+ */
+typedef struct dbox__dboxstr
+{
+  wimp_w wind;                    /* Real window handle                    */
+  dbox_eventhandler eventProc;    /* User event handler procedure          */
+  void *eventHandle;              /* Pointer to handler information        */
+  dbox_raweventhandler rawEventProc; /* Pointer to raw event handler       */
+  void *rawEventHandle;           /* Pointer to raw handler information    */
+  wimp_caretstr oldCaret;        /* Where the caret was before this opened */
+  wimp_wind *windDef;             /* Pointer to complete window definiton  */
+  wimp_wind *temp;                /* Pointer to template for this window   */
+  char *indirect;                 /* Pointer to indirected text            */
+  int titleIcon;                  /* Icon for the window title, or -1      */
+  BOOL isOpen                 :1; /* Is the dbox open?                     */
+  BOOL isStatic               :1; /* Is this a static or menu dbox         */
+  BOOL restoreCaret           :1; /* Do we return the caret when finished? */
+  BOOL moveDrag               :1; /* Click on window starts window move    */
+}
+dbox__dboxstr;
+
+/*
+ * A structure for passing to the dbox__fillinHandler() routine to make sure
+ * that the thing runs smoothly.
+ */
+typedef struct
+{
+  dbox_field f;                   /* The clicked field, or -2              */
+}
+dbox__fillinstr;
+
+#define dbox__CLICKMAX 10         /* Number of clicks which fit in stack   */
+
+typedef struct
+{
+  dbox d;
+  sculptrix_slabDescriptor s;
+}
+dbox__cstackstr;
+
+static dbox__cstackstr dbox__clicked[dbox__CLICKMAX];
+                                  /* Click stack array                     */
+static int dbox__click;           /* Click stack stack pointer             */
+static dbox dbox__menuDbox;       /* Currently open menu dbox (or 0)       */
+static BOOL dbox__closedForUs;    /* Is this a 'real' close event?         */
+static BOOL dbox__shiftRet=FALSE; /* Is this a sh-RETURN press for a dbox? */
+
+static dbox__mf dbox__tmsmf;      /* Where to go to find menu coords       */
+static dbox__esm dbox__tmsesm;    /* Are we expecting a submenu            */
+static dbox__ddb dbox__tmsddb;    /* How do we display a dialogue box?     */
+
+/* This routine is for a bodge to get round menu help problems.  It is     */
+/* to be used *only* by the event segment for its own processing of help   */
+/* requests.                                                               */
+wimp_w dbox__menuDboxWindow(void)
+{
+  return (dbox__menuDbox->wind);
+}
+
+/*
+ * void dbox__rms(dbox__mf f,dbox__esm esm,dbox__ddb ddb)
+ *
+ * Use
+ *  Registers support functions for handling an alternative menu handling
+ *  system (e.g. TMS).
+ */
+
+void dbox__rms(dbox__mf f,dbox__esm esm,dbox__ddb ddb)
+{
+  dbox__tmsmf=f;
+  dbox__tmsesm=esm;
+  dbox__tmsddb=ddb;
+}
+
+/*
+ * BOOL wasAdjustClick(void)
+ *
+ * Use
+ *  Returns whether the last event was caused by a mouse click with the
+ *  adjust mouse button.  Useful for deciding whether you want to bump a
+ *  value up or down, or for keeping a dbox on-screen.
+ *
+ * Returns
+ *  TRUE if the last event WAS caused by an adjust click.
+ */
+
+BOOL dbox_wasAdjustClick(void)
+{
+  wimp_eventstr *e=wimpt_last_event();
+  if ((e->e==wimp_EBUT && e->data.but.m.bbits==wimp_BRIGHT)||dbox__shiftRet)
+    return (TRUE);
+  else
+    return (FALSE);
+}
+
+/*
+ * wimp_icon *dbox__idef(dbox d,wimp_i i)
+ *
+ * Use
+ *  This routine returns a pointer to the icon definition specified.
+ *
+ * Parameters
+ *  dbox d == dbox handle
+ *  wimp_i i == the icon handle
+ *
+ * Returns
+ *  A pointer to the icon definition.
+ */
+
+#define dbox__idef(d,i) ((wimp_icon *)((d)->windDef+1)+(i))
+
+#ifdef notdef
+static wimp_icon *dbox__idef(dbox d,wimp_i i)
+{
+  return ((wimp_icon *)(d->windDef+1)+i);
+}
+#endif
+
+/*
+ * int dbox__fieldlength(dbox d,dbox_field f)
+ *
+ * Use
+ *  Returns the length of the text in field specified
+ *
+ * Parameters
+ *  dbox d == dbox handle
+ *  dbox_field f == field number (icon handle to the uninitiated!)
+ *
+ * Returns
+ *  The length of the field.  Why isn't this a size_t?
+ */
+
+static int dbox__fieldlength(dbox d, dbox_field f)
+{
+  char a[255];
+  dbox_getfield((dbox) d, f, a, 255);
+  return(strlen(a));
+}
+
+/*
+ * void dbox__nextWritable(BOOL fromTop,dbox d,BOOL forward)
+ *
+ * Use
+ *  This call moves the caret around the window it is in.  The fromTop
+ *  parameter says whether you want to move the caret either to one
+ *  extremity or the other, or just move it along.  The routine, unlike the
+ *  standard RISC_OSlib one, actually scrolls the window to keep the caret
+ *  in view.
+ *
+ * Parameters
+ *  BOOL fromTop == whether you want to move to an extremity, or just up or
+ *    down one.
+ *  dbox d == the dbox you think the caret is in.  If it isn't, you're in
+ *    deep sh*te.
+ *  BOOL forward == whether you want to search forward or backward from your
+ *    starting position.
+ */
+
+static void dbox__nextWritable(BOOL fromTop,dbox d,BOOL forwards)
+{
+  wimp_caretstr c;
+  wimp_icon idef;
+  wimp_i i;
+  int iterations;
+  int dir;
+  int bt;
+  wimp_wstate state;
+  int sw,sh,ox,oy;
+  wimpt_noerr(wimp_get_caret_pos(&c));
+  if (forwards)
+    dir=1;
+  else
+    dir=-1;
+  if (fromTop)
+  {
+    if (forwards)
+      i=0;
+    else
+      i=d->windDef->nicons;
+  }
+  else
+    i=c.i+dir;
+  for (iterations=0;iterations<d->windDef->nicons;iterations++,i+=dir)
+  {
+    if (i>d->windDef->nicons)
+    {
+      i=-1;
+      iterations--;
+      continue;
+    }
+    if (i<0)
+    {
+      i=d->windDef->nicons+1;
+      iterations--;
+      continue;
+    }
+    wimpt_noerr(wimp_get_icon_info(d->wind,i,&idef));
+    bt=(((int)idef.flags)>>12) & 15;
+    if
+    (
+      (bt==15 || bt==14) &&
+      ((idef.flags & wimp_INOSELECT)==0) &&
+      ((idef.flags & wimp_IDELETED)==0)
+    )
+      break;
+  }
+  if (iterations==d->windDef->nicons)
+    return;
+  c.w=d->wind;
+  c.i=i;
+  c.height=-1;
+  c.index=dbox__fieldlength(d,i);
+  wimpt_noerr(wimp_set_caret_pos(&c));
+  wimpt_noerr(wimp_get_wind_state(d->wind,&state));
+  sw=state.o.box.x1-state.o.box.x0;
+  sh=state.o.box.y1-state.o.box.y0;
+  ox=state.o.box.x0-state.o.x;
+  oy=state.o.box.y1-state.o.y;
+  if (state.o.box.x0>idef.box.x0+ox)
+    state.o.x=idef.box.x0-24;
+  if (state.o.box.x1<idef.box.x1+ox)
+    state.o.x=idef.box.x1+24-sw;
+  if (state.o.box.y0>idef.box.y0+oy)
+    state.o.y=idef.box.y0-24+sh;
+  if (state.o.box.y1<idef.box.y1+oy)
+    state.o.y=idef.box.y1+24;
+  wimpt_noerr(wimp_open_wind(&state.o));
+}
+
+/*
+ * void dbox__checkRadio(dbox d,dbox_field f)
+ *
+ * Use
+ *  Checks to see if the specified dbox_field is a radio button (button type
+ *  debounced and nonzero ESG) and if so selects it and unselects other
+ *  fields with the same ESG number.
+ *
+ * Parameters
+ *  dbox d == the dbox containing the clicked field
+ *  dbox_field f == the field wot was clicked
+ */
+
+static void dbox__checkRadio(dbox d,dbox_field f)
+{
+  wimp_icon *idef=dbox__idef(d,f);
+  int esg;
+  int i;
+  if ((idef->flags & 0x0000F000) == (wimp_BCLICKDEBOUNCE<<12))
+  {
+    esg=idef->flags & 0x001F0000;
+    if (esg)
+    {
+      dbox_selecticon(d,f,TRUE);
+      idef=dbox__idef(d,0);
+      for (i=0;i<d->windDef->nicons;i++,idef++)
+      {
+        if (i!=f && (idef->flags & 0x001F0000)==esg)
+          dbox_selecticon(d,i,FALSE);
+      }
+    }
+  }
+}
+
+/*
+ * void dbox__eventhandler(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Event handler for dboxes.  Handles ops as follows:
+ *
+ *  * Clicks on icons are passed to dbox handler if present
+ *  * Key presses are dealt with:
+ *      cursor keys move caret
+ *      return reports a click on icon 0
+ *      escape reports a click on icon 1
+ *      a close operation reports a click on icon dbox_CLOSE
+ *  * If a menu dbox closes in the backgound (i.e. the WIMP makes off with
+ *    it), a close operation is passed to the dbox concerned.
+ *
+ * Parameters
+ *  wimp_eventstr *e == a pointer to the current WIMP event
+ *  void *handle == the jolly old handle, which is a pointer to the
+ *    dbox__dboxstr.
+ */
+
+_dll_static void dbox__eventhandler(wimp_eventstr *e,void *handle)
+{
+  dbox d=(dbox)handle;
+  BOOL handled=FALSE;
+
+  dbox__shiftRet=FALSE;
+  if (d->rawEventProc)
+    handled=(d->rawEventProc)(d,e,(void *)d->rawEventHandle);
+  if (!handled)
+  {
+    switch (e->e)
+    {
+      case wimp_EREDRAW:
+        if (d->titleIcon!=-1)
+          wimpt_redraw(dbox_drawEmbeddedTitle,d);
+        else
+          wimpt_redraw(0,0);
+        break;
+      case wimp_EOPEN:
+        wimpt_noerr(wimp_open_wind(&e->data.o));
+        break;
+      case wimp_ECLOSE:
+        if (d->eventProc)
+          (d->eventProc)(d,dbox_CLOSE,d->eventHandle);
+        break;
+      case wimp_EBUT:
+        if (e->data.but.m.bbits==wimp_BRIGHT ||
+            e->data.but.m.bbits==wimp_BLEFT)
+        {
+          dbox__checkRadio(d,e->data.but.m.i);
+          if (d->eventProc && e->data.but.m.i!=-1)
+            (d->eventProc)(d,e->data.but.m.i,d->eventHandle);
+          if (d->moveDrag)
+          {
+            wimp_dragstr dr;
+            dr.window=d->wind;
+            dr.type=wimp_MOVE_WIND;
+            wimp_drag_box(&dr);
+          }
+        }
+        break;
+      case wimp_EKEY:
+        switch (akbd_translate(e->data.key.chcode))
+        {
+          case key_sReturn:
+          case key_skEnter:
+            dbox__shiftRet=TRUE;
+            /* Treat as normal return */
+          case key_Return:
+          case key_kEnter:
+            if (d->eventProc && !dbox_shadeicon(d,0,dbox_READSTATE))
+              (d->eventProc)(d,0,d->eventHandle);
+            break;
+          case key_sEsc:
+            dbox__shiftRet=TRUE;
+            /* Treat as normal Escape */
+          case key_Esc:
+            if (d->eventProc && !dbox_shadeicon(d,1,dbox_READSTATE))
+              (d->eventProc)(d,1,d->eventHandle);
+            break;
+          case key_Down:
+          case key_Tab:
+            dbox__nextWritable(FALSE,d,TRUE);
+            break;
+          case key_sTab:
+          case key_Up:
+            dbox__nextWritable(FALSE,d,FALSE);
+            break;
+          case key_cDown:
+            dbox__nextWritable(TRUE,d,FALSE);
+            break;
+          case key_cUp:
+            dbox__nextWritable(TRUE,d,TRUE);
+            break;
+          default:
+            wimp_processkey(e->data.key.chcode);
+            break;
+        }
+        break;
+      case wimp_ESEND:
+      case wimp_ESENDWANTACK:
+        switch (e->data.msg.hdr.action)
+        {
+          case wimp_MHELPREQUEST:
+            if (d->eventProc)
+              (d->eventProc)(d,dbox_HELP,d->eventHandle);
+            break;
+        }
+        break;
+    }
+  }
+}
+
+/*
+ * dbox dbox_create(char *template)
+ *
+ * Use
+ *  Creates a dbox from a template and returns a handle to it.  It calls
+ *  werr() sensibly with nice messages if it failed.
+ *
+ * Parameters
+ *  char *name == name of template to use
+ *
+ * Returns
+ *  Abstract handle to dbox or NULL if the dbox could not be
+ *  created
+ */
+
+dbox dbox_create(char *name)
+{
+  template *temp=template_find(name);
+  wimp_wind *w=template_syshandle(name);
+  dbox d=(dbox)mem_alloc(sizeof(dbox__dboxstr));
+  wimp_icon *icn;
+  int i;
+  BOOL unshade=wimpt_options() & wimpt_ONOWIMPSHADE;
+  if (d)
+  {
+    if (d->windDef=(wimp_wind *)mem_alloc
+    (
+      sizeof(wimp_wind)+w->nicons*sizeof(wimp_icon)
+    ),
+    d->windDef==0)
+    {
+      mem_free(d);
+      werr
+      (
+        FALSE,
+        msgs_lookup("dboxNEM:Not enough memory for new dialogue box.")
+      );
+      return (0);
+    }
+    memcpy(d->windDef,w,sizeof(wimp_wind)+w->nicons*sizeof(wimp_icon));
+    if (temp->workspacesize!=0)
+    {
+      if (d->indirect=(char *)mem_alloc(temp->workspacesize),d->indirect==0)
+      {
+        mem_free(d->windDef);
+           mem_free(d);
+        werr
+        (
+          FALSE,
+          msgs_lookup("dboxNEM:Not enough memory for new dialogue box.")
+        );
+        return (0);
+      }
+      memcpy(d->indirect,temp->workspace,temp->workspacesize);
+      for (i=0;i<d->windDef->nicons;i++)
+      {
+        icn=dbox__idef(d,i);
+        if (unshade)
+          icn->flags &= 0xffbfffff;
+        if ((icn->flags&wimp_INDIRECT)!=0)
+        {
+          icn->data.indirecttext.buffer+=d->indirect-temp->workspace;
+          if ((icn->flags&3)==2)
+            icn->data.indirectsprite.spritearea=(void *)1;
+          else
+          {
+            if (icn->data.indirecttext.validstring!=(char *)-1)
+            {
+              icn->data.indirecttext.validstring+=
+                                               d->indirect-temp->workspace;
+            }
+          }
+        }
+      }
+      if (d->windDef->titleflags&wimp_INDIRECT)
+      {
+        d->windDef->title.indirecttext.buffer+=d->indirect-temp->workspace;
+        if ((d->windDef->titleflags&3)==2)
+          d->windDef->title.indirectsprite.spritearea=(void *)1;
+        else
+        {
+          if (d->windDef->title.indirecttext.validstring!=(char *)-1)
+          {
+            d->windDef->title.indirecttext.validstring+=
+                                               d->indirect-temp->workspace;
+          }
+        }
+      }
+    }
+    else
+      d->indirect=0;
+    if (wimp_create_wind(d->windDef,&d->wind)==0)
+    {
+      d->eventProc=0;
+      d->rawEventProc=0;
+      d->isOpen=FALSE;
+      d->isStatic=FALSE;
+      d->titleIcon=-1;
+      d->moveDrag=FALSE;
+      d->temp=w;
+      win_activeinc();
+      win_register_event_handler(d->wind,_dllEntry(dbox__eventhandler),d);
+    }
+    else
+    {
+      mem_free(d->windDef);
+      mem_free(d->indirect);
+      mem_free(d);
+      d=0;
+      werr
+      (
+        FALSE,
+        msgs_lookup("dboxTMW:Too many windows - "
+                               "%s could not create window/dialogue box."),
+        wimpt_programname()
+      );
+    }
+  }
+  else
+    werr
+    (
+      FALSE,
+      msgs_lookup("dboxNEM:Not enough memory for new dialogue box.")
+    );
+  return (d);
+}
+
+/*
+ * void dbox__setMenuDbox(dbox d)
+ *
+ * Use
+ *  This routine handles the updating of the dbox__menuDbox variable.  It
+ *  is needed 'cos if the user maniacally starts opening submenus, the thing
+ *  can get a bit confused.  If there already is one, it gets a wimp_ECLOSE
+ *  event faked to it courtesy of a combination of wimpt_fake_event() and
+ *  event_process().
+ *
+ * Parameters
+ *  dbox d == the new prospective menu dbox.
+ */
+
+static void dbox__setMenuDbox(dbox d)
+{
+  dbox__menuDbox=d;
+}
+
+/*
+ * void dbox_display(dbox d,dbox_openType how)
+ *
+ * Use
+ *  Displays a dbox on the screen.  The new dbox_openType is compatible with
+ *  the old TRUE/FALSE system.  Note that is the event was a submenu, then
+ *  the dbox will be opened as a submenu regardless of how you want it done.
+ *
+ *  If the dbox conatins a writable icon, then the caret is placed within
+ *  the first one.  This is handled automatically by the WIMP for submenu
+ *  dboxes, but not (unfortunately) for static ones.
+ *
+ * Parameters
+ *  dbox d == dbox handle
+ *  dbox_openType how == how you want the dbox opened
+ */
+
+void dbox_display(dbox d,dbox_openType how)
+{
+  wimp_wstate state;
+  int scx=wimpt_scwidth();
+  int scy=wimpt_scheight();
+  int w;
+  int h;
+  wimp_caretstr c;
+  wimp_eventstr *e;
+  int x;
+  int y;
+
+  wimpt_noerr(wimp_get_wind_state(d->wind,&state));
+  state.o.behind=(wimp_w)-1;
+  w=state.o.box.x1-state.o.box.x0;
+  h=state.o.box.y1-state.o.box.y0;
+  d->isStatic=TRUE;
+  switch (how)
+  {
+    case dbox_MENU_OVERPTR:
+      d->isStatic=FALSE;
+    case dbox_STATIC_OVERPTR:
+      bbc_mouse(&x,&y,0,0);
+      state.o.box.x0=x-w/2;
+      state.o.box.x1=x+w/2;
+      state.o.box.y0=y-h/2;
+      state.o.box.y1=y+h/2;
+      break;
+    case dbox_MENU_LASTPOS:
+      d->isStatic=FALSE;
+    case dbox_STATIC_LASTPOS:
+      /* Nothin' doin' */
+      break;
+    case dbox_MENU_CENTRE:
+      d->isStatic=FALSE;
+    case dbox_STATIC_CENTRE:
+      state.o.box.x0=(scx-w)/2;
+      state.o.box.x1=(scx+w)/2;
+      state.o.box.y0=(scy-h)/2;
+      state.o.box.y1=(scy+h)/2;
+      break;
+  }
+  win_adjustBox(&state.o);
+  if (d->isStatic)
+  {
+    wimpt_noerr(wimp_open_wind(&state.o));
+    if (!d->isOpen)
+    {
+      d->isOpen=TRUE;
+      d->isStatic=TRUE;
+      wimpt_noerr(wimp_get_caret_pos(&d->oldCaret));
+      d->restoreCaret=TRUE;
+      dbox__nextWritable(TRUE,d,TRUE);
+      wimpt_noerr(wimp_get_caret_pos(&c));
+      if (c.w!=d->wind)
+        d->restoreCaret=FALSE;
+      else
+      {
+        c.i=-1;
+        c.x=-500000;
+        c.height=0x2000000;
+        wimpt_noerr(wimp_set_caret_pos(&c));
+      }
+    }
+  }
+  else
+  {
+    if (dbox_wasSubmenu() && (wimpt_last_event()->e==wimp_ESEND ||
+                              wimpt_last_event()->e==wimp_ESENDWANTACK))
+    {
+      e=wimpt_last_event();
+      x=e->data.msg.data.words[1];
+      y=e->data.msg.data.words[2];
+      wimpt_noerr(wimp_create_submenu((wimp_menustr *)d->wind,x,y));
+      d->restoreCaret=FALSE;
+    }
+    else if (dbox__tmsesm && dbox__tmsesm())
+    {
+      dbox__tmsmf(&x,&y);
+      state.o.box.x0=x;
+      state.o.box.x1=x+w;
+      state.o.box.y0=y-h;
+      state.o.box.y1=y;
+      dbox__tmsddb(&state.o);
+      wimpt_noerr(wimp_get_caret_pos(&d->oldCaret));
+      d->restoreCaret=TRUE;
+      dbox__nextWritable(TRUE,d,TRUE);
+    }
+    else
+    {
+      wimpt_noerr(wimp_create_menu(
+        (wimp_menustr *)d->wind,
+        state.o.box.x0,
+        state.o.box.y1
+      ));
+      d->restoreCaret=FALSE;
+    }
+    d->isOpen=TRUE;
+    d->isStatic=FALSE;
+    dbox__setMenuDbox(d);
+  }
+}
+
+/*
+ * void dbox_openDisplaced(dbox d)
+ *
+ * Use
+ *  Displaces the dbox from its original height by the statutory 48 OS
+ *  units.  If it would overlap the icon bar, it gets moved up to a sensible
+ *  height.  The dbox must be opened by this call once only.  It must be
+ *  closed using dbox_deleteNoUpdate().  The dbox is opened as a static
+ *  dbox, of course.
+ *
+ * Parameters
+ *  dbox d == the dbox
+ */
+
+void dbox_openDisplaced(dbox d)
+{
+  int new=0;
+  wimp_wstate s;
+  wimp_caretstr c;
+  if (d->isOpen)
+  {
+    werr
+    (
+      TRUE,
+      msgs_lookup("dboxCOD:(dbox_openDisplaced): "
+                                             "failed - dbox already open.")
+    );
+  }
+  if (d->temp->box.y0-48<132)
+  {
+    new=((976-d->temp->box.y1)/48-4)*48+d->temp->box.y1;
+    d->temp->box.y0+=new-d->temp->box.y1;
+    d->temp->box.y1=new;
+  }
+  else
+  {
+    d->temp->box.y0-=48;
+    d->temp->box.y1-=48;
+  }
+  wimpt_noerr(wimp_get_wind_state(d->wind,&s));
+  s.o.box=d->temp->box;
+  s.o.behind=-1;
+  wimpt_noerr(wimp_open_wind(&s.o));
+  d->isOpen=TRUE;
+  d->isStatic=TRUE;
+  wimpt_noerr(wimp_get_caret_pos(&d->oldCaret));
+  d->restoreCaret=TRUE;
+  dbox__nextWritable(TRUE,d,TRUE);
+  wimpt_noerr(wimp_get_caret_pos(&c));
+  if (c.w!=d->wind)
+    d->restoreCaret=FALSE;
+  else
+  {
+    wimpt_noerr(wimp_open_wind(&s.o));
+    c.i=-1;
+    c.x=-500000;
+    wimpt_noerr(wimp_set_caret_pos(&c));
+  }
+}
+
+/*
+ * void dbox_hide(dbox d)
+ *
+ * Use
+ *  Closes the dbox specified in whatever manner necessary to stop it being
+ *  seen.  The window can still be created real easy.
+ *
+ * Parameters
+ *  dbox d == dialogue box handle
+ */
+
+void dbox_hide(dbox d)
+{
+  if (d==dbox__menuDbox)
+  {
+    if (!dbox__closedForUs)
+      event_clear_current_menu();
+    dbox__menuDbox=0;
+  }
+  wimpt_noerr(wimp_close_wind(d->wind));
+  if (d->restoreCaret)
+    wimp_set_caret_pos(&d->oldCaret);
+  d->isOpen=FALSE;
+}
+
+/*
+ * void dbox_deleteNoUpdate(dbox d)
+ *
+ * Use
+ *  Zaps a dbox without storing the thing's position away, so it reappears
+ *  where you want it.
+ *
+ * Parameters
+ *  dbox d == the handle
+ */
+
+void dbox_deleteNoUpdate(dbox d)
+{
+  if (d->isOpen)
+    dbox_hide(d);
+  win_register_event_handler(d->wind,0,0);
+  win_activedec();
+  wimpt_noerr(wimp_delete_wind(d->wind));
+  mem_free(d->indirect);
+  mem_free(d->windDef);
+  mem_free(d);
+}
+
+/*
+ * void dbox_updatePosition(dbox d)
+ *
+ * Use
+ *  Stores the position of the dialogue box away, so that next time a dbox
+ *  using the same template is opened, it goes to that place.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ */
+
+void dbox_updatePosition(dbox d)
+{
+  wimp_wstate s;
+  wimp_get_wind_state(d->wind,&s);
+  d->temp->box=s.o.box;
+}
+
+/*
+ * void dbox_delete(dbox d)
+ *
+ * Use
+ *  Utterly zaps the dialogue box specified.  Updates the template, so it's
+ *  right next time around, though.  The window is deleted, and the dbox's
+ *  space is freed.
+ *
+ * Parameters
+ *  dbox d == dialogue box handle
+ */
+
+void dbox_delete(dbox d)
+{
+  if (d->isStatic)
+    dbox_updatePosition(d);
+  dbox_deleteNoUpdate(d);
+}
+
+/*
+ * void dbox_eventHandler(dbox d,dbox_eventhandler proc,void *handle)
+ *
+ * Use
+ *  This routine attaches an event handler to a dbox.  Pass 0 as the pointer
+ *  to the procedure if you want to remove the handler. Event handers are an
+ *  alternative to using dbox_fillin().
+ *
+ * Parameters
+ *  dbox d == the dbox you want to attach a handler to.
+ *  dbox_eventhandler proc == the hander procedure.
+ *  void *handle == up to you.  It gets passed to the procedure, though.
+ */
+
+void dbox_eventHandler(dbox d,dbox_eventhandler proc,void *handle)
+{
+  d->eventProc=proc;
+  d->eventHandle=handle;
+}
+
+/*
+ * void dbox_rawEventHandler(dbox d,dbox_raweventhandler proc,void *handle)
+ *
+ * Use
+ *  This routine attaches a raw event handler to a dbox.  Pass 0 as the
+ *  pointer to the procedure if you want to remove the handler.  A raw event
+ *  handler gets passed all the WIMP events received by the dbox.  It should
+ *  return FALSE if it could not process the event itself, or TRUE if it
+ *  did.
+ *
+ * Parameters
+ *  dbox d == the dbox you want to attach a handler to.
+ *  dbox_eventhandler proc == the hander procedure.
+ *  void *handle == up to you.  It gets passed to the procedure, though.
+ */
+
+void dbox_rawEventHandler(dbox d,dbox_raweventhandler proc,void *handle)
+{
+  d->rawEventProc=proc;
+  d->rawEventHandle=handle;
+}
+
+/*
+ * void dbox__fillinHandler(dbox d,dbox_field clicked,void *handle)
+ *
+ * Use
+ *  This is the dbox handler used by dbox_fillin().
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field == the field that was clicked
+ *  void *handle == a pointer to a dbox__fillinstr
+ */
+
+static void dbox__fillinHandler(dbox d,dbox_field clicked,void *handle)
+{
+  dbox__fillinstr *f=(dbox__fillinstr *)handle;
+  d=d;
+  f->f=clicked;
+}
+
+/*
+ * dbox_field dbox_fillin(dbox d)
+ *
+ * Use
+ *  This is a nice simple way of handling a dbox.  It means you can handle
+ *  everything from an in-line point of view. Functions can easily return
+ *  the results they need (like dbox_query()).  Unfortunately, it will only
+ *  work with menu dboxes, and will complain bitterly at you if you try and
+ *  do anything different.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *
+ * Returns
+ *  The field number that was clicked.
+ */
+
+dbox_field dbox_fillin(dbox d)
+{
+  dbox__fillinstr f;
+  if (d->isStatic)
+  {
+    werr
+    (
+      TRUE,
+      msgs_lookup("dboxFRE:(dbox_fillin, caller fault): "
+                                "dbox_fillin only works with menu dboxes.")
+    );
+  }
+  f.f=dbox_ENDFILLIN;
+  dbox_eventHandler(d,dbox__fillinHandler,&f);
+  while (f.f==dbox_ENDFILLIN)
+    event_process();
+  dbox_eventHandler(d,0,0);
+  return (f.f);
+}
+
+/*
+ * void dbox_eventProcess(void)
+ *
+ * Use
+ *  Part of the private interface between dbox and event for processing
+ *  dialogue box events.
+ */
+
+void dbox__eventProcess(void)
+{
+  static wimp_eventstr real;
+  static BOOL faking;
+  wimp_eventstr fake;
+  wimp_wstate state;
+
+  dbox__closedForUs=FALSE;
+  if (faking)
+  {
+    wimpt_fake_event(&real);
+    faking=FALSE;
+    event__process();
+    return;
+  }
+  if (dbox__menuDbox)
+  {
+    wimpt_noerr(wimpt_poll(event_getmask(),&real));
+    wimpt_noerr(wimp_get_wind_state(dbox__menuDbox->wind,&state));
+    if ((((state.flags & wimp_WOPEN)==0) || real.e==wimp_EMENU) &&
+                                                        real.e!=wimp_EREDRAW)
+    {
+      fake.e=wimp_ECLOSE;
+      fake.data.o.w=dbox__menuDbox->wind;
+      wimpt_fake_event(&fake);
+      dbox__closedForUs=TRUE /* (real.e!=wimp_EMENU) */ ;
+      faking=TRUE;
+    }
+    else
+      wimpt_fake_event(&real);
+  }
+  event__process();
+}
+
+/*
+ * void dbox_setfield(dbox d,dbox_field f,char *string,...)
+ *
+ * Use
+ *  This routine will write the string into the field specified, if and only
+ *  if the field's data is indirected.  The icon is checked to make sure
+ *  it's been indirected, and if the string is too long, we hack off bits
+ *  until it fits.  Normally, the end bit is chopped off.  However, you can
+ *  set the icon's right-aligned bit to indicate that you want the
+ *  *beginning* bit chopped off.
+ *
+ * Parameters
+ *  dbox d == the dbox
+ *  dbox_field f == the field
+ *  char *string == a printf-style format string
+ */
+
+void dbox_setfield(dbox d,dbox_field f,char *string,...)
+{
+  wimp_icon *i=dbox__idef(d,f);
+  wimp_caretstr c;
+  va_list ap;
+  char field[1024];
+  int j;
+  char *buff;
+  BOOL different=FALSE;
+  BOOL stop=FALSE;
+  int max;
+  char *fptr;
+  BOOL dots=FALSE;
+  char x,y;
+  BOOL rJust=FALSE;
+
+  /* --- Construct the string to fill in the buffer --- *
+   *
+   * If the buffer overflows here, we're pretty much stuffed.  We can try
+   * to chop the end off and hope it doesn't damage anything too badly,
+   * though.  If the format string is `%s', we can just use the string given
+   * in the first variable arg, though, so we're safe there.
+   */
+
+  va_start(ap,string);
+  if (string[0]=='%' && string[1]=='.')
+  {
+    dots=TRUE;
+    string+=2;
+  }
+  if (!strcmp(string,"%s"))
+    fptr=va_arg(ap,char *);
+  else
+  {
+    vsprintf(field,string,ap);
+    field[1023]=0;
+    fptr=field;
+  }
+  va_end(ap);
+
+  /* --- Make sure the string's indirected --- */
+
+  if (!(i->flags & wimp_INDIRECT))
+  {
+    werr(TRUE,msgs_lookup("dboxSFNIND:(dbox_setfield, caller fault): "
+                          "Icon is not indirected."));
+  }
+
+  /* --- Write the string to the icon, noting differences --- *
+   *
+   * If the string is too long for the buffer, truncate it.  Note that if
+   * it's more than 1K long, we've already died horridly, because sprintf
+   * will have overflowed our own buffer above.
+   */
+
+  buff=i->data.indirecttext.buffer;
+  max=i->data.indirecttext.bufflen-1;
+  j=strlen(fptr);
+  if (j>max)
+  {
+    if (rJust=(i->flags & wimp_IRJUST),rJust)
+      fptr+=j-max;
+  }
+  else
+    dots=FALSE;
+  j=0;
+  while (!stop)
+  {
+    x=*buff++;
+    y=*fptr++;
+    if (max==j || y<' ')
+      y=0;
+    else if (dots && ((rJust && j<3) || (!rJust && max-j<4)))
+      y='.';
+    if (x<' ')
+      x=0;
+    if (x!=y)
+    {
+      different=TRUE;
+      buff[-1]=y;
+    }
+    if (y)
+      j++;
+    else
+      stop=TRUE;
+  }
+
+  /* --- If the icon has changed, redraw it, and move the caret --- */
+
+  if (different)
+  {
+    wimpt_noerr(wimp_set_icon_state(d->wind,f,0,0));
+    wimpt_noerr(wimp_get_caret_pos(&c));
+    if (c.w==d->wind && c.i==f)
+    {
+      if (c.index>j)
+      {
+        c.index=j;
+        c.height=-1;
+      }
+      wimpt_noerr(wimp_set_caret_pos(&c));
+    }
+  }
+}
+
+/*
+ * void dbox_clickicon(dbox d,dbox_field f)
+ *
+ * Use
+ *  Informs a 3D button manager (e.g. Sculptrix) of a click on an icon.  Icon
+ *  clicks are stacked, so that unclick calls unslab icons in reverse order
+ *  to slabbing.  If any 3D button managers are loaded, it's assumed that
+ *  you will want to use them.  Otherwise, icons are selected and unselected
+ *  (which fits in with RISC OS 3's inferior 3D button system)
+ *
+ * Parameters
+ *  dbox d == the dbox
+ *  dbox_field f == the field
+ */
+
+void dbox_clickicon(dbox d,dbox_field f)
+{
+  wimp_mousestr m;
+
+  if (dbox__click==dbox__CLICKMAX)
+  {
+    werr(FALSE,
+         msgs_lookup("dboxSTK:Only enough stack space for %i icons."),
+         dbox__CLICKMAX);
+    return;
+  }
+
+  dbox__clicked[dbox__click].s.w=d->wind;
+  dbox__clicked[dbox__click].s.i=f;
+  dbox__clicked[dbox__click].d=d;
+
+  if (wimpt_last_event()->e!=wimp_EKEY && !(wimpt_options() & 7))
+  {
+    dbox__clicked[dbox__click].d=0;
+    dbox__click++;
+    return;
+  }
+
+  if (wimpt_options() & wimpt_OSCULPTRIX)
+    wimpt_noerr(sculptrix_slabIcon(d->wind,f,&dbox__clicked[dbox__click].s));
+  if (wimpt_options() & wimpt_OINTERFACE)
+  {
+    m.w=d->wind;
+    m.i=f;
+    m.bbits=(dbox_wasAdjustClick() ? wimp_BRIGHT : wimp_BLEFT);
+    m.x=m.y=0;
+    wimpt_noerr(interface_slabButton(&m));
+  }
+  if (!(wimpt_options() & 7))
+    dbox_selecticon(d,f,dbox_SETSTATE);
+  dbox__click++;
+}
+
+/*
+ * void dbox_unclick(void)
+ *
+ * Use
+ *  This routine declicks the last icon to be 'dbox_clickicon'ed.  If you
+ *  intend to delete the dbox after the click, you should use code like
+ *  this:
+ *
+ *    dbox_hide(d);
+ *    dbox_unclick();
+ *    dbox_delete(d);
+ */
+
+void dbox_unclick(void)
+{
+  wimp_mousestr m;
+
+  if (dbox__click==0)
+  {
+    werr(TRUE,msgs_lookup("dboxCSU:(dbox_unclick): Click stack underflow."));
+    return;
+  }
+
+  dbox__click--;
+  if (dbox__clicked[dbox__click].d)
+  {
+    if (wimpt_options() & wimpt_OSCULPTRIX)
+      wimpt_noerr(sculptrix_unslabIcon(&dbox__clicked[dbox__click].s));
+    if (wimpt_options() & wimpt_OINTERFACE)
+    {
+      m.w=dbox__clicked[dbox__click].s.w;
+      m.i=dbox__clicked[dbox__click].s.i;
+      m.bbits=m.x=m.y=0;
+      wimpt_noerr(interface_slabButton(&m));
+    }
+    if (!(wimpt_options() & 7))
+    {
+      dbox_selecticon(dbox__clicked[dbox__click].d,
+                      dbox__clicked[dbox__click].s.i,
+                      dbox_RESETSTATE);
+    }
+  }
+}
+
+/*
+ * void dbox_unclickAll(void)
+ *
+ * Use
+ *  This call dbox_unclick()s all the 'dbox_clickicon'ed icons in the dbox.
+ *  You shouldn't really need to use it.  It's mainly there for consistency
+ *  with Armen's WimpLib v. 3.00 (written ages ago, and only used by the
+ *  author).  I've not needed to use it yet.
+ */
+
+void dbox_unclickAll(void)
+{
+  while (dbox__click)
+    dbox_unclick();
+}
+
+/*
+ * void dbox_getfield(dbox d,dbox_field f,char *buffer,int size)
+ *
+ * Use
+ *  This is the same routine as in RISC_OSlib.  It returns the contents of
+ *  the icon text in the buffer.
+ */
+
+void dbox_getfield(dbox d, dbox_field f, char *buffer, int size)
+{
+  wimp_icon *i = dbox__idef(d, f);
+  int j = 0;
+  char *from;
+
+  if (i->flags & wimp_ITEXT)
+  {
+    if (i->flags & wimp_INDIRECT)
+    {
+      while (i->data.indirecttext.buffer[j] >= 32)
+        j++;
+      from=i->data.indirecttext.buffer;
+    }
+    else
+    {
+      while (i->data.text[j] >= 32 && j < 11)
+        j++;
+      from=&i->data.text[0];
+    }
+    if (j>size)
+      j=size;
+    memcpy(buffer,from,j);
+  }
+  buffer[j]=0;
+}
+
+/*
+ * void dbox_scanfield(dbox d,dbox_field f,char *format,...)
+ *
+ * Use
+ *  Reads in scanf()-style the contents of a field.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field number
+ *  char *format == a scanf() style format string
+ */
+
+void dbox_scanfield(dbox d,dbox_field f,char *format,...)
+{
+  char field[1024];
+  va_list ap;
+  va_start(ap,format);
+  dbox_getfield(d,f,field,1024);
+  vsscanf(field,format,ap);
+  va_end(ap);
+}
+
+/*
+ * BOOL dbox_selecticon(dbox d,dbox_field f,dbox_action a)
+ *
+ * Use
+ *  This call will read the icon's state of selection and return it, and
+ *  optionally alter it as specified in the dbox_action parameter.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field you're interested in
+ *  dbox_action a == what you want to do with it
+ */
+
+BOOL dbox_selecticon(dbox d,dbox_field f,dbox_action a)
+{
+  wimp_icon icn;
+  BOOL selected;
+  wimpt_noerr(wimp_get_icon_info(d->wind,f,&icn));
+
+  selected=(icn.flags & wimp_ISELECTED) ? TRUE : FALSE;
+  switch (a)
+  {
+    case dbox_READSTATE:
+      return (selected);
+      break;
+    case dbox_SETSTATE:
+      if (selected)
+        return (TRUE);
+      icn.flags |= wimp_ISELECTED;
+      break;
+    case dbox_RESETSTATE:
+      if (!selected)
+        return (FALSE);
+      icn.flags &= ~wimp_ISELECTED;
+      break;
+    case dbox_TOGGLESTATE:
+      icn.flags ^= wimp_ISELECTED;
+      break;
+  }
+  wimpt_noerr(wimp_set_icon_state
+  (
+    d->wind,
+    f,
+    icn.flags & wimp_ISELECTED,
+    wimp_ISELECTED
+  ));
+  return (selected);
+}
+
+/*
+ * BOOL dbox_shadeicon(dbox d,dbox_field f,dbox_action a)
+ *
+ * Use
+ *  This call will read the icon's state of shading and return it, and
+ *  optionally alter it as specified in the dbox_action parameter.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field you're interested in
+ *  dbox_action a == what you want to do with it
+ */
+
+BOOL dbox_shadeicon(dbox d,dbox_field f,dbox_action a)
+{
+  BOOL shaded;                         /* The old value of the shading    */
+  BOOL shade;                          /* Whether to shade the icon       */
+  wimp_icon *icn=dbox__idef(d,f);      /* Find the icon in the window def */
+  wimp_icon real;
+  wimp_caretstr c;
+
+  /* --- Get the current shading state --- */
+
+  wimpt_noerr(wimp_get_icon_info(d->wind,f,&real));
+
+  if (wimpt_options() & wimpt_ONOWIMPSHADE)
+    shaded=!!(icn->flags & wimp_INOSELECT);
+  else
+    shaded=!!(real.flags & wimp_INOSELECT);
+
+  /* --- Find the new shading state --- */
+
+  switch (a)
+  {
+    case dbox_SETSTATE:
+      shade=TRUE;
+      break;
+    case dbox_RESETSTATE:
+      shade=FALSE;
+      break;
+    case dbox_TOGGLESTATE:
+      shade=!shaded;
+      break;
+    case dbox_READSTATE:
+    default:
+      shade=shaded;
+      break;
+  }
+
+  /* --- If there's nothing to do, then don't do it --- */
+
+  if (shade==shaded)
+    return (shaded);
+
+  /* --- Do appropriate things to the icon --- */
+
+  if (wimpt_options() & wimpt_ONOWIMPSHADE)
+  {
+    wimp_iconflags old;
+    wimp_iconflags new;
+    int contents;
+    int fhandle;
+
+    if (shade)
+    {
+      old=new=real.flags;
+      contents=old & 3;
+
+      if (wimp_readsysinfo(wimp_IFONTHANDLE,&fhandle))
+        fhandle=0;
+      if (fhandle && (contents&wimp_ISPRITE))
+        contents&=~wimp_ITEXT;
+
+      if (contents!=wimp_ITEXT)
+        new=new | 0x00400000;
+      if (contents & wimp_ITEXT)
+        new=(new & ~0x0f1ff000) | 0x021f0000;
+      icn->flags=old | 0x00400000;
+      wimpt_noerr(wimp_set_icon_state(d->wind,f,new,0xffffffff));
+    }
+    else
+    {
+      icn->flags = (icn->flags & 0x0f1ff000) | (real.flags & 0xf0a00fff);
+      wimpt_noerr(wimp_set_icon_state(d->wind,f,icn->flags,0xffffffff));
+    }
+    if (wimpt_options() & wimpt_OSCULPTRIX)
+      wimpt_noerr(sculptrix_updateIcon(d->wind,f));
+  }
+  else
+    wimpt_noerr(wimp_set_icon_state(d->wind,f,shade<<22,0x00400000));
+
+  if (shade)
+  {
+    wimpt_noerr(wimp_get_caret_pos(&c));
+    if (c.w==d->wind && c.i==f)
+    {
+        c.i=-1;
+        c.x=-500000;
+        wimpt_noerr(wimp_set_caret_pos(&c));
+    }
+  }
+
+  /* --- Now return the original value --- */
+
+  return (shaded);
+}
+
+/*
+ * wimp_w dbox_syshandle(dbox d)
+ *
+ * Use
+ *  Returns the window handle used by the dbox specified, because your poor
+ *  underprivileged code can't access my nice data structure.  This is for
+ *  setting up things like calls to event_attachmenu and suchlike, which
+ *  don't know about cunning things like dboxes.
+ *
+ * Parameters
+ *  dbox d == the dbox you're interested in
+ *
+ * Returns
+ *  The window handle, which is a wimp_w
+ */
+
+wimp_w dbox_syshandle(dbox d)
+{
+  return (d->wind);
+}
+
+/*
+ * int dbox_getNumeric(dbox d,dbox_field f)
+ *
+ * Use
+ *  Reads an integer from a field.  If there is no semblance to a valid
+ *  integer, 0 is returned.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field to read from
+ */
+
+int dbox_getNumeric(dbox d,dbox_field f)
+{
+  int val;
+  dbox_scanfield(d,f,"%d",&val);
+  return (val);
+}
+
+/*
+ * void dbox_setNumeric(dbox d,dbox_field f,int val)
+ *
+ * Use
+ *  Writes the integer value specified into the field.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field to set
+ *  int val == the integer value to write
+ */
+
+void dbox_setNumeric(dbox d,dbox_field f,int val)
+{
+  dbox_setfield(d,f,"%i",val);
+}
+
+/*
+ * dbox_field dbox_helpField(void)
+ *
+ * Use
+ *  Returns field number that Help is interested in.
+ *
+ * Returns
+ *  Field number.
+ */
+
+dbox_field dbox_helpField(void)
+{
+  wimp_eventstr *e=wimpt_last_event();
+  int icon;
+  int win;
+  wimp_icon icn;
+  if (help_wasHelp())
+  {
+    win=e->data.msg.data.helprequest.m.w;
+    icon=e->data.msg.data.helprequest.m.i;
+    wimpt_noerr(wimp_get_icon_info(win,icon,&icn));
+    if ((wimpt_options() & wimpt_ONOWIMPSHADE) &&
+        (icn.flags & 0x001f0000) == 0x001f0000)
+      return (-1);
+    else
+      return (icon);
+  }
+  else
+    werr
+    (
+      TRUE,
+      msgs_lookup("dboxHFE:(dbox_helpField, caller fault): "
+                                        "Not called on HELPREQUEST event.")
+    );
+  return (0);
+}
+
+/*----- Routines for Elite-style monologue boxes --------------------------*/
+
+/*
+ * void dbox_setEmbeddedTitle(dbox d,dbox_field icon,BOOL moveDrag)
+ *
+ * Use
+ *  Gives the specified dialogue box an inbuilt title (in a group box, round
+ *  the outside, as seen in Elite).  This is drawn automatically normally,
+ *  but raw event handlers might want to do extra drawing, so the entry
+ *  point to the redraw code is also supplied.
+ *
+ * Parameters
+ *  dbox d == the dialogue box to do this to
+ *  dbox_field icon == the icon around which the title is to be drawn
+ *  BOOL moveDrag == allow a click on any of the dialogue box to move it
+ */
+
+void dbox_setEmbeddedTitle(dbox d,dbox_field icon,BOOL moveDrag)
+{
+  d->titleIcon=icon;
+  d->moveDrag=moveDrag;
+}
+
+/*
+ * void dbox_drawEmbeddedTitle(wimp_redrawstr *r,void *handle)
+ *
+ * Use
+ *  Redraws an embedded title (as seen in Elite).  This is for the use of
+ *  raw event handlers, which might want to do this sort of thing, because
+ *  the redraw is normally handled automatically.
+ *
+ * Parameters
+ *  wimp_redrawstr *r == the redraw information I need
+ *  void *handle == a dbox, really.  This is for passing to wimpt_redraw.
+ */
+
+void dbox_drawEmbeddedTitle(wimp_redrawstr *r,void *handle)
+{
+  dbox d=handle;
+  char *t=d->windDef->title.indirecttext.buffer;
+  wimp_icon title;
+  wimp_icon border;
+  int len;
+  if (d->titleIcon==-1)
+    return;
+  for (len=0;t[len]>31;len++)
+    /* blank */ ;
+
+  if (wimpt_options() & wimpt_OSCULPTRIX)
+  {
+    /* --- We've got Sculptrix, so do a really good job --- *
+     *
+     * Since Sculptrix can do proper ridge/plinth intersections, we use this
+     * in preference.
+     *
+     * It now does the whole job in one go.
+     */
+
+    sculptrix_plotGroupBox(dbox__idef(d,d->titleIcon),r,0,t);
+    return;
+  }
+
+  border.box=dbox__idef(d,d->titleIcon)->box;
+  border.flags=wimp_ITEXT | wimp_INDIRECT;
+
+  title.box.x0=border.box.x0+16;
+  title.box.y0=border.box.y1-20;
+  title.box.x1=border.box.x0+32+wimpt_stringWidth(t);
+  title.box.y1=border.box.y1+28;
+  title.flags=wimp_ITEXT |
+              wimp_INDIRECT |
+              wimp_IFILLED |
+              wimp_IHCENTRE |
+              0x17000000;
+  title.data.indirecttext.buffer=t;
+  title.data.indirecttext.bufflen=len+1;
+
+  if (wimpt_options() & wimpt_OINTERFACE)
+  {
+    /* --- We can make do with Interface, although it isn't as nice --- *
+     *
+     * Interface makes a passable job at ridge-and-plinth group borders,
+     * though they're not as nice as Sculptrix's, because the ridged border
+     * doesn't intersect the title plinth properly.
+     */
+
+    border.data.indirecttext.validstring="Z1,0,0,4,0";
+    title.data.indirecttext.validstring="Z0,0,0,4,0";
+
+    _swi(XInterface_Plot3dIcon,_inr(0,1),r,&title);
+    _swi(XInterface_Plot3dIcon,_inr(0,1),r,&border);
+  }
+  else
+  {
+    /* --- Use RISC OS 3 borders if available --- *
+     *
+     * If not, RISC OS 2 will just plot a black border, which should look OK
+     * although not as nice.  Note that we can't do the STASIS-conforming
+     * ridge-and-plinth group box, although a channel will do at a pinch.
+     */
+
+    border.box.x0-=8;
+    border.box.y0-=8;
+    border.box.x1+=8;
+    border.box.y1+=8;
+    border.flags |= wimp_IBORDER;
+    border.data.indirecttext.validstring="r4";
+    border.data.indirecttext.buffer="";
+    border.data.indirecttext.bufflen=1;
+    title.data.indirecttext.validstring=(char *)-1;
+    wimp_ploticon(&border);
+  }
+  wimp_ploticon(&title);
+}
+
+/*
+ * BOOL dbox_hasTitle(dbox d)
+ *
+ * Use
+ *  Returns TRUE if the given dialogue box has a window title bar.
+ *
+ * Parameters
+ *  dbox d == the dialogue box to check
+ *
+ * Returns
+ *  TRUE if the dialogue box has a title bar
+ */
+
+BOOL dbox_hasTitle(dbox d)
+{
+  return (!!(d->windDef->flags & wimp_WTITLE));
+}
diff --git a/StraySrc/Libraries/Steel/c/event b/StraySrc/Libraries/Steel/c/event
new file mode 100644 (file)
index 0000000..f88f935
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * event.c
+ *
+ * Handling and dispatching events
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "event.h"
+#include "wimpt.h"
+#include "win.h"
+#include "menu.h"
+#include "msgs.h"
+#include "werr.h"
+#include "alarm.h"
+#include "mem.h"
+#include "swis.h"
+
+#define dbox__INTERNALS
+#include "dbox.h"
+
+/*----- Global variables --------------------------------------------------*/
+
+static wimp_emask event__mask=wimp_EMNULL;
+
+static menu event__currentMenu;
+static event_menu_maker event__currentMaker;
+static event_menu_proc event__menuProc;
+static void *event__menuHandle;
+
+/* --- For bodging menus which move around in memory --- */
+
+static int event__menuX;
+static int event__menuY;
+
+static BOOL event__recreating;
+static event_menuPurpose event__purpose;
+static BOOL event__returnMenuHelp;
+
+/*----- Event masks -------------------------------------------------------*/
+
+void event_setmask (wimp_emask mask)
+{
+  event__mask = mask;
+}
+
+wimp_emask event_getmask (void)
+{
+  if (win_any_idles())
+    return (event__mask&~wimp_EMNULL);
+  else
+    return (event__mask);
+}
+
+/*----- Menu button handling ----------------------------------------------*/
+
+typedef struct event__midbstr
+{
+  event_midbhandler proc;
+  int gadget;
+  void *handlea;
+  void *handleb;
+  void *handlec;
+}
+event__midbstr;
+
+/*
+ * BOOL event_attachMidbHandler(wimp_w w,
+ *                              event_midbhandler proc,
+ *                              int gadget,
+ *                              void *handlea,
+ *                              void *handleb,
+ *                              void *handlec)
+ *
+ * Use
+ *  Registers a function to be called by event when a menu button event is
+ *  received by a particular window.  Typically, this handler will display a
+ *  menu at the mouse coordinates, although you can do anything you want.
+ *
+ *  You shouldn't need to call this function very much.  It's really for
+ *  allowing other systems to supply menu attachment functions like event_-
+ *  attachmenu etc.
+ *
+ * Parameters
+ *  wimp_w == the window to which to attach the function
+ *  event_midbhandler proc == the function to call when a menu button event
+ *    is received for the window
+ *  others == arguments to be passed (unprocessed) to proc when it's called.
+ *
+ * Returns
+ *  TRUE if the attachment succeeded.
+ */
+
+BOOL event_attachMidbHandler(wimp_w w,
+                             event_midbhandler proc,
+                             int gadget,
+                             void *handlea,
+                             void *handleb,
+                             void *handlec)
+{
+  event__midbstr *e=win_getmenuh(w);
+  if (!e && proc)
+  {
+    if (e=mem_alloc(sizeof(event__midbstr)),!e)
+    {
+      werr(FALSE,msgs_lookup("eventNMAM:Not enough memory to attach menu"));
+      return (FALSE);
+    }
+    win_setmenuh(w,e);
+  }
+  if (proc)
+  {
+    e->proc=proc;
+    e->gadget=gadget;
+    e->handlea=handlea;
+    e->handleb=handleb;
+    e->handlec=handlec;
+  }
+  else if (e)
+  {
+    mem_free(e);
+    win_setmenuh(w,0);
+  }
+  return (TRUE);
+}
+
+void event_attachedMenu(wimp_w w,
+                        menu *m,
+                        event_menu_maker *mk,
+                        event_menu_proc *proc,
+                        void **handle)
+{
+  event__midbstr *e=win_getmenuh(w);
+  if (e)
+  {
+    *m=(e->gadget ? 0 : e->handlea);
+    *mk=(e->gadget ? (event_menu_maker)e->handlea : 0);
+    *proc=(event_menu_proc)e->handleb;
+    *handle=e->handlec;
+  }
+  else
+  {
+    *m=0;
+    *mk=0;
+    *proc=0;
+    *handle=0;
+  }
+}
+
+/*----- Menu displaying ---------------------------------------------------*/
+
+/*
+ * void event__displayMenu(void)
+ *
+ * Use
+ *  Displays (or redisplays) the current menu.  It is assumed that the menu
+ *  maker has been called to set up the current menu pointer.
+ */
+
+static void event__displayMenu(void)
+{
+  wimp_menustr *m;
+  m=menu_syshandle(event__currentMenu);
+  if (win_anyWindows()==FALSE)
+  {
+    werr(FALSE,
+         msgs_lookup("eventTMWM:Too many windows - "
+                               "%s could not create menu."),
+         wimpt_programname());
+  }
+  else
+    wimpt_noerr(wimp_create_menu(m,event__menuX,event__menuY));
+}
+
+/*
+ * void event__findMenu(BOOL iconbar)
+ *
+ * Use
+ *  Sets up the global event__menuX and event__menuY for the current menu
+ *  for a subsequent call of event__displayMenu.  Also (as a side-effect)
+ *  calls the menu maker.
+ *
+ * Parameters
+ *  BOOL iconbar == whether the menu has been opened from the iconbar
+ */
+
+static void event__findMenu(BOOL iconbar)
+{
+  wimp_mousestr m;
+  wimp_menustr *mn;
+  wimp_menuitem *it;
+  int height;
+  if (event__currentMaker)
+  {
+    event__recreating=FALSE;
+    event__currentMenu=event__currentMaker(event__menuHandle);
+  }
+  wimpt_noerr(wimp_get_point_info(&m));
+  event__menuX=m.x-64;
+  if (iconbar)
+  {
+    mn=menu_syshandle(event__currentMenu);
+    height=0;
+    it=(wimp_menuitem *)(mn+1);
+    for (;;)
+    {
+      height+=44; /* I know it may not be, but it should. */
+      if (it->flags & wimp_MSEPARATE)
+        height+=24;
+      if (it->flags & wimp_MLAST)
+        break;
+      it++;
+    }
+    event__menuY=96+height;
+  }
+  else
+    event__menuY=m.y;
+}
+
+/*
+ * void event_openMenu(menu it,event_menu_proc proc,void *handle)
+ * void event_makeMenu(event_menu_maker it,event_menu_proc proc,void *handle)
+ * void event_openIconbarMenu(...)
+ * void event_makeIconbarMenu(...)
+ *
+ * Use
+ *  Opens a menu onto the screen and tells your routine when it's finished.
+ *
+ * Parameters
+ *  menu it == the menu or menu maker procedure
+ *  event_menu_proc proc == the menu handler function
+ *  void *handle == it's jolly old handle
+ */
+
+void event_openMenu(menu it,event_menu_proc proc,void *handle)
+{
+  event__currentMenu=it;
+  event__currentMaker=0;
+  event__menuProc=proc;
+  event__menuHandle=handle;
+  event__findMenu(FALSE);
+  event__displayMenu();
+}
+
+void event_makeMenu(event_menu_maker maker,event_menu_proc proc,void *handle)
+{
+  event__currentMaker=maker;
+  event__menuProc=proc;
+  event__menuHandle=handle;
+  event__findMenu(FALSE);
+  event__displayMenu();
+}
+
+void event_openIconbarMenu(menu it,event_menu_proc proc,void *handle)
+{
+  event__currentMenu=it;
+  event__currentMaker=0;
+  event__menuProc=proc;
+  event__menuHandle=handle;
+  event__findMenu(TRUE);
+  event__displayMenu();
+}
+
+void event_makeIconbarMenu(event_menu_maker maker,
+                           event_menu_proc proc,
+                           void *handle)
+{
+  event__currentMaker=maker;
+  event__menuProc=proc;
+  event__menuHandle=handle;
+  event__findMenu(TRUE);
+  event__displayMenu();
+}
+
+/*----- Menu attachment ---------------------------------------------------*/
+
+/*
+ * event__defaultmidb(wimp_w w,
+ *                    int made,
+ *                    void *handlea,
+ *                    void *handleb,
+ *                    void *handlec)
+ *
+ * Use
+ *  Default menu button handler for windows (to support event_attachmenu
+ *  etc.)
+ *
+ * Parameters
+ *  As for an event_midbhandler.
+ */
+
+static void event__defaultmidb(wimp_w w,
+                               int made,
+                               void *handlea,
+                               void *handleb,
+                               void *handlec)
+{
+  if (w==win_ICONBAR)
+  {
+    if (!made)
+    {
+      event_openIconbarMenu((menu)handlea,
+                            (event_menu_proc)handleb,
+                            handlec);
+    }
+    else
+    {
+      event_makeIconbarMenu((event_menu_maker)handlea,
+                            (event_menu_proc)handleb,
+                            handlec);
+    }
+  }
+  else
+  {
+    if (!made)
+    {
+      event_openMenu((menu)handlea,
+                     (event_menu_proc)handleb,
+                     handlec);
+    }
+    else
+    {
+      event_makeMenu((event_menu_maker)handlea,
+                     (event_menu_proc)handleb,
+                     handlec);
+    }
+  }
+}
+
+/*----- Default menu attachment -------------------------------------------*/
+
+/*
+ * void event_attachmenu(wimp_w w,menu m,event_menu_proc p,void *handle)
+ *
+ * Use
+ *  Attaches a menu to a window so that it opens when you click menu on it.
+ *
+ * Parameters
+ *  wimp_w w == the window to attach to
+ *  menu m == the menu to attach to it
+ *  event_menu_proc p == what to do when a menu item is chosen
+ *  void *handle == something else to send to p
+ */
+
+BOOL event_attachmenu(wimp_w w,menu m,event_menu_proc p,void *handle)
+{
+  return (event_attachMidbHandler(w,
+                                  event__defaultmidb,
+                                  FALSE,
+                                  m,
+                                  (void *)p,
+                                  handle));
+}
+
+/*
+ * void event_attachmenumaker(wimp_w w,
+ *                            event_menu_maker m,
+ *                            event_menu_proc p,
+ *                            void *handle)
+ *
+ * Use
+ *  Attaches a menu to a window so that it opens when you click menu on it.
+ *
+ * Parameters
+ *  wimp_w w == the window to attach to
+ *  event_menu_maker m == how to create the menu
+ *  event_menu_proc p == what to do when a menu item is chosen
+ *  void *handle == something else to send to p
+ */
+
+BOOL event_attachmenumaker(wimp_w w,
+                           event_menu_maker m,
+                           event_menu_proc p,
+                           void *handle)
+{
+  return (event_attachMidbHandler(w,
+                                  event__defaultmidb,
+                                  TRUE,
+                                  (void *)m,
+                                  (void *)p,
+                                  handle));
+}
+
+/*----- Pointless window counting -----------------------------------------*/
+
+BOOL event_anywindows(void)
+{
+  return(win_activeno() != 0);
+}
+
+/*----- Event processing -- the interesting bit ---------------------------*/
+
+void event_returnMenuHelp(BOOL doit)
+{
+  event__returnMenuHelp=doit;
+}
+
+event_menuPurpose event_whyMenuEvent(void)
+{
+  return (event__purpose);
+}
+
+BOOL event_is_menu_being_recreated(void)
+{
+ return event__recreating;
+}
+
+void (event_process)(void)
+{
+  event_process();
+}
+/*
+ * void event__menuHit(int *hits)
+ *
+ * Use
+ *  Sends a menu hit array to the current menu handling procedure
+ *
+ * Parameters
+ *  int *hits == an array of menu hits (WIMP-style) to convert to obscure
+ *    RISC_OSLib format (1-indexed :-( ) and bundled to an event handler.
+ */
+
+static void event__menuHit(int *hits)
+{
+  int i;
+  char buff[9]; /* Silly event -- using chars! */
+  if (event__currentMenu)
+  {
+    for (i=0;hits[i]!=-1;i++)
+      buff[i]=hits[i]+1;
+    buff[i]=hits[i]+1;
+    event__menuProc(event__menuHandle,buff);
+  }
+}
+
+/*
+ * void event__process(void)
+ *
+ * Use
+ *  Processes events :-)
+ */
+
+void event__process(void)
+{
+  wimp_eventstr e;
+  int i;
+  static BOOL lastWasMenu;
+  int nextAlarm;
+
+  /* --- Terminate the app if it has no windows --- */
+
+  if (!event_anywindows())
+    exit(0);
+
+  /* --- If we just clicked on a menu, we may need to reopen it --- */
+
+  if (lastWasMenu &&
+      event__currentMenu &&
+      wimpt_last_event()->e==wimp_EMENU)
+  {
+    wimp_mousestr m;
+    wimpt_noerr(wimp_get_point_info(&m));
+    if (m.bbits & wimp_BRIGHT)
+    {
+      if (event__currentMaker)
+      {
+        event__recreating=TRUE;
+        event__currentMenu=event__currentMaker(event__menuHandle);
+      }
+      event__displayMenu();
+    }
+    else
+    {
+      i=-1;
+      event__purpose=event_MENUDELETE;
+      event__menuHit(&i);
+    }
+  }
+
+  /* --- Get an event from wimpt and process it --- */
+
+  wimpt_noerr(wimpt_poll(event_getmask(),&e));
+  lastWasMenu=FALSE;
+
+  switch (e.e)
+  {
+    case wimp_ENULL:
+      while (alarm_next(&nextAlarm) && alarm_timenow()-nextAlarm>=0)
+        alarm_callnext();
+      break;
+    case wimp_EBUT:
+      if (e.data.but.m.bbits & wimp_BMID)
+      {
+        wimp_w w=(e.data.but.m.w<=-1) ? win_ICONBAR : e.data.but.m.w;
+        event__midbstr *m=win_getmenuh(w);
+        if (m)
+        {
+          (m->proc)(w,m->gadget,m->handlea,m->handleb,m->handlec);
+          return;
+        }
+      }
+      break;
+    case wimp_EMENU:
+      event__purpose=event_MENUSELECT;
+      event__menuHit(e.data.menu);
+      lastWasMenu=TRUE;
+      break;
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e.data.msg.hdr.action)
+      {
+
+        case wimp_MMENUWARN:
+          if (e.data.msg.data.words[0]>0x8000)
+          {
+            if (win_anyWindows()==FALSE)
+            {
+              werr(FALSE,
+                   msgs_lookup("eventTMWS:Too many windows - "
+                                         "%s could not create submenu."),
+                   wimpt_programname());
+            }
+            else
+            {
+              wimpt_noerr(wimp_create_submenu(
+                               (wimp_menustr *)e.data.msg.data.words[0],
+                               e.data.msg.data.words[1],
+                               e.data.msg.data.words[2]));
+            }
+          }
+          else
+          {
+            for (i=3;e.data.msg.data.words[i] != -1;i++)
+              /* blank! */;
+            e.data.msg.data.words[i++] = -1;
+            event__purpose=event_MENUSUBMENU;
+            event__menuHit(e.data.msg.data.words+3);
+          }
+          break;
+        case wimp_MHELPREQUEST:
+          if (event__returnMenuHelp &&
+              e.data.msg.data.helprequest.m.w!=dbox__menuDboxWindow())
+          {
+            int buff[20];
+
+            wimpt_noerr(wimp_getmenustate(1,
+                                          buff,
+                                          e.data.msg.data.helprequest.m.w,
+                                          e.data.msg.data.helprequest.m.i));
+            if (buff[0]!=-1)
+            {
+              event__purpose=event_MENUHELP;
+              event__menuHit(buff);
+            }
+          }
+          break;
+        case 0x400C9:        /* Message_MenusDeleted */
+          e.e=wimp_EMENU;
+          e.data.menu[0]=-1;
+          event__purpose=event_MENUDELETE;
+          event__menuHit(e.data.menu);
+          break;
+      }
+      break;
+  }
+
+  if (!win_processevent(&e))
+  {
+
+    /* --- Default event handling --- */
+
+    switch (e.e)
+    {
+      case wimp_EREDRAW:
+        werr(TRUE,msgs_lookup("Internal error: unserviced redraw event"));
+        break;
+      case wimp_EOPEN:
+        wimpt_noerr(wimp_open_wind(&e.data.o));
+        break;
+      case wimp_EKEY:
+        wimp_processkey(e.data.key.chcode);
+        break;
+    }
+  }
+}
+
+void event_clear_current_menu(void)
+{
+  wimpt_noerr(wimp_create_menu((wimp_menustr*)-1,0,0));
+  if (event__currentMenu)
+  {
+    int i=-1;
+    event__purpose=event_MENUDELETE;
+    event__menuHit(&i);
+    event__currentMenu=0;
+  }
+}
diff --git a/StraySrc/Libraries/Steel/c/exception b/StraySrc/Libraries/Steel/c/exception
new file mode 100644 (file)
index 0000000..957804d
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Exception
+ *  Handles odd errors in Steel programs
+ *
+ * 1.00 (24 September 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "msgs.h"
+#include "exception.h"
+#include "wimpt.h"
+#include "werr.h"
+#include "visdelay.h"
+
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+static BOOL exception__handled;
+static int *exception__handler;
+
+/*
+ * int exception_registerHandler(exception_handler env)
+ *
+ * Use
+ *  Registers the current point as being a sensible place to go after an
+ *  exception.  This is implemented as a macro for the simple reason that
+ *  things tend to go a tad wrong if you define your exception_handlers in a
+ *  function and then return.
+ *
+ * Parameters
+ *  exception_handler env == an undefined variable of the type
+ *    exception_handler.
+ */
+
+#ifndef exception_registerHandler
+#define exception_registerHandler(env) \
+  (exception__registerHandler((env),setjmp(env)))
+#endif
+
+/*
+ * void exception_generate(char *message,...)
+ *
+ * Use
+ *  Generates a Steel exception, to be handled in an appropriate manner.
+ *
+ * Parameters
+ *  char *message == printf()-type format string
+ */
+
+void exception_generate(char *message,...)
+{
+  char buffer[256];
+  va_list ap;
+  va_start(ap,message);
+  vsprintf(buffer,message,ap);
+  va_end(ap);
+  visdelay_suspend(); /* It doesn't mind if we suspend indefinitely */
+  if (exception__handled==FALSE)
+  {
+    werr(FALSE,msgs_lookup("excFATAL:Fatal internal error: '%s'"),buffer);
+    exit(1);
+  }
+  else
+  {
+    if (werr_error((wimpt_options() & wimpt_ONOBACKTRACE) ? 2 : 3,
+                   msgs_lookup("excSEV:Internal error: '%s'.  Click OK "
+                               "to continue, or Cancel to quit %s."),
+                   buffer,
+                   wimpt_programname())==0)
+    {
+      if (werr_error(2,
+                     msgs_lookup("excAYS:Are you sure you want to quit %s?  "
+                                 "Click OK to continue, or Cancel to quit."),
+                     wimpt_programname())==0)
+      {
+        exit(1);
+      }
+      else
+        longjmp(exception__handler,1);
+    }
+    else
+      longjmp(exception__handler,1);
+  }
+}
+
+/*
+ * int exception__registerHandler(jmp_buf handler)
+ *
+ * Use
+ *  This routine is for the use of exception segment only, and should not be
+ *  called from your code.
+ */
+
+int exception__registerHandler(jmp_buf handler,int result)
+{
+  if (result==0)
+  {
+    exception__handled=TRUE;
+    exception__handler=handler;
+  }
+  return (result);
+}
diff --git a/StraySrc/Libraries/Steel/c/fileicon b/StraySrc/Libraries/Steel/c/fileicon
new file mode 100644 (file)
index 0000000..8762535
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * fileicon
+ *
+ * creates a file icon in a window, plonk over another one.
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "fileicon.h"
+#include "wimp.h"
+#include "wimpt.h"
+#include "werr.h"
+#include "msgs.h"
+#include "buffer.h"
+#include <stdio.h>
+#include <string.h>
+
+static BOOL fileicon__spriteExist(char *name)
+{
+  BOOL there;
+  if (wimp_spriteop(40,name))
+    there=FALSE;
+  else
+    there=TRUE;
+  return (there);
+}
+
+char *fileicon_spriteName(int filetype,char *name)
+{
+  char *spritename=buffer_find();
+  char *leaf=name;
+  char *p;
+  for (p=name;*p!=0;p++)
+  {
+    if (*p=='.')
+      leaf=p+1;
+  }
+  switch (filetype)
+  {
+    case 0x3000:
+      strcpy(spritename,"file_xxx");
+      break;
+    case 0x2000:
+      if (fileicon__spriteExist(leaf))
+        strcpy(spritename,leaf);
+      else
+        strcpy(spritename,"application");
+      break;
+    case 0x1000:
+      strcpy(spritename,"directory");
+      break;
+    default:
+      sprintf(spritename,"file_%.3x",filetype);
+      if (!fileicon__spriteExist(spritename))
+        strcpy(spritename,"file_xxx");
+      break;
+  }
+  return (spritename);
+}
+
+void fileicon(wimp_w w,wimp_i i,int filetype,char *name)
+{
+  wimp_icreate icn;
+  wimp_i ih;
+  wimpt_noerr(wimp_get_icon_info(w,i,&(icn.i)));
+  wimpt_noerr(wimp_delete_icon(w,i));
+  if ((icn.i.flags & wimp_INDIRECT)==0)
+    werr(TRUE,msgs_lookup("ficnNII:(fileicon, caller fault): "
+                                             "Icon must be indirected."));
+  icn.i.flags=
+  (
+    wimp_ISPRITE |
+    wimp_IHCENTRE |
+    wimp_IVCENTRE |
+    wimp_IFILLED |
+    wimp_INDIRECT |
+    wimp_IBTYPE * wimp_BDEBOUNCEDRAG |
+    wimp_IFORECOL * 7 |
+    wimp_IBACKCOL * 1
+  );
+  strcpy(icn.i.data.indirectsprite.name,fileicon_spriteName(filetype,name));
+  icn.i.data.indirectsprite.spritearea=(void *)1;
+  icn.i.data.indirectsprite.nameisname=TRUE;
+  icn.w=w;
+  wimpt_noerr(wimp_create_icon(&icn,&ih));
+  wimpt_noerr(wimp_set_icon_state(w,ih,0,0));
+  if (ih!=i)
+    werr(TRUE,msgs_lookup("ficnIHD:(fileicon): Icon handle has changed."));
+}
diff --git a/StraySrc/Libraries/Steel/c/font b/StraySrc/Libraries/Steel/c/font
new file mode 100644 (file)
index 0000000..c7b29b5
--- /dev/null
@@ -0,0 +1,584 @@
+/************************************************************************/
+/* © Acorn Computers Ltd, 1992.                                         */
+/*                                                                      */
+/* This file forms part of an unsupported source release of RISC_OSLib. */
+/*                                                                      */
+/* It may be freely used to create executable images for saleable       */
+/* products but cannot be sold in source form or as an object library   */
+/* without the prior written consent of Acorn Computers Ltd.            */
+/*                                                                      */
+/* If this file is re-distributed (even if modified) it should retain   */
+/* this copyright notice.                                               */
+/*                                                                      */
+/************************************************************************/
+
+/*
+ * Title  : c.font
+ * Purpose: access to RISC OS font facilities
+ * History: IDJ: 06-Feb-92: prepared for source release
+ */
+
+#ifndef __stddef_h
+#include <stddef.h>
+#endif
+#include "h.os"
+#include "h.trace"
+#include "h.font"
+
+
+/*                          F O N T    S W I 's                          */
+#define CacheAddr            0x40080
+#define FindFont             0x40081
+#define LoseFont             0x40082
+#define ReadDefn             0x40083
+#define ReadInfo             0x40084
+#define StringWidth          0x40085
+#define Paint                0x40086
+#define Caret                0x40087
+#define ConverttoOS          0x40088
+#define Converttopoints      0x40089
+#define SetFont              0x4008A
+#define CurrentFont          0x4008B
+#define FutureFont           0x4008C
+#define FindCaret            0x4008D
+#define CharBBox             0x4008E
+#define ReadScaleFactor      0x4008F
+#define SetScaleFactor       0x40090
+#define ListFonts            0x40091
+#define SetFontColours       0x40092
+#define SetPalette           0x40093
+#define ReadThresholds       0x40094
+#define SetThresholds        0x40095
+#define FindCaretJ           0x40096
+#define StringBBox           0x40097
+#define ReadColourTable      0x40098
+#define MakeBitmap           0x40099
+#define UnCacheFile          0x4009A
+#define SetFontMax           0x4009B
+#define ReadFontMax          0x4009C
+#define ReadFontPrefix       0x4009D
+#define SwitchOutputToBuffer 0x4009E
+#define ReadFontMetrics      0x4009F
+
+#pragma no_check_stack
+
+os_error *font_cacheaddress(int *version, int *cacheused, int *cachesize)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[0] = 0;
+   e = os_swix(CacheAddr, &r);
+
+   if (!e)
+   {
+      *version = r.r[0];
+      *cacheused = r.r[1];
+      *cachesize = r.r[2];
+   }
+
+   return e;
+}
+
+
+os_error *font_find(char *name, int xsize, int ysize, int xres, int yres, font *fontadd)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = (int)name;
+   r.r[2] = xsize;
+   r.r[3] = ysize;
+   r.r[4] = xres;
+   r.r[5] = yres;
+
+   e = os_swix(FindFont, &r);
+
+   *fontadd = (font) r.r[0];
+
+   return e;
+}
+
+os_error *font_lose(font f)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[0] = f;
+   e = os_swix(LoseFont, &r);
+   return e;
+}
+
+
+os_error * font_readdef(font f, font_def *d)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[0] = (int)f;
+   r.r[1] = (int)&d->name;
+
+   e = os_swix(ReadDefn, &r);
+
+   d->xsize = r.r[2];
+   d->ysize = r.r[3];
+   d->xres = r.r[4];
+   d->yres = r.r[5];
+   d->usage = r.r[6];
+   d->age = r.r[7];
+
+   return(e);
+}
+
+
+os_error *font_readinfo(font f, font_info *i)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[0] = f;
+
+   e = os_swix(ReadInfo, &r);
+
+   i->minx = r.r[1];
+   i->miny = r.r[2];
+   i->maxx = r.r[3];
+   i->maxy = r.r[4];
+
+   return e;
+}
+
+
+os_error *font_strwidth(font_string *fs)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = (int)fs->s;
+   r.r[2] = fs->x;
+   r.r[3] = fs->y;
+   r.r[4] = fs->split;
+   r.r[5] = fs->term;
+
+   e = os_swix(StringWidth, &r);
+
+   fs->x = r.r[2];
+   fs->y = r.r[3];
+   fs->split = r.r[4];
+   fs->term = r.r[5];
+
+   return e;
+}
+
+
+os_error *font_paint(char *s, int options, int x, int y)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = (int)s;
+   r.r[2] = options;
+   r.r[3] = x;
+   r.r[4] = y;
+
+   e = os_swix(Paint, &r);
+
+   return e;
+}
+
+
+os_error *font_caret(int colour, int height, int flags, int x, int y)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[0] = colour;
+   r.r[1] = height;
+   r.r[2] = flags;
+   r.r[3] = x;
+   r.r[4] = y;
+
+   e = os_swix(Caret, &r);
+
+   return e;
+}
+
+
+os_error *font_converttoos(int x_inch, int y_inch, int *x_os, int *y_os)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = x_inch;
+   r.r[2] = y_inch;
+
+   e = os_swix(ConverttoOS, &r);
+
+   *x_os = r.r[1];
+   *y_os = r.r[2];
+
+   return e;
+}
+
+
+os_error *font_converttopoints(int x_os, int y_os, int *x_inch, int *y_inch)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = x_os;
+   r.r[2] = y_os;
+
+   e = os_swix(Converttopoints, &r);
+
+   *x_inch = r.r[1];
+   *y_inch = r.r[2];
+
+   return e;
+}
+
+
+os_error *font_setfont(font f)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[0] = f;
+
+   e = os_swix(SetFont, &r);
+
+   return(e);
+}
+
+
+os_error *font_current(font_state *f)
+{
+   os_regset r;
+   os_error *e;
+
+   e = os_swix(CurrentFont, &r);
+
+   f->f = r.r[0];
+   f->back_colour = r.r[1];
+   f->fore_colour = r.r[2];
+   f->offset = r.r[3];
+
+   return(e);
+}
+
+
+os_error *font_future(font_state *f)
+{
+   os_regset r;
+   os_error *e;
+
+   e = os_swix(FutureFont, &r);
+
+   f->f = r.r[0];
+   f->back_colour = r.r[1];
+   f->fore_colour = r.r[2];
+   f->offset = r.r[3];
+
+   return(e);
+}
+
+
+os_error *font_findcaret(font_string *fs)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = (int)fs->s;
+   r.r[2] = fs->x;
+   r.r[3] = fs->y;
+
+   e = os_swix(FindCaret, &r);
+
+   fs->x = r.r[2];
+   fs->y = r.r[3];
+   fs->split = r.r[4];
+   fs->term = r.r[5];
+
+   return e;
+}
+
+
+os_error *font_charbbox(font f, char ch, int options, font_info *i)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[0] = f;
+   r.r[1] = ch;
+   r.r[2] = options;
+
+   e = os_swix(CharBBox, &r);
+
+   i->minx = r.r[1];
+   i->miny = r.r[2];
+   i->maxx = r.r[3];
+   i->maxy = r.r[4];
+
+   return e;
+}
+
+
+os_error *font_readscalefactor(int *x, int *y)
+{
+   os_regset r;
+   os_error *e;
+
+   e = os_swix(ReadScaleFactor, &r);
+
+   *x = r.r[1];
+   *y = r.r[2];
+
+   return e;
+}
+
+
+os_error *font_setscalefactor(int x, int y)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = x;
+   r.r[2] = y;
+
+   e = os_swix(SetScaleFactor, &r);
+
+   return e;
+}
+
+
+os_error *font_list(char *a, int *count)
+{
+   os_regset r;
+   os_error *e;
+   int i;
+
+   r.r[1] = (int)a;
+   r.r[2] = *count;
+   r.r[3] = -1;
+
+   e = os_swix(ListFonts, &r);
+
+   if (!e)
+   {
+
+      *count = r.r[2];
+      i = 0;
+        
+      while (a[i] >= 32 && i <= 99)
+
+           ++i;
+
+      a[i] = 0;
+
+   }
+   else /* error return: probably some filing system error */
+      *count = -1; /* signal end of list */
+
+   return e;
+
+}
+
+
+os_error *font_setcolour(font f, int background, int foreground, int offset)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[0] = f;
+   r.r[1] = background;
+   r.r[2] = foreground;
+   r.r[3] = offset;
+
+   e = os_swix(SetFontColours, &r);
+
+   return e;
+}
+
+
+os_error *font_setpalette(int background, int foreground, int offset, 
+                          int physical_back, int physical_fore)
+
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = background;
+   r.r[2] = foreground;
+   r.r[3] = offset;
+   r.r[4] = physical_back;
+   r.r[5] = physical_fore;
+
+   e = os_swix(SetPalette, &r);
+
+   return e;
+}
+
+
+os_error *font_readthresholds(font_threshold *th)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = (int)th;
+
+   e = os_swix(ReadThresholds, &r);
+
+   return e;
+}
+
+
+os_error *font_setthresholds(font_threshold *th)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = (int)th;
+
+   e = os_swix(SetThresholds, &r);
+
+   return e;
+}
+
+
+os_error *font_findcaretj(font_string *fs, int offset_x, int offset_y)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = (int)fs->s;
+   r.r[2] = fs->x;
+   r.r[3] = fs->y;
+   r.r[4] = offset_x;
+   r.r[5] = offset_y;
+
+   e = os_swix(FindCaretJ, &r);
+
+   fs->x = r.r[2];
+   fs->y = r.r[3];
+   fs->split = r.r[4];
+   fs->term = r.r[5];
+
+   return e;
+}
+
+
+os_error *font_stringbbox(char *s, font_info *fi)
+{
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = (int)s;
+
+   e = os_swix(StringBBox, &r);
+
+   fi->minx = r.r[1];
+   fi->miny = r.r[2];
+   fi->maxx = r.r[3];
+   fi->maxy = r.r[4];
+
+   return e;
+}
+
+/*-----------------------------------------------------------------*/
+/*Routines for conversion of fonts to Draw module path objects. See
+   the documentation of SWI Font_SwitchOutputToBuffer.*/
+
+os_error *font_output_to_null (BOOL add_hints, BOOL output_skeleton,
+                               font_action_on_bitmap action_on_bitmap)
+
+{  
+   os_regset reg_set;
+   os_error *error;
+
+   tracef0 ("font_output_to_null\n");
+
+   reg_set.r[0] =
+      1 /*no output*/ +
+      (add_hints? 1 << 1: 0) +
+      (output_skeleton? 1 << 2: 0) +
+      (  action_on_bitmap == font_ERROR?
+            1 << 4:
+         action_on_bitmap == font_CONVERT?
+            1 << 3:
+            0
+      );
+   reg_set.r[1] = 8;
+
+   if ((error = os_swix (SwitchOutputToBuffer, &reg_set)) != NULL) 
+      return error;
+
+   return NULL;
+}           
+
+
+os_error *font_output_size (size_t *size_ptr)
+{  
+   os_regset reg_set;
+   os_error *error;
+
+   tracef0 ("font_output_size\n");
+
+   reg_set.r [0] =  0;
+   reg_set.r [1] = -1;
+
+   if ((error = os_swix (SwitchOutputToBuffer, &reg_set)) != NULL)
+      return error;
+
+   *size_ptr = reg_set.r [1];
+   tracef1 ("font_output_size: made %d bytes of path\n", *size_ptr);
+   return NULL;
+}
+
+
+os_error *font_output_to_buffer(drawmod_buffer *buff_ptr, BOOL add_hints,
+                                BOOL output_skeleton, 
+                                font_action_on_bitmap action_on_bitmap)
+
+{  
+   os_regset reg_set;
+   os_error *error;
+
+   tracef0 ("font_output_to_buffer\n");
+
+   reg_set.r[0] =
+      (add_hints? 1 << 1: 0) +
+      (output_skeleton? 1 << 2: 0) +
+      (  action_on_bitmap == font_ERROR?
+            1 << 4:
+         action_on_bitmap == font_CONVERT?
+            1 << 3:
+            0
+      );
+   reg_set.r[1] = (int) buff_ptr;
+
+   tracef1 ("font_output_to_buffer: path going to 0x%p\n", buff_ptr);
+   if ((error = os_swix (SwitchOutputToBuffer, &reg_set)) != NULL) 
+      return error;
+
+   return NULL;
+}
+
+
+os_error *font_output_to_screen (void)
+{  
+   os_regset reg_set;
+   os_error *error;
+
+   tracef0 ("font_output_to_screen\n");
+
+   reg_set.r [0] = 0;
+   reg_set.r [1] = 0;
+
+   if ((error = os_swix (SwitchOutputToBuffer, &reg_set)) != NULL) 
+      return error;
+
+   return NULL;
+}
+
+#pragma check_stack
diff --git a/StraySrc/Libraries/Steel/c/fontMenu b/StraySrc/Libraries/Steel/c/fontMenu
new file mode 100644 (file)
index 0000000..8c0cea6
--- /dev/null
@@ -0,0 +1,610 @@
+/*
+ * fontMenu
+ *  creates (and handles) a hierarchical font menu
+ *
+ * v. 1.00 (22 August 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wimp.h"
+#include "fontMenu.h"
+#include "msgs.h"
+#include "werr.h"
+#include "wimpt.h"
+#include "menuExt.h"
+#include "buffer.h"
+#include <stdio.h>
+#include "font.h"
+#include "visdelay.h"
+#include "win.h"
+#include "utils.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+static BOOL fontMenu__created;
+static menu fontMenu__menu;
+static char fontMenu__oldFontPath[256];
+static BOOL fontMenu__anyFonts;
+static BOOL fontMenu__includeSystem;
+static int fontMenu__tick1=-1;
+static int fontMenu__tick2=-1;
+
+/*
+ * char *fontMenu__fontFamily(char *fontname)
+ *
+ * Use
+ *  Returns the family name of the given font.
+ *
+ * Parameters
+ *  char *fontname == the name of the font.
+ *
+ * Returns
+ *  The family name of the font (i.e. returns "Trinity" for "Trinity.Medium")
+ *  as a pointer to a read-only internal static object.
+ */
+
+static char *fontMenu__fontFamily(char *fontname)
+{
+  char *fontFamily=buffer_find();
+  int index=0;
+  char c=fontname[index];
+  while (c!='.' && c>31)
+  {
+    fontFamily[index++]=c;
+    c=fontname[index];
+  }
+  fontFamily[index]='\0';
+  return (fontFamily);
+}
+
+/*
+ * char *fontMenu__fontLeaf(char *fontname)
+ *
+ * Use
+ *  Returns the leafname of the font (i.e. for "Trinity.Bold.Italic", it
+ *  returns "Bold.Italic").  If there is no leafname, it returns
+ *  "(Regular)".
+ *
+ * Parameters
+ *  char *fontname == the font name
+ *
+ * Returns
+ *  A pointer to the leafname (to an internal static object)
+ */
+
+static char *fontMenu__fontLeaf(char *fontname)
+{
+  char *fontLeaf=buffer_find();
+  int index=0;
+  int outi=0;
+  char c=fontname[index];
+  BOOL stopHere=FALSE;
+  while (!stopHere)
+  {
+    index++;
+    if (c<32)
+      return (msgs_lookup("fontmRF:(Regular)"));
+    else if (c=='.')
+      stopHere=TRUE;
+    c=fontname[index];
+  }
+  while (c>31)
+    c=fontLeaf[outi++]=fontname[index++];
+  fontLeaf[outi-1]='\0';
+  return (fontLeaf);
+}
+
+/*
+ * void fontMenu__handleSubmenu(char *buffer,int *count,menu sub)
+ *
+ * Use
+ *  Creates one of those submenus for the font menu.
+ *
+ * Parameters
+ *  char *buffer == a buffer to store font names
+ *  int *count == pointer to the current font count
+ *  menu sub == the submenu handle
+ */
+
+static void fontMenu__handleSubmenu(char *buffer,int *count,menu sub)
+{
+  char newbuff[50];
+  char gadbuff[50];
+  strcpy(newbuff,buffer);
+  wimpt_noerr(font_list(buffer,count));
+  while
+  (
+    strcpy(gadbuff,fontMenu__fontFamily(buffer)),
+    *count!=-1 && strcmp(gadbuff,fontMenu__fontFamily(newbuff))==0
+  )
+  {
+    menu_extend(sub,fontMenu__fontLeaf(buffer));
+    strcpy(newbuff,buffer);
+    wimpt_noerr(font_list(buffer,count));
+  }
+}
+
+/*
+ * menu fontMenu_createFontMenu(BOOL includeSystem)
+ *
+ * Use
+ *  Creates a hierarchical font menu and returns a handle.  If the menu is
+ *  out-of-date it will be recreated, if not the old handle will be
+ *  returned.  You must call this before using routines such as
+ *  fontMenu_make() (so that the system knows whether you want to use a
+ *  menu containing the system font or not).  The returned pointer will be
+ *  NULL if there are no fonts.
+ *
+ * Parameters
+ *  BOOL includeSystem == whether you want to include a 'System font' item
+ *
+ * Returns
+ *  A menu handle for the menu.
+ */
+
+menu fontMenu_createFontMenu(BOOL includeSystem)
+{
+  char *fontpath=getenv("Font$Path");
+  int fontCount=0;
+  char currentfont[50];
+  char lastTicked[50];
+  int subIndex=1;
+  menu submenu;
+  if (fontMenu__includeSystem!=includeSystem && fontMenu__created==TRUE)
+  {
+    fontMenu__created=FALSE;
+    menu_dispose(&fontMenu__menu,TRUE);
+    fontMenu__menu=0;
+  }
+  fontMenu__includeSystem=includeSystem;
+  if (fontpath)
+    fontMenu__anyFonts=TRUE;
+  else
+    fontMenu__anyFonts=FALSE;
+  if (fontMenu__created==TRUE && strcmp(fontpath,fontMenu__oldFontPath)==0)
+    return (fontMenu__menu);
+  visdelay_begin();
+  if (fontMenu__created==TRUE)
+  {
+    strcpy(lastTicked,fontMenu_fontname(fontMenu__tick1,fontMenu__tick2));
+    menu_dispose(&fontMenu__menu,TRUE);
+  }
+  if (fontMenu__anyFonts==FALSE)
+  {
+    visdelay_end();
+    if (includeSystem==FALSE)
+    {
+      werr(FALSE,msgs_lookup("fontmNF:No fonts available."));
+      fontMenu__created=FALSE;
+      return (0);
+    }
+    else
+    {
+      fontMenu__menu=menu_new
+      (
+        msgs_lookup("fontmFT:Fonts"),msgs_lookup("fontmSF:System font")
+      );
+      fontMenu__created=TRUE;
+      return (fontMenu__menu);
+    }
+  }
+  strcpy(fontMenu__oldFontPath,fontpath);
+  wimpt_noerr(font_list(currentfont,&fontCount));
+  if (includeSystem)
+  {
+    fontMenu__menu=menu_new
+    (
+      msgs_lookup("fontmFT:Fonts"),msgs_lookup("fontmSF:System font")
+    );
+    menu_extend(fontMenu__menu,fontMenu__fontFamily(currentfont));
+    subIndex++;
+  }
+  else if (fontCount==-1)
+  {
+    werr(FALSE,msgs_lookup("fontmNF:No fonts available."));
+    fontMenu__created=FALSE;
+    return (0);
+  }
+  else
+  {
+    fontMenu__menu=menu_new
+    (
+      msgs_lookup("fontmFT:Fonts"),fontMenu__fontFamily(currentfont)
+    );
+  }
+  if (!fontMenu__menu)
+  {
+    werr
+    (
+      FALSE,
+      msgs_lookup("fontmNEM:Not enough memory to create font menu.")
+    );
+    return (0);
+  }
+  while (fontCount!=-1)
+  {
+    submenu=menu_new
+    (
+      fontMenu__fontFamily(currentfont),
+      fontMenu__fontLeaf(currentfont)
+    );
+    if (submenu)
+    {
+      fontMenu__handleSubmenu(currentfont,&fontCount,submenu);
+      menuExt_submenu(fontMenu__menu,subIndex++,submenu);
+      if (fontCount!=-1)
+        menu_extend(fontMenu__menu,fontMenu__fontFamily(currentfont));
+    }
+  }
+  fontMenu__tick1=-1;
+  if (fontMenu__created)
+    fontMenu_tickGivenName(lastTicked);
+  visdelay_end();
+  fontMenu__created=TRUE;
+  return (fontMenu__menu);
+}
+
+/*
+ * menu fontMenu(BOOL includeSystem)
+ *
+ * Use
+ *  Compatibility.  Don't use this function.
+ */
+
+menu fontMenu(BOOL includeSystem)
+{
+  menu f=fontMenu_createFontMenu(includeSystem);
+  if (!f)
+    exit(0);
+  return (f);
+}
+
+/*
+ * char *fontMenu_fontname(int item1,int item2)
+ *
+ * Use
+ *  Returns the font name given by the the menu hit passed.  Example code:
+ *
+ *  switch (hit[n])
+ *  {
+ *    ...
+ *    case FONTMENU:
+ *      {
+ *        char *fontname=fontMenu_fontname(hit[n+1],hit[n+2]);
+ *        ...
+ *      }
+ *      break;
+ *    ...
+ *  }
+ *
+ *  Type promotion does the rest!  If the hits give a silly result, then a
+ *  null string (not a null pointer!) is returned.
+ *
+ *  You should check for the system font yourself (hit[n+1]==1).
+ *
+ * Parameters
+ *  int item1 == the item number in the main menu
+ *  int item2 == the item number in the submenu
+ *
+ * Returns
+ *  A pointer to a read-only string.
+ */
+
+char *fontMenu_fontname(int item1,int item2)
+{
+  int hits[3];
+  char *buffer=buffer_find();
+  char *reg;
+  if (item1==1 && item2==0 && fontMenu__includeSystem==TRUE)
+    return (msgs_lookup("fontmSF:System font"));
+  if (item1==-1)
+    return ("");
+  hits[0]=item1-1;
+  if (item2==0)
+    hits[1]=0;
+  else
+    hits[1]=item2-1;
+  hits[2]=-1;
+  wimpt_noerr(wimp_decode_menu
+  (
+    (wimp_menustr *)menu_syshandle(fontMenu__menu),
+    hits,
+    buffer
+  ));
+  utils_ctermToNterm(buffer);
+  reg=strstr(buffer,msgs_lookup("fontmRF:(Regular)"));
+  if (reg)
+    *(reg-1)='\0';
+  return (buffer);
+}
+
+/*
+ * void fontMenu_submenu(BOOL includeSystem)
+ *
+ * Use
+ *  Opens a font menu as the submenu of another menu.
+ *
+ * Parameters
+ *  BOOL includeSystem == whether we need to include a system font item.
+ */
+
+void fontMenu_submenu(BOOL includeSystem)
+{
+  wimp_eventstr *e=wimpt_last_event();
+  int x=e->data.msg.data.words[1];
+  int y=e->data.msg.data.words[2];
+  if
+  (
+    (e->e!=wimp_ESEND &&
+    e->e!=wimp_ESENDWANTACK) ||
+    e->data.msg.hdr.action!=wimp_MMENUWARN
+  )
+    return;
+  if (win_anyWindows()==FALSE)
+  {
+    werr
+    (
+      FALSE,
+      msgs_lookup("fontmTMWS:Too many windows - "
+                                         "%s could not create submenu."),
+      wimpt_programname()
+    );
+  }
+  else
+  {
+    visdelay_begin();
+    fontMenu(includeSystem);
+    wimpt_noerr(wimp_create_submenu
+    (
+      (wimp_menustr *)menu_syshandle(fontMenu__menu),
+      x,
+      y
+    ));
+    visdelay_end();
+  }
+}
+
+/*
+ * wimp_menuitem *fontMenu__menuItem(wimp_menustr *m,int item)
+ *
+ * Use
+ *  Returns a pointer to the menu item given.
+ *
+ * Parameters
+ *  wimp_menustr *m == the menu handle
+ *  int item == the item number (starting at one)
+ *
+ * Returns
+ *  A pointer to the correct menu item structure.
+ */
+
+static wimp_menuitem *fontMenu__menuItem(wimp_menustr *m,int item)
+{
+  return ((wimp_menuitem *)(m+1)+item-1);
+}
+
+/*
+ * char *fontMenu__menuText(wimp_menustr *m,int item,char *buffer)
+ *
+ * Use
+ *  Returns the text of a menu item.
+ *
+ * Parameters
+ *  wimp_menustr *m == the menu handle
+ *  int item == the item number (1 upwards)
+ *  char *buffer == buffer in which to put the string
+ *
+ * Returns
+ *  A pointer to the menu item's text (may or may not be in buffer)
+ */
+
+static char *fontMenu__menuText(wimp_menustr *m,int item,char *buffer)
+{
+  int i;
+  char c;
+  wimp_menuitem *itm=fontMenu__menuItem(m,item);
+  if (itm->iconflags & wimp_INDIRECT)
+  {
+    c=itm->data.indirecttext.buffer[0];
+    for (i=0;i<254 && c>31;i++)
+      c=buffer[i]=itm->data.indirecttext.buffer[i];
+    buffer[i]='\0';
+  }
+  else
+  {
+    c=itm->data.text[0];
+    for (i=0;i<=11 && c>31;i++)
+      c=buffer[i]=itm->data.text[i];
+    buffer[i]='\0';
+  }
+  return (buffer);
+}
+
+/*
+ * wimp_menustr *fontMenu__submenu(wimp_menustr *m,int item)
+ *
+ * Use
+ *  Returns the handle of the submenu of a menu item.
+ *
+ * Parameters
+ *  wimp_menustr *m == the menu handle
+ *  int item == the item number
+ *
+ * Returns
+ *  A pointer to the submenu
+ */
+
+static wimp_menustr *fontMenu__submenu(wimp_menustr *m,int item)
+{
+  return (fontMenu__menuItem(m,item)->submenu);
+}
+
+/*
+ * void fontMenu_findFont(char *name,int *item1,int *item2)
+ *
+ * Use
+ *  Finds a font in the font list.  Returns the result in two integers,
+ *  which are the menu item numbers in the main font menu and the submenu
+ *  respectively.  -1 is returned as the first item number if the font
+ *  wasn't found.
+ *
+ * Parameters
+ *  char *name == the (case sensitive) name of the font.
+ *  int *item1 == where to store the first item number.
+ *  int *item2 == where to store the second item number.
+ */
+
+void fontMenu_findFont(char *name,int *item1,int *item2)
+{
+  int i=1;
+  int j;
+  wimp_menustr *m=menu_syshandle(fontMenu__menu);
+  wimp_menustr *s;
+  char *family=fontMenu__fontFamily(name);
+  char *leaf=fontMenu__fontLeaf(name);
+  char buffer[40];
+  if
+  (
+    strcmp(name,msgs_lookup("fontmSF:System font"))==0 &&
+    fontMenu__includeSystem==TRUE
+  )
+  {
+    *item1=1;
+    *item2=-1;
+    return;
+  }
+  do
+  {
+    if (strcmp(fontMenu__menuText(m,i,buffer),family)==0)
+    {
+      s=fontMenu__submenu(m,i);
+      j=1;
+      do
+      {
+        if (strcmp(fontMenu__menuText(s,j,buffer),leaf)==0)
+        {
+          *item1=i;
+          *item2=j;
+          return;
+        }
+        j++;
+      }
+      while ((fontMenu__menuItem(s,j-1)->flags&wimp_MLAST)==0);
+      *item1=-1;
+      return;
+    }
+    i++;
+  }
+  while ((fontMenu__menuItem(m,i-1)->flags&wimp_MLAST)==0);
+  *item1=-1;
+  return;
+}
+
+/*
+ * void fontMenu__tickItem(wimp_menustr *m,item i,BOOL onOrOff)
+ *
+ * Use
+ *  Ticks a menu item (low-level)
+ *
+ * Parameters
+ *  wimp_menustr *m == the menu handle
+ *  item i == the menu item
+ *  BOOL onOrOff == tick is on or off
+ */
+
+static void fontMenu__tickItem(wimp_menustr *m,int i,BOOL onOrOff)
+{
+  if (onOrOff)
+    fontMenu__menuItem(m,i)->flags|=wimp_MTICK;
+  else
+    fontMenu__menuItem(m,i)->flags&=~wimp_MTICK;
+}
+
+/*
+ * void fontMenu__doTick(BOOL onOrOff)
+ *
+ * Use
+ *  Ticks on or off the current font.
+ *
+ * Parameters
+ *  BOOL onOrOff == whether we want to tick or untick the font.
+ */
+
+static void fontMenu__doTick(BOOL onOrOff)
+{
+  wimp_menustr *m=menu_syshandle(fontMenu__menu);
+  if (fontMenu__tick1==1 && fontMenu__tick2==-1)
+  {
+    fontMenu__tickItem(m,1,onOrOff);
+  }
+  else if (fontMenu__tick1!=-1)
+  {
+    fontMenu__tickItem(m,fontMenu__tick1,onOrOff);
+    fontMenu__tickItem
+    (
+      fontMenu__submenu(m,fontMenu__tick1),
+      fontMenu__tick2,
+      onOrOff
+    );
+  }
+}
+
+/*
+ * void fontMenu_tick(int item1,int item2)
+ *
+ * Use
+ *  Ticks the item specified.  Only one font may be ticked at a time.  If
+ *  the menu item specified is silly, no item will be ticked.  No range
+ *  checking is performed.
+ *
+ * Parameters
+ *  int item1 == the item number in the main menu
+ *  int item2 == the item number in the submenu
+ */
+
+void fontMenu_tick(int item1,int item2)
+{
+  fontMenu__doTick(FALSE);
+  fontMenu__tick1=item1;
+  fontMenu__tick2=item2;
+  fontMenu__doTick(TRUE);
+}
+
+/*
+ * void fontMenu_tickGivenName(char *name)
+ *
+ * Use
+ *  Ticks the item specified by it's name.  If the name is silly, no item
+ *  will be ticked.
+ *
+ * Parameters
+ *  char *name == the font name to tick
+ */
+
+void fontMenu_tickGivenName(char *name)
+{
+  int i1,i2;
+  fontMenu_findFont(name,&i1,&i2);
+  fontMenu_tick(i1,i2);
+}
diff --git a/StraySrc/Libraries/Steel/c/help b/StraySrc/Libraries/Steel/c/help
new file mode 100644 (file)
index 0000000..2f99aa2
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+ * Help
+ *  Provides support for the !Help application
+ *
+ * v. 1.00 (25 July 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wimp.h"
+#include "wimpt.h"
+#include "help.h"
+#include "msgs.h"
+#include "werr.h"
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+static wimp_msgstr help__msg;
+static wimp_t help__hisHandle;
+static wimp_w help__window;
+static wimp_i help__icon;
+
+static char *help__transString=
+   "-0123456789"
+   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+   "abcdefghijklmnopqrstuvwxyz";
+
+#define help__TRANSLEN 62
+
+/*
+ * void help_startHelp(void)
+ *
+ * Use
+ *  This call sets up a new message to bundle off to !Help.
+ */
+
+void help_startHelp(void)
+{
+  wimp_eventstr *e=wimpt_last_event();
+  help__msg.hdr.size=256;
+  help__msg.hdr.your_ref=e->data.msg.hdr.my_ref;
+  help__msg.hdr.action=wimp_MHELPREPLY;
+  help__msg.data.helpreply.text[0]='\0';
+  help__hisHandle=e->data.msg.hdr.task;
+  help__window=e->data.msg.data.helprequest.m.w;
+  help__icon=e->data.msg.data.helprequest.m.i;
+}
+
+/*
+ * void help_addLine(char *line,...)
+ *
+ * Use
+ *  This call adds a line of text to the current help message.  If the
+ *  message starts off blank, then the line will become the current message,
+ *  otherwise the message will have a '|m' followed by the new line appended
+ *  on the end.
+ *
+ * Parameters
+ *  char *line == a printf()-style format string.
+ */
+
+void help_addLine(char *line,...)
+{
+  va_list ap;
+  char buffer[255];
+  va_start(ap,line);
+  vsprintf(buffer,line,ap);
+  va_end(ap);
+  if (help__msg.data.helpreply.text[0]=='\0')
+    strcpy(help__msg.data.helpreply.text,buffer);
+  else
+  {
+    strcat(help__msg.data.helpreply.text,"|m");
+    strcat(help__msg.data.helpreply.text,buffer);
+  }
+}
+
+/*
+ * void help_endHelp(void)
+ *
+ * Use
+ *  This call bundles off the current help message to the application.
+ */
+
+void help_endHelp(void)
+{
+  help__msg.hdr.size=((sizeof(wimp_msghdr)+strlen(help__msg.data.helpreply.text)+1)&(~3))+4;
+  wimpt_noerr(wimp_sendmessage(wimp_ESEND,&help__msg,help__hisHandle));
+}
+
+/*
+ * void help_readFromIcon(void)
+ *
+ * Use
+ *  This call will read a help message from the icon the help system is
+ *  interested in, and tack it on the end of the message.  The help message
+ *  should be stored in the icon's validation string with the command 'H'
+ *  (e.g. validation string == "A0-9;B3;HType a number in this icon."
+ *  Alternatively, you can use a message-file tag, which will be looked up.
+ */
+
+void help_readFromIcon(void)
+{
+  wimp_icon icn;
+  char *vs;
+  int i;
+  char msg[255];
+  BOOL foundMsg=FALSE;
+  BOOL doneMsg=FALSE;
+  int msgIndex=0;
+  char *mfl;
+  if (help__icon<0)
+    return;
+  wimpt_noerr(wimp_get_icon_info(help__window,help__icon,&icn));
+  if 
+  (
+    (icn.flags&wimp_INDIRECT)==0 ||
+    (icn.flags&(wimp_ITEXT|wimp_ISPRITE))==wimp_ISPRITE ||
+    ((wimpt_options() & wimpt_ONOWIMPSHADE) &&
+     (icn.flags & 0x001f0000)==0x001f0000) ||
+    icn.data.indirecttext.validstring==(char *)-1 
+  )
+    return;
+  vs=icn.data.indirecttext.validstring;
+  if (vs[0]=='H' || vs[0]=='h')
+  {
+    foundMsg=TRUE;
+    vs++;
+  }
+  for (i=0;vs[i]>31;i++)
+  {
+    switch (vs[i])
+    {
+      case '\\':
+        if (vs[i+1]>31)
+        {
+          i++;
+          if (foundMsg)
+            msg[msgIndex++]=vs[i];
+        }
+        break;
+      case ';':
+        if (foundMsg)
+        {
+          foundMsg=FALSE;
+          doneMsg=TRUE;
+        }
+        if (vs[i+1]>31)
+        {
+          i++;
+          switch (vs[i])
+          {
+            case 'H':
+            case 'h':
+              if (!doneMsg)
+                foundMsg=TRUE;
+              break;
+          }
+        }
+        break;
+      default:
+        if (foundMsg)
+          msg[msgIndex++]=vs[i];
+        break;
+    }
+  }
+  msg[msgIndex]='\0';
+  if (msg[0])
+  {
+    mfl=msgs_lookup(msg);
+    if (mfl)
+      help_addLine("%s",mfl);
+    else
+      help_addLine("%s",msg);
+  }
+}
+
+/*
+ * BOOL help_wasHelp(void)
+ *
+ * Use
+ *  Informs caller if the last event was a help request.
+ *
+ * Returns
+ *  TRUE if it was.
+ */
+
+BOOL help_wasHelp(void)
+{
+  wimp_eventstr *e=wimpt_last_event();
+  if
+  (
+    (e->e==wimp_ESEND ||
+    e->e==wimp_ESENDWANTACK) && 
+    e->data.msg.hdr.action==wimp_MHELPREQUEST
+  )
+    return (TRUE);
+  else
+    return (FALSE);
+}
+
+/*
+ * void help_readFromMenu(char *prefix,int hit[])
+ *
+ * Use
+ *  Converts the menu hit structure into a message tag and then reads the
+ *  message and adds it to the help message being constructed.
+ *  The message tag is constructed from the prefix, followed by a character
+ *  for each entry in the hit structure.  The characters are in order (first
+ *  to last) 0-9,A-Z,a-z, giving 62 entries.  This WILL be enough for any
+ *  *reasonable* menu...
+ *
+ * Parameters
+ *  char *prefix == 
+ *  int hit[] == a menu hit structure as passed to a menu handler.
+ */
+
+void help_readFromMenu(char *prefix,int hit[])
+{
+  char tag[20];
+  int i=0;
+  char *p;
+  strcpy(tag,prefix);
+  p=tag+strlen(tag);
+  while (hit[i])
+  {
+    if (hit[i]>=help__TRANSLEN)
+      werr(TRUE,msgs_lookup("(help_readFromMenu, caller fault): menu event array out of range."));
+    *(p++)=help__transString[hit[i++]];
+  }
+  *p=0;
+  help_addLine("%s",msgs_lookup(tag));
+}
diff --git a/StraySrc/Libraries/Steel/c/ibicon b/StraySrc/Libraries/Steel/c/ibicon
new file mode 100644 (file)
index 0000000..de1e383
--- /dev/null
@@ -0,0 +1,690 @@
+/*
+ * ibicon
+ *
+ * proper icon bar mangement (multiple icons, etc.)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wimp.h"
+#include "wimpt.h"
+#include "os.h"
+#include "swis.h"
+#include "bbc.h"
+#include "win.h"
+#include "werr.h"
+#include "ibicon.h"
+#include "msgs.h"
+#include "event.h"
+#include "mem.h"
+#include "swiv.h"
+#include <string.h>
+#include <stdio.h>
+
+#include "dll.h"
+
+#ifndef _dll_NODLL
+  extern void _dllEntry(ibicon__events)(wimp_eventstr *e,void *handle);
+  extern menu _dllEntry(ibicon__menumaker)(void *handle);
+  extern void _dllEntry(ibicon__menuhandler)(int hits[],void *handle);
+  extern void _dllEntry(ibicon__menuhelphandler)(int hits[],void *handle);
+#endif
+
+typedef struct ibicon__ibiconstr
+{
+  struct ibicon__ibiconstr *next;
+  struct ibicon__ibiconstr *prev;
+  wimp_i icon;
+  char *data;
+  char *valid;
+  menu mnu;
+  event_menu_maker maker;
+  menu_selectProc menusel;
+  menu_helpProc menuhelp;
+  void *menuHandle;
+  ibicon_handler handler;
+  void *handle;
+  ibicon_rawHandler raw;
+  void *rawHandle;
+}
+ibicon__ibiconstr;
+
+static ibicon ibicon__anchor;
+static BOOL ibicon__eventHandler;        /* Do we have an event handler?   */
+static ibicon ibicon__menuicon;          /* The last icon to open a menu   */
+static int ibicon__priority;             /* Icon priorities (RISC OS 3)    */
+
+/*
+ * os_error *ibicon__spriteOp
+ * (
+ *   int op,
+ *   sprite_area *a,
+ *   char *name,
+ *   _kernel_swi_regs *r
+ * )
+ *
+ * Use
+ *  Does an OS_SpriteOp call.  It's designed for calls that return more than
+ *  they receive.
+ *
+ * Parameters
+ *  int op == the operation number to perform
+ *  sprite_area *a == the sprite area to do the op on.  May be 1 for the
+ *    WIMP area or 0 for the system area
+ *  char *name == the name of the sprite
+ *  os_regset *r == a regiser set to return inforation in
+ *
+ * Returns
+ *  An error block if anything went wrong
+ */
+
+static os_error *ibicon__spriteOp
+(
+  int op,
+  sprite_area *a,
+  char *name,
+  os_regset *r
+)
+{
+  int swinum;
+  if ((int)a==1)
+    swinum=XWimp_SpriteOp;
+  else
+  {
+    swinum=XOS_SpriteOp;
+    if (a!=0)
+      op+=256;
+  }
+  r->r[0]=op;
+  r->r[1]=(int)a;
+  r->r[2]=(int)name;
+  return (os_swix(swinum,r));
+}
+
+/*
+ * void ibicon__spriteSize(char *name,sprite_area *a,wimp_box *b,BOOL centre)
+ *
+ * Use
+ *  Returns the size of the sprite specified.  If requested, it also
+ *  centres the result given within a 68 OS unit vertical area.
+ *
+ * Parameters
+ *  char *name == the name of the sprite of which to return the size
+ *  sprite_area *a == the sprite area (same conventions as above)
+ *  wimp_box *b == a box structure to fill in
+ *  BOOL centre == whether to centre the icon vertically
+ */
+
+static void ibicon__spriteSize
+(
+  char *name,
+  sprite_area *a,
+  wimp_box *b,
+  BOOL centre
+)
+{
+  os_regset r;
+  int height;
+  b->x0=0;
+  wimpt_noerr(ibicon__spriteOp(40,a,name,&r));
+  b->x1=r.r[3]<<bbc_modevar(r.r[6],bbc_XEigFactor);
+  height=r.r[4]<<bbc_modevar(r.r[6],bbc_YEigFactor);
+  if (centre)
+  {
+    b->y0=(68-height)>>1;
+    b->y1=68-b->y0;
+  }
+  else
+  {
+    b->y0=0;
+    b->y1=height;
+  }
+}
+
+/*
+ * ibicon ibicon_find(wimp_i icon)
+ *
+ * Use
+ *  Return the ibicon handle of an icon.
+ *
+ * Parameters
+ *  wimp_i icon == the icon to find
+ */
+
+ibicon ibicon_find(wimp_i icon)
+{
+  ibicon i;
+  for (i=ibicon__anchor;i;i=i->next)
+  {
+    if (i->icon==icon)
+      return (i);
+    if (i->icon>icon)
+      return (0);
+  }
+  return (0);
+}
+
+/*
+ * wimp_i ibicon_syshandle(ibicon i)
+ *
+ * Use
+ *  Returns the low-level WIMP handle for the icon concerned.
+ *
+ * Parameters
+ *  ibicon i == the icon whose handle is desired
+ *
+ * Returns
+ *  The WIMP icon handle for the icon
+ */
+
+wimp_i ibicon_syshandle(ibicon i)
+{
+  return (i->icon);
+}
+
+/*
+ * void ibicon__menuhandler(int hit[],void *handle)
+ *
+ * Use
+ *  Handles clicks on icon bar menus.  It acts an event_menu_proc and passes
+ *  the information on the relevant icon.
+ *
+ * Parameters
+ *  int hit[] == the hit string to be processed.
+ *  void *handle == not worth the effort of worrying about
+ */
+
+_dll_static void ibicon__menuhandler(int hit[],void *handle)
+{
+  handle=handle;
+  if (ibicon__menuicon)
+  {
+    if (ibicon__menuicon->menusel)
+      (ibicon__menuicon->menusel)(hit,ibicon__menuicon->menuHandle);
+  }
+}
+
+/*
+ * void ibicon__menuhelphandler(int hit[],void *handle)
+ *
+ * Use
+ *  Handles help request for icon bar menus.  It acts a menu_helpProc or
+ *  whatever and passes the information on the relevant icon.
+ *
+ * Parameters
+ *  int hit[] == the hit string to be processed.
+ *  void *handle == not worth the effort of worrying about
+ */
+
+_dll_static void ibicon__menuhelphandler(int hit[],void *handle)
+{
+  handle=handle;
+  if (ibicon__menuicon)
+  {
+    if (ibicon__menuicon->menuhelp)
+      (ibicon__menuicon->menuhelp)(hit,ibicon__menuicon->menuHandle);
+  }
+}
+
+/*
+ * menu ibicon__menumaker(void *handle)
+ *
+ * Use
+ *  Handles menus and things for the icon bar.  Acts as an event_menu_maker
+ *  and passes the request on to the icon concerned.
+ *
+ * Parameters
+ *  void *handle == nothing worth worrying about
+ *
+ * Returns
+ *  The menu to display
+ */
+
+_dll_static menu ibicon__menumaker(void *handle)
+{
+  wimp_eventstr *e=wimpt_last_event();
+  handle=handle;
+  if (e->e==wimp_EBUT)
+    ibicon__menuicon=ibicon_find(e->data.but.m.i);
+  if (ibicon__menuicon)
+  {
+    if (ibicon__menuicon->mnu)
+      return (ibicon__menuicon->mnu);
+    else if (ibicon__menuicon->maker)
+      return ((ibicon__menuicon->maker)(ibicon__menuicon->menuHandle));
+  }
+  return (0);  /* menu is dead - icon disappeared */
+}
+
+/*
+ * void ibicon__events(wimp_eventstr *e,void *handle)
+ *
+ * Purpose
+ *  Event handler installed for both win_ICONBAR and win_ICONBARLOAD.
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event
+ *  void *handle == nothing interesting
+ */
+
+_dll_static void ibicon__events(wimp_eventstr *e,void *handle)
+{
+  wimp_i icn=-1;
+  ibicon i;
+  ibicon_eventType type=ibicon_NOTHING;
+  handle=handle;
+  switch (e->e)
+  {
+    case wimp_EBUT:
+      icn=e->data.but.m.i;
+      switch (e->data.but.m.bbits)
+      {
+        case wimp_BLEFT:
+          type=ibicon_LEFTCLICK;
+          break;
+        case wimp_BRIGHT:
+          type=ibicon_RIGHTCLICK;
+          break;
+      }
+      break;
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MDATASAVE:
+          type=ibicon_SAVE;
+          icn=e->data.msg.data.datasave.i;
+          break;
+        case wimp_MDATALOAD:
+          type=ibicon_LOAD;
+          icn=e->data.msg.data.dataload.i;
+          break;
+        case wimp_MHELPREQUEST:
+          type=ibicon_HELP;
+          icn=e->data.msg.data.helprequest.m.i;
+          break;
+      }
+  }
+  if (i=ibicon_find(icn),!i)
+    return;
+  if (i->raw)
+  {
+    if ((i->raw)(i,e,i->rawHandle))
+      type=ibicon_NOTHING;
+  }
+  if (type!=ibicon_NOTHING)
+  {
+    if (i->handler)
+      (i->handler)(i,type,i->handle);
+  }
+}
+
+/*
+ * void ibicon_setPriority(int priority)
+ *
+ * Use
+ *  Sets the priority with which to create icons under RISC OS 3.
+ *
+ * Parameters
+ *  int priority == the new setting
+ */
+
+void ibicon_setPriority(int priority)
+{
+  ibicon__priority=priority;
+}
+
+/*
+ * ibicon ibicon_create
+ * (
+ *   int where,
+ *   char *spritename,
+ *   sprite_area *sprarea,
+ *   char *text,
+ *   int maxtext
+ * )
+ *
+ * Use
+ *  Creates an icon in the icon bar.  Where is up to you.  Specify a
+ *  sprite-only icon by passing 0 for text.  Use the macros to define where
+ *  and what area you want the sprite from.
+ *
+ * Parameters
+ *  int where == what part of the icon bar you want to put the icon in.
+ *    Macros are defined for the RISC OS 2 possibilities.  Wait for the
+ *    RISC OS 3 macros, or just pass a window handle.
+ *  char *spritename == the name of the sprite to display
+ *  sprite_area *sprarea == the area from which the sprite area comes.  Use
+ *    the macros provided for odd things like the WIMP area.  If you have
+ *    text as well, then this will be ignored anyway.
+ *  char *text == the text for the icon.  May be a NULL pointer, for no
+ *    text.
+ *  int maxtext == the max length the text entry can be.  If 0 then the
+ *    length of the text given will be used.
+ *
+ * Returns
+ *  A handle to the icon if successful, or 0 if not.
+ */
+
+ibicon ibicon_create
+(
+  int where,
+  char *spritename,
+  sprite_area *sprarea,
+  char *text,
+  int maxtext
+)
+{
+  wimp_icreate i;
+  ibicon new=mem_alloc(sizeof(ibicon__ibiconstr));
+  ibicon c;
+  if (!new)
+  {
+    werr(FALSE,msgs_lookup("ibicnNEM:Not enough memory for icon."));
+    return (0);
+  }
+  if (!ibicon__eventHandler)
+  {
+    win_register_event_handler(win_ICONBAR,_dllEntry(ibicon__events),0);
+    win_register_event_handler(win_ICONBARLOAD,_dllEntry(ibicon__events),0);
+    menu_attachMaker
+    (
+      win_ICONBAR,
+      _dllEntry(ibicon__menumaker),
+      _dllEntry(ibicon__menuhandler),
+      _dllEntry(ibicon__menuhelphandler),
+      0
+    );
+    ibicon__eventHandler=TRUE;
+  }
+  if (text)
+  {
+    if (!maxtext)
+      maxtext=strlen(text);
+    if (new->data=mem_alloc(maxtext+1),!new->data)
+    {
+      mem_free(new);
+      werr(FALSE,msgs_lookup("ibicnNEM:Not enough memory for icon."));
+      return (0);
+    }
+    if (new->valid=mem_alloc(15),!new->valid)
+    {
+      mem_free(new);
+      mem_free(new->data);
+      werr(FALSE,msgs_lookup("ibicnNEM:Not enough memory for icon."));
+      return (0);
+    }
+    strcpy(new->data,text);
+    sprintf(new->valid,"S%s",spritename);
+    i.i.data.indirecttext.buffer=new->data;
+    i.i.data.indirecttext.validstring=new->valid;
+    i.i.data.indirecttext.bufflen=maxtext+1;
+    ibicon__spriteSize(spritename,sprarea,&i.i.box,FALSE);
+    i.i.box.y0-=16;
+    i.i.box.y1+=20;
+    if (i.i.box.x1<16*maxtext)
+      i.i.box.x1=16*maxtext;
+  }
+  else
+  {
+    if (new->data=mem_alloc(15),!new->data)
+    {
+      mem_free(new);
+      werr(FALSE,msgs_lookup("ibicnNEM:Not enough memory for icon."));
+      return (0);
+    }
+    strcpy(new->data,spritename);
+    new->valid=0;
+    i.i.data.indirectsprite.name=new->data;
+    i.i.data.indirectsprite.spritearea=(void *)sprarea;
+    i.i.data.indirectsprite.nameisname=TRUE;
+    ibicon__spriteSize(spritename,sprarea,&i.i.box,TRUE);
+  }
+  switch (where)
+  {
+    case ibicon_LEFTSEARCHLEFT:
+    case ibicon_LEFTSEARCHRIGHT:
+      if (wimpt_getVersion()<300)
+        where=ibicon_LEFT;
+      break;
+    case ibicon_RIGHTSEARCHLEFT:
+    case ibicon_RIGHTSEARCHRIGHT:
+      if (wimpt_getVersion()<300)
+        where=ibicon_RIGHT;
+      break;
+  }
+  i.w=where;
+  i.i.flags=
+  (
+    wimp_ISPRITE |
+    (text ? wimp_ITEXT : 0) |
+    wimp_IHCENTRE |
+    (text ? 0 : wimp_IVCENTRE) |
+    wimp_INDIRECT |
+    wimp_IBTYPE * wimp_BCLICKDEBOUNCE |
+    wimp_IFORECOL * 7 |
+    wimp_IBACKCOL * 1
+  );
+  wimpt_noerr(_swix(XWimp_CreateIcon,_inr(0,1)+_out(0),
+                    ibicon__priority,(int)&i,
+                    &new->icon));
+  win_activeinc();
+  for (c=(ibicon)&ibicon__anchor;c->next;c=c->next)
+  {
+    if (c->next->icon>new->icon)
+      break;
+  }
+  new->next=c->next;
+  if (ibicon__anchor)
+    new->prev=c;
+  else
+    new->prev=0;
+  if (c->next)
+    c->next->prev=new;
+  c->next=new;
+  new->mnu=0;
+  new->maker=0;
+  new->menusel=0;
+  new->menuhelp=0;
+  new->menuHandle=0;
+  new->handler=0;
+  new->handle=0;
+  new->raw=0;
+  new->rawHandle=0;
+  win_activeinc();
+  return (new);
+}
+
+/*
+ * void ibicon_changeSprite(ibicon i,char *newsprite)
+ *
+ * Use
+ *  Chnage the sprite displayed in an icon
+ *
+ * Parameters
+ *  ibicon i == the icon to change
+ *  char *newsprite == the new name
+ */
+
+void ibicon_changeSprite(ibicon i,char *newsprite)
+{
+  if (i->valid)
+    sprintf(i->valid,"S%s",newsprite);
+  else
+    strcpy(i->data,newsprite);
+  wimpt_noerr(wimp_set_icon_state(-2,i->icon,0,0));
+}
+
+/*
+ * void ibicon_changeText(ibicon i,char *newtext)
+ *
+ * Use
+ *  Change the text of an icon.
+ *
+ * Parameters
+ *  ibicon i == the icon to change
+ *  char *text == the new text to display
+ */
+
+void ibicon_changeText(ibicon i,char *newtext)
+{
+  if (i->valid)
+    strcpy(i->data,newtext);
+  else
+    werr(TRUE,msgs_lookup("ibicnCCT:(ibicon_changeText, caller fault): "
+                         "Attempt to write text to sprite-only ibicon."));
+  wimpt_noerr(wimp_set_icon_state(-2,i->icon,0,0));
+}
+
+/*
+ * void ibicon_attachMenu
+ * (
+ *   ibicon i,
+ *   menu m,
+ *   menu_selectProc sel,
+ *   menu_helpProc help,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Attaches a menu to an icon in the icon bar
+ *
+ * Parameters
+ *  ibicon i == the icon to attach to
+ *  menu m == the menu to attach
+ *  menu_selectProc sel == a handler function for the menu
+ *  menu_helpProc help == a help processor for the menu
+ *  void *handle == a handle passed to the handler
+ */
+
+void ibicon_attachMenu
+(
+  ibicon i,
+  menu m,
+  menu_selectProc sel,
+  menu_helpProc help,
+  void *handle
+)
+{
+  i->mnu=m;
+  i->maker=0;
+  i->menusel=sel;
+  i->menuhelp=help;
+  i->menuHandle=handle;
+}
+
+/*
+ * void ibicon_attachMenuMaker
+ * (
+ *   ibicon i,
+ *   event_menu_maker m,
+ *   menu_selectProc sel,
+ *   menu_helpProc help,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Attaches a menu maker to an icon in the icon bar
+ *
+ * Parameters
+ *  ibicon i == the icon to attach to
+ *  event_menu_maker m == the menu maker to attach
+ *  menu_selectProc sel == a handler function for the menu
+ *  menu_helpProc help == a help processor for the menu
+ *  void *handle == a handle passed to the handler
+ */
+
+void ibicon_attachMenuMaker
+(
+  ibicon i,
+  event_menu_maker m,
+  menu_selectProc sel,
+  menu_helpProc help,
+  void *handle
+)
+{
+  i->mnu=0;
+  i->maker=m;
+  i->menusel=sel;
+  i->menuhelp=help;
+  i->menuHandle=handle;
+}
+
+/*
+ * void ibicon_removeIcon(ibicon i)
+ *
+ * Use
+ *  Removes an icon totally from the icon bar.
+ *
+ * Parameters
+ *  ibicon i == the icon to vape
+ */
+
+void ibicon_removeIcon(ibicon i)
+{
+  wimpt_noerr(wimp_delete_icon(-2,i->icon));
+  if (i->prev)
+    i->prev->next=i->next;
+  else
+    ibicon__anchor=i->next;
+  if (i->next)
+    i->next->prev=i->prev;
+  mem_free(i);
+  win_activedec();
+}
+
+/*
+ * void ibicon_eventHandler(ibicon i,ibicon_handler p,void *handle)
+ *
+ * Use
+ *  Attaches the handler to an icon.
+ *
+ * Parameters
+ *  ibicon i == the icon to attach
+ *  ibicon_handler p == the handler
+ *  void *handle == a pointer to pass to the handler
+ */
+
+void ibicon_eventHandler(ibicon i,ibicon_handler p,void *handle)
+{
+  i->handler=p;
+  i->handle=handle;
+}
+
+/*
+ * void ibicon_rawEventHandler(ibicon i,ibicon_rawHandler p,void *handle)
+ *
+ * Use
+ *  Attaches a raw event handler.  This can 'vet' events before ibicon gets
+ *  it mucky mits on them.
+ *
+ * Parameters
+ *  ibicon i == the icon to attach
+ *  ibicon_rawHandler p == the handler
+ *  void *handle == a pointer to pass to the handler
+ */
+
+void ibicon_rawEventHandler(ibicon i,ibicon_rawHandler p,void *handle)
+{
+  i->raw=p;
+  i->rawHandle=handle;
+}
diff --git a/StraySrc/Libraries/Steel/c/interface b/StraySrc/Libraries/Steel/c/interface
new file mode 100644 (file)
index 0000000..ce1759c
--- /dev/null
@@ -0,0 +1,102 @@
+/************************************
+
+ interface segment of Wimp routines
+
+   Controls low-level access to
+   Interface module.
+
+   Version 1.00 (29 June 1993)
+   © 1993-1998 Straylight
+
+************************************/
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+
+#include "swiv.h"
+#include "os.h"
+#include "wimp.h"
+#include "swis.h"
+#include "pointer.h"
+#include "interface.h"
+#include "visdelay.h"
+
+static sprite_area *interface__area;
+
+void interface_spritearea(sprite_area *a)
+{
+  interface__area=a;
+}
+
+os_error *interface_slabButton(wimp_mousestr *mouse)
+{
+  os_error *e;
+  visdelay_state s;
+  s=visdelay_suspend();
+  e=_swix(XInterface_SlabButton,_in(1),mouse);
+  visdelay_resume(s);
+  return (e);
+}
+
+os_error *interface_render3dWindow(wimp_redrawstr *rdr)
+{
+  os_error *e;
+  e=_swix(XInterface_Render3dWindow,_in(1),rdr);
+  return (e);
+}
+
+os_error *interface_initialise(wimp_t task)
+{
+  os_error *e;
+  e=_swix(XInterface_Initialise,_in(0),task);
+  return (e);
+}
+
+os_error *interface_closeDown(wimp_t task)
+{
+  os_error *e;
+  e=_swix(XInterface_CloseDown,_in(0),task);
+  return (e);
+}
+
+os_error *interface_poll(wimp_eventstr *evnt,wimp_t task)
+{
+  int event=evnt->e;
+  os_error *e;
+  if (interface__area)
+    event|=1<<((unsigned int)31); /* New Interface flag for sprite area */
+  e=_swix(XInterface_Poll,_inr(0,2),event,interface__area,task);
+  return (e);
+}
+
+os_error *interface_setWorkareaPointer(interface_pointerstr *s)
+{
+  os_error *e;
+  e=_swix(XInterface_SetWorkareaPointer,_in(1),s);
+  return (e);
+}
+
+os_error *interface_removeWorkareaPointer(interface_pointerstr *s)
+{
+  os_error *e;
+  e=_swix(XInterface_RemoveWorkareaPointer,_in(1),s);
+  return (e);
+}
diff --git a/StraySrc/Libraries/Steel/c/keyString b/StraySrc/Libraries/Steel/c/keyString
new file mode 100644 (file)
index 0000000..d92c30b
--- /dev/null
@@ -0,0 +1,534 @@
+/*
+ * keyString
+ *  Converts keypresses to strings
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "akbd.h"
+#include "msgs.h"
+#include "keyString.h"
+#include "buffer.h"
+#include <string.h>
+#include <stdio.h>
+
+/*
+ * char *keyString(int key)
+ *
+ * Use
+ *  Converts a keypress as returned by the WIMP into a string suitable for
+ *  displaying to the user, for example as a keyboard shortcut.  The routine
+ *  handles the following cases:
+ *
+ *  * Function keys and Print, possibly with <Shift> and/or <Ctrl>
+ *  * Alphabetic keys with <Ctrl>
+ *
+ *  Note: f12 is not trapped; neither is <Ctrl> M, since this is <Return>.
+ *
+ * Parameters
+ *  int key == the key pressed
+ *
+ * Returns
+ *  A pointer to a READ-ONLY string, or 0 if the key was invalid.
+ */
+
+char *keyString(int key)
+{
+  return (keyString_convert(key,FALSE));
+}
+
+typedef struct
+{
+  int c : 8;
+  int shift : 1;
+  int ctrl : 1;
+  int keypad : 1;
+  int func : 1;
+}
+keyString__keyEntry;
+
+static keyString__keyEntry keyString__lower[]=
+{
+  /* --- 0x000 - 0x00F --- */
+
+  ' ',         0,1,0,0,
+  'A',         0,1,0,0,
+  'B',         0,1,0,0,
+  'C',         0,1,0,0,
+  'D',         0,1,0,0,
+  'E',         0,1,0,0,
+  'F',         0,1,0,0,
+  'G',         0,1,0,0,
+  'H',         0,1,0,0,
+  'I',         0,1,0,0,
+  'J',         0,1,0,0,
+  'K',         0,1,0,0,
+  'L',         0,1,0,0,
+  'M',         0,1,0,0,
+  'N',         0,1,0,0,
+  'O',         0,1,0,0,
+
+  /* --- 0x010 - 0x01F --- */
+
+  'P',         0,1,0,0,
+  'Q',         0,1,0,0,
+  'R',         0,1,0,0,
+  'S',         0,1,0,0,
+  'T',         0,1,0,0,
+  'U',         0,1,0,0,
+  'V',         0,1,0,0,
+  'W',         0,1,0,0,
+  'X',         0,1,0,0,
+  'Y',         0,1,0,0,
+  'Z',         0,1,0,0,
+  0x01B,       0,0,0,0,
+  0x01C,       0,0,0,0,
+  0x01D,       0,0,0,0,
+  0x01E,       0,0,0,0,
+  0x07F,       0,1,0,0,
+};
+
+static keyString__keyEntry keyString__upper[]=
+{
+  /* --- 0x100 - 0x10F --- */
+
+  ' ',         1,1,0,0,
+  'A',         1,1,0,0,
+  'B',         1,1,0,0,
+  'C',         1,1,0,0,
+  'D',         1,1,0,0,
+  'E',         1,1,0,0,
+  'F',         1,1,0,0,
+  'G',         1,1,0,0,
+  'H',         1,1,0,0,
+  'I',         1,1,0,0,
+  'J',         1,1,0,0,
+  'K',         1,1,0,0,
+  'L',         1,1,0,0,
+  'M',         1,1,0,0,
+  'N',         1,1,0,0,
+  'O',         1,1,0,0,
+
+  /* --- 0x110 - 0x11F --- */
+
+  'P',         1,1,0,0,
+  'Q',         1,1,0,0,
+  'R',         1,1,0,0,
+  'S',         1,1,0,0,
+  'T',         1,1,0,0,
+  'U',         1,1,0,0,
+  'V',         1,1,0,0,
+  'W',         1,1,0,0,
+  'X',         1,1,0,0,
+  'Y',         1,1,0,0,
+  'Z',         1,1,0,0,
+  0x01B,       1,0,0,0,
+  0x01C,       1,0,0,0,
+  0x01D,       1,0,0,0,
+  0x01E,       1,0,0,0,
+  0x07F,       1,1,0,0,
+
+  /* --- 0x120 - 0x12F --- */
+
+  ' ',         1,0,0,0,
+  '/',         0,1,1,0,
+  '*',         0,1,1,0,
+  '#',         0,1,1,0,
+  '-',         0,1,1,0,
+  '+',         0,1,1,0,
+  0x01D,       0,1,1,0,
+  '.',         0,1,1,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  '[',         0,1,0,0,
+  '\\',                0,1,0,0,
+  ']',         0,1,0,0,
+  0,           0,0,0,0,
+  '-',         0,1,0,0,
+
+  /* --- 0x130 - 0x13F --- */
+
+  '0',         0,1,0,0,
+  '1',         0,1,0,0,
+  '2',         0,1,0,0,
+  '3',         0,1,0,0,
+  '4',         0,1,0,0,
+  '5',         0,1,0,0,
+  '6',         0,1,0,0,
+  '7',         0,1,0,0,
+  '8',         0,1,0,0,
+  '9',         0,1,0,0,
+  0,           0,0,0,0,
+  0x01B,       0,1,0,0,
+  0x01C,       0,1,0,0,
+  0x01D,       0,1,0,0,
+  0x01E,       0,1,0,0,
+  0,           0,0,0,0,
+
+  /* --- 0x140 - 0x14F --- */
+
+  0,           0,0,0,0,
+  '/',         1,1,1,0,
+  '*',         1,1,1,0,
+  '#',         1,1,1,0,
+  '-',         1,1,1,0,
+  '+',         1,1,1,0,
+  0x01D,       1,1,1,0,
+  '.',         1,1,1,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  '[',         1,1,0,0,
+  '\\',                1,1,0,0,
+  ']',         1,1,0,0,
+  0,           0,0,0,0,
+  '-',         1,1,0,0,
+
+  /* --- 0x150 - 0x15F --- */
+
+  '0',         1,1,0,0,
+  '1',         1,1,0,0,
+  '2',         1,1,0,0,
+  '3',         1,1,0,0,
+  '4',         1,1,0,0,
+  '5',         1,1,0,0,
+  '6',         1,1,0,0,
+  '7',         1,1,0,0,
+  '8',         1,1,0,0,
+  '9',         1,1,0,0,
+  0,           0,0,0,0,
+  0x01B,       1,1,0,0,
+  0x01C,       1,1,0,0,
+  0x01D,       1,1,0,0,
+  0x01E,       1,1,0,0,
+  0,           0,0,0,0,
+
+  /* --- 0x160 - 0x16F --- */
+
+  0,           0,0,0,0,
+  '/',         0,0,1,0,
+  '*',         0,0,1,0,
+  '#',         0,0,1,0,
+  '-',         0,0,1,0,
+  '+',         0,0,1,0,
+  0x01D,       0,0,1,0,
+  '.',         0,0,1,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+
+  /* --- 0x170 - 0x17F --- */
+
+  0,           0,0,0,0,
+  '/',         1,0,1,0,
+  '*',         1,0,1,0,
+  '#',         1,0,1,0,
+  '-',         1,0,1,0,
+  '+',         1,0,1,0,
+  0x01D,       1,0,1,0,
+  '.',         1,0,1,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+  0x07F,       1,0,0,0,
+
+  /* --- 0x180 - 0x18F --- */
+
+  0,           0,0,0,1,
+  1,           0,0,0,1,
+  2,           0,0,0,1,
+  3,           0,0,0,1,
+  4,           0,0,0,1,
+  5,           0,0,0,1,
+  6,           0,0,0,1,
+  7,           0,0,0,1,
+  8,           0,0,0,1,
+  9,           0,0,0,1,
+  13,          0,0,0,1,
+  14,          0,0,0,1,
+  15,          0,0,0,1,
+  16,          0,0,0,1,
+  17,          0,0,0,1,
+  18,          0,0,0,1,
+
+  /* --- 0x190 - 0x19F --- */
+
+  0,           1,0,0,1,
+  1,           1,0,0,1,
+  2,           1,0,0,1,
+  3,           1,0,0,1,
+  4,           1,0,0,1,
+  5,           1,0,0,1,
+  6,           1,0,0,1,
+  7,           1,0,0,1,
+  8,           1,0,0,1,
+  9,           1,0,0,1,
+  13,          1,0,0,1,
+  14,          1,0,0,1,
+  15,          1,0,0,1,
+  16,          1,0,0,1,
+  17,          1,0,0,1,
+  18,          1,0,0,1,
+
+  /* --- 0x1A0 - 0x1AF --- */
+
+  0,           0,1,0,1,
+  1,           0,1,0,1,
+  2,           0,1,0,1,
+  3,           0,1,0,1,
+  4,           0,1,0,1,
+  5,           0,1,0,1,
+  6,           0,1,0,1,
+  7,           0,1,0,1,
+  8,           0,1,0,1,
+  9,           0,1,0,1,
+  13,          0,1,0,1,
+  14,          0,1,0,1,
+  15,          0,1,0,1,
+  16,          0,1,0,1,
+  17,          0,1,0,1,
+  18,          0,1,0,1,
+
+  /* --- 0x1B0 - 0x1BF --- */
+
+  0,           1,1,0,1,
+  1,           1,1,0,1,
+  2,           1,1,0,1,
+  3,           1,1,0,1,
+  4,           1,1,0,1,
+  5,           1,1,0,1,
+  6,           1,1,0,1,
+  7,           1,1,0,1,
+  8,           1,1,0,1,
+  9,           1,1,0,1,
+  13,          1,1,0,1,
+  14,          1,1,0,1,
+  15,          1,1,0,1,
+  16,          1,1,0,1,
+  17,          1,1,0,1,
+  18,          1,1,0,1,
+
+  /* --- 0x1C0 - 0x1CF --- */
+
+  '0',         0,0,1,0,
+  '1',         0,0,1,0,
+  '2',         0,0,1,0,
+  '3',         0,0,1,0,
+  '4',         0,0,1,0,
+  '5',         0,0,1,0,
+  '6',         0,0,1,0,
+  '7',         0,0,1,0,
+  '8',         0,0,1,0,
+  '9',         0,0,1,0,
+  10,          0,0,0,1,
+  11,          0,0,0,1,
+  12,          0,0,0,1,
+  19,          0,0,0,1,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+
+  /* --- 0x1D0 - 0x1DF --- */
+
+  '0',         1,0,1,0,
+  '1',         1,0,1,0,
+  '2',         1,0,1,0,
+  '3',         1,0,1,0,
+  '4',         1,0,1,0,
+  '5',         1,0,1,0,
+  '6',         1,0,1,0,
+  '7',         1,0,1,0,
+  '8',         1,0,1,0,
+  '9',         1,0,1,0,
+  10,          1,0,0,1,
+  11,          1,0,0,1,
+  12,          1,0,0,1,
+  19,          1,0,0,1,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+
+  /* --- 0x1E0 - 0x1EF --- */
+
+  '0',         0,1,1,0,
+  '1',         0,1,1,0,
+  '2',         0,1,1,0,
+  '3',         0,1,1,0,
+  '4',         0,1,1,0,
+  '5',         0,1,1,0,
+  '6',         0,1,1,0,
+  '7',         0,1,1,0,
+  '8',         0,1,1,0,
+  '9',         0,1,1,0,
+  10,          0,1,0,1,
+  11,          0,1,0,1,
+  12,          0,1,0,1,
+  19,          0,1,0,1,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+
+  /* --- 0x1F0 - 0x1FF --- */
+
+  '0',         1,1,1,0,
+  '1',         1,1,1,0,
+  '2',         1,1,1,0,
+  '3',         1,1,1,0,
+  '4',         1,1,1,0,
+  '5',         1,1,1,0,
+  '6',         1,1,1,0,
+  '7',         1,1,1,0,
+  '8',         1,1,1,0,
+  '9',         1,1,1,0,
+  10,          1,1,0,1,
+  11,          1,1,0,1,
+  12,          1,1,0,1,
+  19,          1,1,0,1,
+  0,           0,0,0,0,
+  0,           0,0,0,0,
+};
+
+static char *keyString__fkeys[]=
+{
+  "kstrPRT:Print",
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  0,
+  "kstrF13:Tab",
+  "kstrF14:Copy",
+  "kstrF15:Left",
+  "kstrF16:Right",
+  "kstrF17:Down",
+  "kstrF18:Up",
+  "kstrF19:Insert",
+};
+
+static char *keyString__lowctl[]=
+{
+  "kstrESC:Escape",
+  "kstrBSP:Backspace",
+  "kstrRET:Return",
+  "kstrHOME:Home",
+};
+
+/*
+ * char *keyString_convert(int key,BOOL mnu)
+ *
+ * Use
+ *  Converts a STEEL extended keypress into a string suitable for displaying
+ *  either as a short-cut string in a dialogue box or in a menu
+ *
+ * Parameters
+ *  int key == the keypress to translate
+ *  BOOL mnu == TRUE to create menu shortcut string, FALSE for dbox
+ *
+ * Returns
+ *  A pointer to the string, or 0
+ */
+
+char *keyString_convert(int key,BOOL mnu)
+{
+  keyString__keyEntry ke;
+  char base[20];
+  char *bp;
+  char *buffer=buffer_find();
+
+  /* --- Make sure it's not a printable character --- */
+
+  if (key<' ')
+    ke=keyString__lower[key];
+  else if (key>0x0FF)
+    ke=keyString__upper[key-0x100];
+  else if (key==0x07F)
+  {
+    ke.c=0x07F;
+    ke.shift=ke.ctrl=ke.keypad=ke.func=0;
+  }
+  else
+    return (0);
+  if (!ke.c && !ke.func)
+    return (0);
+
+  /* --- Get the name of the base key --- */
+
+  if (ke.func)
+  {
+    if (ke.c==12)
+      return (0);  /* Always let F12 through */
+    bp=keyString__fkeys[ke.c];
+    if (!bp)
+    {
+      sprintf(base,"%s%i",msgs_lookup("kstrF:F"),ke.c);
+      bp=base;
+    }
+    else
+      bp=msgs_lookup(bp);
+  }
+  else if (ke.c==0x01D && ke.keypad)
+  {
+    ke.keypad=0;
+    bp=msgs_lookup("kstrENT:Enter");
+  }
+  else if (ke.c>0x01A && ke.c<0x01F)
+    bp=msgs_lookup(keyString__lowctl[ke.c-0x01B]);
+  else if (ke.c==0x07f)
+    bp=msgs_lookup("kstrDEL:Delete");
+  else if (ke.c==0x020)
+    bp=msgs_lookup("kstrSPC:Space");
+  else
+  {
+    base[0]=ke.c;
+    base[1]=0;
+    bp=base;
+  }
+
+  /* --- Build the keyname in the buffer --- */
+
+  buffer[0]=0;
+  if (ke.shift)
+    strcat(buffer,mnu ? "\x8B" : msgs_lookup("kstrSH:Shift "));
+  if (ke.ctrl)
+    strcat(buffer,mnu ? "^" : msgs_lookup("kstrCTL:Ctrl "));
+  if (ke.keypad)
+    strcat(buffer,mnu ? "~" : msgs_lookup("kstrKPD:Keypad "));
+  strcat(buffer,bp);
+
+  /* --- Well, that's it at last --- */
+
+  return (buffer);
+}
diff --git a/StraySrc/Libraries/Steel/c/listbox b/StraySrc/Libraries/Steel/c/listbox
new file mode 100644 (file)
index 0000000..8986f9e
--- /dev/null
@@ -0,0 +1,1741 @@
+/*
+ * ListBox
+ *  Provides handling for list boxes
+ *
+ * v. 1.00 (27 July 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "wimp.h"
+#include "wimpt.h"
+#include "event.h"
+#include "win.h"
+#include "template.h"
+#include "listbox.h"
+#include "werr.h"
+#include "msgs.h"
+#include "bbc.h"
+#include "mem.h"
+#include "utils.h"
+#include "help.h"
+#include "visdelay.h"
+#include "dll.h"
+
+#ifndef _dll_NODLL
+  extern void _dllEntry(list__events)(wimp_eventstr *e,void *handle);
+#endif
+
+#define list__ITEMHEIGHT 44
+#define list__MINHEIGHT 176
+
+/*
+ * A structure for the list items
+ */
+typedef struct list__item
+{
+  struct list__item *next;
+  struct list__item *prev;
+  void *handle;
+  char *data;
+  BOOL selected :1;
+  BOOL nsel :1;
+}
+list__item;
+
+/*
+ * A structure that says everything about a listbox
+ */
+typedef struct list__liststr
+{
+  wimp_w wind;
+  wimp_box visSize;
+  wimp_wind *windDef;
+  int foreg;
+  int backg;
+  list_eventhandler events;
+  void *evntHandle;
+  list_raweventhandler rawEvents;
+  void *rawHandle;
+  list_redrawhandler rdr;
+  void *redrawHandle;
+  int items;
+  int width;
+  list_item selected;
+  list_item list;
+  int nsel;
+  pane p;
+  int iHeight;
+  int extWidth;
+  int extraWidth;
+  BOOL alterSize :1;
+  BOOL multSel :1;
+  BOOL update :1;
+}
+list__liststr;
+
+static list list__dragging;
+static int list__dragIndex;
+static int list__currentIndex;
+
+_dll_static void list__events(wimp_eventstr *e,void *handle);
+
+/*
+ * void list__resize(list l)
+ *
+ * Use
+ *  This routine will resize a list box according to how many items there
+ *  are in it.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+static void list__resize(list l)
+{
+  wimp_wstate s;
+  int height;
+  int width;
+  BOOL open;
+  int maxlen;
+  wimp_redrawstr extent;
+  wimp_box b;
+  BOOL hscr=FALSE,ohscr;
+  BOOL vscr=FALSE,ovscr;
+  wimp_winfo w;
+  menu_handler mhnd;
+  pane p=0;
+  int xe=0,ye=0;
+  int scbh=0;
+
+  /* --- Find out if there's anything to do --- */
+
+  if (!l->wind || !l->update)
+    return;
+
+  /* --- Get information about the window --- */
+
+  wimpt_noerr(wimp_get_wind_state(l->wind,&s));
+  open=s.flags & wimp_WOPEN;
+  height=l->items*l->iHeight;
+  width=maxlen=l->width+16+l->extraWidth;
+
+  /* --- If it's a pane listbox, add in scroll bars if necessary --- */
+
+  if (!l->alterSize)
+  {
+    /* --- First, read the position and scroll sizes --- */
+
+    win_gadgetWidths(wimp_WNEW | wimp_WVSCR | wimp_WHSCR,&b);
+
+    /* --- Get the outline extents of the window --- */
+
+    ohscr=s.flags & wimp_WHSCR;
+    ovscr=s.flags & wimp_WVSCR;
+    scbh=b.y0-wimpt_dy();
+    xe=s.o.box.x1-s.o.box.x0+(ovscr ? b.x1-wimpt_dx() : 0);
+    ye=s.o.box.y1-s.o.box.y0+(ohscr ? scbh : 0);
+
+    /* --- Now find out if we really want scroll bars --- */
+
+    if (maxlen>xe)
+    {
+      hscr=TRUE;
+      ye-=b.y0-wimpt_dy();
+    }
+
+    if (height>ye)
+    {
+      vscr=TRUE;
+      xe-=b.x1-wimpt_dx();
+    }
+
+    if (!hscr && maxlen>xe)
+    {
+      hscr=TRUE;
+      ye-=b.y0-wimpt_dy();
+    }
+
+    /* --- If we changed the scroll bars, recreate the window --- */
+
+    if (!hscr!=!ohscr || !vscr!=!ovscr)
+    {
+      /* --- Update the scroll bar flags --- */
+
+      ohscr=hscr;
+      ovscr=vscr;
+
+      /* --- Save all the window's info so we recreate it properly --- */
+
+      if (l->p)
+      {
+        p=l->p;
+        pane_removePane(p,l->wind);
+      }
+      w.w=l->wind;
+      wimpt_noerr(wimp_get_wind_info(&w));
+      menu_saveHandler(l->wind,&mhnd);
+      wimpt_noerr(wimp_delete_wind(l->wind));
+      win_register_event_handler(l->wind,0,0);
+
+      /* --- Set up window with new scroll bar gadgetry --- */
+
+      w.info.flags&=~(wimp_WHSCR | wimp_WVSCR);
+      if (hscr)
+        w.info.flags|=wimp_WHSCR;
+      if (vscr)
+        w.info.flags|=wimp_WVSCR;
+      w.info.flags|=wimp_WNEW;
+      w.info.ex.x1+=200;
+      w.info.ex.y0-=200;
+      wimpt_noerr(wimp_create_wind(&w.info,&l->wind));
+
+      /* --- Read the new outline and check the sizes again --- */
+
+      s.o.w=l->wind;
+      s.o.box.x1=s.o.box.x0+xe;
+      s.o.box.y0=s.o.box.y1-ye;
+      wimpt_noerr(wimp_open_wind(&s.o));
+
+      /* --- Restore everything we saved above --- */
+
+      if (!open)
+        wimpt_noerr(wimp_close_wind(l->wind));
+      win_register_event_handler(l->wind,_dllEntry(list__events),l);
+      menu_restoreHandler(l->wind,&mhnd);
+    }
+  }
+  else
+    xe=l->visSize.x1-l->visSize.x0;
+
+  /* --- Correct the extent dimensions --- */
+
+  if (width<xe)
+    width=xe;
+  if (height<ye && !l->alterSize)
+    height=ye;
+  if (height<list__MINHEIGHT-scbh)
+    height=list__MINHEIGHT-scbh;
+
+  extent.w=l->wind;
+  extent.box.x0=l->visSize.x0;
+  extent.box.x1=l->visSize.x0+width;
+  extent.box.y0=-height;
+  extent.box.y1=0;
+  l->extWidth=width; /* Remember the width of the window for redrawing */
+  wimpt_noerr(wimp_set_extent(&extent));
+  if (open)
+  {
+    wimpt_noerr(wimp_open_wind(&s.o));
+    wimpt_noerr(wimp_force_redraw(&extent));
+  }
+  if (p)
+  {
+    l->p=p;
+    pane_addListbox(p,l);
+  }
+}
+
+/*
+ * void list__rescanSize(list l)
+ *
+ * Use
+ *  Recalculates a list box's width.
+ */
+
+static void list__rescanSize(list l)
+{
+  list_item itm;
+  int len;
+
+  if (!l->wind || !l->update)
+    return;
+
+  l->width=0;
+  itm=l->list;
+  while (itm)
+  {
+    len=wimpt_stringWidth(itm->data);
+    if (len>l->width)
+      l->width=len;
+    itm=itm->next;
+  }
+  list__resize(l);
+}
+
+/*
+ * void list__event(list l,list_item clicked)
+ *
+ * Use
+ *  Posts an event to the event handler registered for the list box (if it's
+ *  there).
+ *
+ * Parameters
+ *  list l == the list box handle
+ *  list_item clicked == the item that was clicked
+ */
+
+static void list__event(list l,list_item clicked)
+{
+  if (l->events)
+    (l->events)(l,clicked,l->evntHandle);
+}
+
+/*
+ * void list__defaultRedraw(list l,
+ *                          wimp_box *b,
+ *                          char *text,
+ *                          BOOL selected)
+ *
+ * Use
+ *  Standard redraw handler for list boxes.  This may be overridden if the
+ *  list box is a fancy one.
+ *
+ * Parameters
+ *  As for list redraw handlers, except that there's no handle passed to it.
+ */
+
+static void list__defaultRedraw(list l,
+                                wimp_box *b,
+                                char *text,
+                                BOOL selected)
+{
+  wimp_icon icn;
+  icn.box=*b;
+  icn.flags=0x00000131+(l->foreg<<24)+(l->backg<<28);
+  icn.data.indirecttext.validstring=(char *)-1;
+  icn.data.indirecttext.bufflen=0;
+  if (selected)
+    icn.flags|=wimp_ISELECTED;
+  else
+    icn.flags&=~wimp_ISELECTED;
+  icn.data.indirecttext.buffer=text;
+  wimpt_noerr(wimp_ploticon(&icn));
+}
+
+/*
+ * void list__redraw(wimp_redrawstr *r,void *handle)
+ *
+ * Use
+ *  Redraws a list box window
+ *
+ * Parameters
+ *  wimp_redrawstr *r == redraw structure for this redraw event
+ *  void *handle == pointer to this list box
+ */
+
+static void list__redraw(wimp_redrawstr *r,void *handle)
+{
+  list l=(list)handle;
+  list_item itm=l->list;
+  int ox=r->box.x0-r->scx;
+  int oy=r->box.y1-r->scy;
+  int i=0;
+  int first=-(r->g.y1-r->box.y1+r->scy)/l->iHeight;
+  int last=first+(r->g.y1-r->g.y0)/l->iHeight+1;
+  wimp_box box;
+  box.x0=l->visSize.x0;
+  box.x1=l->visSize.x0+l->extWidth;
+  box.y1=0;
+  box.y0=-l->iHeight;
+  while (itm)
+  {
+    if (i>=first && i<=last)
+    {
+      if (l->rdr)
+      {
+        (l->rdr)(l,itm,r,&box,itm->data,
+                 itm->selected || itm->nsel,l->redrawHandle);
+      }
+      else
+        list__defaultRedraw(l,&box,itm->data,itm->selected || itm->nsel);
+    }
+    itm=itm->next;
+    box.y0-=l->iHeight;
+    box.y1-=l->iHeight;
+    i++;
+  }
+  wimpt_noerr(wimp_setcolour(l->backg));
+  if (i<=last)
+  {
+    bbc_rectanglefill(l->visSize.x0+ox,
+                      box.y1+oy-l->iHeight*(last-i+1)-wimpt_dy(),
+                      l->extWidth,
+                      l->iHeight*(last-i+1));
+  }
+}
+
+/*
+ * list_item list__coordsToItem(int x,int y,list l)
+ *
+ * Use
+ *  Given a screen position and a list handle, returns
+ *  the item beneath the point.
+ *
+ * Parameters
+ *  int x == absolute OS-unit screen x-coordinate of the point
+ *  int y == absolute OS-unit screen y-coordinate of the point
+ *  list l == the list handle
+ *
+ * Returns
+ *  The list item handle
+ */
+
+static list_item list__coordsToItem(int x,int y,list l)
+{
+  wimp_wstate state;
+  int oy;
+  list_item i;
+  int index;
+  x=x;
+  wimpt_noerr(wimp_get_wind_state(l->wind,&state));
+  oy=state.o.box.y1-state.o.y;
+  index=-(y-oy+wimpt_dy())/l->iHeight;
+  if (index>=l->items)
+    return (list_NOITEM);
+  i=list_indexToItem(l,index);
+  return (i);
+}
+
+/*
+ * void list__selectIdles(void *handle)
+ *
+ * Use
+ *  Gets passed idle events when dragging out a selection.
+ *
+ * Parameters
+ *  void *handle == a NULL pointer
+ */
+
+#define min2(x,y) ((x)<(y) ? (x) : (y))
+#define max2(x,y) ((x)>(y) ? (x) : (y))
+#define min3(x,y,z) min2(min2(x,y),z)
+#define max3(x,y,z) max2(max2(x,y),z)
+
+static void list__redrawItem(list l,int i);
+
+static void list__selectIdles(void *handle)
+{
+  /* --- Rewritten 24-Jun-1993 - MDW --- */
+
+  /* --- Variables required to update the drag --- */
+  wimp_mousestr m;                    /* Pointer state (window coords)     */
+  wimp_wstate s;                      /* Position of window                */
+  int ox,oy;                          /* Screen coords of window origin    */
+  int i;                              /* Item index counter                */
+  int start;                          /* Index to start processing items   */
+  int end;                            /* Index to finish processing items  */
+  int index;                          /* Index of item under pointer       */
+  list_item item;                     /* List item ptr (for list traverse) */
+  int sel;                            /* -1 == ignore, 0 == deselect,      */
+                                      /* 1 == select                       */
+
+  handle=handle;
+
+  /* --- Set up pointer position --- */
+  wimpt_noerr(wimp_get_point_info(&m)); /* I only need the coordinates     */
+  wimpt_noerr(wimp_get_wind_state(list__dragging->wind,&s)); /* For origin,*/
+                                      /* and scrolling the window          */
+  ox=s.o.box.x0-s.o.x;                /* Derive position of window origin  */
+  oy=s.o.box.y1-s.o.y;                /* from state as per PRM             */
+  m.x-=ox;                            /* Now convert mouse position to     */
+  m.y-=oy;                            /* window coordinates                */
+  index=-(m.y+wimpt_dy())/list__dragging->iHeight; /* Calc item under ptr  */
+  if (index<0)                        /* Stop negative indices             */
+    index=0;
+
+  /* --- Set up for loop through list items --- */
+  start=min3(list__currentIndex,list__dragIndex,index);
+  end=max3(list__currentIndex,list__dragIndex,index);
+  item=list__dragging->list;
+  i=0;
+  sel=-1;
+
+  /* --- Now loop through the relevant icons --- */
+  while (item)                        /* Carry on until we run out of items*/
+  {
+    if (i==start)
+      sel=0;
+    if (list__dragIndex<index)
+    {
+      if (i==list__dragIndex)
+        sel=TRUE;
+      if (i==index+1)
+        sel=FALSE;
+    }
+    else
+    {
+      if (i==index)
+        sel=TRUE;
+      if (i==list__dragIndex+1)
+        sel=FALSE;
+    }
+    if (i==end+1)
+      sel=-1;
+    if (sel!=-1 && !item->selected && sel!=item->nsel)
+    {
+      item->nsel=sel;
+      list__redrawItem(list__dragging,i);
+      list__dragging->nsel+=(sel==TRUE)-(sel==FALSE);
+    }
+    i++;
+    item=item->next;
+  }
+  list__currentIndex=index;
+
+  /* --- Scroll the window to include the added selection --- */
+  if (m.y>s.o.y)                      /* If pointer too far up, scroll up  */
+    s.o.y=m.y;
+  else if (m.y+s.o.box.y1-s.o.box.y0<s.o.y) /* If too far down, scroll down*/
+    s.o.y=m.y+s.o.box.y1-s.o.box.y0;
+  wimpt_noerr(wimp_open_wind(&s.o));  /* Open the window in new position   */
+}
+
+/*
+ * BOOL list__selectUnknowns(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Unknown event handler for dragging out selections.
+ *
+ * Parameters
+ *  wimp_eventstr *e == the unknown event
+ *  void *handle == a NULL pointer
+ *
+ * Returns
+ *  TRUE if the event was interesting
+ */
+
+static BOOL list__selectUnknowns(wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  list_item i;
+  handle=handle;
+  switch (e->e)
+  {
+    case wimp_EUSERDRAG:
+      list__selectIdles(0);
+      for (i=list__dragging->list;i;i=i->next)
+      {
+        if (i->nsel)
+          i->selected=TRUE;
+        i->nsel=FALSE;
+      }
+      win_remove_unknown_event_processor(list__selectUnknowns,0);
+      win_remove_idle_claimer(list__selectIdles,0);
+      handled=TRUE;
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * BOOL list__modeChange(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Handles mode change events for list boxes (rescan the width)
+ */
+
+static BOOL list__modeChange(wimp_eventstr *e,void *handle)
+{
+  list l=handle;
+
+  switch (e->e)
+  {
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      if (e->data.msg.hdr.action==wimp_MMODECHANGE ||
+          e->data.msg.hdr.action==0x400CF)
+        list__rescanSize(l);
+      break;
+  }
+  return (FALSE);
+}
+
+/*
+ * void list__events(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  The event handler for list boxes.
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event
+ *  void *handle == the list box handle
+ */
+
+_dll_static void list__events(wimp_eventstr *e,void *handle)
+{
+  list l=(list)handle;
+  BOOL handled=FALSE;
+  if (l->rawEvents)
+    handled=(l->rawEvents)(l,e,l->rawHandle);
+  if (!handled)
+  {
+    switch (e->e)
+    {
+      case wimp_EREDRAW:
+        wimpt_redraw(list__redraw,l);
+        break;
+      case wimp_EOPEN:
+        wimpt_noerr(wimp_open_wind(&e->data.o));
+        break;
+      case wimp_ECLOSE:
+        list__event(l,list_CLOSE);
+        break;
+      case wimp_EBUT:
+        if
+        (
+          e->data.but.m.bbits & wimp_BLEFT ||
+          e->data.but.m.bbits & wimp_BRIGHT ||
+          e->data.but.m.bbits & wimp_BCLICKLEFT ||
+          e->data.but.m.bbits & wimp_BCLICKRIGHT
+        )
+        {
+          list_item i=list__coordsToItem(e->data.but.m.x,e->data.but.m.y,l);
+          if (e->data.but.m.bbits&wimp_BLEFT || l->multSel==FALSE)
+            list_selectItem(l,i);
+          else
+            list_addToSelection(l,i,list_TOGGLESTATE);
+          list__event(l,l->selected);
+        }
+        else if
+        (
+          (e->data.but.m.bbits & wimp_BDRAGLEFT ||
+          e->data.but.m.bbits & wimp_BDRAGRIGHT) &&
+          l->multSel==TRUE
+        )
+        {
+          wimp_dragstr d;
+          wimp_wstate s;
+          wimpt_noerr(wimp_get_wind_state(l->wind,&s));
+          d.type=wimp_USER_HIDDEN;
+          d.parent.x0=e->data.but.m.x;
+          d.parent.y0=0x9001;
+          d.parent.x1=e->data.but.m.x;
+          d.parent.y1=0x6FFE;
+          wimpt_noerr(wimp_drag_box(&d));
+          list__dragging=l;
+          list__dragIndex=-(e->data.but.m.y+wimpt_dy()-s.o.box.y1+s.o.y)/
+                                                            l->iHeight;
+          list__currentIndex=list__dragIndex;
+          list__selectIdles(0);
+          win_add_unknown_event_processor(list__selectUnknowns,0);
+          win_addIdleClaimer(list__selectIdles,2,0);
+        }
+        break;
+      case wimp_EKEY:
+        wimpt_noerr(wimp_processkey(e->data.key.chcode));
+        break;
+      case wimp_ESCROLL:
+        {
+          int height=e->data.scroll.o.box.y1-e->data.scroll.o.box.y0;
+          int width=e->data.scroll.o.box.x1-e->data.scroll.o.box.x0;
+          switch (e->data.scroll.y)
+          {
+            case -2:
+              {
+                int bottom=-(e->data.scroll.o.y-height)/l->iHeight;
+                int itms=height/l->iHeight;
+                if (-bottom*l->iHeight==e->data.scroll.o.y-height)
+                  bottom--;
+                e->data.scroll.o.y=-(bottom+itms)*l->iHeight+height;
+              }
+              break;
+            case -1:
+              {
+                int bottom=-(e->data.scroll.o.y-height)/l->iHeight;
+                bottom++;
+                e->data.scroll.o.y=-bottom*l->iHeight+height;
+              }
+              break;
+            case 0:
+              break;
+            case 1:
+              {
+                int top=-(e->data.scroll.o.y)/l->iHeight;
+                if (-top*l->iHeight==e->data.scroll.o.y)
+                  top--;
+                e->data.scroll.o.y=-top*l->iHeight;
+              }
+              break;
+            case 2:
+              {
+                int top=-(e->data.scroll.o.y)/l->iHeight;
+                int itms=height/l->iHeight;
+                if (-top*l->iHeight!=e->data.scroll.o.y);
+                  top++;
+                e->data.scroll.o.y=-(top-itms)*l->iHeight;
+              }
+              break;
+          }
+          switch (e->data.scroll.x)
+          {
+            case -2:
+              e->data.scroll.o.x-=width;
+              break;
+            case -1:
+              e->data.scroll.o.x-=32;
+              break;
+            case 0:
+              break;
+            case 1:
+              e->data.scroll.o.x+=32;
+              break;
+            case 2:
+              e->data.scroll.o.x+=width;
+              break;
+          }
+          wimpt_noerr(wimp_open_wind(&(e->data.scroll.o)));
+        }
+        break;
+      case wimp_ESEND:
+      case wimp_ESENDWANTACK:
+        switch (e->data.msg.hdr.action)
+        {
+          case wimp_MHELPREQUEST:
+            list__event(l,list_HELP);
+            break;
+        }
+        break;
+    }
+  }
+}
+
+/*
+ * list_item list__findItem(list l,list_item i)
+ *
+ * Use
+ *  Returns a pointer to a list item.
+ *
+ * Parameters
+ *  list l == the list
+ *  list_item i == the item number
+ *
+ * Returns
+ *  A pointer to the list item or 0 if it couldn't be found.
+ */
+
+#define list__findItem(l,i) (i)
+
+/*
+ * void list_isPane(list l,pane p)
+ *
+ * Use
+ *  This routine is part of the private interface between the listbox and
+ *  pane segments.  Do *NOT* try to call it in your own code.
+ */
+
+void list_isPane(list l,pane p)
+{
+  l->p=p;
+  if (l->p!=p && p)
+    list__resize(l);
+}
+
+/*
+ * void list__redrawItem(list l,int item)
+ *
+ * Use
+ *  Calls for a redraw of a single list item
+ *
+ * Parameters
+ *  list l == the list handle
+ *  int i == the item index
+ */
+
+static void list__redrawItem(list l,int i)
+{
+  wimp_redrawstr r;
+  wimp_wstate s;
+  BOOL more;
+  if (i!=-1)
+  {
+    wimpt_noerr(wimp_get_wind_state(l->wind,&s));
+    r.w=l->wind;
+    r.box.x0=s.o.x;
+    r.box.x1=s.o.x+s.o.box.x1-s.o.box.x0;
+    r.box.y0=-l->iHeight*i-l->iHeight;
+    r.box.y1=-l->iHeight*i;
+    wimpt_noerr(wimp_update_wind(&r,&more));
+    while (more)
+    {
+      list__redraw(&r,l);
+      wimpt_noerr(wimp_get_rectangle(&r,&more));
+    }
+  }
+}
+
+/*
+ * void list_selectItem(list l,list_item item)
+ *
+ * Use
+ *  Makes the item the currently selected one.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  list_item item == the item number
+ */
+
+void list_selectItem(list l,list_item item)
+{
+  list_item i=l->list;
+  int c=0;
+  visdelay_begin();
+  while (i)
+  {
+    if (i->selected==TRUE && i!=item)
+    {
+      i->selected=FALSE;
+      list__redrawItem(l,c);
+      l->nsel--;
+    }
+    c++;
+    i=i->next;
+  }
+  visdelay_end();
+  l->selected=list_NOITEM;
+  list_addToSelection(l,item,list_SETSTATE);
+}
+
+/*
+ * list_item list_selected(list l)
+ *
+ * Use
+ *  Returns the currently selected item of the list.
+ *
+ * Parameters
+ *  list l == the list handle
+ *
+ * Returns
+ *  The item number of the currently selected item.
+ */
+
+list_item list_selected(list l)
+{
+  list_item itm=l->list;
+  while (itm)
+  {
+    if (itm->selected)
+      return (itm);
+    itm=itm->next;
+  }
+  return (list_NOITEM);
+}
+
+/*
+ * list list_create(char *name,BOOL alterSize)
+ *
+ * Use
+ *  Creates a new list box window, and returns a handle to it.  Initially,
+ *  there are no items, and the list box is not shown.  The function returns
+ *  0 if the call fails for one reason or another (not enough windows or
+ *  memory).
+ *
+ * Parameters
+ *  char *name == the name to match in the template file
+ *  BOOL alterSize == TRUE if we are allowed to change the box's visible
+ *    size.
+ *
+ * Returns
+ *  An abstract handle for the list box.
+ */
+
+list list_create(char *name,BOOL alterSize)
+{
+  list new=(list)mem_alloc(sizeof(list__liststr));
+  if (new==0)
+  {
+    werr(FALSE,msgs_lookup("listNEM:Not enough room to create list box."));
+    return (0);
+  }
+
+  win_activeinc();
+  new->events=0;
+  new->rawEvents=0;
+  new->items=0;
+  new->width=0;
+  new->list=0;
+  new->selected=list_NOITEM;
+  new->windDef=template_syshandle(name);
+  new->alterSize=alterSize;
+  new->wind=0;
+  new->foreg=new->windDef->colours[wimp_WCWKAREAFORE];
+  new->backg=new->windDef->colours[wimp_WCWKAREABACK];
+  new->multSel=FALSE;
+  new->nsel=0;
+  new->p=0;
+  new->rdr=0;
+  new->extraWidth=0;
+  new->iHeight=list__ITEMHEIGHT;
+  return (new);
+}
+
+/*
+ * char *list_itemData(list l,list_item i)
+ *
+ * Use
+ *  Returns the string for an item
+ *
+ * Parameters
+ *  list l == the list handle
+ *  list_item i == the item's handle
+ *
+ * Returns
+ *  A pointer to the item's data
+ */
+
+char *list_itemData(list l,list_item i)
+{
+  l=l;
+  return (list__findItem(l,i)->data);
+}
+
+/*
+ * list_item list_addItem(list l,char *data,BOOL inOrder)
+ *
+ * Use
+ *  Adds a new piece of data into the list.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  char *data == the data (as a char *, because most of the time you'll
+ *    want to be using character strings).
+ *
+ * Returns
+ *  A handle for the list item.  This is 0 if the call failed.
+ */
+
+list_item list_addItem(list l,char *data,BOOL inOrder)
+{
+  list_item itm=(list_item)&(l->list);
+  list_item new=(list_item)mem_alloc(sizeof(list__item));
+  int len;
+
+  if (!new)
+  {
+    werr(FALSE,msgs_lookup("listNEMI:Not enough room to add new item."));
+    return (0);
+  }
+  if (new->data=mem_alloc(strlen(data)+1),!new->data)
+  {
+    mem_free(new);
+    werr(FALSE,msgs_lookup("listNEMI:Not enough room to add new item."));
+    return (0);
+  }
+  strcpy(new->data,data);
+  while (itm->next)
+  {
+    if (utils_caselessCmp(itm->next->data,data)>0 && inOrder==TRUE)
+      break;
+    itm=itm->next;
+  }
+  new->next=itm->next;
+  new->prev=itm;
+  itm->next=new;
+  if (new->next)
+    new->next->prev=new;
+  new->handle=0;
+  new->selected=FALSE;
+  new->nsel=FALSE;
+  l->items++;
+  len=wimpt_stringWidth(data);
+  if (len>l->width)
+    l->width=len;
+  list__resize(l);
+  return (new);
+}
+
+/*
+ * list_item list_findItem(list l,char *data)
+ *
+ * Use
+ *  Searches through a list and returns the item number of the item whose
+ *  data matches that given in the function.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  char *data == the data to compare with
+ *
+ * Returns
+ *  The item number of the item, or -1 if no match.
+ */
+
+list_item list_findItem(list l,char *data)
+{
+  list_item itm=l->list;
+  list_item found=list_NOITEM;
+  while (itm!=0)
+  {
+    if (utils_caselessCmp(itm->data,data)==0)
+      found=itm;
+    itm=itm->next;
+  }
+  return (found);
+}
+
+/*
+ * void list_removeItem(list l,list_item i)
+ *
+ * Use
+ *  Removes an item from the list.
+ *
+ * Parameters
+ *  list l == the list's handle
+ *  list_item i == the item number
+ */
+
+void list_removeItem(list l,list_item i)
+{
+  if (i==l->selected)
+    l->selected=list_NOITEM;
+  if (i->selected)
+    l->nsel--;
+  if (i->prev)
+    i->prev->next=i->next;
+  if (i->next)
+    i->next->prev=i->prev;
+  l->items--;
+  mem_free(i->data);
+  mem_free(i);
+  list__rescanSize(l);
+}
+
+/*
+ * void list_delete(list l)
+ *
+ * Use
+ *  Destroys a list totally.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_delete(list l)
+{
+  list_item itm=l->list;
+  list_item i;
+  if (l->wind)
+    list_unlink(l);
+  win_activedec();
+  while (itm)
+  {
+    i=itm;
+    itm=i->next;
+    mem_free(i->data);
+    mem_free(i);
+  }
+  mem_free(l);
+}
+
+/*
+ * void list_updatePosition(list l)
+ *
+ * Use
+ *  Writes the position of the listbox back into the template, so any new
+ *  list boxes created from the template open at that position.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_updatePosition(list l)
+{
+  wimp_winfo *w;
+  if (w=(wimp_winfo *)mem_alloc
+  (
+    sizeof(wimp_winfo)+l->windDef->nicons*sizeof(wimp_icon)
+  ),
+  w);
+  {
+    w->w=l->wind;
+    wimpt_noerr(wimp_get_wind_info(w));
+    *(l->windDef)=w->info;
+    l->windDef->colours[wimp_WCWKAREABACK]=l->backg;
+                                   /* Put colour back into *your* life :-) */
+    mem_free(w);
+  }
+}
+
+/*
+ * BOOL list_link(list l)
+ *
+ * Use
+ *  Links a list box to a WIMP window.  If the list is already linked,
+ *  nothing happens.  The list box is not displayed.
+ *
+ * Parameters
+ *  list l == the list handle
+ *
+ * Returns
+ *  TRUE if the link succeeded (may run out of windows!)
+ */
+
+BOOL list_link(list l)
+{
+  int ox,oy;
+  if (l->wind!=0)
+    return(TRUE);
+  l->windDef->colours[wimp_WCWKAREABACK]=255;
+                       /* We draw the whole lot anyway, so this is quicker */
+  if (wimp_create_wind(l->windDef,&l->wind))
+  {
+    werr
+    (
+      FALSE,
+      msgs_lookup("listTMW:Too many windows - "
+                                         "%s could not create list box."),
+      wimpt_programname()
+    );
+    l->wind=0;
+    l->windDef->colours[wimp_WCWKAREABACK]=l->backg;
+                                    /* Put it back for reading again later */
+    return (FALSE);
+  }
+  l->windDef->colours[wimp_WCWKAREABACK]=l->backg;
+                                    /* Put it back for reading again later */
+  win_register_event_handler(l->wind,_dllEntry(list__events),l);
+  win_add_unknown_event_processor(list__modeChange,l);
+  ox=l->windDef->box.x0-l->windDef->scx;
+  oy=l->windDef->box.y1-l->windDef->scy;
+  l->visSize.x0=l->windDef->ex.x0;
+  l->visSize.y0=l->windDef->box.y0-oy;
+  l->visSize.x1=l->windDef->ex.x1;
+  l->visSize.y1=l->windDef->box.y1-oy;
+  l->update=TRUE;
+  list__rescanSize(l);
+  return (TRUE);
+}
+
+/*
+ * void list_unlink(list l)
+ *
+ * Use
+ *  Unlinks the list box from its window and deletes the window.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_unlink(list l)
+{
+  if (l->wind==0)
+    return;
+  list_updatePosition(l);
+  win_register_event_handler(l->wind,0,0);
+  win_remove_unknown_event_processor(list__modeChange,l);
+  wimpt_noerr(wimp_delete_wind(l->wind));
+  l->wind=0;
+}
+/*
+ * void list_unlinkNoUpdate(list l)
+ *
+ * Use
+ *  Unlinks a list from its window without storing its final position back
+ *  in memory.  Note that list_delete() calls list_unlink(), so make sure
+ *  you call this routine before deleting the list box it you want to
+ *  prevent the position being written back.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_unlinkNoUpdate(list l)
+{
+  if (l->wind==0)
+    return;
+  win_register_event_handler(l->wind,0,0);
+  wimpt_noerr(wimp_delete_wind(l->wind));
+  l->wind=0;
+}
+
+
+/*
+ * void list_update(list l,BOOL really)
+ *
+ * Use
+ *  Enables or disables list updating (i.e. whether the listbox resizes and
+ *  redraws itself between every operation).  If you're going to do some
+ *  lengthy operation, it would be a good idea to turn update off first,
+ *  and then turn it on again afterwards.
+ *
+ *  Note that this is an all-or-nothing thing -- no counter is kept.
+ *
+ * Parameters
+ *  list l == the listbox which we're messing about with
+ *  BOOL really == whether to turn the update on or off
+ */
+
+void list_update(list l,BOOL really)
+{
+  l->update=really;
+  if (really)
+    list__rescanSize(l);
+}
+
+/*
+ * void list_display(list l)
+ *
+ * Use
+ *  Displays a list box on-screen
+ *
+ * Parameters
+ *  list l == the list
+ */
+
+void list_display(list l)
+{
+  wimp_wstate state;
+  if (l->wind==0)
+  {
+    if (list_link(l)==0)
+      return;
+  }
+  wimpt_noerr(wimp_get_wind_state(l->wind,&state));
+  state.o.behind=(wimp_w)-1;
+  wimpt_noerr(wimp_open_wind(&state.o));
+}
+
+/*
+ * void list_openDisplaced(list l)
+ *
+ * Use
+ *  Opens the listbox on-screen displaced from its previous position by the
+ *  normal 48 OS units.  It must be unlinked using list_unlinkNoUpdate
+ *  before deletion.
+ *
+ * Parameters
+ *  list l == the list handle.
+ */
+
+void list_openDisplaced(list l)
+{
+  int new=0;
+  wimp_wstate s;
+  if (l->windDef->box.y0-48<132)
+  {
+    new=((976-l->windDef->box.y1)/48-4)*48+l->windDef->box.y1;
+    l->windDef->box.y0+=new-l->windDef->box.y1;
+    l->windDef->box.y1=new;
+  }
+  else
+  {
+    l->windDef->box.y0-=48;
+    l->windDef->box.y1-=48;
+  }
+  wimpt_noerr(wimp_get_wind_state(l->wind,&s));
+  s.o.box=l->windDef->box;
+  s.o.behind=-1;
+  wimpt_noerr(wimp_open_wind(&s.o));
+}
+
+/*
+ * void list_hide(list l)
+ *
+ * Use
+ *  Stops the list box being displayed
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_hide(list l)
+{
+  wimpt_noerr(wimp_close_wind(l->wind));
+}
+
+/*
+ * wimp_w list_syshandle(list l)
+ *
+ * Use
+ *  Returns the WIMP window handle being used for the list box.
+ *
+ * Parameters
+ *  list l == the list
+ *
+ * Returns
+ *  The window handle (a wimp_w).
+ */
+
+wimp_w list_syshandle(list l)
+{
+  return (l->wind);
+}
+
+/*
+ * void list_eventHandler(list l,list_eventhandler proc,void *handle)
+ *
+ * Use
+ *  Attaches an event handler to the list box.  Most won't actually need
+ *  this, just the stand-alone ones, or ones that do clever-dick things.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  list_eventhandler proc == the procedure to handle events
+ *  void *handle == the jolly olde pointer to the user-defined data
+ */
+
+void list_eventHandler(list l,list_eventhandler proc,void *handle)
+{
+  l->events=proc;
+  l->evntHandle=handle;
+}
+
+/*
+ * void list_rawEventHandler(list l,list_raweventhandler proc,void *handle)
+ *
+ * Use
+ *  Attaches the raw event handler procedure to the list box.  You can then
+ *  vet any events coming into the list box and have your wicked way with
+ *  them.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  list_raweventhandler proc == the raw event handler routine
+ *  void *handle == the (now-famous) caller defined handle.
+ */
+
+void list_rawEventHandler(list l,list_raweventhandler proc,void *handle)
+{
+  l->rawEvents=proc;
+  l->rawHandle=handle;
+}
+
+/*
+ * void list_redrawHandler(list l,list_redrawhandler rdr,void *handle)
+ *
+ * Use
+ *  Attaches a replacement redraw handler to the list box.  The new handler
+ *  redraws individual items in the list.  It must fill in the box it is
+ *  passed, because the WIMP does not fill in the background.  The part of
+ *  the list box not populated by items is filled in the window background
+ *  colour automatically.  Using this, you can achieve quite a pleasing
+ *  effect by making the background grey (colour 1) and the actual item
+ *  backgrounds white (colour 0), indicating clearly the bottom of the list.
+ *
+ *  You can also implement other things like items being shaded etc.
+ *
+ * Parameters
+ *  list l == the list to which the redraw handler is to be attached
+ *  list_redrawhandler == the replacement redraw routine (or 0 to cancel)
+ *  void *handle == a pointer to pass the redraw routine
+ */
+
+void list_redrawHandler(list l,list_redrawhandler rdr,void *handle)
+{
+  l->rdr=rdr;
+  l->redrawHandle=handle;
+}
+
+/*
+ * void list_widthAdd(list l,int extra)
+ *
+ * Use
+ *  Since redraw handlers can basically do whatever they want to for each
+ *  items, the list manager no longer really has any idea about how wide an
+ *  item is.  Since the main thing displayed in lists is text, it is assumed
+ *  that the width of an item is the width of the longest piece of text plus
+ *  a constant (e.g. for a sprite on the side).  If this is not so, I'll
+ *  have to rethink this bit...
+ *
+ * Parameters
+ *  list l == the list we're setting the width of
+ *  int extra == the constant to add to each item
+ */
+
+void list_widthAdd(list l,int extra)
+{
+  l->extraWidth=extra;
+  list__resize(l); /* In case it's open */
+}
+
+/*
+ * void list_setItemHeight(list l,int height)
+ *
+ * Use
+ *  Sets the height of items in the specified list box.  By default, the
+ *  height is 44 OS units (the height of menu items).  This should be
+ *  sufficient for most purposes.
+ *
+ * Parameters
+ *  list l == the list to set
+ *  int height == the new height of each item, in OS units
+ */
+
+void list_setItemHeight(list l,int height)
+{
+  l->iHeight=height;
+  list__resize(l); /* In case it's open now */
+}
+
+/*
+ * int list_items(list l)
+ *
+ * Use
+ *  Informs the caller how many items there are in a list
+ *
+ * Parameters
+ *  list l == the list handle
+ *
+ * Returns
+ *  The number of items in a list
+ */
+
+int list_items(list l)
+{
+  return (l->items);
+}
+
+/*
+ * void list_doForItems
+ * (
+ *   list l,
+ *   void (*proc)(list l,list_item i,void *handle),
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Performs an operation on all of the items in a list box.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  void (*proc)(list l,list_item i,void *handle) == the procedure to use
+ *  void *handle == a handle to pass to the procedure.
+ */
+
+void list_doForItems
+(
+  list l,
+  void (*proc)(list l,list_item i,void *handle),
+  void *handle
+)
+{
+  list_item i=l->list;
+  list_item next;
+  visdelay_begin();
+  while (i)
+  {
+    next=i->next;
+    proc(l,i,handle);
+    i=next;
+  }
+  visdelay_end();
+}
+
+/*
+ * void list_attachData(list l,list_item i,void *data)
+ *
+ * Use
+ *  Attaches a data structure to a list item.  This is a bit of an
+ *  afterthought really.
+ *
+ * Parameters
+ *  list l == the list
+ *  list_item i == the list item
+ *  void *data == a pointer to the data structure
+ */
+
+void list_attachData(list l,list_item i,void *data)
+{
+  l=l;
+  list__findItem(l,i)->handle=data;
+}
+
+/*
+ * void *list_getData(list l,list_item i)
+ *
+ * Use
+ *  Returns the data attached to a list item.  The item number may have
+ *  changed etc. with items deleted and added.
+ *
+ * Parameters
+ *  list l == the list
+ *  list_item i == the list item number
+ *
+ * Returns
+ *  A pointer to the data structure attached using list_attachData().
+ */
+
+void *list_getData(list l,list_item i)
+{
+  l=l;
+  if (i!=list_NOITEM)
+    return (list__findItem(l,i)->handle);
+  else
+    return (0);
+}
+
+/*
+ * void list_multipleSelection(list l)
+ *
+ * Use
+ *  Makes a list able to handle a multiple selection.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_multipleSelection(list l)
+{
+  l->multSel=TRUE;
+}
+
+/*
+ * BOOL list_addToSelection(list l,list_item i,list_action a)
+ *
+ * Use
+ *  Adds an item to the current selection.
+ *
+ * Parameters
+ *  list l == the list
+ *  list_item i == the list item
+ *  list_action a == what to do with the state
+ *
+ * Returns
+ *  The previous state of the item
+ */
+
+BOOL list_addToSelection(list l,list_item i,list_action a)
+{
+#ifdef notdef
+  wimp_wstate state;
+  int top;
+  int bottom;
+  int height;
+#endif
+  BOOL ostate;
+  if (i==list_NOITEM)
+    return (FALSE);
+  l->selected=i;
+  ostate=i->selected;
+  switch (a)
+  {
+    case list_SETSTATE:
+      i->selected=TRUE;
+      break;
+    case list_RESETSTATE:
+      i->selected=FALSE;
+      break;
+    case list_TOGGLESTATE:
+      i->selected=!(i->selected);
+      break;
+  }
+  l->nsel+=i->selected-ostate;
+  if (l->wind==0 || i->selected==ostate)
+    return (ostate);
+  list__redrawItem(l,list_itemToIndex(l,l->selected));
+#ifdef notdef
+  top=-l->iHeight*list_itemToIndex(l,i);
+  bottom=top-l->iHeight;
+  wimpt_noerr(wimp_get_wind_state(l->wind,&state));
+  height=state.o.box.y1-state.o.box.y0;
+  if (state.o.y<top)
+    state.o.y=top;
+  if (state.o.y-height>bottom)
+    state.o.y=bottom+height;
+  wimpt_noerr(wimp_open_wind(&state.o));
+#endif
+  return (ostate);
+}
+
+/*
+ * void list_doForSelected
+ * (
+ *   list l,
+ *   void (*proc)(list l,list_item i,void *handle),
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Performs a user-specified action for each selected list item.
+ *
+ * Parameters
+ *  list l == the list box
+ *  void (*proc)(list l,list_item i,void *handle) == the procedure to do
+ *    the thing
+ *  void *handle == a handle to pass to the routine.
+ */
+
+void list_doForSelected
+(
+  list l,
+  void (*proc)(list l,list_item i,void *handle),
+  void *handle
+)
+{
+  list_item i=l->list;
+  list_item next;
+  visdelay_begin();
+  while (i)
+  {
+    next=i->next;
+    if (i->selected)
+      proc(l,i,handle);
+    i=next;
+  }
+  visdelay_end();
+}
+
+/*
+ * void list__sel(list l,list_item i,void *handle)
+ *
+ * Use
+ *  Selects a single item in a list.  This is a list_doForItems() procedure.
+ *
+ * Parameters
+ *  list l == the list
+ *  list_item i == the list item to select
+ *  void *handle == a pointer to a variable of type list_action
+ */
+
+static void list__sel(list l,list_item i,void *handle)
+{
+  list_action *a=(list_action *)handle;
+  list_addToSelection(l,i,*a);
+}
+
+/*
+ * void list_selectAll(list l,list_action a)
+ *
+ * Use
+ *  Selects all the items in a list
+ *
+ * Parameters
+ *  list l == the list
+ *  list_action a == what to do with the icons (list_READSTATE ain't all
+ *    that useful, and list_TOGGLESTATE is downright wierd).
+ */
+
+void list_selectAll(list l,list_action a)
+{
+  list_doForItems(l,list__sel,&a);
+}
+
+/*
+ * int list_numSelected(list l)
+ *
+ * Use
+ *  Informs the caller how many items are selected.
+ *
+ * Parameters
+ *  list l == the list handle
+ *
+ * Returns
+ *  An integer indicating the number of selected items
+ */
+
+int list_numSelected(list l)
+{
+  return (l->nsel);
+}
+
+/*
+ * int list_itemToIndex(list l,list_item i)
+ *
+ * Use
+ *  Translates a list_item into the index of the item.  This avoids
+ *  assumptions about the mapping of indices to item numbers.  In the
+ *  future, for example, the list_item data type may be used as a pointer to
+ *  the list item data structure in memory.  Most of the time this will be
+ *  irrelevant anyway.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  list_item i == the list item to translate
+ *
+ * Returns
+ *  An integer giving the index of the item.  The first item has index 0, as
+ *  for C arrays.
+ */
+
+int list_itemToIndex(list l,list_item i)
+{
+  int ind=0;
+  list_item itm=l->list;
+  while (itm)
+  {
+    if (itm==i)
+      return (ind);
+    itm=itm->next;
+    ind++;
+  }
+  return (-1);
+}
+
+/*
+ * list_item list_indexToItem(list l,int index)
+ *
+ * Use
+ *  Performs the reverse operation to the previous routine.  It will
+ *  translate an index to a list_item.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  int index == the index of the item required
+ *
+ * Returns
+ *  The equivalent list_item for the item.
+ */
+
+list_item list_indexToItem(list l,int index)
+{
+  int ind=0;
+  list_item itm=l->list;
+  while (itm)
+  {
+    if (ind==index)
+      return (itm);
+    itm=itm->next;
+    ind++;
+  }
+  return (list_NOITEM);
+}
+
+/*
+ * list_item list_helpItem(list l)
+ *
+ * Use
+ *  Returns the item that Help is interested in.
+ *
+ * Parameters
+ *  list l == the list's handle
+ *
+ * Returns
+ *  A list_item
+ */
+
+list_item list_helpItem(list l)
+{
+  wimp_eventstr *e=wimpt_last_event();
+  if (help_wasHelp())
+    return (list__coordsToItem
+    (
+      e->data.msg.data.helprequest.m.x,
+      e->data.msg.data.helprequest.m.y,l
+    ));
+  else
+    werr(TRUE,msgs_lookup("listHIE:(list_helpItem, caller fault): "
+                                     "Not called on HELPREQUEST event."));
+  return (0);
+}
diff --git a/StraySrc/Libraries/Steel/c/mem b/StraySrc/Libraries/Steel/c/mem
new file mode 100644 (file)
index 0000000..ddb04f3
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+ * mem
+ *  Store handling for Steel
+ *
+ * version 1.00 6 September 1993
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "flex.h"
+#include "heap.h"
+#include "wimpt.h"
+#include "mem.h"
+#include "kernel.h"
+#include "bbc.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define mem__MALLOC 1
+#define mem__HEAP 2
+#define mem__RMA 3
+#define mem__USER 4
+
+/* #define mem__DEBUG_MALLOC */
+/* Uncomment previous line for memDebug */
+
+#define mem__MAGIC 0x45464153             /* Says 'SAFE'                   */
+#define mem__SENTINEL 0x59524442          /* Says 'BDRY'                   */
+
+#define OS_Module 0x2001E
+
+typedef struct mem__rmaListstr
+{
+  struct mem__rmaListstr *next;
+  struct mem__rmaListstr *prev;
+#ifdef mem__DEBUG_MALLOC
+  int length;
+  int check;
+  int *sentinel;
+#endif
+}
+mem__rmaListstr;
+
+static BOOL mem__initedFlex;
+static BOOL mem__initedHeap;
+static int mem__currentAlloc=mem__MALLOC;
+static mem__rmaListstr *mem__rmaList;
+#ifdef mem__DEBUG_MALLOC
+  static mem__rmaListstr *mem__mallocList;
+#endif
+static BOOL mem__usedRMA;
+
+static mem_allocProc mem__userAlloc;
+static mem_freeProc mem__userFree;
+
+/*
+ * void mem_flexdInit(const char *name)
+ *
+ * Use
+ *  Initialises flex system.  If flex is already initialised, nothing
+ *  happens.  This call should be used in preference to flex_init().
+ */
+
+void mem_flexdInit(const char *name, long max)
+{
+  if (!mem__initedFlex)
+  {
+    flex_dinit(name, max);
+    atexit(flex_die);
+    mem__initedFlex=TRUE;
+  }
+}
+
+#ifdef _DLL
+void (mem_flexInit)(void) { mem_flexInit(); }
+#endif
+
+/*
+ * void mem_heapInit(void)
+ *
+ * Use
+ *  Initialises heap system.  If heap is already initialised, nothing
+ *  happens.  If flex is not initialised, it is initialised for you.  This
+ *  call should be used in preference to heap_init().  Note that unlike
+ *  earlier versioms, this call will NOT set up ArmenLib to use heap by
+ *  default.  This would be duplicating the functionality of mem_useHeap().
+ */
+
+void mem_heapInit(void)
+{
+  if (!mem__initedHeap)
+  {
+    mem_flexInit();
+    heap_init();
+    mem__initedHeap=TRUE;
+  }
+}
+
+/*
+ * void mem_useMalloc(void)
+ *
+ * Use
+ *  Makes ArmenLib use malloc() etc. for memory allocation.
+ */
+
+void mem_useMalloc(void)
+{
+  mem__currentAlloc=mem__MALLOC;
+}
+
+/*
+ * void mem_useHeap(void)
+ *
+ * Use
+ *  Makes ArmenLib use heap_alloc() etc. for memory allocation.  It is
+ *  initialised if necessary.
+ */
+
+void mem_useHeap(void)
+{
+  mem_heapInit();
+  mem__currentAlloc=mem__HEAP;
+}
+
+/*
+ * void mem_useUser(mem_allocProc alloc,mem_freeProc free)
+ *
+ * Use
+ *  Makes ArmenLib use your own user-defined memory allocation procedures.
+ *
+ * Parameters
+ *  mem_allocProc alloc == a routine to allocate a block of memory.  If a
+ *    block of sufficient size cannot be allocated, return 0.  Problems
+ *    about allocating blocks of 0 size are handled before your routine is
+ *    called.
+ *  mem_freeProc free == a routine to free a block of memory.  A valid
+ *    pointer will be passed to your routine.
+ */
+
+void mem_useUser(mem_allocProc alloc,mem_freeProc free)
+{
+  mem__currentAlloc=mem__USER;
+  mem__userAlloc=alloc;
+  mem__userFree=free;
+}
+
+/*
+ * void mem_useRMA(void)
+ *
+ * Use
+ *  Makes ArmenLib use the RMA for memory allocation.
+ */
+
+void mem_useRMA(void)
+{
+  mem__currentAlloc=mem__RMA;
+}
+
+/*
+ * void mem__tidyRMA(void)
+ *
+ * Use
+ *  Frees any blocks allocated from the RMA at the end of the program, to
+ *  avoid any problems with blocks being non-deallocatable.
+ */
+
+static void mem__tidyRMA(void)
+{
+  mem__rmaListstr *l=mem__rmaList;
+  mem__rmaListstr *m;
+  while (l!=0)
+  {
+    m=l;
+    l=m->next;
+    mem_RMAfree(m+1);
+  }
+}
+
+/*
+ * void *mem_RMAalloc(size_t size)
+ *
+ * Use
+ *  Allocates a block of memory from the relocatable module area.
+ *
+ * Parameters
+ *  size_t size == the size of the block
+ *
+ * Returns
+ *  A pointer to the block (or 0)
+ */
+
+void *mem_RMAalloc(size_t size)
+{
+  _kernel_swi_regs r;
+  mem__rmaListstr *l;
+  if (mem__usedRMA==FALSE)
+  {
+    atexit(mem__tidyRMA);
+    mem__usedRMA=TRUE;
+  }
+  r.r[0]=6;
+  r.r[3]=size+sizeof(mem__rmaListstr);
+  if (_kernel_swi(OS_Module,&r,&r))
+    return (0);
+  else
+  {
+    l=(mem__rmaListstr *)r.r[2];
+    if (mem__rmaList)
+      mem__rmaList->prev=l;
+    l->next=mem__rmaList;
+    l->prev=0;
+    mem__rmaList=l;
+    return ((void *)(l+1));
+  }
+}
+
+/*
+ * void mem_RMAfree(void *ptr)
+ *
+ * Use
+ *  Frees a block allocated using RMAalloc.
+ *
+ * Parameters
+ *  void *ptr == a pointer to the block.
+ */
+
+void mem_RMAfree(void *ptr)
+{
+  _kernel_swi_regs r;
+  mem__rmaListstr *l=((mem__rmaListstr *)(ptr))-1;
+  if (l->prev!=0)
+    l->prev->next=l->next;
+  else
+    mem__rmaList=l->next;
+  if (l->next!=0)
+    l->next->prev=l->prev;
+  r.r[0]=7;
+  r.r[2]=(int)l;
+  wimpt_noerr((os_error *)_kernel_swi(OS_Module,&r,&r));
+}
+
+#ifdef mem__DEBUG_MALLOC
+
+#define mem__PASS_TEST 1
+#define mem__PASS_DONE 0
+#define mem__PASS_BAD 2
+#define mem__PASS_DUMP 3
+
+#define mem__walkmsg(x) \
+  { \
+    if (pass==mem__PASS_DUMP) \
+      printf(x); \
+    else \
+      pass=mem__PASS_BAD; \
+  }
+
+/*
+ * static void mem__walkMalloc(char *op)
+ *
+ * Use
+ *  Part of checked malloc routines.  Checks that all allocated blocks are
+ *  behaving well.
+ *
+ * Parameters
+ *  char *op == are we allocating or deallocating?
+ */
+
+static void mem__walkMalloc(char *op)
+{
+  mem__rmaListstr *l;
+  int pass=mem__PASS_TEST;
+  while (pass!=mem__PASS_DONE)
+  {
+    l=mem__mallocList;
+    while (l)
+    {
+      if (pass==mem__PASS_DUMP)
+        printf("\n%p %-8i ",(l+1),l->length);
+      if (l->check!=mem__MAGIC)
+        mem__walkmsg("Bad block header ");
+      if (*(l->sentinel)!=mem__SENTINEL)
+        mem__walkmsg("Block overflow   ");
+      if ((int)l->next<0x8000 && l->next!=0)
+        mem__walkmsg("Bad forward link ");
+      if (l->next)
+      {
+        if (l->next->prev!=l)
+          mem__walkmsg("Link corrupted   ");
+      }
+      if (l)
+        l=l->next;
+    }
+    switch (pass)
+    {
+      case mem__PASS_BAD:
+        pass=mem__PASS_DUMP;
+        bbc_vdu(26);
+        bbc_vdu(4);
+        bbc_vdu(12);
+        bbc_vdu(14);
+        bbc_vdu(7);
+        printf("Error found in malloc chain during %s\n",op);
+        printf("  malloc block dump follows\n\n");
+        printf("Address  Length   Faults");
+             /* 12345678 12345678 */
+        break;
+      case mem__PASS_DUMP:
+        printf
+        (
+          "\n"
+          "\n"
+          "Please report this error to Straylight.\n"
+          "\n"
+          "If debugging, press SHIFT-F12 for backtrace, otherwise, press\n"
+          "any key to quit program.\n"
+        );
+        bbc_get();
+        wimpt_forceredraw();
+        exit(1);
+        break;
+      case mem__PASS_TEST:
+        pass=mem__PASS_DONE;
+        break;
+    }
+  }
+}
+
+/*
+ * void *mem__debugAlloc(size_t size)
+ *
+ * Use
+ *  malloc debugging allocation routine.
+ *
+ * Parameters
+ *  size_t size == the size of the block
+ *
+ * Returns
+ *  A pointer to the block (or 0)
+ */
+
+static void *mem__debugAlloc(size_t size)
+{
+  mem__rmaListstr *l;
+  int sent;
+  mem__walkMalloc("alloc");
+  if (l=malloc(size+sizeof(mem__rmaListstr)+4),!l)
+    return (0);
+  else
+  {
+    if (mem__mallocList)
+      mem__mallocList->prev=l;
+    l->next=mem__mallocList;
+    l->prev=0;
+    l->check=mem__MAGIC;
+    mem__mallocList=l;
+    sent=(int)(l+1)+size;
+    if (sent%4)
+      sent+=4-sent%4;
+    l->sentinel=(int *)sent;
+    l->length=size;
+    *(l->sentinel)=mem__SENTINEL;
+    return ((void *)(l+1));
+  }
+}
+
+/*
+ * void mem__debugFree(void *ptr)
+ *
+ * Use
+ *  Frees a block allocated using mem__debugAlloc
+ *
+ * Parameters
+ *  void *ptr == a pointer to the block.
+ */
+
+static void mem__debugFree(void *ptr)
+{
+  mem__rmaListstr *l=((mem__rmaListstr *)(ptr))-1;
+  mem__walkMalloc("free");
+  if (l->prev!=0)
+    l->prev->next=l->next;
+  else
+    mem__mallocList=l->next;
+  if (l->next!=0)
+    l->next->prev=l->prev;
+  free(l);
+}
+
+#endif
+
+/*
+ * void *mem_alloc(size_t size)
+ *
+ * Use
+ *  Allocates a block of memory using malloc (or heap if initialised).  If
+ *  size is zero, or allocation fails then a NULL pointer is returned.
+ *
+ * Parameters
+ *  size_t size == how big you want the block.
+ *
+ * Returns
+ *  A pointer to the block allocated.
+ */
+
+void *mem_alloc(size_t size)
+{
+  int *ptr=0;
+  if (size==0)
+    return (0);
+  size+=2*sizeof(int);
+  switch (mem__currentAlloc)
+  {
+    case mem__HEAP:
+      ptr=heap_alloc(size);
+      break;
+    case mem__MALLOC:
+    #ifdef mem__DEBUG_MALLOC
+      ptr=mem__debugAlloc(size);
+    #else
+      ptr=malloc(size);
+    #endif
+      break;
+    case mem__RMA:
+      ptr=mem_RMAalloc(size);
+      break;
+    case mem__USER:
+      ptr=mem__userAlloc(size);
+      break;
+  }
+  if (ptr==0)
+    return (0);
+  ptr[0]=mem__currentAlloc;
+  ptr[1]=size;
+  return ((void *)(ptr+2));
+}
+
+/*
+ * void mem_free(void *ptr)
+ *
+ * Purpose
+ *  Frees a block of memory.  It must have been allocated using mem_alloc().
+ *  If ptr is NULL, then mem_free() does nothing.
+ *
+ * Parameters
+ *  void *ptr == the pointer returned by mem_alloc()
+ */
+
+void mem_free(void *ptr)
+{
+  int *i=((int *)ptr)-2;
+  if (ptr==0)
+    return;
+  switch (i[0])
+  {
+    case mem__MALLOC:
+    #ifdef mem__DEBUG_MALLOC
+      mem__debugFree(i);
+    #else
+      free(i);
+    #endif
+      break;
+    case mem__HEAP:
+      heap_free(i);
+      break;
+    case mem__RMA:
+      mem_RMAfree(i);
+      break;
+    case mem__USER:
+      mem__userFree(i);
+      break;
+  }
+}
+
+/*
+ * size_t mem_sizeOfBlock(void *ptr)
+ *
+ * Use
+ *  Returns the allocated size of the block.
+ *
+ * Parameters
+ *  void *ptr == the pointer to the block
+ *
+ * Returns
+ *  The size of the block.
+ */
+
+size_t mem_sizeOfBlock(void *ptr)
+{
+  int *i=((int *)ptr)-2;
+  if (ptr==0)
+    return (0);
+  else
+    return (i[1]);
+}
+
+/*
+ * void *mem_reAlloc(void *ptr,size_t newSize)
+ *
+ * Use
+ *  Alters the size of the block given.  If the block could not be resized,
+ *  its contents are unchanged.  Note that the block may move as a result of
+ *  this call.
+ *
+ * Parameters
+ *  void *ptr == a pointer to the block.  This may be NULL, in which case,
+ *    this call behaves exactly like mem_alloc().
+ *  size_t newSize == the new size to make the block.  This may be zero, in
+ *    which case the block is freed.
+ *
+ * Returns
+ *  A pointer to the block.
+ */
+
+void *mem_reAlloc(void *ptr,size_t newSize)
+{
+  void *newPtr;
+  int size=mem_sizeOfBlock(ptr);
+  if (ptr==0)
+    return (mem_alloc(newSize));
+  if (newPtr=mem_alloc(newSize),newSize==0)
+    return (0);
+  if (newSize<size)
+    size=newSize;
+  memcpy(newPtr,ptr,size);
+  mem_free(ptr);
+  return (newPtr);
+}
+
+/*
+ * void mem_allowFlexBudge(BOOL allow)
+ *
+ * Use
+ *  A slightly more sensible way to allow flex store to be shunted around.
+ *
+ * Parameters
+ *  BOOL allow == whether you want flex store to be shifted around willy-
+ *    nilly.
+ */
+
+void mem_allowFlexBudge(BOOL allow)
+{
+  _kernel_register_slotextend(allow ? flex_budge : flex_dont_budge);
+}
diff --git a/StraySrc/Libraries/Steel/c/menu b/StraySrc/Libraries/Steel/c/menu
new file mode 100644 (file)
index 0000000..5d4867f
--- /dev/null
@@ -0,0 +1,945 @@
+/*
+ * menu
+ *
+ *  A working menu system
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "menu.h"
+#include "mem.h"
+#include "wimp.h"
+#include "werr.h"
+#include "msgs.h"
+#include "resspr.h"
+#include "event.h"
+#include "wimpt.h"
+#include "os.h"
+#include "swis.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "dll.h"
+
+#ifndef _dll_NODLL
+  extern void _dllEntry(menu__menuproc)(void *handle,char hits[]);
+  extern menu _dllEntry(menu__menumaker)(void *handle);
+#endif
+
+typedef struct menu__menustr
+{
+  int items;
+  int maxlen;
+  BOOL submenu;
+  char *indirect;
+  int indbytes;
+  wimp_menustr *syshandle;       /* This points to the actual structure,   */
+                                 /* and 1 word ahead of a back-pointer to  */
+                                 /* this structure                         */
+}
+menu__menustr;
+
+typedef struct
+{
+  event_menu_maker m;
+  menu_selectProc sel;
+  menu_helpProc help;
+  void *handle;
+}
+menu__handlerstr;
+
+static menu__handlerstr menu__instant;
+
+/*---------------------------------------------------------------------------
+
+  The syntax of menu strings is an extension of the system used by the
+  RISC_OSlib menu segment:
+
+    menu_description ::= <flags> <item> <sep> { <flags> <item> <sep> }
+    flags ::= '!' | '~' | '>' | ' ' | '+'
+    sep ::= ',' | '|'
+    item ::= <a bunch of other characters>
+
+  flags have meanings as follows:
+
+    ' ' has no effect
+    '~' shades the item
+    '>' item has a menu dbox attached
+    '!' item is ticked
+    '+' open submenu even if item is shaded
+
+---------------------------------------------------------------------------*/
+
+/*
+ * static BOOL menu__ROparse(menu m,char **p,wimp_menuitem *item)
+ *
+ * Use
+ *  Reads the next menu entry for a RISC_OSlib-style menu definition.
+ *
+ * Parameters
+ *  menu m == the menu structure that this is being added to.
+ *  char **p == pass-by-reference pointer to next item to parse.  This is
+ *    updated to point to the next item after successful termination, to the
+ *    point where an error was discovered, or to zero to indicate successful
+ *    completion of the entire menu.
+ *  wimp_menuitem *item == pointer to structure for the routine to deposit
+ *    its output.
+ *
+ * Returns
+ *  TRUE for successful termination, or FALSE to indicate an error.
+ */
+
+static BOOL menu__ROparse(menu m,char **p,wimp_menuitem *item)
+{
+  char *ind;
+  int len=0;
+  int diff;
+  wimp_menuflags f=0;
+  wimp_iconflags i=
+  (
+    (7*wimp_IFORECOL) |
+    wimp_ITEXT |
+    wimp_IVCENTRE |
+    wimp_IFILLED
+  );
+  BOOL done=FALSE;
+  wimp_menuitem *itm;
+  char *eptr;
+  item->submenu=(wimp_menustr *)-1;
+  while (!done)
+  {
+    switch (**p)
+    {
+      case '!':
+        f|=wimp_MTICK;
+        (*p)++;
+        break;
+      case ' ':
+        (*p)++;
+        break;
+      case '>':
+        f|=wimp_MSUBLINKMSG;
+        item->submenu=(wimp_menustr *)1;
+        (*p)++;
+        break;
+      case '~':
+        i|=wimp_INOSELECT;
+        (*p)++;
+        break;
+      case '+':
+        f|=wimp_MOPENSUB;
+        (*p)++;
+        break;
+      default:
+        done=TRUE;
+        break;
+    }
+  }
+  done=FALSE;
+  for (eptr=*p;*eptr!=0 && *eptr!='|' && *eptr!=',';eptr++,len++)
+    /* blank */;
+  if (len>12)
+  {
+    i|=wimp_INDIRECT;
+    if (ind=mem_reAlloc(m->indirect,m->indbytes+len+1),!ind)
+                               /* This will allocate memory if there isn't */
+                               /* any indirected workspace yet             */
+    {
+      werr
+      (
+        FALSE,
+        msgs_lookup("menuNEM:Not enough memory to construct menu.")
+      );
+      return (FALSE);
+    }
+    itm=(wimp_menuitem *)(m->syshandle+1);
+    while (itm!=item)
+    {
+      if (itm->iconflags & wimp_INDIRECT)
+      {
+        diff=itm->data.indirecttext.buffer-m->indirect;
+        if (diff<m->indbytes && diff>=0)
+          itm->data.indirecttext.buffer=ind+diff;
+      }
+      itm++;
+    }
+    m->indirect=ind;
+    ind+=m->indbytes;
+    m->indbytes+=len+1;
+    item->data.indirecttext.buffer=ind;
+    item->data.indirecttext.validstring=(char *)-1;
+    item->data.indirecttext.bufflen=len+1;
+  }
+  else
+    ind=item->data.text;
+  while (**p!=0 && **p!='|' && **p!=',')
+    *(ind++)=*((*p)++);
+  *(ind++)=0;
+  if (**p=='|')
+    f|=wimp_MSEPARATE;
+  if (!**p)
+    *p=0;
+  else
+    (*p)++;
+  item->flags=f;
+  item->iconflags=i;
+  if (len>m->maxlen)
+    m->maxlen=len;
+  m->items+=1;
+  return (TRUE);
+}
+
+/*
+ * int menu__ROitemCount(char *string)
+ *
+ * Use
+ *  Counts the number of menu items specified in a RISC_OSlib style menu
+ *  string.
+ *
+ * Parameters
+ *  char *s == pointer to the menu string
+ *
+ * Returns
+ *  The number of items specified
+ */
+
+static int menu__ROitemCount(char *s)
+{
+  int count=1;
+  if (*s=='|')
+    s++;
+  while (*s)
+  {
+    switch (*s)
+    {
+      case '|':
+      case ',':
+        count++;
+        break;
+    }
+    s++;
+  }
+  return (count);
+}
+
+/*
+ * menu menu_new(char *title,char *items)
+ *
+ * Use
+ *  Creates a menu as per the old RISC_OSlib system.
+ *
+ * Parameters
+ *  char *title == the menu title (truncated to 12 chars if necessary)
+ *  char *items == the menu item text.  Data is indirected where required.
+ *
+ * Returns
+ *  A pointer to the menu if successful, or a NULL pointer if not.
+ */
+
+menu menu_new(char *title,char *items)
+{
+  menu m;
+  int i;
+  menu *t;
+  wimp_menuitem *itm;
+  int ino=menu__ROitemCount(items);
+  if (m=mem_alloc(sizeof(menu__menustr)),!m)
+  {
+    werr(FALSE,msgs_lookup("menuNEM:Not enough memory to construct menu."));
+    return (0);
+  }
+  if (t=mem_alloc
+  (
+    sizeof(menu)+sizeof(wimp_menuhdr)+ino*sizeof(wimp_menuitem)+4
+  ),
+  !t)
+  {
+    mem_free(m);
+    werr(FALSE,msgs_lookup("menuNEM:Not enough memory to construct menu."));
+    return (0);
+  }
+  m->syshandle=(wimp_menustr *)(t+1);
+  m->indirect=0;
+  m->indbytes=0;
+  m->submenu=FALSE;
+  m->items=0;
+  m->maxlen=strlen(title);
+  strcpy(m->syshandle->hdr.title,title);
+  m->syshandle->hdr.tit_fcol=7;
+  m->syshandle->hdr.tit_bcol=2;
+  m->syshandle->hdr.work_fcol=7;
+  m->syshandle->hdr.work_bcol=0;
+  m->syshandle->hdr.height=44;
+  m->syshandle->hdr.gap=0;
+  *t=m;
+  itm=((wimp_menuitem *)(m->syshandle+1))-1;
+  for (i=0;i<ino;i++)
+  {
+    itm++;
+    if (!items)
+      werr(TRUE,msgs_lookup("menuICOU:(menu_new): Menu item undercount."));
+    if (!menu__ROparse(m,&items,itm))
+    {
+      if (m->indirect)
+        mem_free(m->indirect);
+      mem_free(m);
+      mem_free(t);
+      return (0);
+    }
+  }
+  if (items)
+    werr(TRUE,msgs_lookup("menuICOO:(menu_new): Menu item overcount."));
+  if (ino!=m->items)
+    werr(TRUE,msgs_lookup("menuIMSC:(menu_new): Menu item count mismatch."));
+  itm->flags|=wimp_MLAST;
+  m->syshandle->hdr.width=16*m->maxlen+16;
+  return (m);
+}
+
+/*
+ * wimp_menuitem *menu__itmPointer(menu m,int i)
+ *
+ * Use
+ *  Returns a pointer to the specified menu item.  Items are numbered
+ *  starting from 1.
+ *
+ * Parameters
+ *  menu m == the menu to look up
+ *  int i == the item number to find
+ *
+ * Returns
+ *  A pointer to the specified menu item
+ */
+
+static wimp_menuitem *menu__itmPointer(menu m,int i)
+{
+  return ((wimp_menuitem *)(m->syshandle+1)+(i-1));
+}
+
+/*
+ * void menu_submenu(menu main,int item,menu submenu)
+ *
+ * Use
+ *  Attaches a menu as a submenu, but it will put in a submenu warning flag,
+ *  so the user-friendly too-many-windows messages come up right!
+ *
+ * Parameters
+ *  menu main == the main menu
+ *  int item == the menu item number
+ *  menu submenu == the submenu
+ */
+
+void menu_submenu(menu main,int item,menu submenu)
+{
+  wimp_menuitem *i=menu__itmPointer(main,item);
+  if (submenu)
+  {
+    i->flags|=wimp_MSUBLINKMSG;
+    i->submenu=(wimp_menuptr)(submenu->syshandle);
+    submenu->submenu=TRUE;
+  }
+  else
+  {
+    i->flags&=~wimp_MSUBLINKMSG;
+    i->submenu=(wimp_menuptr)-1;
+  }
+}
+
+/*
+ * void menu_dispose(menu *m,BOOL recurse)
+ *
+ * Use
+ *  Kill off a menu or menu tree.  Won't work on submenus.
+ *
+ * Parameters
+ *  menu *m == pointer to menu to Domestos-ise.
+ *  BOOL recurse == do we want to kill its submenus too?
+ */
+
+void menu_dispose(menu *m,BOOL recurse)
+{
+  int i;
+  wimp_menuitem *itm=(wimp_menuitem *)((*m)->syshandle+1);
+  menu s;
+  if (recurse)
+  {
+    for (i=0;i<(*m)->items;i++);
+    {
+      if ((int)(itm->submenu)>=0x8000)
+      {
+        s=*((menu *)itm->submenu-1);
+        menu_dispose(&s,TRUE);
+      }
+      itm++;
+    }
+  }
+  if ((*m)->indirect)
+    mem_free((*m)->indirect);
+  mem_free(*m);
+}
+
+/*
+ * wimp_menustr *menu_syshandle(menu m)
+ *
+ * Use
+ *  Returns pointer to actual menu structure.
+ *
+ * Parameters
+ *  menu m == menu handle for which structure is required.
+ *
+ * Returns
+ *  A pointer to the WIMP menu structure.
+ */
+
+wimp_menustr *menu_syshandle(menu m)
+{
+  return (m->syshandle);
+}
+
+/*
+ * void menu_extend(menu m,char *items)
+ *
+ * Use
+ *  Extend the given menu by a bit.
+ *
+ * Parameters
+ *  menu m == the menu to extend
+ *  char *items == the items to tag on the end
+ */
+
+void menu_extend(menu m,char *items)
+{
+  wimp_menuitem *itm;
+  wimp_menuitem *start;
+  int i;
+  int ino=menu__ROitemCount(items);
+  menu *t=mem_reAlloc
+  (
+    (menu *)m->syshandle-1,
+    sizeof(menu)+sizeof(wimp_menuhdr)+(ino+m->items)*sizeof(wimp_menuitem)+4
+  );
+  if (!t)
+  {
+    werr(FALSE,msgs_lookup("menuNEME:Not enough memory to extend menu."));
+    return;
+  }
+  m->syshandle=(wimp_menustr *)(t+1);
+  start=itm=menu__itmPointer(m,m->items);
+  if (*items=='|')
+  {
+    itm->flags|=wimp_MSEPARATE;
+    items++;
+  }
+  for (i=0;i<ino;i++)
+  {
+    itm++;
+    if (!menu__ROparse(m,&items,itm))
+      return;
+  }
+  start->flags&=~wimp_MLAST;
+  itm->flags|=wimp_MLAST;
+  m->syshandle->hdr.width=16*m->maxlen+16;
+}
+
+/*
+ * void menu_setflags(menu m,int i,BOOL tick,BOOL shade)
+ *
+ * Use
+ *  Changes menu item properties
+ *
+ * Parameters
+ *  menu m == menu to change
+ *  int i == menu item to change
+ *  BOOL tick == tick the item
+ *  BOOL shade == shade the item
+ */
+
+void menu_setflags(menu m,int i,BOOL tick,BOOL shade)
+{
+  wimp_menuitem *itm=menu__itmPointer(m,i);
+  if (tick)
+    itm->flags|=wimp_MTICK;
+  else
+    itm->flags&=~wimp_MTICK;
+  if (shade)
+    itm->iconflags|=wimp_INOSELECT;
+  else
+    itm->iconflags&=~wimp_INOSELECT;
+}
+
+/*
+ * void menu_make_writeable(menu m,int i,char *buff,int bufflen,char *valid)
+ *
+ * Use
+ *  Makes a menu entry writable (sorry about the spelling - it's Acorn's
+ *  fault)
+ *
+ * Parameters
+ *  menu m == the menu in question
+ *  int i == the item to be handled
+ *  char *buff == where the data is to reside
+ *  int bufflen == max length of data that can be crammed into buff
+ *  char *valid == validation string (0 for none)
+ */
+
+void menu_make_writeable(menu m,int i,char *buff,int bufflen,char *valid)
+{
+  wimp_menuitem *itm=menu__itmPointer(m,i);
+  if (!valid)
+    valid=(char *)-1;
+  itm->iconflags|=wimp_INDIRECT;
+  itm->flags|=wimp_MWRITABLE;
+  itm->data.indirecttext.buffer=buff;
+  itm->data.indirecttext.bufflen=bufflen;
+  itm->data.indirecttext.validstring=valid;
+}
+
+/*
+ * void menu_make_sprite(menu m,int i,char *name)
+ *
+ * Use
+ *  Turns a menu entry into a sprite.  Utterly useless, but there you go...
+ *
+ * Parameters
+ *  menu m == the menu we're dealing with
+ *  int i == the item to sprite-ise
+ *  char *name == the sprite name
+ */
+
+void menu_make_sprite(menu m,int i,char *name)
+{
+  wimp_menuitem *itm=menu__itmPointer(m,i);
+  itm->iconflags|=wimp_INDIRECT|wimp_ISPRITE;
+  itm->iconflags&=~wimp_ITEXT;
+  itm->data.indirectsprite.name=name;
+  itm->data.indirectsprite.spritearea=resspr_area();
+  itm->data.indirectsprite.nameisname=TRUE;
+}
+
+/*
+ * void menu_redirectItem(menu m,int i,char *buff,int bufflen,char *valid)
+ *
+ * Use
+ *  Allows you to make a menu item's data point to your workspace, so you
+ *  can change the text of an item at any time.  The buffer length isn't
+ *  important.
+ *
+ * Parameters
+ *  menu m == the menu in question
+ *  int i == the item to be handled
+ *  char *buff == where the data is to reside
+ *  int bufflen == max length of data that can be crammed into buff
+ *  char *valid == validation string (0 for none)
+ */
+
+void menu_redirectItem(menu m,int i,char *buff,int bufflen,char *valid)
+{
+  wimp_menuitem *itm=menu__itmPointer(m,i);
+  if (!valid)
+    valid=(char *)-1;
+  itm->iconflags|=wimp_INDIRECT;
+  itm->data.indirecttext.buffer=buff;
+  itm->data.indirecttext.bufflen=bufflen;
+  itm->data.indirecttext.validstring=valid;
+}
+
+/*
+ * void menu_minWidth(menu m,int min)
+ *
+ * Use
+ *  Sets the minimum permissable width of a menu (in characters).  Note that
+ *  this call will not make the menu thinner than the width calculated
+ *  during menu_new or menu_extend.
+ *
+ * Parameters
+ *  menu m == the menu to change
+ *  int min == the minumum allowable width fro the menu in characters.  If
+ *    0 is passed, the width reverts to the calculated width.
+ */
+
+void menu_minWidth(menu m,int min)
+{
+  if (!min)
+    min=16*m->maxlen+16;
+  else
+  {
+    min=16*min+16;
+    if (min<m->syshandle->hdr.width)
+      return;
+  }
+  m->syshandle->hdr.width=min;
+}
+
+/*
+ * void menu_settitle(menu m,char *title)
+ *
+ * Use
+ *  Change a menu title.
+ *
+ * Parameters
+ *  menu m == the menu to change
+ *  char *title == the new title
+ */
+
+void menu_settitle(menu m,char *title)
+{
+  strncpy(m->syshandle->hdr.title,title,12);
+}
+
+/*
+ * int *menu__processHits(int hit[])
+ *
+ * Use
+ *  Processes a hit string as necessary (translates WIMP menu items to C
+ *  ones etc.)
+ *
+ * Parameters
+ *  int hit[] == PBR array to process, terminated by -1.
+ *
+ * Returns
+ *  The array
+ */
+
+static int *menu__processHits(int hit[])
+{
+  int i=0;
+  do
+    hit[i++]++;
+  while (hit[i-1]);
+  return (hit);
+}
+
+/*
+ * menu menu__menumaker(void *handle)
+ *
+ * Use
+ *  A surrogate menu maker.
+ *
+ * Parameters
+ *  void *handle == pointer to information about the real maker
+ *
+ * Returns
+ *  The menu to display
+ */
+
+_dll_static menu menu__menumaker(void *handle)
+{
+  menu__handlerstr *m=handle;
+  return ((m->m)(m->handle));
+}
+
+/*
+ * void menu__menuproc(void *handle,char hit[])
+ *
+ * Use
+ *  General menu handler for menus registered using the menu functions
+ *  rather than the standard event ones.
+ *
+ * Parameters
+ *  void *handle == pointer to the control block for this menu
+ *  char hit[] == an array of menu hits (ignored)
+ */
+
+_dll_static void menu__menuproc(void *handle,char hit[])
+{
+  menu__handlerstr *m=handle;
+  int hits[20];
+  int minusone=-1;
+  wimp_eventstr *e=wimpt_last_event();
+  hit=hit;
+  switch (event_whyMenuEvent())
+  {
+    case event_MENUSELECT:
+      if (m->sel)
+        (m->sel)(menu__processHits(e->data.menu),m->handle);
+      break;
+    case event_MENUDELETE:
+      if (m->sel)
+        (m->sel)(menu__processHits(&minusone),m->handle);
+      break;
+    case event_MENUSUBMENU:
+      if (m->sel)
+        (m->sel)(menu__processHits(e->data.msg.data.words+3),m->handle);
+      break;
+    case event_MENUHELP:
+      if (m->help)
+      {
+        wimpt_noerr(wimp_getmenustate(1,
+                                      hits,
+                                      e->data.msg.data.helprequest.m.w,
+                                      e->data.msg.data.helprequest.m.i));
+        (m->help)(menu__processHits(hits),m->handle);
+      }
+      break;
+    default:
+      werr(TRUE,msgs_lookup("menuUKNME:(menu__menuproc): "
+                            "Unknown menu event type."));
+  }
+}
+
+/*
+ * void menu_attach
+ * (
+ *   wimp_w w,
+ *   menu m,
+ *   menu_selectProc sel,
+ *   menu_helpProc help,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Basically equivalent to event_attachmenu, only it handles help requests
+ *  neatly etc.  Source code compatibility *cannot* be assured, because I
+ *  want to be able to expand this routine to cater for later changes.  I
+ *  will try to soften the blow (if any) by supplying macros that will work
+ *  with older programs, but I can't guarantee anything.
+ *
+ * Parameters
+ *  wimp_w w == the window to attach to
+ *  menu m == the menu to attach
+ *  menu_selectProc sel == procedure to handle most selection-type events
+ *  menu_helpProc help == procedure to handle help requests for the menu
+ */
+
+void menu_attach
+(
+  wimp_w w,
+  menu m,
+  menu_selectProc sel,
+  menu_helpProc help,
+  void *handle
+)
+{
+  menu__handlerstr *h=0;
+  void *old;
+  menu om;
+  event_menu_maker omm;
+  event_menu_proc omp;
+  if (m)
+  {
+    if (h=mem_alloc(sizeof(menu__handlerstr)),!h)
+    {
+      werr
+      (
+        FALSE,
+        msgs_lookup("menuNEM:Not enough memory to construct menu.")
+      );
+      return;
+    }
+    h->sel=sel;
+    h->help=help;
+    h->handle=handle;
+  }
+  event_attachedMenu(w,&om,&omm,&omp,&old);
+  if (omp==menu__menuproc)
+    mem_free(old);
+  event_attachmenu(w,m,_dllEntry(menu__menuproc),h);
+}
+
+/*
+ * void menu_attachMaker
+ * (
+ *   wimp_w w,
+ *   event_menu_maker m,
+ *   menu_selectProc sel,
+ *   menu_helpProc help,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  This routine deals with event_attachmenumaker as menu_attach deals with
+ *  event_attachmenu.
+ *
+ * Parameters
+ *  wimp_w w == the window to attach to
+ *  menu m == the menu to attach
+ *  menu_selectProc sel == procedure to handle most selection-type events
+ *  menu_helpProc help == procedure to handle help requests for the menu
+ */
+
+void menu_attachMaker
+(
+  wimp_w w,
+  event_menu_maker m,
+  menu_selectProc sel,
+  menu_helpProc help,
+  void *handle
+)
+{
+  menu__handlerstr *h=0;
+  void *old;
+  menu om;
+  event_menu_maker omm;
+  event_menu_proc omp;
+  if (m)
+  {
+    if (h=mem_alloc(sizeof(menu__handlerstr)),!h)
+    {
+      werr
+      (
+        FALSE,
+        msgs_lookup("menuNEM:Not enough memory to construct menu.")
+      );
+      return;
+    }
+    h->sel=sel;
+    h->help=help;
+    h->handle=handle;
+    h->m=m;
+  }
+  event_attachedMenu(w,&om,&omm,&omp,&old);
+  if (omp==menu__menuproc)
+    mem_free(old);
+  event_attachmenumaker(w,
+                        _dllEntry(menu__menumaker),
+                        _dllEntry(menu__menuproc),
+                        h);
+}
+
+/*
+ * void menu_open(menu m,menu_selectProc sel,menu_helpProc help,void *handle)
+ *
+ * Use
+ *  Analagous to event_openMenu().
+ *
+ * Parameters
+ *  As above.
+ */
+
+void menu_open(menu m,menu_selectProc sel,menu_helpProc help,void *handle)
+{
+  menu__instant.sel=sel;
+  menu__instant.help=help;
+  menu__instant.handle=handle;
+  event_openMenu(m,_dllEntry(menu__menuproc),&menu__instant);
+}
+
+/*
+ * void menu_make(event_menu_maker m,menu_selectProc sel,menu_helpProc help,void *handle)
+ *
+ * Use
+ *  Analagous to event_makeMenu().
+ *
+ * Parameters
+ *  As above.
+ */
+
+void menu_make(event_menu_maker m,menu_selectProc sel,menu_helpProc help,void *handle)
+{
+  menu__instant.sel=sel;
+  menu__instant.help=help;
+  menu__instant.handle=handle;
+  menu__instant.m=m;
+  event_makeMenu(_dllEntry(menu__menumaker),
+                 _dllEntry(menu__menuproc),
+                 &menu__instant);
+}
+
+/*
+ * void menu_saveHandler(wimp_w w,menu_handler *h)
+ *
+ * Use
+ *  Saves information about the menu handle for the given window in the
+ *  block specified.  This can be used *only* to restore the handler for a
+ *  window later (although it needn't be the same one).  Note too that the
+ *  window need not have to have menu handlers registered using the menu
+ *  calls, or even have any at all.
+ *
+ * Parameters
+ *  wimp_w w == the window whose menu handlers we are to save
+ *  menu_handler *h == pointer to a chunk of memory to fill in.
+ */
+
+void menu_saveHandler(wimp_w w,menu_handler *h)
+{
+  event_menu_maker mk;
+  event_menu_proc p;
+  menu m;
+  void *hand;
+  menu__handlerstr *ha;
+  event_attachedMenu(w,&m,&mk,&p,&hand);
+  if (p==_dllEntry(menu__menuproc))
+  {
+    ha=hand;
+    h->doneByMenu=TRUE;
+    h->info.m.m=m;
+    h->info.m.make=ha->m;
+    h->info.m.sel=ha->sel;
+    h->info.m.help=ha->help;
+    h->info.m.handle=ha->handle;
+  }
+  else
+  {
+    h->doneByMenu=FALSE;
+    h->info.e.m=m;
+    h->info.e.make=mk;
+    h->info.e.proc=p;
+    h->info.e.handle=hand;
+  }
+}
+
+/*
+ * void menu_restoreHandler(wimp_w w,menu_handler *h)
+ *
+ * Use
+ *  Restores handlers from a structure filled in by menu_saveHandler.
+ *
+ * Parameters
+ *  wimp_w w == the window whose handlers we are to set up.
+ *  menu_handler *h == pointer to a chunk of memory filled in correctly.
+ */
+
+void menu_restoreHandler(wimp_w w,menu_handler *h)
+{
+  if (h->doneByMenu)
+  {
+    if (h->info.m.m)
+    {
+      menu_attach(w,
+                  h->info.m.m,
+                  h->info.m.sel,
+                  h->info.m.help,
+                  h->info.m.handle);
+    }
+    else
+    {
+      menu_attachMaker(w,
+                       h->info.m.make,
+                       h->info.m.sel,
+                       h->info.m.help,
+                       h->info.m.handle);
+    }
+  }
+  else
+  {
+    if (h->info.e.m)
+      event_attachmenu(w,h->info.e.m,h->info.e.proc,h->info.e.handle);
+    else
+    {
+      event_attachmenumaker(w,
+                            h->info.e.make,
+                            h->info.e.proc,
+                            h->info.e.handle);
+    }
+  }
+}
diff --git a/StraySrc/Libraries/Steel/c/msgs b/StraySrc/Libraries/Steel/c/msgs
new file mode 100644 (file)
index 0000000..bd116e4
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * msgs.c
+ *
+ * Handling of messages files
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "os.h"
+#include "mem.h"
+#include "werr.h"
+#include "res.h"
+#include "msgs.h"
+
+/*----- Special types -----------------------------------------------------*/
+
+typedef struct msgs__node
+{
+  struct msgs__node *left;
+  struct msgs__node *right;
+  char tag[20];
+  char *message;
+}
+msgs__node;
+
+/*----- Variables ---------------------------------------------------------*/
+
+#define msgs__HASHSIZE 64
+
+static msgs__node *msgs__all[msgs__HASHSIZE];
+
+/*----- Main code ---------------------------------------------------------*/
+
+/*
+ * int msgs__hash(char *p)
+ *
+ * Use
+ *  Hashes the string pointed to by p
+ */
+
+static int msgs__hash(char *p)
+{
+  unsigned int h=0;
+  unsigned int seed=0x46bc93d5;
+  for (;*p && *p!=':';p++)
+  {
+    h=(h*(*p)) ^ seed ^ h;
+    seed=seed*3141592621ul + 271828189;
+  }
+  return ((int)h & (msgs__HASHSIZE-1));
+}
+
+/*
+ * void msgs__add(msgs__node *t,msgs__node **p)
+ *
+ * Use
+ *  Adds node t to the tree with *p as its root
+ */
+
+static void msgs__add(msgs__node *t,msgs__node **p)
+{
+  int s;
+  if (*p)
+  {
+    s=strcmp(t->tag,(*p)->tag);
+    if (s>0)
+      msgs__add(t,&(*p)->right);
+    else if (s<0)
+      msgs__add(t,&(*p)->left);
+  }
+  else
+    *p=t;
+}
+
+/*
+ * int msgs__cmp(char *a,char *b)
+ *
+ * Use
+ *  Compares a tag-and-default a with a tag b.
+ */
+
+static int msgs__cmp(char *a,char *b)
+{
+  for (;;)
+  {
+    if ((*a==':' || *a==0) && *b==0)
+      return (0);
+    else if (*a!=*b)
+      return (*a-*b);
+    a++;
+    b++;
+  }
+}
+
+/*
+ * msgs__node *msgs__find(char *tag,msgs__node *t)
+ *
+ * Use
+ *  Finds the tag in the tree pointed to by t
+ */
+
+static msgs__node *msgs__find(char *tag,msgs__node *t)
+{
+  int s;
+  if (!t)
+    return (0);
+  s=msgs__cmp(tag,t->tag);
+  if (s>0)
+    return (msgs__find(tag,t->right));
+  else if (s<0)
+    return (msgs__find(tag,t->left));
+  else
+    return (t);
+}
+
+/*
+ * void msgs__insert(msgs__node *t)
+ *
+ * Use
+ *  Inserts the given messages structure into the overall messages system.
+ *
+ * Parameters
+ *  msgs__node *t == pointer to a filled in messages structure to fit in.
+ */
+
+static void msgs__insert(msgs__node *t)
+{
+  int i=msgs__hash(t->tag);
+  t->left=t->right=0;
+  msgs__add(t,msgs__all+i);
+}
+
+/*
+ * void msgs_readfile(char *name)
+ *
+ * Use
+ *  Loads the messages file given by name into the messages area.
+ */
+
+void msgs_readfile(char *name)
+{
+  FILE *fp=res_openfile(name,"r");
+  int c;
+  enum
+  {
+    newline,
+    comment,
+    tag,
+    newalt,
+    message,
+    endoffile
+  }
+  state=newline;
+  msgs__node *t[10];
+  char *p=0;
+  int len=0;
+  int i;
+  int alts=0;
+  char msg[1024];
+
+  if (!fp)
+    return;
+
+  while (state!=endoffile)
+  {
+    c=getc(fp);
+
+    switch (state)
+    {
+      case newline:
+        if (c==';' || c=='|' || c=='#')
+          state=comment;
+        else if (c==EOF)
+          state=endoffile;
+        else if (!isspace(c))
+        {
+          alts=0;
+          t[alts]=mem_alloc(sizeof(msgs__node));
+          if (!t[alts])
+          {
+            fclose(fp);
+            werr(FALSE,
+                 msgs_lookup("msgsNEM:Not enough memory to read "
+                                     "messages file '%s'"),
+                 name);
+            return;
+          }
+          p=t[alts]->tag;
+          *p++=c;
+          state=tag;
+        }
+        break;
+
+      case comment:
+        if (c=='\n')
+          state=newline;
+        else if (c==EOF)
+          state=endoffile;
+        break;
+
+      case newalt:
+        if (c==EOF)
+        {
+          for (i=0;i<alts;i++)
+            mem_free(t[i]);
+          werr(FALSE,
+               msgs_lookup("msgsEOF:Unexpected end of file in "
+                                   "messages file '%s'"),
+               name);
+          state=endoffile;
+        }
+        else
+        {
+          t[alts]=mem_alloc(sizeof(msgs__node));
+          if (!t[alts])
+          {
+            fclose(fp);
+            for (i=0;i<alts;i++)
+              mem_free(t[i]);
+            werr(FALSE,
+                 msgs_lookup("msgsNEM:Not enough memory to read "
+                                     "messages file '%s'"),
+                 name);
+            return;
+          }
+          p=t[alts]->tag;
+          *p++=c;
+          state=tag;
+        }
+        break;
+
+      case tag:
+        if (c=='\n' || c=='/')
+        {
+          *p++=0;
+          alts++;
+          state=newalt;
+        }
+        else if (c==':')
+        {
+          *p++=0;
+          alts++;
+          len=0;
+          p=msg;
+          state=message;
+        }
+        else if (c==EOF)
+        {
+          for (i=0;i<=alts;i++)
+            mem_free(t[i]);
+          werr(FALSE,
+               msgs_lookup("msgsEOF:Unexpected end of file in "
+                                   "messages file '%s'"),
+               name);
+          state=endoffile;
+        }
+        else
+          *p++=c;
+        break;
+
+      case message:
+        if (c==EOF || c=='\n')
+        {
+          *p=0;
+          p=mem_alloc(len+1);
+          if (!p)
+          {
+            fclose(fp);
+            for (i=0;i<alts;i++)
+              mem_free(t[i]);
+            werr(FALSE,
+                 msgs_lookup("msgsNEM:Not enough memory to read "
+                                     "messages file '%s'"),
+                 name);
+            return;
+          }
+          strcpy(p,msg);
+          for (i=0;i<alts;i++)
+          {
+            t[i]->message=p;
+            msgs__insert(t[i]);
+          }
+          alts=0;
+          state=(c==EOF ? endoffile : newline);
+        }
+        else
+        {
+          *p++=c;
+          len++;
+        }
+        break;
+    }
+  }
+  fclose(fp);
+}
+
+/*
+ * void msgs_init(void)
+ *
+ * Use
+ *  Reads the messages file `Messages' into memory.
+ */
+
+void msgs_init(void)
+{
+  msgs_readfile("Messages");
+}
+
+/*
+ * char *msgs_lookup(char *tag)
+ *
+ * Use
+ *  Searches the messages for one with a given tag.
+ */
+
+char *msgs_lookup(char *tag)
+{
+  msgs__node *t=msgs__find(tag,msgs__all[msgs__hash(tag)]);
+  char *p;
+  if (t)
+    return (t->message);
+  p=tag;
+  while (*p)
+  {
+    if (*p++==':')
+      return (p);
+  }
+  return (tag);
+}
+
+/*
+ * void msgs_delete(void)
+ *
+ * Use
+ *  Removes all messages from memory.
+ */
+
+static void msgs__delTree(msgs__node *t)
+{
+  if (!t)
+    return;
+  msgs__delTree(t->left);
+  msgs__delTree(t->right);
+  mem_free(t);
+  return;
+}
+
+void msgs_delete(void)
+{
+  int i;
+  for (i=0;i<msgs__HASHSIZE;i++)
+  {
+    msgs__delTree(msgs__all[i]);
+    msgs__all[i]=0;
+  }
+}
diff --git a/StraySrc/Libraries/Steel/c/nopoll b/StraySrc/Libraries/Steel/c/nopoll
new file mode 100644 (file)
index 0000000..4460af6
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * nopoll
+ *  Provides handling for a dialogue box without polling (for error boxes
+ *  and so on
+ *
+ * v. 1.00 (30 July 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*---------------------------------------------------------------------------
+
+  Support is provided for three action buttons, here referred to as 'OK',
+  'Cancel' and 'Other'.  Fair enough?  Good.  'OK' is the default action
+  button, which may also be selected by pressing return.  Pressing escape
+  is equivalent to clicking Cancel.  The 'Other' button (good, eh?) has no
+  keyboard equivalent.  To indicate that you don't want a particular button
+  to exist, just pass -1 as the number.
+
+---------------------------------------------------------------------------*/
+
+#include "dbox.h"
+#include "wimpt.h"
+#include "coords.h"
+#include "bbc.h"
+#include "os.h"
+#include "nopoll.h"
+#include "interface.h"
+#include "sculptrix.h"
+#include "visdelay.h"
+#include "resspr.h"
+#include "swiv.h"
+
+#define OS_Mouse 0x2001C
+#define XWimpExt_Redraw 0x65783
+
+static dbox nopoll__d;
+static dbox_field nopoll__f;
+
+/*
+ * void nopoll__clickicon(dbox d,dbox_field f)
+ *
+ * Use
+ *  Clicks in a given field in a nice way
+ */
+
+static void nopoll__clickicon(dbox d,dbox_field f)
+{
+  nopoll__d=d;
+  nopoll__f=f;
+  if (wimpt_options() & 7)
+    dbox_clickicon(d,f);
+  else
+    dbox_selecticon(d,f,TRUE);
+}
+
+/*
+ * void nopoll__unclick(void)
+ *
+ * Use
+ *  Unclicks a clicked icon
+ */
+
+static void nopoll__unclick(void)
+{
+  if (wimpt_options() & 7)
+    dbox_unclick();
+  else
+    dbox_selecticon(nopoll__d,nopoll__f,FALSE);
+}
+
+/*
+ * void nopoll__mouseRectangle(wimp_w window)
+ *
+ * Use
+ *  Sets up the mouse rectangle to the limits of the window specified.
+ *
+ * Parameters
+ *  wimp_w window == the window handle
+ */
+
+static void nopoll__mouseRectangle(wimp_w window)
+{
+  wimp_wstate s;
+  wimpt_noerr(wimp_get_wind_state(window,&s));
+  wimpt_noerr((os_error *)bbc_mouserect(s.o.box.x0-wimpt_dx(),
+                            s.o.box.y0-wimpt_dy(),
+                            s.o.box.x1,
+                            s.o.box.y1));
+}
+
+/*
+ * void nopoll__freeMouse(void)
+ *
+ * Use
+ *  Frees the mouse from the current mouse rectangle.
+ */
+
+static void nopoll__freeMouse(void)
+{
+  bbc_mouserect(0,0,wimpt_scwidth()-wimpt_dx(),wimpt_scheight()-wimpt_dy());
+}
+
+/*
+ * void nopoll_showDbox(dbox d,nopoll_appearFlags flags)
+ *
+ * Use
+ *  Displays a dbox on-screen without polling the WIMP.  Useful for
+ *  copyright windows and things.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  nopoll_appearFlags flags == how you want the dbox to appear
+ */
+
+void nopoll_showDbox(dbox d,nopoll_appearFlags flags)
+{
+  wimp_w wind=dbox_syshandle(d);
+  wimp_redrawstr rdr;
+  int more=0;
+
+  switch (flags)
+  {
+    case nopoll_ASIS:
+      dbox_display(d,dbox_STATIC_LASTPOS);
+      break;
+    case nopoll_CENTRE:
+      dbox_display(d,dbox_STATIC_CENTRE);
+      break;
+    case nopoll_ONPTR:
+      dbox_display(d,dbox_STATIC_OVERPTR);
+      break;
+  }
+  rdr.w=wind;
+  wimpt_noerr(wimp_redraw_wind(&rdr,&more));
+  while (more)
+  {
+    if (wimpt_options() & wimpt_OSCULPTRIX)
+    {
+      wimpt_noerr(sculptrix_setSpriteArea(resspr_area()));
+      wimpt_noerr(sculptrix_redrawWindow(&rdr));
+    }
+    if (wimpt_options() & wimpt_OINTERFACE)
+      wimpt_noerr(interface_render3dWindow(&rdr));
+    if (wimpt_options() & wimpt_OWIMPEXT)
+      wimpt_noerr(_swix(XWimpExt_Redraw,_in(1),&rdr));
+    if (!dbox_hasTitle(d))
+      dbox_drawEmbeddedTitle(&rdr,d);
+    wimpt_noerr(wimp_get_rectangle(&rdr,&more));
+  }
+}
+
+/*
+ * int nopoll_doDbox
+ * (
+ *   dbox d,
+ *   nopoll_appearFlags flags,
+ *   dbox_field OK,
+ *   dbox_field cancel,
+ *   dbox_field other
+ * )
+ *
+ * Use
+ *  Opens a NoPoll dialogue box, continues until it gets a sensible result,
+ *  closes it, and then returns the result.
+ *
+ * Parameters
+ *  dbox d == the dialogue box you want to use for this.
+ *  nopoll_appearFlags flags == how you want the box to appear (see above)
+ *  dbox_field OK == the number of the OK button
+ *  dbox_field cancel == the number of the Cancel button
+ *  dbox_field other == the number of the Other button
+ *
+ * Returns
+ *  One of the macros defined above, depending on what the user did.
+ */
+
+int nopoll_doDbox
+(
+  dbox d,
+  nopoll_appearFlags flags,
+  dbox_field OK,
+  dbox_field cancel,
+  dbox_field other
+)
+{
+  wimp_w wind=dbox_syshandle(d);
+  wimp_wstate state;
+  wimp_icon icn;
+  wimp_box okBox={-1,-1,-1,-1};
+  wimp_box cancelBox=okBox;
+  wimp_box otherBox=okBox;
+  wimp_mousestr m;
+  coords_cvtstr crds;
+  int done=0;
+  BOOL ignoreClick=TRUE;
+  int b;
+  coords_pointstr p;
+  int key;
+  int dummy;
+  visdelay_state visstate=visdelay_suspend();
+  wimpt_noerr(wimp_get_point_info(&m));
+  nopoll_showDbox(d,flags);
+  nopoll__mouseRectangle(wind);
+  wimpt_noerr(wimp_get_wind_state(wind,&state));
+  crds.box=state.o.box;
+  crds.scx=state.o.x;
+  crds.scy=state.o.y;
+  if (OK!=-1)
+  {
+    wimpt_noerr(wimp_get_icon_info(wind,OK,&icn));
+    okBox=icn.box;
+    coords_box_toscreen(&okBox,&crds);
+  }
+  if (cancel!=-1)
+  {
+    wimpt_noerr(wimp_get_icon_info(wind,cancel,&icn));
+    cancelBox=icn.box;
+    coords_box_toscreen(&cancelBox,&crds);
+  }
+  if (other!=-1)
+  {
+    wimpt_noerr(wimp_get_icon_info(wind,other,&icn));
+    otherBox=icn.box;
+    coords_box_toscreen(&otherBox,&crds);
+  }
+  while (!done)
+  {
+    bbc_mouse(&p.x,&p.y,&b,0);
+    if ((b==1 || b==4) && !ignoreClick)
+    {
+      if (coords_withinbox(&p,&okBox))
+        done=nopoll_OK;
+      else if (coords_withinbox(&p,&cancelBox))
+        done=nopoll_CANCEL;
+      else if (coords_withinbox(&p,&otherBox))
+        done=nopoll_OTHER;
+      else
+        ignoreClick=TRUE;
+    }
+    else
+    {
+      if (b!=1 && b!=4)
+        ignoreClick=FALSE;
+      key=0;
+      dummy=0;
+      wimpt_noerr(os_byte(129,&key,&dummy));
+      if (dummy!=0)
+        key=-1;
+      switch (key)
+      {
+        case 13:
+          if (OK!=-1)
+            done=nopoll_OK;
+          break;
+        case 27:
+          if (cancel!=-1)
+            done=nopoll_CANCEL;
+          else if (OK!=-1)
+            done=nopoll_OK;
+          break;
+      }
+    }
+  }
+  visdelay_resume(visstate);
+  switch (done)
+  {
+    case nopoll_OK:
+      nopoll__clickicon(d,OK);
+      break;
+    case nopoll_CANCEL:
+      nopoll__clickicon(d,cancel);
+      break;
+    case nopoll_OTHER:
+      nopoll__clickicon(d,other);
+      break;
+  }
+  dbox_hide(d);
+  nopoll__unclick();
+  nopoll__freeMouse();
+  return (done);
+}
diff --git a/StraySrc/Libraries/Steel/c/pane b/StraySrc/Libraries/Steel/c/pane
new file mode 100644 (file)
index 0000000..70fe536
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Pane
+ *   Handles all those many problems you get with panes
+ *
+ * v. 1.100 (25 July 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wimp.h"
+#include "wimpt.h"
+#include "pane.h"
+#include "werr.h"
+#include "msgs.h"
+#include "mem.h"
+#include "win.h"
+#include <stdlib.h>
+
+typedef enum
+{
+  pane__WINDOW,
+  pane__LISTBOX
+}
+pane__paneType;
+
+typedef union
+{
+  list l;
+}
+pane__handle;
+
+typedef struct pane__paneItem
+{
+  struct pane__paneItem *next;
+  wimp_w pane;
+  pane__paneType type;
+  pane__handle handle;
+  wimp_box box;
+}
+pane__paneItem;
+
+typedef struct pane__panestr
+{
+  wimp_w tool;
+  pane__paneItem *panes;
+}
+pane__panestr;
+
+/*
+ * pane pane_create(wimp_w tool)
+ *
+ * Use
+ *  Sets up a structure for a pane, and returns a handle.
+ *
+ * Parameters
+ *  wimp_w tool == the window handle of the tool window (the one that isn't
+ *  a pane)
+ *
+ * Returns
+ *  An abstract handle to the pane.
+ */
+
+pane pane_create(wimp_w tool)
+{
+  pane newPane=(pane)mem_alloc(sizeof(pane__panestr));
+  if (newPane)
+  {
+    newPane->tool=tool;
+    newPane->panes=0;
+  }
+  else
+    werr(FALSE,msgs_lookup("paneNEM:Not enough memory to register pane."));
+  return (newPane);
+}
+
+/*
+ * void pane_addPane(pane p,wimp_w w)
+ *
+ * Use
+ *  Registers a new pane as being associated with the tool window given in 
+ *  pane_create().
+ *
+ * Parameters
+ *  pane p == the pane handle for the tool window
+ *  wimp_w w == the window handle of the new pane
+ */
+
+void pane_addPane(pane p,wimp_w w)
+{
+  pane__paneItem *new;
+  wimp_wstate ts;
+  wimp_wstate ps;
+  if (p==0)
+    return;
+  if (new=mem_alloc(sizeof(pane__paneItem)),!new)
+    return;
+  new->pane=w;
+  new->type=pane__WINDOW;
+  wimpt_noerr(wimp_get_wind_state(w,&ps));
+  wimpt_noerr(wimp_get_wind_state(p->tool,&ts));
+  new->box.x0=ps.o.box.x0-ts.o.box.x0;
+  new->box.y0=ps.o.box.y0-ts.o.box.y0;
+  new->box.x1=ps.o.box.x1-ts.o.box.x0;
+  new->box.y1=ps.o.box.y1-ts.o.box.y0;
+  new->next=p->panes;
+  p->panes=new;
+}
+
+/*
+ * void pane_addListbox(pane p,list l)
+ *
+ * Use
+ *  Adds a listbox to the tool window.  Handles things properly, so that
+ *  scroll bars and things appear at the right time.
+ *
+ * Parameters
+ *  pane p == the pane to add to
+ *  list l == the list to add
+ */
+
+void pane_addListbox(pane p,list l)
+{
+  wimp_w w=list_syshandle(l);
+  pane__paneItem *new;
+  wimp_wstate ts;
+  wimp_wstate ps;
+  list_isPane(l,p);
+  if (p==0)
+    return;
+  if (new=mem_alloc(sizeof(pane__paneItem)),!new)
+    return;
+  new->pane=w;
+  new->type=pane__LISTBOX;
+  new->handle.l=l;
+  wimpt_noerr(wimp_get_wind_state(w,&ps));
+  wimpt_noerr(wimp_get_wind_state(p->tool,&ts));
+  new->box.x0=ps.o.box.x0-ts.o.box.x0;
+  new->box.y0=ps.o.box.y0-ts.o.box.y0;
+  new->box.x1=ps.o.box.x1-ts.o.box.x0;
+  new->box.y1=ps.o.box.y1-ts.o.box.y0;
+  new->next=p->panes;
+  p->panes=new;
+}
+
+/*
+ * void pane_delete(pane p)
+ *
+ * Use
+ *  Destroys and mem_free()s the memory occupied by a pane structure.
+ *
+ * Parameters
+ *  pane p == the pane's handle
+ */
+
+void pane_delete(pane p)
+{
+  pane__paneItem *itm=p->panes;
+  pane__paneItem *i;
+  while (itm)
+  {
+    i=itm;
+    itm=i->next;
+    switch (i->type)
+    {
+      case pane__LISTBOX:
+        list_isPane(i->handle.l,0);
+        break;
+    }
+    mem_free(i);
+  }
+  mem_free(p);
+}
+
+/*
+ * void pane_removePane(pane p,wimp_w w)
+ *
+ * Use
+ *  Removes the specified pane from the structure.
+ *
+ * Parameters
+ *  pane p == the pane in question
+ *  wimp_w w == the window to remove
+ */
+
+void pane_removePane(pane p,wimp_w w)
+{
+  pane__paneItem *i=(pane__paneItem *)(&p->panes);
+  pane__paneItem *it;
+  while (i->next)
+  {
+    if (i->next->pane==w)
+    {
+      it=i->next;
+      i->next=it->next;
+      switch (it->type)
+      {
+        case pane__LISTBOX:
+          list_isPane(it->handle.l,0);
+          break;
+      }
+      mem_free(it);
+      return;
+    }
+    i=i->next;
+  }
+}
+
+/*
+ * void pane__doMove(pane p,wimp_openstr *o)
+ *
+ * Use
+ *  Moves a set of panes to the place specified.
+ *
+ * Parameters
+ *  pane p == the pane handle
+ *  wimp_openstr *o == where to put them
+ */
+
+static void pane__doMove(pane p,wimp_openstr *o)
+{
+  pane__paneItem *i=p->panes;
+  wimp_wstate state;
+  wimp_w behind;
+  behind=o->behind;
+  if (behind==-2)
+  {
+    wimpt_noerr(wimp_open_wind(o));
+    wimpt_noerr(wimp_get_wind_state(o->w,&state));
+    behind=state.o.behind;
+    i=p->panes;
+    if (behind==i->pane)
+    {
+      wimpt_noerr(wimp_get_wind_state(i->pane,&state));
+      behind=state.o.behind;
+    }
+  }
+  i=p->panes;
+  while (i)
+  {
+    wimpt_noerr(wimp_get_wind_state(i->pane,&state));
+    state.o.box.x0=o->box.x0+i->box.x0;
+    state.o.box.y0=o->box.y0+i->box.y0;
+    state.o.box.x1=o->box.x0+i->box.x1;
+    state.o.box.y1=o->box.y0+i->box.y1;
+    state.o.behind=behind;
+    behind=i->pane;
+    wimpt_noerr(wimp_open_wind(&state.o));
+    i=i->next;
+  }
+  o->behind=behind;
+  wimpt_noerr(wimp_open_wind(o));
+}
+
+/*
+ * void pane_updatePanes(pane p)
+ *
+ * Use
+ *  Updates position of panes attached to the main window after it has been 
+ *  moved.
+ *
+ * Parameters
+ *  pane p == the pane handle
+ */
+
+void pane_updatePanes(pane p)
+{
+  wimp_wstate s;
+  wimpt_noerr(wimp_get_wind_state(p->tool,&s));
+  pane__doMove(p,&s.o);
+}
+
+/*
+ * void pane_moved(pane p)
+ *
+ * Use
+ *  Asks the pane segment to reopen a pane in response to an wimp_EOPEN
+ *  event.
+ *
+ * Parameters
+ *  pane p == the pane handle
+ */
+
+void pane_moved(pane p)
+{
+  wimp_eventstr *e=wimpt_last_event();
+  if (e->e!=wimp_EOPEN || e->data.o.w!=p->tool)
+  {
+    werr
+    (
+      TRUE,
+      msgs_lookup("paneIPH:(pane_moved, caller fault): "
+                       "not a wimp_EOPEN event or with wrong pane handle.")
+    );
+    return;
+  }
+  if (wimpt_justChangedMode())
+    win_adjustBox(&e->data.o);
+  pane__doMove(p,&e->data.o);
+}
+
+/*
+ * void pane_front(pane p)
+ *
+ * Use
+ *  Moves a tool window and associated panes to the front of the screen.
+ *
+ * Parameters
+ *  pane p == the pane handle
+ */
+
+void pane_front(pane p)
+{
+  wimp_wstate s;
+  wimpt_noerr(wimp_get_wind_state(p->tool,&s));
+  s.o.behind=-1;
+  pane__doMove(p,&s.o);
+}
+
+/*
+ * void pane_close(pane p)
+ *
+ * Use
+ *  This routine will close all the windows attached to the pane structure.
+ *
+ * Parameters
+ *  pane p == the pane handle
+ */
+
+void pane_close(pane p)
+{
+  pane__paneItem *i=p->panes;
+  wimpt_noerr(wimp_close_wind(p->tool));
+  while (i)
+  {
+    wimpt_noerr(wimp_close_wind(i->pane));
+    i=i->next;
+  }
+}
diff --git a/StraySrc/Libraries/Steel/c/pointer b/StraySrc/Libraries/Steel/c/pointer
new file mode 100644 (file)
index 0000000..51dfbd5
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * pointer.c
+ *
+ * Handling of pointer-shape changing
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+
+#include "os.h"
+#include "sprite.h"
+#include "swis.h"
+#include "wimpt.h"
+#include "pointer.h"
+
+static BOOL pointer__notDefault;
+
+/*
+ * os_error *pointer__magicSpriteOp(sprite_area *a,
+ *                                  sprite _id *sid,
+ *                                  os_regset *r)
+ *
+ * Use
+ *  Performs a sprite op of the appropriate kind for the sprite area given.
+ *
+ * Parameters
+ *  sprite_area *a == the sprite area to do the op on
+ *  sprite_id *sid == the sprite id to do it to
+ *  os_regset r == other registers for the op
+ *
+ * Returns
+ *  An error or 0.
+ */
+
+static os_error *pointer__magicSpriteOp(sprite_area *a,
+                                        sprite_id *sid,
+                                        os_regset *r)
+{
+  if (a==(sprite_area *)1)
+  {
+    /* --- The WIMP sprite area --- */
+
+    r->r[0]&=~0x300;
+    r->r[2]=(int)sid->s.name;
+    return (os_swix(XWimp_SpriteOp,r));
+  }
+  else if (!a)
+  {
+    /* --- The nasty system sprite area --- */
+
+    r->r[0]&=~0x300;
+    r->r[2]=(int)sid->s.name;
+    return (os_swix(XOS_SpriteOp,r));
+  }
+  else
+  {
+    /* --- A nice user sprite area --- */
+
+    r->r[0]&=~0x300;
+    if (sid->tag)
+    {
+      r->r[0]|=0x200;
+      r->r[2]=(int)sid->s.addr;
+    }
+    else
+    {
+      r->r[0]|=0x100;
+      r->r[2]=(int)sid->s.name;
+    }
+    r->r[1]=(int)a;
+
+    return (os_swix(XOS_SpriteOp,r));
+  }
+}
+
+/*
+ * BOOL pointer__spriteExist(sprite_area *a,char *name)
+ *
+ * Use
+ *  Returns whether a named sprite exists in the given area
+ *
+ * Parameters
+ *  sprite_area *a == the sprite area
+ *  char *name == the name of the sprite to test
+ *
+ * Returns
+ *  TRUE if the sprite is there
+ */
+
+static BOOL pointer__spriteExist(sprite_area *a,char *name)
+{
+  os_regset r;
+  sprite_id sid;
+
+  sid.s.name=name;
+  sid.tag=0;
+
+  r.r[0]=40;
+  return (!pointer__magicSpriteOp(a,&sid,&r));
+}
+
+/*
+ * os_error *pointer_set_shape(sprite_area *a,sprite_id *sid,int x,int y)
+ *
+ * Use
+ *  Sets the pointer shape to be the pointer specified.  If a pointer with
+ *  name `name<dx><dy>' is found in the sprite area, that's used instead, and
+ *  the active point is scaled assuming that the original was specified in
+ *  mode-8 type coordinates.
+ *
+ * Parameters
+ *  sprite_area *a == the sprite area containing the sprite
+ *  sprite_id *sid == pointer to the sprite identifier (dumb idea)
+ *  int x,int y == coordinates (in pixels) of the hot-spot
+ */
+
+os_error *pointer_set_shape(sprite_area *a,sprite_id *sid,int x,int y)
+{
+  char buffer[15];
+  sprite_id s;
+  os_regset r;
+
+  if (!sid->tag)
+  {
+    /* --- Try and find a good match for the mode --- */
+
+    sprintf(buffer,"%s%i%i",sid->s.name,wimpt_dx(),wimpt_dy());
+    if (pointer__spriteExist(a,buffer))
+    {
+      s.s.name=buffer;
+      s.tag=0;
+      sid=&s;
+      x=(x*2)/wimpt_dx();
+      y=(y*4)/wimpt_dy();
+    }
+  }
+
+  /* --- Now set up the pointer shape --- */
+
+  r.r[0]=36;
+  r.r[3]=2;                     /* Set everything up as nicely as possible */
+  r.r[4]=x;
+  r.r[5]=y;
+  r.r[6]=r.r[7]=0;              /* No translation table, no zoom box       */
+  pointer__notDefault=TRUE;
+  return (pointer__magicSpriteOp(a,sid,&r));
+}
+
+/*
+ * void pointer_reset_shape(void)
+ *
+ * Use
+ *  Resets the pointer shape
+ */
+
+void pointer_reset_shape(void)
+{
+  if (pointer__notDefault)
+    os_cli("%pointer");
+  pointer__notDefault=FALSE;
+}
diff --git a/StraySrc/Libraries/Steel/c/prefs b/StraySrc/Libraries/Steel/c/prefs
new file mode 100644 (file)
index 0000000..72df861
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * prefs
+ *
+ * Preferences loading and saving
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "prefs.h"
+#include "os.h"
+#include "utils.h"
+#include "msgs.h"
+#include "choices.h"
+#include "res.h"
+#include "kernel.h"
+#include "werr.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#define unused(x) ((x)=(x))
+
+static prefs_prefstr *prefs__prefs;
+
+/*
+ * char *prefs__match(char *a,char *b)
+ *
+ * Use
+ *  Checks to see if the first part of a matches b.  If it does, it returns
+ *  the rest of a.
+ *
+ * Parameters
+ *  char *a == an input string
+ *  char *b == a keyword
+ *
+ * Returns
+ *  The part of a following b, or NULL if no match
+ */
+
+static char *prefs__match(char *a,char *b)
+{
+  if (!*a)
+    return (0);
+  while (*b)
+  {
+    if (tolower(*(a++))!=tolower(*(b++)))
+      return (0);
+  }
+  while (*a==' ')
+    a++;
+  if (*a=='=')
+    a++;
+  while (*a==' ')
+    a++;
+  return (a);
+}
+
+/*
+ * char *prefs_readBoolean(char *tag,char *args,void *handle)
+ *
+ * Use
+ *  Reads a Boolean variable (i.e. one that can be either TRUE or FALSE).
+ */
+
+char *prefs_readBoolean(char *tag,char *args,void *handle)
+{
+  unused(tag);
+  if (utils_caselessCmp(args,"true")==0)
+    *(BOOL *)handle=TRUE;
+  else if (utils_caselessCmp(args,"false")==0)
+    *(BOOL *)handle=FALSE;
+  else
+    return (msgs_lookup("prefsRBB:Bad boolean variable '%s' at line %i (must be 'true' or 'false')"));
+  return (0);
+}
+
+/*
+ * char *prefs_writeBoolean(char *tag,FILE *fp,void *handle)
+ *
+ * Use
+ *  Writes a Boolean variable to the preferences file.
+ */
+
+char *prefs_writeBoolean(char *tag,FILE *fp,void *handle)
+{
+  fprintf(fp,"%s=%s\n",tag,*(BOOL *)handle ? "true" : "false");
+  return (0);
+}
+
+/*
+ * char *prefs_readNumeric(char *tag,char *args,void *handle)
+ *
+ * Use
+ *  Reads a signed integer from the preferences file.
+ */
+
+char *prefs_readNumeric(char *tag,char *args,void *handle)
+{
+  unused(tag);
+  sscanf(args,"%d",(int *)handle);
+  return (0);
+}
+
+/*
+ * char *prefs_writeNumeric(char *tag,FILE *fp,void *handle)
+ *
+ * Use
+ *  Writes a signed integer to the preferences file.
+ */
+
+char *prefs_writeNumeric(char *tag,FILE *fp,void *handle)
+{
+  fprintf(fp,"%s=%i\n",tag,*(int *)handle);
+  return (0);
+}
+
+/*
+ * char *prefs_readString(char *tag,char *args,void *handle)
+ *
+ * Use
+ *  Reads a string from the preferences file.  It is assumed that the buffer
+ *  pointed to by handle is big enough.
+ */
+
+char *prefs_readString(char *tag,char *args,void *handle)
+{
+  char *p;
+  unused(tag);
+  if (*args=='\'')
+  {
+    for (p=++args;*p && *p!='\'';p++)
+      /* blank! */;
+    *p=0;
+  }
+  strcpy((char *)handle,args);
+  return (0);
+}
+
+/*
+ * char *prefs_writeString(char *tag,FILE *fp,void *handle)
+ *
+ * Use
+ *  Writes a signed integer to the preferences file.
+ */
+
+char *prefs_writeString(char *tag,FILE *fp,void *handle)
+{
+  fprintf(fp,"%s='%s'\n",tag,(char *)handle);
+  return (0);
+}
+
+/*
+ * void prefs_preferences(prefs_prefstr *p)
+ *
+ * Use
+ *  Sets up the prefs system to use the preferences definition specified.
+ *  'p' should be a pointer to an array of prefs_prefstrs, terminated by an
+ *  entry with a null 'tag'.  The preferences file created will be called
+ *  'Choices' in the current application's directory (<App$Dir>.Choices).
+ *
+ * Parameters
+ *  prefs_prefstr *p == pointer to an array of preferences definitions
+ */
+
+void prefs_preferences(prefs_prefstr *p)
+{
+  prefs__prefs=p;
+}
+
+/*
+ * void prefs_read(void)
+ *
+ * Use
+ *  Reads preferences from the preferences file.
+ */
+
+void prefs_read(void)
+{
+  FILE *fp;
+  int i;
+  int line=0;
+  char buff[256];
+  char *p;
+  char *args;
+  char *error;
+  char *preffile=choices_name("Choices",FALSE);
+
+  /* --- Make sure the Preferences file exists --- *
+   *
+   * If we can't find the Preferences, we leave the user's buffer unchanged
+   * to allow defaults
+   */
+
+  if (!res_fileExists(preffile))
+    return;
+
+  /* --- Open the Preferences file --- */
+
+  fp=fopen(preffile,"r");
+  if (!fp)
+  {
+    werr(FALSE,
+         msgs_lookup("prefsERP:Error reading preferences.  "
+                     "Assuming default preferences."));
+    return;
+  }
+
+  /* --- Read the file a line at a time and parse it --- */
+
+  while (fgets(buff,256,fp))
+  {
+    /* --- Bump line count for error messages --- */
+
+    line++;
+
+    /* --- Strip leading spaces --- */
+
+    for (p=buff;isspace(*p);p++)
+      /* blank! */;
+
+    /* --- fgets leaves a return on the end -- kill it --- */
+
+    utils_ctermToNterm(p);
+
+    /* --- Do something about the line --- */
+
+    switch (*p)
+    {
+      /* --- Discard blank lines and comments --- */
+      case 0:
+      case ';':
+        break;
+
+      /* --- Otherwise find the parser for this variable and call it --- */
+
+      default:
+        for (i=0;prefs__prefs[i].tag;i++)
+        {
+          if (args=prefs__match(p,prefs__prefs[i].tag),args)
+          {
+            if (prefs__prefs[i].read)
+            {
+              if (error=prefs__prefs[i].read(prefs__prefs[i].tag,
+                                             args,
+                                             prefs__prefs[i].handle),error)
+              {
+                werr(FALSE,error,prefs__prefs[i].tag,line);
+                fclose(fp);
+                return;
+              }
+            }
+            break;
+          }
+        }
+        break;
+    }
+  }
+  fclose(fp);
+}
+
+/*
+ * void prefs_write(void)
+ *
+ * Use
+ *  Writes preferences out to disk.
+ */
+
+void prefs_write(void)
+{
+  int i;
+  FILE *fp=fopen(choices_name("Choices",TRUE),"w");
+  char *error;
+
+  /* --- Complain if we can't write the file --- */
+
+  if (!fp)
+  {
+    werr(FALSE,
+         msgs_lookup("prefsEWP:Error writing preferences: '%s'"),
+         _kernel_last_oserror()->errmess);
+    return;
+  }
+
+  /* --- Go through the entries one by one calling the output fns --- */
+
+  for (i=0;prefs__prefs[i].tag;i++)
+  {
+    if (prefs__prefs[i].tag[0]==';' || prefs__prefs[i].tag[0]=='\n')
+      fprintf(fp,"%s",prefs__prefs[i].tag);
+    else if (!prefs__prefs[i].write)
+      /* blank! */;
+    else if (error=prefs__prefs[i].write(prefs__prefs[i].tag,
+                                         fp,
+                                         prefs__prefs[i].handle),error)
+    {
+      werr(FALSE,error,prefs__prefs[i].tag);
+      fclose(fp);
+      return;
+    }
+  }
+
+  /* --- Close the file and exit --- */
+
+  fclose(fp);
+  return;
+}
diff --git a/StraySrc/Libraries/Steel/c/print b/StraySrc/Libraries/Steel/c/print
new file mode 100644 (file)
index 0000000..2754d6e
--- /dev/null
@@ -0,0 +1,269 @@
+/************************************************************************/
+/* © Acorn Computers Ltd, 1992.                                         */
+/*                                                                      */
+/* This file forms part of an unsupported source release of RISC_OSLib. */
+/*                                                                      */
+/* It may be freely used to create executable images for saleable       */
+/* products but cannot be sold in source form or as an object library   */
+/* without the prior written consent of Acorn Computers Ltd.            */
+/*                                                                      */
+/* If this file is re-distributed (even if modified) it should retain   */
+/* this copyright notice.                                               */
+/*                                                                      */
+/************************************************************************/
+
+/*
+ * Title: print.c
+ * Purpose: provide printer driver access
+ * History: IDJ: 06-Feb-92: prepared for source release
+ *
+ */
+
+
+#include "os.h"
+#include "print.h"
+
+
+
+/*                          Printer Driver SWI's                             */
+
+#define Info          0x00080140
+#define SetInfo       0x00080141
+#define CheckFeatures 0x00080142
+#define PageSize      0x00080143
+#define SetPageSize   0x00080144
+#define SelectJob     0x00080145
+#define CurrentJob    0x00080146
+/* FontSWI goes in here - only the font manager may use this */
+#define EndJob        0x00080148
+#define AbortJob      0x00080149
+#define Reset         0x0008014A
+#define GiveRectangle 0x0008014B
+#define DrawPage      0x0008014C
+#define GetRectangle  0x0008014D
+#define CancelJob     0x0008014E
+#define ScreenDump    0x0008014F
+#define SelectIllus   0x00080153
+
+#pragma no_check_stack
+
+
+os_error * print_info(print_infostr *i)
+{ 
+   os_regset r;
+   os_error *e;
+
+   e = os_swix(Info, &r);
+
+   i->version     = r.r[0] & 0xFFFF;
+   i->identity    = r.r[0] >> 16;
+   i->xres        = r.r[1];
+   i->yres        = r.r[2];
+   i->features    = r.r[3];
+   i->description = (char*)r.r[4];
+   i->xhalf       = r.r[5];
+   i->yhalf       = r.r[6];
+   i->number      = r.r[7];
+
+   return(e);
+}
+
+
+os_error * print_setinfo(print_infostr *i)
+{ 
+   os_regset r;
+
+   r.r[1] = i->xres;
+   r.r[2] = i->yres;
+   r.r[3] = i->features;
+   r.r[5] = i->xhalf;
+   r.r[6] = i->yhalf;
+   r.r[7] = i->number;
+
+   return(os_swix(SetInfo, &r));
+}
+
+
+os_error * print_checkfeatures(int mask,int value)
+{ 
+   os_regset r;
+
+   r.r[0] = mask;
+   r.r[1] = value;
+
+   return(os_swix(CheckFeatures, &r));
+}
+
+
+os_error * print_pagesize(print_pagesizestr *p)
+{ 
+   os_regset r;
+   os_error *e;
+
+   e = os_swix(PageSize, &r);
+
+   p->xsize = r.r[1];
+   p->ysize = r.r[2];
+   p->bbox.x0 = r.r[3];
+   p->bbox.y0 = r.r[4];
+   p->bbox.x1 = r.r[5];
+   p->bbox.y1 = r.r[6];
+
+   return(e);
+}
+
+
+os_error * print_setpagesize(print_pagesizestr *p)
+{ 
+   os_regset r;
+
+   r.r[1] = p->xsize;
+   r.r[2] = p->ysize;
+   r.r[3] = p->bbox.x0;
+   r.r[4] = p->bbox.y0;
+   r.r[5] = p->bbox.x1;
+   r.r[6] = p->bbox.y1;
+
+   return(os_swix(SetPageSize, &r));
+}
+
+
+os_error * print_selectjob(int job,char *title, int *oldjobp)
+{ 
+   os_regset r;
+   os_error *e;
+
+   r.r[0] = job;
+   r.r[1] = (int)title;
+
+   e = os_swix(SelectJob,&r);
+
+   *oldjobp = r.r[0];
+
+   return(e);
+}
+
+
+os_error * print_currentjob(int *curjobp)
+{ 
+   os_regset r;
+   os_error *e;
+
+   e = os_swix(CurrentJob,&r);
+
+   *curjobp = r.r[0];
+
+   return(e);
+}
+
+
+os_error * print_endjob(int job)
+{ 
+   os_regset r;
+
+   r.r[0] = job;
+   return os_swix(EndJob,&r);
+}
+
+
+os_error * print_abortjob(int job)
+{ 
+   os_regset r;
+
+   r.r[0] = job;
+   return os_swix(AbortJob,&r);
+}
+
+
+os_error * print_canceljob(int job)
+{ 
+   os_regset r;
+
+   r.r[0] = job;
+   return os_swix(CancelJob,&r);
+}
+
+
+os_error * print_reset(void)
+{ 
+   os_regset r;
+   return os_swix(Reset,&r);
+}
+
+
+os_error *print_giverectangle(int ident, print_box *area,
+                              print_transmatstr *trans,
+                              print_positionstr *posn, int bgcol)
+{ 
+   os_regset r;
+
+   r.r[0] = ident;
+   r.r[1] = (int)area;
+   r.r[2] = (int)trans;
+   r.r[3] = (int)posn;
+   r.r[4] = bgcol;
+
+   return os_swix(GiveRectangle,&r);
+}
+
+
+os_error * print_drawpage(int copies,int sequ,char *page,
+                          print_box *clip,int *more, int *ident)
+{ 
+   os_regset r;
+   os_error *e;
+
+   r.r[0] = copies;     /* number of copies                      */
+   r.r[1] = (int)clip;  /* where to return clip rectangle        */
+   r.r[2] = sequ;       /* pages sequence number within document */
+   r.r[3] = (int)page;  /* 'real' page number as a string        */
+
+   e = os_swix(DrawPage, &r);
+
+   *more = r.r[0];      /* number of copies left to do   */
+   *ident = r.r[2];     /* rectangle identification word */
+
+   return(e);
+}
+
+
+os_error * print_getrectangle(print_box *clip, int *more, int *ident)
+{ 
+   os_regset r;
+   os_error *e;
+
+   r.r[1] = (int)clip;  /* where to return clip rectangle        */
+
+   e = os_swix(GetRectangle, &r);
+
+   *more = r.r[0];      /* number of copies left to do   */
+   *ident = r.r[2];     /* rectangle identification word */
+
+   return(e);
+}
+
+
+os_error * print_screendump(int job)
+{ 
+   os_regset r;
+
+   r.r[0] = job;
+   return os_swix(ScreenDump,&r);
+}
+
+
+os_error * print_selectillustration(int job, char *title, int *oldjobp)
+{ 
+   os_regset r;
+   os_error  *e;
+
+   r.r[0] = job;
+   r.r[1] = (int)title;
+   e = os_swix(SelectIllus, &r);
+
+   *oldjobp = r.r[0];
+   return (e);
+}
+
+#pragma check_stack
+
diff --git a/StraySrc/Libraries/Steel/c/res b/StraySrc/Libraries/Steel/c/res
new file mode 100644 (file)
index 0000000..0e5be32
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * res
+ *
+ * Access to resources
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include "os.h"
+#include "swiv.h"
+#include "swis.h"
+#include "wimpt.h"
+#include "res.h"
+#include "buffer.h"
+
+static char res__prefix[40];
+
+/*
+ *
+ * void res_init(char *progname)
+ *
+ * Use
+ *  Sets up res to use a certain path for resources.  Mainly for
+ *  compatibility with older applications.
+ *
+ * Parameters
+ *  char *progname == the program name (sets up path as <progname$Dir>)
+ */
+
+void res_init(char *progname)
+{
+  sprintf(res__prefix,"<%s$Dir>",progname);
+}
+
+/*
+ * void res_setPrefix(char *prefix)
+ *
+ * Use
+ *  Sets up a full prefix for resources.  This means you can keep resources
+ *  in separate directories.
+ *
+ * Parameters
+ *  char *prefix == the prefix
+ */
+
+void res_setPrefix(char *prefix)
+{
+  strcpy(res__prefix,prefix);
+}
+
+/*
+ * BOOL res_fileExists(char *name)
+ *
+ * Use
+ *  Informs the caller if a given file exists
+ *
+ * Parameters
+ *  char *name == the name of the file
+ *
+ * Returns
+ *  TRUE if the file really does exist
+ */
+
+BOOL res_fileExists(char *name)
+{
+  os_filestr f;
+  f.action=17;
+  f.name=name;
+  if (os_file(&f))
+    return (FALSE);
+  return (!!f.action);
+}
+
+/*
+ * BOOL res__trySuffix(char *name)
+ *
+ * Use
+ *  Tries to find a file with a possible WIMP-style mode suffix (24,23,22
+ *  etc.)  If it did, it updates the name in the caller's buffer, and
+ *  returns TRUE.  Otherwise, the name is preserved, and it returns FALSE.
+ */
+
+static BOOL res__trySuffix(char *name)
+{
+  char *suff;
+  char *end;
+  if (wimpt_getVersion()>=300)
+  {
+    end=name+strlen(name);
+    wimpt_noerr(wimp_readsysinfo(2,(int *)&suff));
+    strcat(name,suff);
+    if (res_fileExists(name))
+      return (TRUE);
+    *end=0;
+  }
+  if (res_fileExists(name))
+    return (TRUE);
+  return (FALSE);
+}
+
+/*
+ * char *res__findCountryName(void)
+ *
+ * Use
+ *  Returns the name of the current country.  If the current country is
+ *  unknown, try the UK.
+ */
+
+static char *res__findCountryName(void)
+{
+  char *buffer=buffer_find();
+  int country=_swi(OS_Byte,_inr(0,2)+_return(1),240,0,255);
+  int len;
+  if (_swi(OS_ServiceCall,
+           _inr(1,4)+_out(5)+_return(1),
+           0x43,2,country,buffer,
+           &len)==1)
+    return ("UK");
+  else
+  {
+    buffer[len]=0;
+    return (buffer);
+  }
+}
+
+/*
+ * int res_findname(const char *resname,char *buf)
+ *
+ * Use
+ *  Returns a full pathname for the resource file as given in the buffer.
+ *  This is for compatibility reasons.  If I was writing this fresh, I
+ *  would return a pointer to an internal static object, but Acorn know
+ *  best...
+ *
+ *  Some new functionality has been added.  It will look for files first in
+ *  the directory set up using res_init or res_setPrefix, and then in the
+ *  'Resources' subdirectory.  If neither is present, then the name returned
+ *  is in the main application directory.
+ *
+ *  Also, under RISC OS 3, it will search for files with mode prefixes, so
+ *  you can use multiple sprite files for different resolutions.  Isn't this
+ *  fun!
+ *
+ * Parameters
+ *  const char *resname == the leafname of the resource file.
+ *  char *buf == where to put the result.
+ *
+ * Returns
+ *  TRUE for compatibility with the Acorn version.  What good it does, I
+ *  don't know.  This is in all a very odd routine indeed.
+ */
+
+int res_findname(const char *resname,char *buf)
+{
+  sprintf(buf,"%s.Resources.%s",res__prefix,resname);
+  if (res__trySuffix(buf))
+    return (TRUE);
+  sprintf(buf,
+          "%s.Resources.%s.%s",
+          res__prefix,
+          res__findCountryName(),
+          resname);
+  if (res__trySuffix(buf))
+    return (TRUE);
+  sprintf(buf,
+          "%s.Resources.UK.%s",
+          res__prefix,
+          resname);
+  if (res__trySuffix(buf))
+    return (TRUE);
+  sprintf(buf,"%s.%s",res__prefix,resname);
+  if (res__trySuffix(buf))
+    return (TRUE);
+  sprintf(buf,"%s.%s",res__prefix,resname);
+  return (TRUE);
+}
+
+/*
+ * char *res_name(const char *resname)
+ *
+ * Use
+ *  Translates the name given as for res_findname and returns a pointer to
+ *  the translated string
+ */
+
+char *res_name(const char *resname)
+{
+  char *buffer=buffer_find();
+  res_findname(resname,buffer);
+  return (buffer);
+}
+
+/*
+ * FILE *res_openfile(const char *resname,const char *mode)
+ *
+ * Use
+ *  Opens a resource file in a given ANSI mode.  It does this without the
+ *  odd adding on of numbers to the end that the Acorn one does (I hope!)
+ *
+ * Parameters
+ *  const char *resname == leafname of file to open
+ *  const char *mode == pointer to ANSI mode string
+ *
+ * Returns
+ *  A standard ANSI-type FILE pointer.
+ */
+
+FILE *res_openfile(const char *resname,const char *mode)
+{
+  return (fopen(res_name(resname),mode));
+}
diff --git a/StraySrc/Libraries/Steel/c/resspr b/StraySrc/Libraries/Steel/c/resspr
new file mode 100644 (file)
index 0000000..1c7b2b9
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * resspr.c
+ *
+ * Loading sprites
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+
+#include "os.h"
+#include "resspr.h"
+#include "mem.h"
+#include "msgs.h"
+#include "werr.h"
+#include "res.h"
+
+static sprite_area *resspr__area=(sprite_area *)1;
+
+/*
+ * void resspr_init(void)
+ *
+ * Use
+ *  Loads the applications `Sprites' file into memory.
+ */
+
+void resspr_init(void)
+{
+  os_filestr f;
+  int size;
+
+  /* --- Find the file and it's length --- */
+
+  f.name=res_name("Sprites");
+  f.action=17;
+  if (os_file(&f) || f.action!=1)
+    return;
+
+  /* --- Create a buffer the right size --- *
+   *
+   * The sprite file size may not be word aligned -- cope with this.
+   */
+
+  size=(f.start+7) & ~3;
+  resspr__area=mem_alloc(size);
+  if (!resspr__area)
+  {
+    werr(FALSE,msgs_lookup("ressprNEM:Not enough memory to load sprites."));
+    exit(0);
+  }
+
+  /* --- Load the sprites into memory --- */
+
+  resspr__area->size=size;
+  f.action=16;
+  f.loadaddr=((int)resspr__area)+4;
+  f.execaddr=0;
+  os_file(&f);
+}
+
+/*
+ * sprite_area *resspr_area(void)
+ *
+ * Use
+ *  Returns the address of the application's sprite area.
+ */
+
+sprite_area *resspr_area(void)
+{
+  return (resspr__area);
+}
diff --git a/StraySrc/Libraries/Steel/c/saveas b/StraySrc/Libraries/Steel/c/saveas
new file mode 100644 (file)
index 0000000..636d933
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * saveas
+ *  Handler for a save dbox under new dbox system
+ *
+ * v. 1.00 (9 August 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wimp.h"
+#include "wimpt.h"
+#include "win.h"
+#include "dbox.h"
+#include "help.h"
+#include "saveas.h"
+#include "fileicon.h"
+#include "stddbox.h"
+#include "msgs.h"
+#include "template.h"
+#include "werr.h"
+
+static dbox saveas__db;
+static int saveas__filetype;
+static xfersend_saveproc saveas__saveproc;
+static xfersend_sendproc saveas__sendproc;
+static xfersend_printproc saveas__printproc;
+static void *saveas__handle;
+static int saveas__estsize;
+static char *saveas__title;
+static BOOL saveas__xfer;
+
+#define saveas__FILEICON 1
+#define saveas__FILENAME 2
+#define saveas__OK 0
+
+/*
+ * BOOL saveas__raw(dbox d,wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Raw event handler for the save as dialogue box.
+ *
+ * Parameters
+ *  dbox d == the saveas dialogue box
+ *  wimp_eventstr *e == the current wimp event
+ *  void *handle == the caller's handle
+ */
+
+static BOOL saveas__raw(dbox d,wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  char name[256];
+  switch (e->e)
+  {
+    case wimp_EBUT:
+      if (e->data.but.m.bbits==wimp_BDRAGLEFT)
+      {
+        dbox_getfield(d,saveas__FILENAME,name,256);
+        saveas__xfer=TRUE;
+        xfersend
+        (
+          saveas__filetype,
+          name,
+          saveas__estsize,
+          saveas__saveproc,
+          saveas__sendproc,
+          saveas__printproc,
+          e,
+          handle
+        );
+        handled=TRUE;
+      }
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void saveas
+ * (
+ *   char *title,
+ *   char *name,
+ *   int filetype,
+ *   int estsize,
+ *   xfersend_saveproc saveproc,
+ *   xfersend_sendproc sendproc,
+ *   xfersend_printproc printproc,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Creates and handles a save as dialogue box (even saving your data for
+ *  you!).
+ *
+ * Parameters
+ *  char *title == the title of the dialogue box.
+ *  char *name == the default filename for the box.
+ *  int filetype == the filetype of the data to be sent.
+ *  int estsize == the estimated file size.
+ *  xfersend_saveproc saveproc == function to save the data.
+ *  xfersend_sendproc sendproc == function to export data to another
+ *    application (RAM transfer).
+ *  xfersend_printproc printproc == function to print data.
+ *  void *handle == your handle to the data (or anything else!)
+ */
+
+void saveas
+(
+  char *title,
+  char *name,
+  int filetype,
+  int estsize,
+  xfersend_saveproc saveproc,
+  xfersend_sendproc sendproc,
+  xfersend_printproc printproc,
+  void *handle
+)
+{
+  BOOL stop=FALSE;
+  int index;
+  BOOL dotYet;
+  char fname[256];
+  saveas__title=title;
+  saveas__filetype=filetype;
+  saveas__estsize=estsize;
+  saveas__saveproc=saveproc;
+  saveas__sendproc=sendproc;
+  saveas__printproc=printproc;
+  saveas__handle=handle;
+  if (template_exists("save"))
+  {
+    if (saveas__db=dbox_create("save"),saveas__db==0)
+      return;
+  }
+  else
+  {
+    if (saveas__db=dbox_create("xfer_send"),saveas__db==0)
+      return;
+  }
+  xfersend_close_on_xfer(TRUE,dbox_syshandle(saveas__db));
+  win_settitle(dbox_syshandle(saveas__db),"%s",saveas__title);
+  dbox_setfield(saveas__db,saveas__FILENAME,"%s",name);
+  fileicon(dbox_syshandle(saveas__db),
+           saveas__FILEICON,
+           saveas__filetype,
+           name);
+  dbox_rawEventHandler(saveas__db,saveas__raw,saveas__handle);
+  dbox_display(saveas__db,FALSE);
+  while (!stop)
+  {
+    switch (dbox_fillin(saveas__db))
+    {
+      case dbox_CLOSE:
+        stop=TRUE;
+        break;
+      case dbox_HELP:
+        if (help_wasHelp())
+        {
+          help_startHelp();
+          help_addLine
+          (
+            msgs_lookup("saveasHM:This is the %s dialogue box."),
+            saveas__title
+          );
+          switch (dbox_helpField())
+          {
+            case saveas__FILEICON:
+              help_addLine(msgs_lookup
+              (
+                "saveasFIH:Drag this icon to a Filer window or "
+                                   "another application to save the file."
+              ));
+              break;
+          }
+          help_readFromIcon();
+          help_endHelp();
+        }
+        break;
+      case saveas__OK:
+        if (wimpt_options() & 7)
+          dbox_clickicon(saveas__db,saveas__OK);
+        dbox_getfield(saveas__db,saveas__FILENAME,fname,256);
+        dotYet=FALSE;
+        for (index=0;fname[index]!=0;index++)
+        {
+          if (fname[index]=='.')
+            dotYet=TRUE;
+        }
+        if (!dotYet)
+        {
+          if (wimpt_options() & 7)
+          {
+            note(msgs_lookup("saveasDI:To save, drag icon to a "
+                                                    "directory viewer."));
+            dbox_unclick();
+          }
+          else
+          {
+            werr(FALSE,msgs_lookup("saveasDI:To save, drag icon to a "
+                                                    "directory viewer."));
+          }
+        }
+        else
+        {
+          saveas__xfer=FALSE;
+          stop=saveas__saveproc(fname,saveas__handle);
+          if (dbox_wasAdjustClick() || !stop)
+          {
+            if (wimpt_options() & 7)
+              dbox_unclick();
+            stop=FALSE;
+          }
+          else
+          {
+            dbox_hide(saveas__db);
+            if (wimpt_options() & 7)
+              dbox_unclick();
+          }
+        }
+        break;
+    }
+  }
+  xfersend_close_on_xfer(FALSE,0);
+  dbox_delete(saveas__db);
+}
+
+/*
+ * BOOL saveas_file_is_safe(void)
+ *
+ * Use
+ *  Informs caller if the file is going to a safe home.
+ *
+ * Returns
+ *  TRUE if the file is 'safe' - i.e. on disk
+ */
+
+BOOL saveas_file_is_safe(void)
+{
+  if (saveas__xfer)
+    return (xfersend_file_is_safe());
+  else
+   return (TRUE);
+}
diff --git a/StraySrc/Libraries/Steel/c/scroller b/StraySrc/Libraries/Steel/c/scroller
new file mode 100644 (file)
index 0000000..f7054d3
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * scroller.c
+ *
+ * Scrolling text in an icon
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "scroller.h"
+
+#include "steel.h"
+#include "bbc.h"
+#include "msgs.h"
+#include "werr.h"
+
+typedef struct scroller__str
+{
+  wimp_w w;              /* Window handle of scroller */
+  wimp_i i;             /* icon Handle */
+  char *string;                 /* Scrolling Message */
+  char *initText;       /* Start Message */
+  int index;            /* Index into actual string */
+  int chars;            /* Printable string index */
+  int initIndent;       /* X indent for initial message */
+  int speed;            /* Speed of scroll */
+  int cspeed;           /* Current speed of scroll */
+  int counter;          /* Current value of delay */
+  wimp_box box;                 /* Icon bounding box */
+  int baseline;                 /* Y Position of message */
+  int len;              /* Length of printable string */
+  int cfg;              /* Current foreground colour */
+  int fg :4;            /* Defualt foreground colour */
+  int bg :4;            /* Defualt background colour */
+  int pixel :8;                 /* Current pixel offset */
+  BOOL started :1;      /* Have we wrapped around? */
+}
+scroller__str;
+
+#define max2(x,y) ((x)>(y) ? (x) : (y))
+#define min2(x,y) ((x)<(y) ? (x) : (y))
+
+/* Display the entire string - used for redraw events */
+
+static void scroller__display(scroller s,char *p)
+{
+  int col;
+  while (*p)
+  {
+    if (*p=='[')
+    {
+      switch (*++p)
+      {
+        case 'C':
+          sscanf(p+1,"%i",&col);
+          wimp_setcolour(col);
+          break;
+        case 'c':
+          wimp_setcolour(s->fg);
+          break;
+      }
+      while (*p++!=']') ;
+    }
+    else
+      bbc_vdu(*p++);
+  }
+}
+
+/* Calculate the length of the string, without control codes */
+
+static int scroller__length(char *p)
+{
+  int i=0;
+  while (*p)
+  {
+    if (*p=='[')
+    {
+      while (*p++!=']') ;
+    }
+    else
+      i++,p++;
+  }
+  return (i);
+}
+
+/* Redraw the icon */
+
+void scroller_redraw(scroller s,wimp_redrawstr *r)
+{
+  int ox,oy;
+  int dx=wimpt_dx(),dy=wimpt_dy();
+  ox=r->box.x0-r->scx;
+  oy=r->box.y1-r->scy;
+
+  /* Does icon bounding box intersect with graphics window */
+
+  if ( !( ox+s->box.x0 <= r->g.x1-dx &&
+          oy+s->box.y0 <= r->g.y1-dy &&
+          ox+s->box.x1-dx >= r->g.x0 &&
+          oy+s->box.y1-dy >= r->g.y0))
+    return;
+
+  /* Yes -- Set graphics window to insection */
+
+  bbc_gwindow(max2(ox+s->box.x0,r->g.x0),
+              max2(oy+s->box.y0,r->g.y0),
+              min2(ox+s->box.x1,r->g.x1)-dx,
+              min2(oy+s->box.y1,r->g.y1)-dy);
+
+  wimp_setcolour(s->bg | 0x80);
+  bbc_clg();
+  wimp_setcolour(s->fg);
+
+  if (s->started)
+  {
+    bbc_move(ox+s->box.x1-16*(s->chars+s->len)-s->pixel,oy+s->baseline);
+    scroller__display(s,s->string);
+  }
+  else
+  {
+    bbc_move(ox+s->box.x1-16*s->chars-s->pixel-s->initIndent,oy+s->baseline);
+    bbc_stringprint(s->initText);
+  }
+  bbc_move(ox+s->box.x1-16*s->chars-s->pixel,oy+s->baseline);
+  scroller__display(s,s->string);
+
+  bbc_gwindow(r->g.x0,
+              r->g.y0,
+              r->g.x1-dx,
+              r->g.y1-dy);
+}
+
+/* Called on idle events to do the scroll */
+
+static void scroller__idles(void *handle)
+{
+  scroller s=handle;
+  wimp_redrawstr r;
+  BOOL more;
+  int ox,oy;
+  if (s->counter)
+  {
+    s->counter--;
+    return;
+  }
+  s->pixel+=s->cspeed;
+  if (s->pixel>16)
+  {
+    s->pixel&=0x0f;
+    s->index++;
+    s->chars++;
+    if (!s->string[s->index])
+    {
+      s->index=0;
+      s->chars=0;
+      s->started=1;
+    }
+    if (s->string[s->index]=='[')
+    {
+      switch (s->string[++s->index])
+      {
+        case 'D':
+          sscanf(s->string+s->index+1,"%i",&s->counter);
+          while (s->string[s->index++]!=']') ;
+          s->pixel-=s->speed;
+          return;
+        case 'C':
+          sscanf(s->string+s->index+1,"%i",&s->cfg);
+          while (s->string[s->index++]!=']') ;
+          break;
+        case 'c':
+          while (s->string[s->index++]!=']') ;
+          s->cfg=s->fg;
+          break;
+        case 'S':
+          s->pixel-=s->cspeed;
+          sscanf(s->string+s->index+1,"%i",&s->cspeed);
+          while (s->string[s->index++]!=']') ;
+          s->pixel+=s->cspeed;
+          break;
+        case 's':
+          s->pixel-=s->cspeed;
+          s->cspeed=s->speed;
+          s->pixel+=s->cspeed;
+          while (s->string[s->index++]!=']') ;
+          break;
+      }
+    }
+  }
+  r.box=s->box;
+  r.box.x0+=s->cspeed;
+  wimp_blockcopy(s->w,&r.box,s->box.x0,s->box.y0);
+  r.box.x0=r.box.x1-s->cspeed;
+  r.w=s->w;
+  wimp_update_wind(&r,&more);
+  ox=r.box.x0-r.scx + s->box.x1-s->pixel;
+  oy=r.box.y1-r.scy + s->baseline;
+  while (more)
+  {
+    wimp_setcolour(s->bg);
+    bbc_rectanglefill(ox,oy-28,16,28);
+    wimp_setcolour(s->cfg);
+    bbc_move(ox,oy);
+    bbc_vdu(s->string[s->index]);
+    wimp_get_rectangle(&r,&more);
+  }
+}
+
+/* Create a new sroller */
+
+scroller scroller_create(dbox d,
+                         dbox_field f,
+                         char *string,
+                         char *initial,
+                         int startDelay)
+{
+  scroller s=mem_alloc(sizeof(scroller__str));
+  wimp_icon i;
+  if (!s)
+  {
+    werr(FALSE,msgs_lookup("scrlNEM:Not enough memory for scrolltext"));
+    return (FALSE);
+  }
+  s->w=dbox_syshandle(d);
+  s->i=f;
+  s->string=string;
+  s->index=s->chars=-1;
+  s->pixel=16;
+  s->counter=startDelay;
+  s->speed=s->cspeed=2;
+  s->started=0;
+  wimpt_noerr(wimp_get_icon_info(s->w,f,&i));
+  s->box=i.box;
+  s->len=scroller__length(string);
+  s->initText=initial;
+  s->initIndent=((i.box.x1-i.box.x0)/2+(strlen(s->initText)*8));
+  s->fg=s->cfg=(i.flags >> 24) & 0x0f;
+  s->bg=(i.flags >> 28) & 0x0f;
+  s->baseline=s->box.y1-(s->box.y1-s->box.y0-32)/2-4;
+  return (s);
+}
+
+void scroller_speed(scroller s,int speed)
+{
+  s->speed=s->cspeed=speed;
+}
+
+void scroller_go(scroller s)
+{
+  win_addIdleClaimer(scroller__idles,2,s);
+}
+
+void scroller_destroy(scroller s)
+{
+  win_removeIdleClaimer(scroller__idles,s);
+  mem_free(s);
+}
diff --git a/StraySrc/Libraries/Steel/c/sprite b/StraySrc/Libraries/Steel/c/sprite
new file mode 100644 (file)
index 0000000..3f1c147
--- /dev/null
@@ -0,0 +1,916 @@
+/************************************************************************/
+/* © Acorn Computers Ltd, 1992.                                         */
+/*                                                                      */
+/* This file forms part of an unsupported source release of RISC_OSLib. */
+/*                                                                      */
+/* It may be freely used to create executable images for saleable       */
+/* products but cannot be sold in source form or as an object library   */
+/* without the prior written consent of Acorn Computers Ltd.            */
+/*                                                                      */
+/* If this file is re-distributed (even if modified) it should retain   */
+/* this copyright notice.                                               */
+/*                                                                      */
+/************************************************************************/
+
+/*
+ * Title  : c.sprite
+ * Purpose: provide access to RISC OS sprite facilities
+ * History: IDJ: 07-Feb-92: prepared for source release
+ *
+ */
+
+
+#include <stddef.h>
+#include "h.os"
+
+#include "h.sprite"
+
+
+/* Basic primitive used by sprite_xxx calls */
+
+#define OS_SpriteOp 0x2E
+
+#define ScreenSave            2
+#define ScreenLoad            3
+
+#define ReadAreaCB            8  /* *SInfo */
+#define ClearSprites          9  /* *SNew */
+#define LoadSpriteFile        10 /* *SLoad <filename> */
+#define MergeSpriteFile       11 /* *SMerge <filename> */
+#define SaveSpriteFile        12 /* *SSave <filename> */
+#define ReturnName            13
+#define GetSprite             14 /* *SGet <n> */
+#define CreateSprite          15
+#define GetSpriteUserCoords   16
+
+#define SelectSprite          24 /* *SChoose <n> [<m>] */
+#define DeleteSprite          25 /* *SDelete <n> */
+#define RenameSprite          26 /* *SRename */
+#define CopySprite            27
+#define PutSprite             28
+#define CreateMask            29
+#define RemoveMask            30
+#define InsertRow             31
+#define DeleteRow             32
+#define FlipAboutXAxis        33
+#define PutSpriteUserCoords   34
+#define AppendSprite          35
+#define SetPointerShape       36
+
+#define ReadSpriteSize        40
+#define ReadPixelColour       41
+#define WritePixelColour      42
+#define ReadPixelMask         43
+#define WritePixelMask        44
+#define InsertCol             45
+#define DeleteCol             46
+#define FlipAboutYAxis        47
+#define PlotMask              48
+#define PlotMaskUserCoords    49
+
+#define PlotMaskScaled        50
+#define PaintCharScaled       51
+#define PutSpriteScaled       52
+#define PutSpriteGreyScaled   53
+#define RemoveLeftHandWastage 54
+#define PlotMaskTransformed   55
+#define PutSpriteTransformed  56
+#define InsertDeleteRows      57
+#define InsertDeleteColumns   58
+
+#define SwitchOutputToSprite  60
+#define SwitchOutputToMask    61
+#define ReadSaveAreaSize      62
+
+#define BadReasonCode         63
+
+#pragma no_check_stack
+
+static os_error * sprite__op(os_regset *r)
+{
+  return os_swix(OS_SpriteOp, r);
+}
+
+
+/******** Simple operations, use no sprite area, no name/sprite pointer ***/
+
+
+os_error * sprite_screensave(const char *filename, sprite_palflag palflag)
+{
+   os_regset r;
+   os_error *result;
+   r.r[0] = 2;
+ /*r.r[1] unused */  
+   r.r[2] = (int) filename;
+   r.r[3] = palflag;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_screenload(const char *filename)
+{
+   os_regset r;
+   os_error *result;
+   r.r[0] = 3;
+ /*r.r[1] unused */  
+   r.r[2] = (int) filename;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+/****** Operations on either system/user area, no name/sprite pointer *****/
+
+static void setfromarea(int op, sprite_area *area, os_regset *r)
+{
+   if (area == sprite_mainarea)
+   {
+      r->r[0] = op;
+ /*   r->r[1] unused */
+   }
+   else
+   {
+      r->r[0] = op + 256;
+      r->r[1] = (int) area;
+   }
+}
+
+
+void sprite_area_initialise(sprite_area *area, int length)
+{
+   area->size    = length; /* No SpriteOp to do this ! */
+   area->number  = 0;
+   area->sproff  = 16;
+   area->freeoff = 16;
+}
+
+
+os_error * sprite_area_readinfo(sprite_area *area, sprite_area *resultarea)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(8, area, &r);
+   result = sprite__op(&r);
+   if (result == NULL) /* Only return result if no error */
+   {
+      resultarea->size    = r.r[2];
+      resultarea->number  = r.r[3];
+      resultarea->sproff  = r.r[4];
+      resultarea->freeoff = r.r[5];
+   }
+   return result;
+}
+
+
+os_error * sprite_area_reinit(sprite_area *area)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(9, area, &r);
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_area_save(sprite_area *area, const char *filename)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(12, area, &r);
+   r.r[2] = (int) filename;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_area_load(sprite_area *area, const char *filename)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(10, area, &r);
+   r.r[2] = (int) filename;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_area_merge(sprite_area *area, const char *filename)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(11, area, &r);
+   r.r[2] = (int) filename;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_getname(sprite_area *area, void *buffer,
+                          int *length, int index)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(13, area, &r);
+   r.r[2] = (int) buffer;
+   r.r[3] = *length;
+   r.r[4] = index;
+   result = sprite__op(&r);
+   if (result == NULL) /* Only return result if no error */
+   {
+      *length = r.r[3];
+   }
+   return result;
+}
+
+
+os_error * sprite_get(sprite_area *area, char *name, sprite_palflag palflag)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(14, area, &r);
+   r.r[2] = (int) name;
+   r.r[3] = palflag;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_get_rp(sprite_area *area, char *name, sprite_palflag palflag,
+                         sprite_ptr *resultaddress)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(14, area, &r);
+   r.r[2] = (int) name;
+   r.r[3] = palflag;
+   result = sprite__op(&r);
+   if (result == NULL) /* Only return result if no error */
+   {
+      *resultaddress = (void *) r.r[2];
+   }
+   return result;
+}
+
+
+os_error * sprite_get_given(sprite_area *area, char *name,
+                            sprite_palflag palflag,
+                            int x0, int y0, int x1, int y1)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(16, area, &r);
+   r.r[2] = (int) name;
+   r.r[3] = palflag;
+   r.r[4] = x0;
+   r.r[5] = y0;
+   r.r[6] = x1;
+   r.r[7] = y1;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_get_given_rp(sprite_area *area, char *name,
+                               sprite_palflag palflag, int x0, int y0,
+                               int x1, int y1, sprite_ptr *resultaddress)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(16, area, &r);
+   r.r[2] = (int) name;
+   r.r[3] = palflag;
+   r.r[4] = x0;
+   r.r[5] = y0;
+   r.r[6] = x1;
+   r.r[7] = y1;
+   result = sprite__op(&r);
+   if (result == NULL) /* Only return result if no error */
+   {
+      *resultaddress = (void *) r.r[2];
+   }
+   return result;
+}
+
+
+os_error * sprite_create(sprite_area *area, char *name, sprite_palflag palflag,
+                         int width, int height, int mode)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(15, area, &r); /* NB. Not all done in numeric order !! */
+   r.r[2] = (int) name;
+   r.r[3] = palflag;
+   r.r[4] = width;
+   r.r[5] = height;
+   r.r[6] = mode;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_create_rp(sprite_area *area, char *name,
+                            sprite_palflag palflag,
+                            int width, int height, int mode,
+                            sprite_ptr *resultaddress)
+{
+   os_regset r;
+   os_error *result;
+   setfromarea(15, area, &r); /* NB. Not all done in numeric order !! */
+   r.r[2] = (int) name;
+   r.r[3] = palflag;
+   r.r[4] = width;
+   r.r[5] = height;
+   r.r[6] = mode;
+   result = sprite__op(&r);
+   if (result == NULL) /* Only return result if no error */
+   {
+      /* spriteop 15 doesn't return pointer to sprite in r2, so....*/
+      /* select the sprite just created (gets its address in r2) */
+      setfromarea(24, area, &r);
+      r.r[2] = (int)name;
+      result = sprite__op(&r);
+      if (result == NULL)
+         *resultaddress = (void *) r.r[2];
+   }
+   return result;
+}
+
+
+/*********** Operations on system/user area, name/sprite pointer **********/
+
+/* Modify op if using sprite address is address, not name */
+/* But only if using own sprite area */
+
+static void setfromtag(int op, sprite_area *area, sprite_id *spr, os_regset *r)
+{
+   if (area == sprite_mainarea)
+   {
+      r->r[0] = op;
+   /* r->r[1] unused */
+   }
+   else
+   {
+      r->r[1] = (int) area;
+      if ((spr->tag) == sprite_id_addr)
+      {
+         r->r[0] = 512 + op;
+         r->r[2] = (int) (spr->s.addr);
+      }
+      else
+      {
+         r->r[0] = 256 + op;
+         r->r[2] = (int) (spr->s.name);
+      }
+   }
+}
+
+
+os_error * sprite_readinfo(sprite_area *area, sprite_id *spr,
+                           sprite_info *resultinfo)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(40, area, spr, &r);
+   result = sprite__op(&r);
+   if (result == NULL) /* Only return result if no error */
+   {
+      resultinfo->width  = r.r[3];
+      resultinfo->height = r.r[4];
+      resultinfo->mask   = r.r[5];
+      resultinfo->mode   = r.r[6];
+   }
+   return result;
+}
+
+
+os_error * sprite_select(sprite_area *area, sprite_id *spr)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(24, area, spr, &r);
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_select_rp(sprite_area *area, sprite_id *spr,
+                            sprite_ptr *resultaddress)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(24, area, spr, &r);
+   result = sprite__op(&r);
+   if (result == NULL) /* Only return result if no error */
+   {
+      *resultaddress = (void *) r.r[2];
+   }
+   return result;
+}
+
+
+os_error * sprite_delete(sprite_area *area, sprite_id *spr)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(25, area, spr, &r);
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_rename(sprite_area *area, sprite_id *spr, char *newname)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(26, area, spr, &r);
+   r.r[3] = (int) newname;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_copy(sprite_area *area, sprite_id *spr, char *copyname)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(27, area, spr, &r);
+   r.r[3] = (int) copyname;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_put(sprite_area *area, sprite_id *spr, int gcol_action)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(28, area, spr, &r);
+   r.r[5] = gcol_action;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_put_given(sprite_area *area, sprite_id *spr, int gcol_action,
+                            int x, int y)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(34, area, spr, &r);
+   r.r[3] = x;
+   r.r[4] = y;
+   r.r[5] = gcol_action;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_put_scaled(sprite_area *area, sprite_id *spr,
+                             int gcol_action,
+                             int x, int y,
+                             sprite_factors *factors,
+                             sprite_pixtrans *pixtrans)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(52, area, spr, &r);
+   r.r[3] = x;
+   r.r[4] = y;
+   r.r[5] = gcol_action;
+   r.r[6] = (int) factors;
+   r.r[7] = (int) pixtrans;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_put_greyscaled(sprite_area *area, sprite_id *spr,
+                                 int x, int y,
+                                 sprite_factors *factors,
+                                 sprite_pixtrans *pixtrans)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(53, area, spr, &r);
+   r.r[3] = x;
+   r.r[4] = y;
+   r.r[5] = 0;                   /* doesn't support mask or gcol action */
+   r.r[6] = (int) factors;
+   r.r[7] = (int) pixtrans;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_put_mask(sprite_area *area, sprite_id *spr)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(48, area, spr, &r);
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_put_mask_given(sprite_area *area, sprite_id *spr,
+                                 int x, int y)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(49, area, spr, &r);
+   r.r[3] = x;
+   r.r[4] = y;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_put_mask_scaled(sprite_area *area, sprite_id *spr,
+                                  int x, int y,
+                                  sprite_factors *factors)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(50, area, spr, &r);
+   r.r[3] = x;
+   r.r[4] = y;
+   r.r[6] = (int) factors;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_put_char_scaled(char ch,
+                                  int x, int y,
+                                  sprite_factors *factors)
+{
+   os_regset r;
+   os_error *result;
+   r.r[0] = 51;
+   r.r[1] = ch;
+   r.r[3] = x;
+   r.r[4] = y;
+   r.r[6] = (int) factors;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_create_mask(sprite_area *area, sprite_id *spr)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(29, area, spr, &r);
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_remove_mask(sprite_area *area, sprite_id *spr)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(30, area, spr, &r);
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_insert_row(sprite_area *area, sprite_id *spr, int row)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(31, area, spr, &r);
+   r.r[3] = row;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_delete_row(sprite_area *area, sprite_id *spr, int row)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(32, area, spr, &r);
+   r.r[3] = row;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_insert_column(sprite_area *area, sprite_id *spr, int column)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(45, area, spr, &r);
+   r.r[3] = column;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_delete_column(sprite_area *area, sprite_id *spr, int column)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(46, area, spr, &r);
+   r.r[3] = column;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_flip_x(sprite_area *area, sprite_id *spr)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(33, area, spr, &r);
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_flip_y(sprite_area *area, sprite_id *spr)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(47, area, spr, &r);
+   result = sprite__op(&r);
+   return result;
+}
+
+os_error * sprite_readsize(sprite_area *area, sprite_id *spr,
+                           sprite_info *resultinfo)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(40, area, spr, &r);
+   result = sprite__op(&r);
+ /* now copy returned data */
+   resultinfo->width = r.r[3] ;
+   resultinfo->height = r.r[4] ;
+   resultinfo->mask = r.r[5] ;
+   resultinfo->mode = r.r[6] ;
+   return result;
+}
+
+os_error * sprite_readpixel(sprite_area *area, sprite_id *spr, int x, int y,
+                            sprite_colour *resultcolour)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(41, area, spr, &r);
+   r.r[3] = x;
+   r.r[4] = y;
+   result = sprite__op(&r);
+   if (result == NULL) /* Only return result if no error */
+   {
+      resultcolour->colour = r.r[5];
+      resultcolour->tint   = r.r[6];
+   }
+   return result;
+}
+
+
+os_error * sprite_writepixel(sprite_area *area, sprite_id *spr, int x, int y,
+                            sprite_colour *colour)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(42, area, spr, &r);
+   r.r[3] = x;
+   r.r[4] = y;
+   r.r[5] = colour->colour;
+   r.r[6] = colour->tint;
+   result = sprite__op(&r);
+   return result;
+}
+
+
+os_error * sprite_readmask(sprite_area *area, sprite_id *spr, int x, int y,
+                           sprite_maskstate *resultmaskstate)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(43, area, spr, &r);
+   r.r[3] = x;
+   r.r[4] = y;
+   result = sprite__op(&r);
+   if (result == NULL) /* Only return result if no error */
+   {
+      *resultmaskstate = r.r[5];
+   }
+   return result;
+}
+
+
+os_error * sprite_writemask(sprite_area *area, sprite_id *spr, int x, int y,
+                            sprite_maskstate *maskstate)
+{
+   os_regset r;
+   os_error *result;
+   setfromtag(44, area, spr, &r);
+   r.r[3] = x;
+   r.r[4] = y;
+   r.r[5] = (int) (*maskstate); /* Use pointer here for consistent interface */
+   result = sprite__op(&r);
+   return result;
+}
+
+os_error *sprite_restorestate(sprite_state state)
+{
+   os_regset r;
+   os_error *result;
+
+   r.r[0] = state.r[0];
+   r.r[1] = state.r[1];
+   r.r[2] = state.r[2];
+   r.r[3] = state.r[3];
+
+   result = sprite__op(&r);
+   return result;
+}
+
+os_error *sprite_outputtosprite(sprite_area *area, sprite_id *id,
+                                int *save_area, sprite_state *state)
+{
+   os_regset r;
+   os_error *result;
+
+   setfromtag(0x3c, area, id, &r);
+   r.r[3] = (int) save_area;
+
+   result = sprite__op(&r);
+   if (result == NULL)
+   {
+      state->r[0] = r.r[0];
+      state->r[1] = r.r[1];
+      state->r[2] = r.r[2];
+      state->r[3] = r.r[3];
+   }
+   return result;
+}
+
+os_error *sprite_outputtomask(sprite_area *area, sprite_id *id,
+                              int *save_area, sprite_state *state)
+{
+   os_regset r;
+   os_error *result;
+
+   setfromtag(0x3d, area, id, &r);
+   r.r[3] = (int) save_area;
+
+   result = sprite__op(&r);
+   if (result == NULL)
+   {
+     state->r[0] = r.r[0];
+     state->r[1] = r.r[1];
+     state->r[2] = r.r[2];
+     state->r[3] = r.r[3];
+   }
+   return result;
+}
+
+os_error *sprite_outputtoscreen(int *save_area, sprite_state *state)
+{
+   os_regset r;
+   os_error *result;
+
+   r.r[0] = 0x3c;
+   r.r[2] = 0;
+   r.r[3] = (int)save_area;
+  
+   result = sprite__op(&r);
+   if (result == NULL)
+   {
+     state->r[0] = r.r[0];
+     state->r[1] = r.r[1];
+     state->r[2] = r.r[2];
+     state->r[3] = r.r[3];
+   }
+   return result;
+
+}
+
+os_error *sprite_sizeof_spritecontext(sprite_area *area, sprite_id *id,
+                                      int *size)
+{
+   os_regset r;
+   os_error *result;
+
+   setfromtag(0x3e, area, id, &r);
+
+   result = sprite__op(&r);
+
+   if (result == NULL)
+     *size = r.r[3];
+
+   return result;
+}
+  
+
+os_error *sprite_sizeof_screencontext(int *size)
+{
+   os_regset r;
+   os_error *result;
+
+   r.r[0] = 0x3e;
+   r.r[2] = 0;
+
+   result = sprite__op(&r);
+
+   if (result == NULL)
+     *size = r.r[3];
+
+   return result;
+}
+
+os_error *sprite_removewastage(sprite_area *area, sprite_id *id)
+{
+   os_regset r;
+   os_error *result;
+
+   setfromtag(0x36, area, id, &r);
+   
+   result = sprite__op(&r);
+
+   return result;
+}
+
+os_error *sprite_change_size (sprite_area *area, 
+                              sprite_id *id, 
+                              BOOL rows, 
+                              int at, 
+                              int number)
+{ 
+   os_regset reg_set;
+   setfromtag (rows? InsertDeleteRows: InsertDeleteColumns, area, id, &reg_set);
+   reg_set.r [3] = at; 
+   reg_set.r [4] = number;
+   return sprite__op (&reg_set);
+}
+
+os_error *sprite_put_mask_trans (sprite_area *area, 
+                                 sprite_id *id, 
+                                 sprite_box *box, 
+                                 sprite_transmat *trans_mat)
+{ 
+   os_regset reg_set;
+   setfromtag (PlotMaskTransformed, area, id, &reg_set);
+   reg_set.r [3] = box == NULL? 0: 1 << 1;
+   reg_set.r [4] = (int) box;
+   reg_set.r [6] = (int) trans_mat;
+   return sprite__op (&reg_set);
+}
+
+os_error *sprite_put_mask_pgm (sprite_area *area, 
+                               sprite_id *id, 
+                               sprite_box *box, 
+                               sprite_pgm *pgm)
+{ 
+   os_regset reg_set;
+   setfromtag (PlotMaskTransformed, area, id, &reg_set);
+   reg_set.r [3] = (box == NULL? 0: 1 << 1) | (1 << 0);
+   reg_set.r [4] = (int) box;
+   reg_set.r [6] = (int) pgm;
+   return sprite__op (&reg_set);
+}
+
+os_error *sprite_put_trans (sprite_area *area, 
+                            sprite_id *id, 
+                            int gcol_action, 
+                            sprite_box *box,
+                            sprite_transmat *trans_mat, 
+                            sprite_pixtrans *pix_trans)
+{ 
+   os_regset reg_set;
+   setfromtag (PutSpriteTransformed, area, id, &reg_set);
+   reg_set.r [3] = box == NULL? 0: 1 << 1;
+   reg_set.r [4] = (int) box;
+   reg_set.r [5] = gcol_action;
+   reg_set.r [6] = (int) trans_mat;
+   reg_set.r [7] = (int) pix_trans;
+   return sprite__op (&reg_set);
+}
+
+os_error *sprite_put_pgm (sprite_area *area, 
+                          sprite_id *id, 
+                          int gcol_action, 
+                          sprite_box *box,
+                          sprite_pgm *pgm, 
+                          sprite_pixtrans *pix_trans)
+{ 
+   os_regset reg_set;
+   setfromtag (PutSpriteTransformed, area, id, &reg_set);
+   reg_set.r [3] = (box == NULL? 0: 1 << 1) | (1 << 0);
+   reg_set.r [4] = (int) box;
+   reg_set.r [5] = gcol_action;
+   reg_set.r [6] = (int) pgm;
+   reg_set.r [7] = (int) pix_trans;
+   return sprite__op (&reg_set);
+}
+
+#pragma check_stack
+
+/* end of c.sprite */
diff --git a/StraySrc/Libraries/Steel/c/stddbox b/StraySrc/Libraries/Steel/c/stddbox
new file mode 100644 (file)
index 0000000..5f37ccd
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * stddbox
+ *
+ * Some standard Straylight dboxes.
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "dbox.h"
+#include "nopoll.h"
+#include "bbc.h"
+#include "stddbox.h"
+#include "werr.h"
+#include "win.h"
+#include "wimpt.h"
+#include "msgs.h"
+#include "saveas.h"
+#include "help.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#define stddbox__WARNING_TITLE 0
+#define stddbox__WARNING_MESSAGE 5
+#define stddbox__WARNING_OK 4
+#define stddbox__WARNING_CANCEL 3
+
+#define stddbox__NOTE_TITLE 2
+#define stddbox__NOTE_MESSAGE 0
+#define stddbox__NOTE_OK 1
+
+#define stddbox__WRITE_OK 0
+#define stddbox__WRITE_WRITE 1
+
+#define stddbox__SAVEWARN_TITLE 0
+#define stddbox__SAVEWARN_MESSAGE 5
+#define stddbox__SAVEWARN_CANCEL 3
+#define stddbox__SAVEWARN_SAVE 4
+#define stddbox__SAVEWARN_REMOVE 7
+
+#define stddbox__PROGINFO_TITLE 0
+#define stddbox__PROGINFO_NAME 7
+#define stddbox__PROGINFO_PURPOSE 5
+#define stddbox__PROGINFO_AUTHOR 3
+#define stddbox__PROGINFO_VERSION 1
+
+static xfersend_saveproc stddbox__save;
+static BOOL stddbox__saved;
+
+/*
+ * BOOL warning(char *okMsg,char *warn,...)
+ *
+ * Use
+ *  Pops up a warning box, with a Cancel button and a default action button
+ *  with your own text in it.
+ *
+ * Parameters
+ *  char *okMsg == what to put in the default action button
+ *  char *warn == the warning message (printf()-style format string)
+ *
+ * Returns
+ *  TRUE if the user chose the OK button.
+ */
+
+BOOL warning(char *okMsg,char *warn,...)
+{
+  dbox warndb=dbox_create("warning");
+  va_list ap;
+  int clicked;
+  char msg[256];
+  va_start(ap,warn);
+  vsprintf(msg,warn,ap);
+  va_end(ap);
+  if (!warndb)
+    return FALSE;
+  win_settitle
+  (
+    dbox_syshandle(warndb),
+    msgs_lookup("stddbWARN:Warning from %s"),
+    wimpt_programname()
+  );
+  dbox_setfield(warndb,stddbox__WARNING_MESSAGE,msg);
+  dbox_setfield(warndb,stddbox__WARNING_OK,okMsg);
+  if (!dbox_hasTitle(warndb))
+    dbox_setEmbeddedTitle(warndb,stddbox__WARNING_TITLE,FALSE);
+  werr_bleepy();
+  clicked=nopoll_doDbox
+  (
+    warndb,
+    nopoll_CENTRE,
+    stddbox__WARNING_OK,
+    stddbox__WARNING_CANCEL,
+    -1
+  );
+  dbox_delete(warndb);
+  return (clicked==nopoll_OK);
+}
+
+/*
+ * void note(char *notemsg,...)
+ *
+ * Use
+ *  Displays a small note on the screen, so you can tell the user that he
+ *  has done something silly, etc.  A lot nicer than old werr().
+ *
+ * Parameters
+ *  char *notemsg == the note (printf()-style format string)
+ */
+
+void note(char *notemsg,...)
+{
+  dbox notedb=dbox_create("note");
+  va_list ap;
+  char msg[256];
+  va_start(ap,notemsg);
+  vsprintf(msg,notemsg,ap);
+  va_end(ap);
+  if (!notedb)
+    return;
+  win_settitle
+  (
+    dbox_syshandle(notedb),
+    msgs_lookup("stddbNOTE:Note from %s"),
+    wimpt_programname()
+  );
+  dbox_setfield(notedb,stddbox__NOTE_MESSAGE,msg);
+  if (!dbox_hasTitle(notedb))
+    dbox_setEmbeddedTitle(notedb,stddbox__NOTE_TITLE,FALSE);
+  nopoll_doDbox(notedb,nopoll_ONPTR,stddbox__NOTE_OK,-1,-1);
+  dbox_delete(notedb);
+}
+
+/*
+ * BOOL writable
+ * (
+ *   char *title,
+ *   char *deflt,
+ *   char *result,
+ *   stddbox_writableHandler proc,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Opens a dialogue box for the user to input a string.  Needs the
+ *  'writable' template.
+ *
+ * Parameters
+ *  char *title == the title for the dialogue box.
+ *  char *default == the default string to put in the writable area.
+ *  char *result == a buffer to contain the result string.  May be 0.
+ *  stddbox_writableHandler proc == proc to call when OK is clicked.  May
+ *    be 0.  Return TRUE if successful (i.e. we may close the dbox).
+ *  void *handle == passed to proc.
+ *
+ * Returns
+ *  TRUE if the string has been updated.
+ */
+
+BOOL writable
+(
+  char *title,
+  char *deflt,
+  char *result,
+  stddbox_writableHandler proc,
+  void *handle
+)
+{
+  dbox w=dbox_create("writable");
+  BOOL stop=FALSE;
+  BOOL changed=FALSE;
+  char buffer[256];
+  BOOL mayClose;
+  if (result==0)
+    result=buffer;
+  if (w==0)
+    return (FALSE);
+  dbox_setfield(w,1,"%s",deflt);
+  win_settitle(dbox_syshandle(w),"%s",title);
+  dbox_display(w,FALSE);
+  while (!stop)
+  {
+    switch (dbox_fillin(w))
+    {
+      case dbox_CLOSE:
+        stop=TRUE;
+        break;
+      case 0:
+        dbox_clickicon(w,0);
+        dbox_getfield(w,1,result,256);
+        if (proc)
+          mayClose=proc(result,handle);
+        else
+          mayClose=TRUE;
+        changed=TRUE;
+        if (dbox_wasAdjustClick() || mayClose==FALSE)
+          dbox_unclick();
+        else
+        {
+          dbox_hide(w);
+          dbox_unclick();
+          stop=TRUE;
+        }
+        break;
+    }
+  }
+  dbox_delete(w);
+  return (changed);
+}
+
+/*
+ * BOOL stddbox__saver(char *filename,void *handle)
+ *
+ * Use
+ *  Passes on the save request to the caller's own save routine, and erases
+ *  the data if the file is now safe.
+ *
+ * Parameters
+ *  char *filename == where to save the file
+ *  void *handle == the caller's handle to the data
+ */
+
+static BOOL stddbox__saver(char *filename,void *handle)
+{
+  if (stddbox__save(filename,handle)==FALSE)
+    return (FALSE);
+  if (saveas_file_is_safe())
+    stddbox__saved=TRUE;
+  return (TRUE);
+}
+
+/*
+ * void saveWarn
+ * (
+ *   BOOL useName,
+ *   void (*dispose)(void *handle),
+ *   char *title,
+ *   char *name,
+ *   int filetype,
+ *   int estsize,
+ *   xfersend_saveproc saveproc,
+ *   xfersend_sendproc sendproc,
+ *   xfersend_printproc printproc,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Pops up a save warning box allowing the use the luxury of saving his
+ *  data before closing the file.  The file is only removed if the data is
+ *  'safe'.
+ *
+ * Parameters
+ *  BOOL useName == whether to use the given name in the warning message
+ *  void (*dispose)(void *handle) == function to dispose the user's data
+ *  the others == as for saveas()
+ */
+
+void saveWarn
+(
+  BOOL useName,
+  void (*dispose)(void *handle),
+  char *title,
+  char *name,
+  int filetype,
+  int estsize,
+  xfersend_saveproc saveproc,
+  xfersend_sendproc sendproc,
+  xfersend_printproc printproc,
+  void *handle
+)
+{
+  dbox d;
+  if (win_anyWindows())
+  {
+    d=dbox_create("saveWarn");
+    if (!d)
+      return;
+    win_settitle
+    (
+      dbox_syshandle(d),
+      msgs_lookup("stddbWARN:Warning from %s"),
+      wimpt_programname()
+    );
+    if (useName)
+      dbox_setfield
+      (
+        d,
+        stddbox__SAVEWARN_MESSAGE,
+        msgs_lookup("stddbREFN:File '%s' has been modified, but not saved.  "
+                    "Do you want to discard these changes, save and then "
+                    "close the file, or cancel?"),
+        name
+      );
+    else
+      dbox_setfield
+      (
+        d,
+        stddbox__SAVEWARN_MESSAGE,
+        msgs_lookup("stddbREF:This file has been modified, but not saved.  "
+                    "Do you want to discard these changes, save and then "
+                    "close the file, or cancel?")
+      );
+    if (!dbox_hasTitle(d))
+      dbox_setEmbeddedTitle(d,stddbox__SAVEWARN_TITLE,FALSE);
+    stddbox__save=saveproc;
+    werr_bleepy();
+    switch (nopoll_doDbox
+    (
+      d,
+      nopoll_CENTRE,
+      stddbox__SAVEWARN_SAVE,
+      stddbox__SAVEWARN_CANCEL,
+      stddbox__SAVEWARN_REMOVE
+    ))
+    {
+      case nopoll_OK:
+        stddbox__saved=FALSE;
+        saveas
+        (
+          title,
+          name,
+          filetype,
+          estsize,
+          stddbox__saver,
+          sendproc,
+          printproc,
+          handle
+        );
+        if (stddbox__saved)
+          dispose(handle);
+        break;
+      case nopoll_CANCEL:
+        break;
+      case nopoll_OTHER:
+        dispose(handle);
+        break;
+    }
+    dbox_delete(d);
+  }
+  else
+  {
+    BOOL killIt;
+    if (useName)
+      killIt=werr_error
+      (
+        2,
+        msgs_lookup("stddbREFN:Are you sure you want to "
+                                             "remove edited file '%s'?"),
+        name
+      );
+    else
+      killIt=werr_error
+      (
+        2,
+        msgs_lookup("stddbREF:Are you sure you want to "
+                                              "remove your edited file?")
+      );
+    if (killIt)
+      dispose(handle);
+  }
+}
+
+/*
+ * void progInfo
+ * (
+ *   char *name,
+ *   char *purpose,
+ *   char *author,
+ *   int version,
+ *   char *date
+ * )
+ *
+ * Use
+ *  Presents a standard progInfo window giving information about an
+ *  application.
+ *
+ * Parameters
+ *  char *name == the name of the program
+ *  char *purpose == what it does
+ *  char *author == author/copyright string (usually something like
+ *    '© 1993-1998 Straylight')
+ *  int version == the version number*100 (e.g. 374 for 3.74 etc.)
+ *  char *date == the date of compilation (use _TIME_NOW)
+ */
+
+void progInfo(char *name,char *purpose,char *author,int version,char *date)
+{
+  dbox d=dbox_create("progInfo");
+  char buffer[100];
+  if (!d)
+    return;
+  if (!dbox_hasTitle(d))
+    dbox_setEmbeddedTitle(d,stddbox__PROGINFO_TITLE,TRUE);
+  dbox_setfield(d,stddbox__PROGINFO_NAME,"%s",name);
+  dbox_setfield(d,stddbox__PROGINFO_PURPOSE,"%s",purpose);
+  dbox_setfield(d,stddbox__PROGINFO_AUTHOR,"%s",author);
+  dbox_setfield
+  (
+    d,
+    stddbox__PROGINFO_VERSION,
+    "%i.%02i (%s)",
+    version/100,
+    version%100,
+    date
+  );
+  sprintf(buffer,
+          msgs_lookup("stddbPIH:This window gives you "
+                      "information about this version of %s."),
+          wimpt_programname());
+  mbox(d,buffer);
+}
+
+/*
+ * void mbox(dbox d)
+ *
+ * Use
+ *  Handles a monologue box (like info windows) where no input is required.
+ *  You should create the dbox, fill in any fields required.  This routine
+ *  then handles the rest.  It deletes the dbox when it's finished - it's of
+ *  no use to the caller anyway - who wants a used dialogue box with no
+ *  input?  Yuk...
+ *
+ *  You can specify a help message tag to be displayed before any messages
+ *  embedded in the icons.  This is passed through msgs_lookup before
+ *  sending to help_addLine.  Specify zero for this to send no message.
+ *
+ * Parameters
+ *  dbox d == the box to handle
+ *  char *help == the help message tag to stick on the top
+ */
+
+void mbox(dbox d,char *help)
+{
+  BOOL done=FALSE;
+  dbox_display(d,dbox_MENU_OVERPTR);
+  while (!done)
+  {
+    switch (dbox_fillin(d))
+    {
+      case dbox_CLOSE:
+        done=TRUE;
+        break;
+      case dbox_HELP:
+        help_startHelp();
+        if (help)
+          help_addLine(msgs_lookup(help));
+        help_readFromIcon();
+        help_endHelp();
+        break;
+    }
+  }
+  dbox_delete(d);
+}
diff --git a/StraySrc/Libraries/Steel/c/tcol b/StraySrc/Libraries/Steel/c/tcol
new file mode 100644 (file)
index 0000000..edd38c2
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Tcol
+ *   A true-colour dialogue box thingy
+ *
+ * v. 1.00 24 July 1993
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "dbox.h"
+#include "buttons.h"
+#include "wimp.h"
+#include "wimpt.h"
+#include "werr.h"
+#include "tcol.h"
+#include "help.h"
+#include "msgs.h"
+#include "mem.h"
+#include "akbd.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define tcol__REDUP 27
+#define tcol__REDDOWN 2
+#define tcol__REDWRITE 3
+#define tcol__REDSLIDE 6
+#define tcol__GREENUP 9
+#define tcol__GREENDOWN 10
+#define tcol__GREENWRITE 11
+#define tcol__GREENSLIDE 14
+#define tcol__BLUEUP 17
+#define tcol__BLUEDOWN 18
+#define tcol__BLUEWRITE 19
+#define tcol__BLUESLIDE 22
+#define tcol__ACTIONOK 0
+#define tcol__COLOUR 25
+#define tcol__ACTIONCANCEL 1
+#define tcol__EDITING 30
+
+/*
+ * A structure to handle everything
+ */
+typedef struct
+{
+  dbox d;
+  tcol_finishhandler proc;
+  void *handle;
+  int red;
+  int green;
+  int blue;
+}
+tcol__tcolstr;
+
+static void tcol__updateColour(tcol__tcolstr *t)
+{
+  wimp_paletteword pal;
+  pal.bytes.red=t->red*255/100;
+  pal.bytes.green=t->green*255/100;
+  pal.bytes.blue=t->blue*255/100;
+  buttons_updateColourButton(t->d,tcol__COLOUR,pal);
+}
+
+static void tcol__updateRed(tcol__tcolstr *t)
+{
+  dbox_setNumeric(t->d,tcol__REDWRITE,t->red);
+  buttons_updateSlider(t->d,tcol__REDSLIDE,100,t->red,11,FALSE);
+  tcol__updateColour(t);
+}
+
+static void tcol__updateGreen(tcol__tcolstr *t)
+{
+  dbox_setNumeric(t->d,tcol__GREENWRITE,t->green);
+  buttons_updateSlider(t->d,tcol__GREENSLIDE,100,t->green,10,FALSE);
+  tcol__updateColour(t);
+}
+
+static void tcol__updateBlue(tcol__tcolstr *t)
+{
+  dbox_setNumeric(t->d,tcol__BLUEWRITE,t->blue);
+  buttons_updateSlider(t->d,tcol__BLUESLIDE,100,t->blue,8,FALSE);
+  tcol__updateColour(t);
+}
+
+static void tcol__redAltered(tcol__tcolstr *t)
+{
+  buttons_arrowClick(t->d,tcol__REDWRITE,0,100,0,FALSE);
+  t->red=dbox_getNumeric(t->d,tcol__REDWRITE);
+  buttons_updateSlider(t->d,tcol__REDSLIDE,100,t->red,11,FALSE);
+  tcol__updateColour(t);
+}
+
+static void tcol__greenAltered(tcol__tcolstr *t)
+{
+  buttons_arrowClick(t->d,tcol__GREENWRITE,0,100,0,FALSE);
+  t->green=dbox_getNumeric(t->d,tcol__GREENWRITE);
+  buttons_updateSlider(t->d,tcol__GREENSLIDE,100,t->green,10,FALSE);
+  tcol__updateColour(t);
+}
+
+static void tcol__blueAltered(tcol__tcolstr *t)
+{
+  buttons_arrowClick(t->d,tcol__BLUEWRITE,0,100,0,FALSE);
+  t->blue=dbox_getNumeric(t->d,tcol__BLUEWRITE);
+  buttons_updateSlider(t->d,tcol__BLUESLIDE,100,t->blue,8,FALSE);
+  tcol__updateColour(t);
+}
+
+static void tcol__redraw(wimp_redrawstr *r,void *handle)
+{
+  tcol__tcolstr *t=(tcol__tcolstr *)handle;
+  wimp_paletteword pal;
+  r=r;
+  pal.bytes.red=t->red*255/100;
+  pal.bytes.green=t->green*255/100;
+  pal.bytes.blue=t->blue*255/100;
+  buttons_redrawSlider(t->d,tcol__REDSLIDE,100,t->red,11,FALSE);
+  buttons_redrawSlider(t->d,tcol__GREENSLIDE,100,t->green,10,FALSE);
+  buttons_redrawSlider(t->d,tcol__BLUESLIDE,100,t->blue,8,FALSE);
+  buttons_redrawColourButton(t->d,tcol__COLOUR,pal);
+}
+
+static BOOL tcol__raw(dbox d,wimp_eventstr *e,void *handle)
+{
+  tcol__tcolstr *t=(tcol__tcolstr *)handle;
+  BOOL handled=FALSE;
+  BOOL cursor=FALSE;
+  int key;
+  switch (e->e)
+  {
+    case wimp_EREDRAW:
+      wimpt_redraw(tcol__redraw,t);
+      handled=TRUE;
+      break;
+    case wimp_EKEY:
+      key=e->data.key.chcode;
+      switch (key)
+      {
+        case akbd_DownK:
+        case akbd_UpK:
+        case akbd_TabK:
+        case akbd_TabK+akbd_Sh:
+        case akbd_UpK+akbd_Ctl:
+        case akbd_DownK+akbd_Ctl:
+          cursor=TRUE;
+      }
+      switch (e->data.key.c.i)
+      {
+        case tcol__REDWRITE:
+          if (handled=buttons_insertChar(d,key,'0','9'),handled || cursor)
+            tcol__redAltered(t);
+          break;
+        case tcol__GREENWRITE:
+          if (handled=buttons_insertChar(d,key,'0','9'),handled || cursor)
+            tcol__greenAltered(t);
+          break;
+        case tcol__BLUEWRITE:
+          if (handled=buttons_insertChar(d,key,'0','9'),handled || cursor)
+            tcol__blueAltered(t);
+          break;
+      }
+      break;
+  }
+  return (handled);
+}
+
+static void tcol__redSlide(dbox d,wimp_i i,int val,void *handle)
+{
+  tcol__tcolstr *t=(tcol__tcolstr *)handle;
+  i=i;
+  d=d;
+  val=val;
+  dbox_setNumeric(t->d,tcol__REDWRITE,t->red);
+  tcol__updateColour(t);
+}
+
+static void tcol__greenSlide(dbox d,wimp_i i,int val,void *handle)
+{
+  tcol__tcolstr *t=(tcol__tcolstr *)handle;
+  i=i;
+  d=d;
+  val=val;
+  dbox_setNumeric(t->d,tcol__GREENWRITE,t->green);
+  tcol__updateColour(t);
+}
+static void tcol__blueSlide(dbox d,wimp_i i,int val,void *handle)
+{
+  tcol__tcolstr *t=(tcol__tcolstr *)handle;
+  i=i;
+  d=d;
+  val=val;
+  dbox_setNumeric(t->d,tcol__BLUEWRITE,t->blue);
+  tcol__updateColour(t);
+}
+
+static void tcol__redArrow(dbox d,dbox_field f,int diff,void *handle)
+{
+  tcol__tcolstr *t=(tcol__tcolstr *)handle;
+  buttons_arrowClick(d,f,0,100,diff,FALSE);
+  tcol__redAltered(t);
+}
+
+static void tcol__greenArrow(dbox d,dbox_field f,int diff,void *handle)
+{
+  tcol__tcolstr *t=(tcol__tcolstr *)handle;
+  buttons_arrowClick(d,f,0,100,diff,FALSE);
+  tcol__greenAltered(t);
+}
+
+static void tcol__blueArrow(dbox d,dbox_field f,int diff,void *handle)
+{
+  tcol__tcolstr *t=(tcol__tcolstr *)handle;
+  buttons_arrowClick(d,f,0,100,diff,FALSE);
+  tcol__blueAltered(t);
+}
+
+static void tcol__handler(dbox d,dbox_field clicked,void *handle)
+{
+  wimp_paletteword pal;
+  tcol__tcolstr *t=(tcol__tcolstr *)handle;
+  switch (clicked)
+  {
+    case dbox_CLOSE:
+      dbox_delete(d);
+      if (t->proc)
+      {
+        (t->proc)(tcol_CANCEL,
+                  pal,
+                  t->handle);
+      }
+      mem_free(t);
+      break;
+    case dbox_HELP:
+      help_startHelp();
+      help_addLine(msgs_lookup("tcolHM:This is the Colour Selector."));
+      help_readFromIcon();
+      help_endHelp();
+      break;
+    case tcol__COLOUR:
+      break;
+    case tcol__ACTIONOK:
+      if (!dbox_wasAdjustClick())
+      {
+        dbox_clickicon(d,tcol__ACTIONOK);
+        dbox_hide(d);
+        dbox_unclick();
+        dbox_delete(d);
+        mem_free(t);
+      }
+      else
+      {
+        dbox_clickicon(d,tcol__ACTIONOK);
+        dbox_unclick();
+      }
+      if (t->proc)
+      {
+        pal.bytes.red=t->red*255/100;
+        pal.bytes.green=t->green*255/100;
+        pal.bytes.blue=t->blue*255/100;
+        (t->proc)(dbox_wasAdjustClick() ? tcol_OK_REOPEN : tcol_OK,
+                  pal,
+                  t->handle);
+      }
+      break;
+    case tcol__ACTIONCANCEL:
+      dbox_clickicon(d,tcol__ACTIONCANCEL);
+      dbox_hide(d);
+      dbox_unclick();
+      dbox_delete(d);
+      if (t->proc)
+      {
+        (t->proc)(tcol_CANCEL,
+                  pal,
+                  t->handle);
+      }
+      mem_free(t);
+      break;
+    case tcol__REDUP:
+      buttons_arrow(d,clicked,d,tcol__REDWRITE,tcol__redArrow,+1,t);
+      break;
+    case tcol__REDDOWN:
+      buttons_arrow(d,clicked,d,tcol__REDWRITE,tcol__redArrow,-1,t);
+      break;
+    case tcol__GREENUP:
+      buttons_arrow(d,clicked,d,tcol__GREENWRITE,tcol__greenArrow,+1,t);
+      break;
+    case tcol__GREENDOWN:
+      buttons_arrow(d,clicked,d,tcol__GREENWRITE,tcol__greenArrow,-1,t);
+      break;
+    case tcol__BLUEUP:
+      buttons_arrow(d,clicked,d,tcol__BLUEWRITE,tcol__blueArrow,+1,t);
+      break;
+    case tcol__BLUEDOWN:
+      buttons_arrow(d,clicked,d,tcol__BLUEWRITE,tcol__blueArrow,-1,t);
+      break;
+    case tcol__REDSLIDE:
+      buttons_slideSlider(d,tcol__REDSLIDE,100,
+        &(t->red),11,FALSE,tcol__redSlide,t);
+      break;
+    case tcol__GREENSLIDE:
+      buttons_slideSlider(d,tcol__GREENSLIDE,100,
+        &(t->green),10,FALSE,tcol__greenSlide,t);
+      break;
+    case tcol__BLUESLIDE:
+      buttons_slideSlider(d,tcol__BLUESLIDE,100,
+        &(t->blue),8,FALSE,tcol__blueSlide,t);
+      break;
+  }
+}
+
+/*
+ * void tcol
+ * (
+ *   char *editing,
+ *   wimp_paletteword c,
+ *   BOOL isStatic,
+ *   tcol_finishhandler proc,
+ *   void *handle
+ *  )
+ *
+ * Use
+ *  Creates and handles a dbox, which allows the user to input a true
+ *  colour.  You must have a template called 'tcol' for this routine.
+ *
+ * Parameters
+ *  char *editing == what we're editing (put in the little box at the top)
+ *  wimp_paletteword c == the initial colour
+ *  BOOL isStatic == whether the dbox is static.  Actually, you can use
+ *   any of the dbox display types (e.g. dbox_STATIC_OVERPTR)
+ *  tcol_finishhandler proc == procedure called when the user clicks OK
+ *  void *handle == the jolly old handle
+ */
+
+void tcol
+(
+  char *editing,
+  wimp_paletteword c,
+  BOOL isStatic,
+  tcol_finishhandler proc,
+  void *handle
+)
+{
+  tcol__tcolstr *t=(tcol__tcolstr *)mem_alloc(sizeof(tcol__tcolstr));
+  if (!t)
+  {
+    werr(FALSE,msgs_lookup("tcolNEM:Not enough memory to create dbox."));
+    return;
+  }
+  t->d=dbox_create("tcol");
+  if (!t->d)
+    return;
+  dbox_rawEventHandler(t->d,tcol__raw,t);
+  dbox_eventHandler(t->d,tcol__handler,t);
+  dbox_setfield(t->d,tcol__EDITING,"%s",editing);
+  t->red=c.bytes.red*100/255;
+  t->green=c.bytes.green*100/255;
+  t->blue=c.bytes.blue*100/255;
+  t->proc=proc;
+  t->handle=handle;
+  tcol__updateRed(t);
+  tcol__updateGreen(t);
+  tcol__updateBlue(t);
+  dbox_display(t->d,isStatic);
+}
diff --git a/StraySrc/Libraries/Steel/c/tearoff b/StraySrc/Libraries/Steel/c/tearoff
new file mode 100644 (file)
index 0000000..a523480
--- /dev/null
@@ -0,0 +1,1828 @@
+/*
+ * tearoff.c
+ *
+ * Straylight TMS Segment
+ * Nice tearoff menu system - impressive even if I do say so myself
+ *
+ * © 1995-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define dbox__INTERNALS
+#define _CORE
+#define _STDAPP
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "steel.h"
+#include "string.h"
+#include "os.h"
+#include "bbc.h"
+#include "xtearoff.h"
+#include "font.h"
+#include "swis.h"
+#include "alarm.h"
+
+#include "tearSupt/tearSupt.h"
+
+/*----- Global defintions -------------------------------------------------*/
+
+static int tearoff__x, tearoff__y;     /* Position to open next menu */
+
+static tearoff
+  tearoff__prevLevel = NULL,           /* Most recent parent */
+  tearoff__currentMenu = NULL,         /* Current Transient menu */
+  tearoff__originatingTearoff = NULL,  /* Most recent tornoff parent */
+  tearoff__tornoffList = NULL,         /* List of torn off menus */
+  tearoff__oldHandle = NULL;           /* Idle event handle */
+
+static wimp_w tearoff__currentDbox=0;  /* Current dbox opened */
+static BOOL tearoff__subMenuPending=FALSE,
+            riscos3,                  /* We are on risos3 */
+            tearoff__menuActive=TRUE;  /* Are menus active */
+static int tearoff__alarmTime,         /* Time alarm was set */
+                  tearoff__alarmTime2;        /* Time 2nd alarm was set */
+static tearoff__alarm tearoff__alm;
+
+/*----- Icon handles for the tear bar -------------------------------------*/
+
+#define tearIcon__tear 0
+#define tearIcon__close 0
+#define tearIcon__fold 1
+
+/*----- Function prototypes for cyclic definitions ------------------------*/
+
+static void tearoff__doIdles(void *handle);
+static void tearoff__windowHandler(wimp_eventstr *e, void *handle);
+
+/*----- Tearoff code - Not for the casual observer!! ----------------------*/
+
+static void tearoff_closeMenus(void)
+{
+  tearSupport_switch(1);
+  wimp_create_menu((wimp_menustr*)-1,0,0);
+  tearSupport_switch(0);
+}
+
+/*----- Window creation routines ----------------------------------------- */
+
+/* --- Create the tear icon in the given window --- */
+
+static void tearoff__createTearIcon(tearoff t /* was wimp_w w [mdw] */)
+{
+  wimp_w w=t->w; /* [mdw] */
+  wimp_icreate ict;
+  wimp_i i;
+
+#ifdef notdef /* [mdw] */
+
+  ict.i.box.x0 = 4;
+  ict.i.box.x1 = 68;
+  ict.i.box.y1 = -4;
+  ict.i.box.y0 = -20;
+
+#else /* [mdw] */
+
+  ict.i.box.x0 = 0;
+  ict.i.box.x1 = t->width;
+  ict.i.box.y1 = 0;
+  ict.i.box.y0 = -24;
+
+#endif /* [mdw] */
+
+  ict.i.flags  = wimp_IVCENTRE |
+                 wimp_IFILLED |
+                 wimp_IBTYPE * wimp_BCLICKDEBOUNCE |
+                 wimp_ISPRITE |
+                 wimp_INDIRECT |
+                 (0x30000000) /* [mdw] */;
+
+  ict.i.data.indirectsprite.name       = "tear";
+  ict.i.data.indirectsprite.spritearea = resspr_area();
+  ict.i.data.indirectsprite.nameisname = 4;
+
+  ict.w = w;
+  wimpt_noerr(wimp_create_icon(&ict, &i));
+}
+
+/* --- Create the close/fold icons in the menu */
+
+static void tearoff__createTornIcons(tearoff t)
+{
+  wimp_icreate ict;
+  wimp_i i;
+
+#ifdef notdef /* [mdw] */
+
+  ict.i.box.x0 = 4;
+  ict.i.box.x1 = 70;
+  ict.i.box.y1 = -4;
+  ict.i.box.y0 = -20;
+
+#else /* [mdw] */
+
+  ict.i.box.x0 = 0;
+  ict.i.box.x1 = (t->width/2)-2;
+  ict.i.box.y1 = 0;
+  ict.i.box.y0 = -24;
+
+#endif /* [mdw] */
+
+  ict.i.flags = wimp_IVCENTRE |
+                wimp_IFILLED |
+                wimp_IBTYPE * wimp_BCLICKDEBOUNCE |
+                wimp_ISPRITE |
+                wimp_INDIRECT |
+                (0x30000000) /* [mdw] */;
+
+  ict.i.data.indirectsprite.name       = "close";
+  ict.i.data.indirectsprite.spritearea = resspr_area();
+  ict.i.data.indirectsprite.nameisname = 4;
+
+  ict.w = t->w;
+  wimpt_noerr(wimp_create_icon(&ict, &i));
+
+/* wimp_set_icon_state(t->w, i, 0, 0); [mdw] */
+
+  /* Now create the fold icon */
+
+#ifdef notdef /* [mdw] */
+
+  ict.i.box.x1 = t->width - 4;
+  ict.i.box.x0 = ict.i.box.x1 - 60;
+  ict.i.box.y1 = -4;
+  ict.i.box.y0 = -20;
+
+#else /* [mdw] */
+
+  ict.i.box.x0 = (t->width/2)+2;
+  ict.i.box.x1 = t->width;
+  ict.i.box.y1 = 0;
+  ict.i.box.y0 = -24;
+
+#endif /* [mdw] */
+
+  ict.i.flags = wimp_IVCENTRE |
+                wimp_IFILLED |
+                wimp_IBTYPE * wimp_BCLICKDEBOUNCE |
+                wimp_ISPRITE | wimp_INDIRECT |
+                wimp_IRJUST | /* [mdw] */
+                (0x30000000) /* [mdw] */;
+
+
+  ict.i.data.indirectsprite.name       = "fold";
+  ict.i.data.indirectsprite.spritearea = resspr_area();
+  ict.i.data.indirectsprite.nameisname = 4;
+
+  ict.w = t->w;
+  wimpt_noerr(wimp_create_icon(&ict, &i));
+
+/* wimp_set_icon_state(t->w, i, 0, 0); [mdw] */
+
+  { /* --- start [mdw] --- */
+
+  wimp_redrawstr r;
+  int more;
+
+  r.w=t->w;
+  r.box.x0=0; r.box.x1=t->width;
+  r.box.y0=-24; r.box.y1=0;
+  wimpt_noerr(wimp_update_wind(&r,&more));
+  while (more)
+  {
+    wimp_setcolour(0);
+    bbc_rectanglefill(r.box.x0-r.scx+t->width/2-2,
+                      r.box.y1-r.scy-24,
+                      4,24);
+    wimpt_noerr(wimp_get_rectangle(&r,&more));
+  }
+
+  /* --- end [mdw] --- */ }
+}
+
+/* --- Called to calculate the width of a menu */
+
+void tearoff_calculateMenuWidth(tearoff t)
+{
+  tearoff__item *i;
+  int cnt;
+  int max,w;
+
+  i=(tearoff__item *)(t+1);
+  max=0;
+  for (cnt=1;cnt<=t->numberOfItems;cnt++,i++)
+  {
+    w=wimpt_stringWidth(i->text);
+    if (w>max) max=w;
+  }
+
+  t->width=max;
+
+  i=(tearoff__item *)(t+1);
+  max=0;
+  for (cnt=1;cnt<=t->numberOfItems;cnt++,i++)
+  {
+    if (i->keys)
+    {
+      w=wimpt_stringWidth(i->keys);
+      if (w>max) max=w;
+    }
+  }
+  if (max) max+=16;
+
+  t->width+=48+16+max;
+  t->keyWidth=max;
+
+  w=wimpt_stringWidth(t->menuTitle);
+  if (t->width<w) t->width=w;
+  if (t->width<150 && t->tearoff) t->width=150;
+}
+
+/* --- Creates a window for a menu --- */
+
+static wimp_w tearoff__createWindow(tearoff t)
+{
+  wimp_wind wind;
+  wimp_icreate ict;
+  wimp_i i;
+  wimp_w w;
+  int extra = (t->tearoff)?tearoff__HEIGHT:0, h;
+  int scy=(bbc_vduvar(bbc_YWindLimit)+1)<<bbc_vduvar(bbc_YEigFactor);
+
+  /* First create the window itself */
+
+  tearoff_calculateMenuWidth(t);
+
+  wind.ex.x0   = 0;
+  wind.ex.x1   = t->width;
+  wind.ex.y0   = -t->numberOfItems * 44 - extra - t->dotted;
+  wind.ex.y1   = 0;
+
+  h = wind.ex.y1-wind.ex.y0;  /* Height */
+
+  wind.box.x0  = 0;
+  wind.box.x1  = t->width;
+  if (t->maxHeight && h > t->maxHeight)
+    wind.box.y0  = -t->maxHeight;
+  else
+    wind.box.y0  = -h;
+  wind.box.y1  = 0;
+  wind.scx     = 0;
+  wind.scy     = 0;
+
+  wind.minsize = 0;
+
+  wind.behind  = -1;
+
+  wind.flags   = wimp_WMOVEABLE |
+                 wimp_WTITLE |
+                 wimp_WNEW;
+
+  t->scrollBar=FALSE;
+
+  if (!t->folded && (t->maxHeight && h > t->maxHeight || (h+50)>scy))
+  {
+    wind.flags |= wimp_WVSCR;
+    t->scrollBar=TRUE;
+  }
+
+  wind.titleflags = wimp_ITEXT |
+                     wimp_IHCENTRE |
+                     wimp_IHCENTRE |
+                     wimp_INDIRECT;
+
+  wind.workflags  = wimp_IBTYPE * wimp_BCLICKDEBOUNCE;
+
+  wind.colours[wimp_WCTITLEFORE]   = 7;
+  wind.colours[wimp_WCTITLEBACK]   = 2;
+  wind.colours[wimp_WCWKAREAFORE]  = 7;
+  wind.colours[wimp_WCWKAREABACK]  = 0;
+  wind.colours[wimp_WCSCROLLOUTER] = 3;
+  wind.colours[wimp_WCSCROLLINNER] = 1;
+  wind.colours[wimp_WCTITLEHI]     = 12;
+  wind.colours[wimp_WCRESERVED]    = 0;
+
+  wind.spritearea = (void *)1;
+
+  wind.title.indirecttext.buffer      = t->menuTitle;
+  wind.title.indirecttext.validstring = 0;
+  wind.title.indirecttext.bufflen     = strlen(t->menuTitle + 1);
+
+  wind.nicons = 0;
+
+  if (wimp_create_wind(&wind, &w)) return -1;
+  t->w=w;
+
+  /* Create tearoff icon if needed */
+
+  if (t->tearoff)
+  {
+
+    #ifdef notdef /* [mdw] */
+
+    /* First the blank bar */
+
+    ict.i.box.x0 = 0;
+    ict.i.box.x1 = t->width;
+    ict.i.box.y1 = 0;
+    ict.i.box.y0 = -tearoff__HEIGHT;
+
+    ict.i.flags  = wimp_IVCENTRE |
+                   wimp_IFILLED |
+                   wimp_IBTYPE * wimp_BIGNORE |
+                   wimp_IBACKCOL * 3 |
+                   wimp_IFORECOL * 7;
+
+    ict.i.flags |= wimp_ITEXT;
+
+    strcpy(ict.i.data.text, "");
+
+    ict.w = w;
+    wimpt_noerr(wimp_create_icon(&ict, &i));
+
+    #endif /* [mdw] */
+
+    /* Now the icons */
+
+    if (!t->tornoff)
+      tearoff__createTearIcon(t /* was `w' [mdw] */);
+    else
+      tearoff__createTornIcons(t);
+
+  }
+  return w;
+}
+
+/*----- Functions to register with dbox -----------------------------------*/
+
+/* --- Registered with dbox so that it can find out where to open dbox --- */
+
+static void tearoff__finder(int *x,int *y)
+{
+  *x=tearoff__x;
+  *y=tearoff__y;
+}
+
+/* --- Registered with dbox also, so that it can tell me to
+       open a dbox */
+
+static void tearoff__openDbox(wimp_openstr *o)
+{
+  if (tearoff__subMenuPending)
+  {
+    tearoff__currentDbox = o->w;
+    wimp_open_wind(o);
+    if (!tearoff__currentMenu) tearSupport_opened(wimpt_task());
+  }
+}
+
+/* --- Registered with dbox so that it knows whether to open the next
+       dbox using above registered function */
+
+static BOOL tearoff__wasSubmenu(void)
+{
+  return tearoff__subMenuPending;
+}
+
+/*----- The tearoff menu handling routines - Yuk --------------------------*/
+
+/* --- Used to either highlight or unhighlight a menu item.
+       The current status of the icon is checked and
+       no change is made if is doesn't need to be. */
+
+void tearoff_highlightItem(int s, tearoff t, BOOL select)
+{
+  wimp_icon textIcon,keyIcon;
+  tearoff__item *item;
+  wimp_redrawstr r;
+  int more;
+
+  if (!s) return;
+  if (!select && s!=t->selected) return;
+
+  item = (tearoff__item *)(t+1);
+  item+=(s-1);
+
+  if (item->shaded) return;
+  r.w=t->w;
+  r.box.x1=t->width-24;
+  r.box.x0=24;
+  r.box.y0=item->y;
+  r.box.y1=item->y+44;
+
+  textIcon.box.y0=item->y;
+  textIcon.box.y1=item->y+44;
+  textIcon.box.x0 = 24;
+  textIcon.box.x1 = 24 + t->width - 48;
+  textIcon.flags = wimp_ITEXT |
+                   wimp_IVCENTRE |
+                   wimp_IFILLED |
+                   wimp_INDIRECT;
+  if (select)
+    textIcon.flags |= wimp_IBACKCOL * 7 |
+                      wimp_IFORECOL * 0;
+  else
+    textIcon.flags |= wimp_IBACKCOL * 0 |
+                      wimp_IFORECOL * 7;
+
+  if (item->shaded) textIcon.flags |= wimp_INOSELECT;
+  textIcon.data.indirecttext.buffer      = item->text;
+  textIcon.data.indirecttext.validstring = "";
+  textIcon.data.indirecttext.bufflen     = strlen(item->text) + 1;
+
+  if (item->keys)
+  {
+    keyIcon.box.x1=t->width-24;
+    keyIcon.box.x0=keyIcon.box.x1-t->keyWidth;
+    keyIcon.box.y0=textIcon.box.y0;
+    keyIcon.box.y1=textIcon.box.y1;
+    keyIcon.flags=wimp_ITEXT |
+                  wimp_IFILLED |
+                  wimp_INDIRECT |
+                  wimp_IRJUST;
+    if (select)
+      keyIcon.flags |= wimp_IBACKCOL * 7 |
+                    wimp_IFORECOL * 0;
+    else
+      keyIcon.flags |= wimp_IBACKCOL * 0 |
+                    wimp_IFORECOL * 7;
+
+    if (item->shaded) keyIcon.flags |= wimp_INOSELECT;
+    keyIcon.data.indirecttext.buffer=item->keys;
+    keyIcon.data.indirecttext.validstring="";
+    keyIcon.data.indirecttext.bufflen=strlen(item->keys)+1;
+  }
+
+  wimp_update_wind(&r,&more);
+  while(more)
+  {
+    wimp_ploticon(&textIcon);
+    if (item->keys) wimp_ploticon(&keyIcon);
+
+    wimp_get_rectangle(&r,&more);
+  }
+}
+
+/* --- Called to deselect the currently highlighted item
+       in a menu. Here, a selected item is one that has
+       been set up by going over a submenu arrow. */
+
+static void tearoff__deselect(tearoff t)
+{
+  if (!t) return;
+  tearoff_highlightItem(t->selected, t, FALSE);
+  t->warned   = FALSE;
+  t->selected = 0;
+}
+
+/* --- Clean up after pointer has lewft a window etc --- */
+
+static void tearoff__cleanUp(void)
+{
+  win_removeIdleClaimer(tearoff__doIdles, tearoff__oldHandle);
+  alarm_remove(tearoff__alarmTime,0);
+  alarm_remove(tearoff__alarmTime2,0);
+  tearoff__alm.item=-1;
+  tearoff__menuActive=TRUE;
+  tearoff__oldHandle = NULL;
+}
+
+/* --- Closes the menu passed, and all sub menus off of it.
+       If the menu passed is top of the current transient
+       menu, then TearoffSupport is told to stop giving me
+       button pressed/menu created messages. */
+
+static void tearoff__closeMenuStructure(tearoff t,tearoff nowOn)
+{
+  tearoff p;
+
+  /* Close dbox if opened */
+
+  if (tearoff__currentDbox)
+  {
+    wimp_close_wind(tearoff__currentDbox);
+    tearoff__currentDbox=0;
+    if (tearoff__prevLevel)
+    {
+      if (tearoff__prevLevel != nowOn)
+      {
+        tearoff__deselect(tearoff__prevLevel);
+        tearoff__prevLevel->selected = FALSE;
+      }
+      tearoff__prevLevel->warned = FALSE;
+      tearoff__prevLevel->sub = NULL;
+    }
+    if (!tearoff__currentMenu) tearSupport_closed();
+  }
+
+  if (!t)
+    return;
+
+  if (t->prev != NULL)
+  {
+    tearoff__prevLevel = NULL;
+    tearoff__originatingTearoff = NULL;
+    if (t->prev->tornoff)
+    {
+      if (t->prev != nowOn) tearoff__deselect(t->prev);
+      else
+        t->prev->warned   = FALSE;
+    }
+  }
+
+  if (t == tearoff__currentMenu)
+  {
+    tearoff__currentMenu = NULL;
+    tearSupport_closed();  /* Stop TearoffSupport Sending messages */
+  }
+
+  while (t)
+  {
+    p = t;
+
+    if (t->tornoff) return;  /* Dont' close a torn off menu */
+
+    wimpt_noerr(wimp_close_wind(t->w));
+    wimpt_noerr(wimp_delete_wind(t->w));
+    win_register_event_handler(t->w, (win_event_handler)0, 0);
+
+    if (t->warned) p = t->sub; else p = NULL;
+
+    if (tearoff__oldHandle == t)
+      tearoff__cleanUp();
+
+    t->warned = FALSE;
+    t->selected = FALSE;
+    t->prev = FALSE;
+    t->open = FALSE;
+    t->sub = NULL;
+    t->w=0;
+
+    (t->selectProc)(tearoff_CLOSE, NULL, t->userHandle);
+
+    t = p;
+  }
+}
+
+/* --- Called to shade a sub menu arrow --- */
+
+#ifdef notdef  /* [mdw] */
+
+static void tearoff__shadeSub(tearoff t,int i,BOOL shade)
+{
+  tearoff__item *item;
+  wimp_redrawstr r;
+  wimp_icon icon;
+  int more;
+
+  if (!t) return;
+
+  item=(tearoff__item *)(t+1);
+  item+=(i-1);
+
+  item->subShaded=shade;
+
+  if (t->open)
+  {
+    r.w=t->w;
+    r.box.x1=icon.box.x1=t->width;
+    r.box.x0=icon.box.x0=t->width-24;
+    r.box.y0=icon.box.y0=item->y;
+    r.box.y1=icon.box.y1=item->y+44;
+
+    icon.flags = wimp_IVCENTRE |
+                 wimp_IHCENTRE |
+                 wimp_IFILLED |
+                 wimp_IBACKCOL * 0 |
+                 wimp_IFORECOL * 7;
+
+    if (item->shaded || item->subShaded) icon.flags |= wimp_INOSELECT;
+
+    if (!riscos3)
+    {
+       icon.flags |= wimp_ITEXT;
+       strcpy(icon.data.text, "\x89");
+    }
+    else
+    {
+      icon.flags |= wimp_ISPRITE |
+                    wimp_ITEXT |
+                    wimp_INDIRECT;
+      icon.data.indirecttext.validstring = "s\x89";
+      icon.data.indirecttext.bufflen     = 1;
+      icon.data.indirecttext.buffer      = "";
+    }
+
+    wimp_update_wind(&r,&more);
+    while(more)
+    {
+      wimp_ploticon(&icon);
+      wimp_get_rectangle(&r,&more);
+    }
+  }
+}
+
+#else
+
+#define tearoff__shadeSub(x,y,z) ((void)0)
+
+#endif
+
+/* --- Called to 'tear' off the given menu --- */
+
+static void tearoff__tearMenu(tearoff t, BOOL close)
+{
+  wimp_dragstr d;
+
+  if (t->tornoff) return;
+
+  t->tornoff = TRUE;
+
+  tearoff__deselect(t->prev);
+
+  /* Do a window move drag */
+
+  d.window = t->w;
+  d.type = wimp_MOVE_WIND;
+  wimp_drag_box(&d);
+
+  /* Add it to the torn off list */
+
+  t->nextTornoff = tearoff__tornoffList;
+  tearoff__tornoffList = t;
+  if (tearoff__currentMenu==t)
+  {
+    tearoff__currentMenu=NULL;
+    tearSupport_closed();
+  }
+
+  /* Close the current menu structure if dragged with select */
+
+  if (close) tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
+
+  /* Shade the sub menu arrow of the previous menu */
+
+  if (t->prev) tearoff__shadeSub(t->prev,t->fromItem,TRUE);
+
+  /* Now we need to alter the tearoff icons at the top of the menu */
+
+  wimp_delete_icon(t->w, tearIcon__tear);  /* Delete tear icon */
+
+  /* Create a close icon - this should be given the same
+     icon number as the tear icon had */
+
+  tearoff__createTornIcons(t);
+}
+
+/* --- Used to 'fold up' the given menu */
+
+static void tearoff__foldMenu(tearoff t, BOOL close)
+{
+  wimp_wstate state;
+  wimp_mousestr m;
+  BOOL sameMenu=FALSE;
+
+  if (!t) return;
+
+  if (close) tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
+
+  /* Close any transient submenus opened from this menu */
+
+  if (t->warned)
+  {
+    tearoff__closeMenuStructure(t->sub,NULL);
+    tearoff__deselect(t);
+  }
+
+  /* Re-open the menu at the right size */
+
+  wimp_get_wind_state(t->w, &state);
+  wimp_get_point_info(&m);
+  if (m.w==t->w) sameMenu=TRUE;
+
+  t->folded = !t->folded;
+
+  if (t->folded)
+  {
+    if (t->scrollBar)
+    {
+      wimpt_noerr(wimp_close_wind(t->w));
+      wimpt_noerr(wimp_delete_wind(t->w));
+      win_register_event_handler(t->w, (win_event_handler)0, 0);
+      if (tearoff__oldHandle==t)
+        tearoff__cleanUp();
+      tearoff__createWindow(t);
+      state.o.w=t->w;
+      state.o.box.y0=state.o.box.y1-tearoff__HEIGHT;
+      win_register_event_handler(t->w, tearoff__windowHandler, t);
+      wimp_open_wind(&(state.o));
+      if (sameMenu && m.i>=-1)
+      {
+        win_addIdleClaimer(tearoff__doIdles, 0, t);
+        tearoff__oldHandle = t;
+      }
+    }
+    else
+    {
+      state.o.box.y0=state.o.box.y1-tearoff__HEIGHT;
+      wimp_open_wind(&(state.o));
+    }
+  }
+  else
+  {
+    int scy=(bbc_vduvar(bbc_YWindLimit)+1)<<bbc_vduvar(bbc_YEigFactor);
+    int h=(t->numberOfItems*44)+t->dotted+tearoff__HEIGHT;
+
+    if (t->maxHeight && h>t->maxHeight || (h+50)>scy)
+    {
+      wimpt_noerr(wimp_close_wind(t->w));
+      wimpt_noerr(wimp_delete_wind(t->w));
+      win_register_event_handler(t->w, (win_event_handler)0, 0);
+      if (tearoff__oldHandle==t)
+        tearoff__cleanUp();
+      tearoff__createWindow(t);
+      state.o.w=t->w;
+      if (t->maxHeight)
+        state.o.box.y0=state.o.box.y1-t->maxHeight;
+      else
+        state.o.box.y0=state.o.box.y1-tearoff__HEIGHT-
+                       (t->numberOfItems*44)-t->dotted;
+      win_register_event_handler(t->w, tearoff__windowHandler, t);
+      win_adjustBox(&state.o);
+      wimp_open_wind(&state.o);
+      if (sameMenu && m.i>=-1)
+      {
+        win_addIdleClaimer(tearoff__doIdles, 0, t);
+        tearoff__oldHandle = t;
+      }
+    }
+    else
+    {
+      state.o.box.y0=state.o.box.y1-tearoff__HEIGHT-
+                     (t->numberOfItems*44)-t->dotted;
+      win_adjustBox(&state.o);
+      wimp_open_wind(&(state.o));
+    }
+  }
+}
+
+/* --- Used to 'un-tear' the given menu - this will be called
+       if it is re-opened as a tranisent of another menu.
+       It is also called in the routine to close a torn off menu */
+
+static wimp_w tearoff__unTearMenu(tearoff t, BOOL update)
+{
+  wimp_redrawstr r;
+  int more;
+  tearoff ptr = tearoff__tornoffList, prev = NULL;
+
+  /* Go through the 'tornoff list', if the menu is found then
+     remove it, untear it, and return it's window handle */
+
+  while (ptr)
+  {
+    if (ptr == t)
+    {
+      /* remove it from list */
+
+      if (!prev) tearoff__tornoffList = t->nextTornoff;
+      else prev->nextTornoff = t->nextTornoff;
+      t->tornoff = FALSE;
+
+      /* Close any transient menu opened from it */
+
+      if (t->warned)
+      {
+        tearoff__closeMenuStructure(t->sub,NULL);
+        tearoff__deselect(t);
+      }
+
+      /* Unshade the sub menu pointer for the previous menu */
+
+      tearoff__shadeSub(t->prev,t->fromItem,FALSE);
+
+      /* Unfold it if it needs to be */
+
+      if (t->folded) tearoff__foldMenu(t, FALSE);
+
+      /* Update if it is being moved - rather than just closed */
+
+      if (update)
+      {
+        wimp_delete_icon(t->w, tearIcon__close);
+        wimp_delete_icon(t->w, tearIcon__fold);
+
+        /* Replace the tear icon */
+
+        tearoff__createTearIcon(t /* was t->w [mdw] */);
+
+        /* Now redraw top of menu */
+
+        r.w      = t->w;
+        r.box.x0 = 0;
+        r.box.x1 = t->width;
+        r.box.y1 = 0;
+        r.box.y0 = -tearoff__HEIGHT;
+
+        wimp_update_wind(&r, &more);
+        while (more)
+        {
+          wimp_get_rectangle(&r, &more);
+        }
+      }
+      return t->w;
+    }
+    prev = ptr;
+    ptr = ptr->nextTornoff;
+  }
+  return (wimp_w)-1;
+}
+
+/* --- Close a torn off menu --- */
+
+static void tearoff__closeTornoff(tearoff t, BOOL close)
+{
+  if (!t) return;
+
+  tearoff__unTearMenu(t,FALSE);
+  tearoff__closeMenuStructure(t,NULL);
+
+  if (tearoff__oldHandle == t)
+    tearoff__cleanUp();
+  if (close) tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
+
+  /* Let the user know about it being close */
+
+  (t->selectProc)(tearoff_CLOSE,t->selected,t->userHandle);
+}
+
+/* --- Called to automatically open a sub menu --- */
+
+static void tearoff__alarmHandler2(int called_at,void *handle)
+{
+  tearoff__menuActive=TRUE;
+}
+
+static void tearoff__alarmHandler(int called_at,void *handle)
+{
+  wimp_wstate state;
+  tearoff t=tearoff__alm.t;
+  tearoff__item *item;
+  int delay,dummy;
+
+  item=(tearoff__item *)(t+1);
+  item+=(tearoff__alm.item-1);
+
+  wimp_get_wind_state(t->w, &state);
+  tearoff__x = state.o.box.x1-24;
+  tearoff__y = state.o.box.y1 + tearoff__y;
+
+  tearoff__prevLevel=t;
+  t->warned = TRUE;
+  if (t->tornoff) tearoff__originatingTearoff = t;
+
+  /* No current submenu opened */
+
+  t->sub = NULL;
+
+  /* Set up the second alarm */
+
+  os_swi3r(XOS_Byte,161,23,0,&dummy,&dummy,&delay);
+  if (delay)
+  {
+    tearoff__menuActive=FALSE;
+    tearoff__alarmTime2=alarm_timenow()+delay*10;
+    alarm_set(tearoff__alarmTime2,tearoff__alarmHandler2,0);
+  }
+
+  /* If item->subMenu is not FALSE, it contains a menu to
+     be opened automatically */
+
+  if (item->subMenu)
+  {
+    tearoff__subMenuPending = TRUE;
+    tearoff_displayMenu(item->sub,0);
+    tearoff__subMenuPending = FALSE;
+  }
+
+  /* Does the user want a tearoff_SUBMENU message? Note
+     that he can have one even if the menu is opened
+     automatically - unlike menu.c */
+
+  if (item->subMenuWarning)
+  {
+    tearoff__subMenuPending = TRUE;
+    (t->selectProc)(tearoff_SUBMENU,t->selected,t->userHandle);
+    tearoff__subMenuPending = FALSE;
+  }
+}
+
+/* --- The biggy - all button events are returned here for
+       dealing with - alter at your own risk. */
+
+static void tearoff__buttons(tearoff t,
+                             wimp_mousestr *m)
+{
+  int itm=0, cnt;
+  BOOL subPointer,justClickShadedArrow=FALSE;
+  wimp_wstate state;
+  tearoff__item *item = (tearoff__item *)(t + 1), *selItem;
+
+  /* First we deal with any type if button event - including the
+     'always' type. Don't bother doing anything if it is folded though */
+
+  if (!tearoff__menuActive) return;
+  selItem=(tearoff__item *)(t+1);
+  if (t->selected) selItem+=(t->selected-1);
+  if (!t->folded)
+  {
+    int cnt,dummy,delay;
+    BOOL wasDbox=!!tearoff__currentDbox;
+
+    itm=0;
+    subPointer=FALSE;
+    tearoff__y=0;
+    wimp_get_wind_state(t->w, &state);
+    m->y = m->y+state.o.y-state.o.box.y1;
+    m->x = m->x+state.o.x-state.o.box.x0;
+    for (cnt = 1; cnt <= t->numberOfItems; cnt++, item++)
+    {
+      if (m->y >= item->y && m->y < item->y+44)
+      {
+        itm = cnt;
+        if (m->x >= t->width - 24) subPointer = TRUE;
+        tearoff__y = item->y+44;
+        break;
+      }
+    }
+
+    item=(tearoff__item *)(t+1);
+    item+=(itm-1);
+
+    if ((subPointer &&
+        (item->subMenu || item->subMenuWarning) &&
+        (t->selected != itm)) ||
+        (!(subPointer &&
+        (item->subMenu || item->subMenuWarning)) &&
+        itm!=tearoff__alm.item) &&
+        m->i<0)
+    {
+      /* We get here if we are over a sub menu arrow AND
+         we weren't over it before, OR we are not over
+         a sub menu arrow at all AND we are not over an
+         icon. */
+
+      /* First close the RISCOS menu using tearoffSupport */
+
+      tearoff_closeMenus();
+
+      /* If this menu is torn off, then close any
+         transient menu opened at the moment */
+
+      if (t->tornoff)
+      tearoff__closeMenuStructure(tearoff__currentMenu, t);
+
+      /* If there is already a menu opened from this menu,
+         then close it. NB This may already have been closed
+         by the line above - but no harm done. */
+
+      if (t->warned)
+      {
+        tearoff__closeMenuStructure(t->sub,t);
+        t->sub = NULL;
+      }
+
+      /* Horrid hack because I can't do co-routines */
+
+      if (wasDbox)
+      {
+        wimp_eventstr e;
+
+        e.e=wimp_ENULL;
+        wimpt_fake_event(&e);
+        return;
+      }
+
+      if (t->selected!=itm)
+      {
+        if (t->selected && !selItem->shaded || itm == 0)
+          tearoff_highlightItem(t->selected, t, FALSE);
+        if (itm) tearoff_highlightItem(itm, t, TRUE);
+        t->selected=itm;
+        alarm_remove(tearoff__alarmTime,0);
+        alarm_remove(tearoff__alarmTime2,0);
+        tearoff__alm.item=-1;
+      }
+      if (tearoff__alm.item==-1)
+      {
+        if (riscos3 && itm && (item->subMenu || item->subMenuWarning))
+        {
+          os_swi3r(XOS_Byte,161,197,0,&dummy,&dummy,&delay);
+          if (delay & 0x80)
+          {
+            os_swi3r(XOS_Byte,161,23,0,&dummy,&dummy,&delay);
+            if (delay)
+            {
+              tearoff__alm.t=t;
+              tearoff__alm.item=itm;
+              tearoff__alarmTime=alarm_timenow()+delay*10;
+              alarm_set(tearoff__alarmTime,tearoff__alarmHandler,0);
+            }
+          }
+        }
+      }
+
+      /* Correct some variables */
+
+      t->warned = FALSE;
+      tearoff__prevLevel = NULL;
+      tearoff__originatingTearoff = NULL;
+    }
+
+  /* Did we go over the 'icon bar' ? */
+
+    if (m->i>=0)
+    {
+      if (t->selected)
+        tearoff_highlightItem(t->selected, t, FALSE);
+      t->selected = 0;
+      if (t->warned) tearoff__closeMenuStructure(t->sub,NULL);
+      t->warned = FALSE;
+      tearoff__alm.item=0;
+      tearoff__prevLevel = NULL;
+      tearoff__originatingTearoff = NULL;
+    }
+
+    /* We are over an arrow icon */
+
+    if (m->i<0 && subPointer &&
+        (item->subMenu || item->subMenuWarning) /* &&
+        !item->subShaded ||
+        (item->subShaded && subPointer && m->bbits) [mdw] */)
+    {
+      /* Get position at which to open next menu */
+
+      wimp_get_wind_state(m->w, &state);
+      tearoff__x = state.o.box.x1+2;
+      tearoff__y = state.o.box.y1 + tearoff__y;
+
+      if (!t->warned)  /* This menu isn't opened yet, and/or submenu
+                          message hasn't been sent */
+      {
+        if (item->subShaded && subPointer && m->bbits)
+          justClickShadedArrow=TRUE;
+
+        tearoff__prevLevel=t;
+        t->warned = TRUE;
+        if (t->tornoff) tearoff__originatingTearoff = t;
+
+        /* No current submenu opened */
+
+        t->sub = NULL;
+
+        /* If item->subMenu is not FALSE, it contains a menu to
+           be opened automatically */
+
+        if (item->subMenu)
+        {
+          tearoff__subMenuPending = TRUE;
+          tearoff_displayMenu(item->sub,0);
+          tearoff__subMenuPending = FALSE;
+        }
+
+        /* Does the user want a tearoff_SUBMENU message? Note
+           that he can have one even if the menu is opened
+           automatically - unlike menu.c */
+
+        if (item->subMenuWarning)
+        {
+          tearoff__subMenuPending = TRUE;
+          (t->selectProc)(tearoff_SUBMENU,t->selected,t->userHandle);
+          tearoff__subMenuPending = FALSE;
+        }
+      }
+      else
+      {
+        /* Since we are here, we know that the menu is already opened,
+           if there is one that is */
+
+        if (t->sub)
+        {
+          /* Close any submenus off of the submenu */
+
+          if (t->sub->warned)
+          {
+            tearoff__closeMenuStructure(t->sub->sub,NULL);
+            tearoff__deselect(t->sub);
+          }
+
+          /* And reposition submenu */
+
+          wimp_get_wind_state(t->sub->w, &state);
+          state.o.box.x0 = tearoff__x;
+          state.o.box.x1 = tearoff__x + t->sub->width;
+          if (t->sub->tearoff) tearoff__y += tearoff__HEIGHT;
+          state.o.box.y0 = tearoff__y - (state.o.box.y1 - state.o.box.y0);
+          state.o.box.y1 = tearoff__y;
+          state.o.behind=-1;
+
+          /* Mangle positional data so that it fits on the screen */
+
+          win_adjustBox(&(state.o));
+
+          /* Top and left to go here */
+
+          wimp_open_wind(&state.o);
+        }
+      }
+    }
+  }
+
+  /* Now we need to deal with actual button presses! */
+
+  if (m->bbits && !justClickShadedArrow)
+  {
+    int dummy;
+
+    /* Was click on tearoff bar */
+
+    if (m->i>=0)
+    {
+      if (m->i == tearIcon__tear && !t->tornoff)
+        tearoff__tearMenu(t, m->bbits & 6);
+      else if (m->i == tearIcon__close && t->tornoff)
+        tearoff__closeTornoff(t, m->bbits & 6);
+      else if (m->i == tearIcon__fold && t->tornoff)
+        tearoff__foldMenu(t, m->bbits & 6);
+    }
+
+    /* No, so select item */
+
+    else
+    {
+      int temp=t->selected;
+
+      /* Don't select a shaded item :-)
+       * (but do close the menu, if we need to [mdw])
+       */
+
+      if (item->shaded)
+      {
+        if (m->bbits & 6)
+          tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
+        return;
+      }
+
+      /* Flash icon in a similar way to the wimp - cunning */
+
+      for (cnt = 1; cnt <= 3; cnt++)
+      {
+        os_byte(19,&dummy,&dummy);  /* Wait for Vsync */
+        os_byte(19,&dummy,&dummy);
+        t->selected=itm;
+        tearoff_highlightItem(itm, t, FALSE);
+        os_byte(19,&dummy,&dummy);
+        os_byte(19,&dummy,&dummy);
+        t->selected=-1;
+        tearoff_highlightItem(itm, t, TRUE);
+      }
+      t->selected=temp;
+
+      /* Close menu structure if select used */
+
+      if (m->bbits & 6)
+        tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
+
+      /* Tell user about click */
+
+      (t->selectProc)(tearoff_SELECTION,itm,t->userHandle);
+    }
+  }
+  return;
+}
+
+/* --- Called on Null events --- */
+
+static void tearoff__doIdles(void *handle)
+{
+  wimp_mousestr m;
+  tearoff t = (tearoff)handle;
+
+  handle = handle;
+  wimp_get_point_info(&m);
+  m.bbits=0;
+  tearoff__buttons(t, &m);
+}
+
+/* --- Routine to program the VDU dash pattern --- */
+
+static void tearoff__makeDashPattern(int ptn)
+{
+  int byte1,byte2;
+  byte1=242;
+  byte2=8;
+  wimpt_noerr(os_byte(163,&byte1,&byte2)); /* Dot-dash length */
+  bbc_vduq(23,6,ptn,ptn,ptn,ptn,ptn,ptn,ptn,ptn);
+}
+
+/* --- Menu redraw routine --- */
+
+void tearoff__doRedraw(tearoff t, wimp_redrawstr *r)
+{
+  tearoff__item *i;
+  wimp_icon icon;
+  int c;
+
+  i = (tearoff__item *)(t+1);
+  wimp_setcolour(7);
+
+  /* Go through each item, and draw the dotted lines where
+     appropriate */
+
+  for (c = 1; c <= t->numberOfItems; c++)
+  {
+    /* Select icon */
+
+    icon.box.y1=i->y+44;
+    icon.box.y0=i->y;
+
+    if (i->selType != tearoff_NONE)
+    {
+      icon.box.x0=0;
+      icon.box.x1=24;
+      icon.flags=wimp_IVCENTRE |
+                 wimp_IHCENTRE |
+                 wimp_IFILLED |
+                 wimp_IBACKCOL * 0 |
+                 wimp_IFORECOL * 7;
+      if (i->shaded) icon.flags |= wimp_INOSELECT;
+      if (!riscos3 && i->selType == tearoff_TICKED)
+      {
+        icon.flags |= wimp_ITEXT;
+        strcpy(icon.data.text, "\x80");
+      }
+      if (riscos3 && i->selType == tearoff_TICKED)
+      {
+        icon.flags |= wimp_ISPRITE | wimp_INDIRECT;
+        icon.data.indirectsprite.name = "\x80";
+        icon.data.indirectsprite.spritearea = (sprite_area *)1;
+        icon.data.indirectsprite.nameisname = 4;
+      }
+      if (i->selType == tearoff_RADIOED)
+      {
+        icon.flags |= wimp_ITEXT;
+        strcpy(icon.data.text, "\x8F");
+      }
+
+      wimpt_noerr(wimp_ploticon(&icon));
+    }
+
+    /* Main text part */
+
+    icon.box.x0 = 24;
+    icon.box.x1 = 24 + t->width - 48;
+    if (i->keys) icon.box.x1-=16*(strlen(i->keys) + 1);
+
+    icon.flags = wimp_ITEXT |
+                 wimp_IVCENTRE |
+                 wimp_IFILLED |
+                 wimp_INDIRECT;
+
+    if (t->selected == c && !i->shaded)
+      icon.flags |= wimp_IBACKCOL * 7 |
+                    wimp_IFORECOL * 0;
+    else
+      icon.flags |= wimp_IBACKCOL * 0 |
+                    wimp_IFORECOL * 7;
+
+    if (i->shaded) icon.flags |= wimp_INOSELECT;
+
+    icon.data.indirecttext.buffer      = i->text;
+    icon.data.indirecttext.validstring = "";
+    icon.data.indirecttext.bufflen     = strlen(i->text) + 1;
+    wimpt_noerr(wimp_ploticon(&icon));
+
+    if (i->keys)
+    {
+      /* Print the control key short cut - right justified of course! */
+
+      icon.box.x0=t->width-24-t->keyWidth;
+      icon.box.x1=t->width-24;
+      icon.flags=wimp_ITEXT |
+                 wimp_IFILLED |
+                 wimp_INDIRECT |
+                 wimp_IRJUST;
+      if (t->selected==c && !i->shaded)
+        icon.flags |= wimp_IBACKCOL * 7 |
+                      wimp_IFORECOL * 0;
+      else
+        icon.flags |= wimp_IBACKCOL * 0 |
+                      wimp_IFORECOL * 7;
+      if (i->shaded) icon.flags |= wimp_INOSELECT;
+      icon.data.indirecttext.buffer=i->keys;
+      icon.data.indirecttext.validstring="";
+      icon.data.indirecttext.bufflen=strlen(i->keys)+1;
+      wimpt_noerr(wimp_ploticon(&icon));
+    }
+
+    /* Sub Arrow */
+
+    if (i->subMenu || i->subMenuWarning)
+    {
+      icon.box.x0 = t->width - 24;
+      icon.box.x1 = t->width;
+
+      icon.flags = wimp_IVCENTRE |
+                   wimp_IHCENTRE |
+                   wimp_IFILLED |
+                   wimp_IBACKCOL * 0 |
+                   wimp_IFORECOL * 7;
+
+      if (i->shaded /* || i->subShaded [mdw] */)
+        icon.flags |= wimp_INOSELECT;
+
+      if (!riscos3)
+      {
+        icon.flags |= wimp_ITEXT;
+        strcpy(icon.data.text, "\x89");
+      }
+      else
+      {
+        icon.flags |= wimp_ISPRITE |
+                      wimp_ITEXT |
+                      wimp_INDIRECT;
+
+        icon.data.indirecttext.validstring = "s\x89";
+        icon.data.indirecttext.bufflen     = 1;
+        icon.data.indirecttext.buffer      = "";
+      }
+      wimpt_noerr(wimp_ploticon(&icon));
+    }
+
+    if (i->dotted)
+    {
+      bbc_move(r->box.x0,r->box.y1+i->y-12-r->scy);
+
+      /* Plot the dotted line */
+
+      tearoff__makeDashPattern(0xf0);
+      wimp_setcolour(7);
+      bbc_plot(bbc_DottedBoth+bbc_DrawRelFore,t->width,0);
+    }
+    i++;
+  }
+}
+
+/* --- Perform the redraw loop --- */
+
+static void tearoff__redrawMenu(tearoff t)
+{
+  wimp_redrawstr r;
+  int more;
+
+  r.w = t->w;
+  wimp_redraw_wind(&r, &more);
+  while (more)
+  {
+    tearoff__doRedraw(t, &r);
+    wimp_get_rectangle(&r, &more);
+  }
+}
+
+/* --- Called to re-open the window - used when the window flags
+       have changed, and for things such as titles changing */
+
+void tearoff_rebuildMenu(tearoff t)
+{
+  wimp_wstate state;
+  BOOL hadIdle=FALSE;
+
+  wimp_get_wind_state(t->w, &state);
+
+  if (tearoff__oldHandle==t)
+  {
+    tearoff__cleanUp();
+    hadIdle=TRUE;
+  }
+  wimpt_noerr(wimp_close_wind(t->w));
+  wimpt_noerr(wimp_delete_wind(t->w));
+  win_register_event_handler(t->w, (win_event_handler)0, 0);
+  tearoff__createWindow(t);
+  state.o.w=t->w;
+  state.o.box.x1=state.o.box.x0+t->width;
+  if (t->maxHeight)
+    state.o.box.y0=state.o.box.y1-t->maxHeight;
+  else
+    state.o.box.y0=state.o.box.y1-tearoff__HEIGHT-
+                   (t->numberOfItems*44)-t->dotted;
+  wimp_open_wind(&(state.o));
+  win_register_event_handler(t->w, tearoff__windowHandler, t);
+  if (hadIdle)
+  {
+    win_addIdleClaimer(tearoff__doIdles,0,t);
+    tearoff__oldHandle=t;
+  }
+}
+
+/* --- Adds/Removes a scrollbar from a menu --- */
+
+static void tearoff__checkForScrollBar(tearoff t)
+{
+  int h;
+  wimp_wstate state;
+  int scy=(bbc_vduvar(bbc_YWindLimit)+1)<<bbc_vduvar(bbc_YEigFactor);
+
+  if (t->folded) return;  /* Don't do anything to a folded menu */
+  h = t->numberOfItems * 44 + t->dotted;
+  if (t->tearoff) h += tearoff__HEIGHT;
+  h += 50;  /* Leave room for title bar */
+
+  if (t->scrollBar && h <= scy &&
+      (!t->maxHeight || (t->maxHeight && h < t->maxHeight)))
+  {
+    /* remove scroll bar */
+
+    wimp_get_wind_state(t->w, &state);
+    wimpt_noerr(wimp_close_wind(t->w));
+    wimpt_noerr(wimp_delete_wind(t->w));
+    win_register_event_handler(t->w, (win_event_handler)0, 0);
+    tearoff__createWindow(t);
+    state.o.w=t->w;
+    state.o.box.y1=
+      state.o.box.y0+(t->numberOfItems*44+t->dotted)+
+      ((t->tearoff)?tearoff__HEIGHT:0);
+    win_register_event_handler(t->w, tearoff__windowHandler, t);
+    wimp_open_wind(&(state.o));
+    return;
+  }
+  if ((!t->scrollBar && h > scy) || wimpt_justChangedMode())
+  {
+    /* Add scroll bar */
+
+    wimp_get_wind_state(t->w, &state);
+    wimpt_noerr(wimp_close_wind(t->w));
+    wimpt_noerr(wimp_delete_wind(t->w));
+    win_register_event_handler(t->w, (win_event_handler)0, 0);
+    tearoff__createWindow(t);
+    state.o.w=t->w;
+    state.o.box.x1=state.o.box.x0+t->width;
+    wimp_open_wind(&(state.o));
+    win_register_event_handler(t->w, tearoff__windowHandler, t);
+    return;
+  }
+}
+
+/* --- Window handler for my psuedo-menus --- */
+
+static void tearoff__windowHandler(wimp_eventstr *e, void *handle)
+{
+  tearoff t = (tearoff)handle;
+  wimp_mousestr m;
+  BOOL ptrOverThisWindow=FALSE;
+
+  switch (e->e)
+    {
+    case wimp_EOPEN:
+      if (wimpt_justChangedMode())
+      {
+        wimp_get_point_info(&m);
+        if (m.w==t->w) ptrOverThisWindow=TRUE;
+        tearoff__checkForScrollBar(t);
+        if (ptrOverThisWindow && m.i>=-1 && !tearoff__oldHandle)
+        {
+          win_addIdleClaimer(tearoff__doIdles, 0, t);
+          tearoff__oldHandle = t;
+        }
+      }
+      else
+        wimpt_noerr(wimp_open_wind(&e->data.o));
+      break;
+
+    case wimp_EREDRAW:
+      tearoff__redrawMenu(t);
+      break;
+
+    case wimp_EBUT:
+      tearoff__buttons(t,&e->data.but.m);
+      break;
+
+    case wimp_EPTRENTER:
+      if (tearoff__oldHandle)
+        tearoff__cleanUp();
+      win_addIdleClaimer(tearoff__doIdles, 0, t);
+      tearoff__oldHandle = t;
+      break;
+
+    case wimp_EPTRLEAVE:
+      if (tearoff__oldHandle)
+        tearoff__cleanUp();
+      if (!t->warned && t->selected)
+      {
+        tearoff_highlightItem(t->selected, t, FALSE);
+        t->selected=0;
+      }
+      break;
+
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MHELPREQUEST:
+        {
+          wimp_wstate state;
+          int x,y,cnt;
+          tearoff__item *item;
+
+          if (e->data.msg.data.helprequest.m.i>=0)
+          {
+            help_startHelp();
+            if (e->data.msg.data.helprequest.m.i==1 && !t->tornoff)
+              help_addLine("Drag to tear off this submenu");
+            if (e->data.msg.data.helprequest.m.i==1 && t->tornoff)
+              help_addLine("Click to close this menu");
+            if (e->data.msg.data.helprequest.m.i==2)
+            {
+              if (t->folded)
+                help_addLine("Click to un-fold this menu");
+              else
+                help_addLine("Click to fold this menu");
+            }
+            help_endHelp();
+            return;
+          }
+          wimp_get_wind_state(t->w,&state);
+          x=e->data.msg.data.helprequest.m.x+state.o.x-state.o.box.x0;
+          y=e->data.msg.data.helprequest.m.y+state.o.y-state.o.box.y1;
+          item=(tearoff__item *)(t+1);
+          for (cnt = 1; cnt <= t->numberOfItems; cnt++, item++)
+          {
+            if (y >= item->y && y < item->y+44)
+            {
+              (t->selectProc)(tearoff_HELP,cnt,t->userHandle);
+              return;
+            }
+          }
+        }
+      }
+
+    default:
+      break;
+    }
+}
+
+/* --- Called to create a menu or a sub menu --- */
+
+BOOL tearoff_displayMenu(tearoff t1,void *handle)
+{
+  wimp_w w;
+  wimp_mousestr m;
+  wimp_wstate state;
+  int height;
+
+  wimp_get_point_info(&m);
+
+  /* If the window is not already torn off, then create
+     the window for it */
+
+  if (w = tearoff__unTearMenu(t1, TRUE), w == -1)
+  {
+    if (!t1->open)
+    {
+      w = tearoff__createWindow(t1);
+      if (w == -1) return FALSE;
+      win_register_event_handler(w, tearoff__windowHandler, t1);
+    }
+    else
+      w=t1->w;
+  }
+
+  if (handle) t1->userHandle=handle;
+
+  wimp_get_wind_state(w, &state);
+  height = state.o.box.y1 - state.o.box.y0;
+  state.o.behind=-1;
+
+  if (t1->tearoff) tearoff__y += tearoff__HEIGHT;
+
+  if (!tearoff__subMenuPending || !tearoff__currentMenu)
+  {
+    /* Here it must be a new menu, not a sub menu of a transient
+       menu */
+
+    tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
+    t1->prev = NULL;
+    if (tearoff__originatingTearoff && tearoff__subMenuPending)
+    {
+      /* It is being opened from a torn off menu */
+
+      t1->prev = tearoff__originatingTearoff;
+      state.o.box.x0 = tearoff__x;
+      state.o.box.x1 = tearoff__x + t1->width;
+      state.o.box.y0 = tearoff__y - height;
+      state.o.box.y1 = tearoff__y;
+      tearoff__originatingTearoff->sub=t1;
+      t1->fromItem=t1->prev->selected;
+    }
+    else
+    {
+      /* Open over the pointer */
+
+      state.o.box.x0 = m.x-64;
+      state.o.box.x1 = state.o.box.x0 + t1->width;
+      state.o.box.y0 = m.y - height;
+      state.o.box.y1 = m.y;
+    }
+    tearoff__currentMenu = t1;
+
+    /* Tell TearoffSupport to send me messages */
+
+    tearSupport_opened(wimpt_task());
+  }
+  else
+  {
+    /* It is a sub menu of a transient menu */
+
+    t1->prev = tearoff__prevLevel;
+    state.o.box.x0 = tearoff__x;
+    state.o.box.x1 = tearoff__x + t1->width;
+    state.o.box.y0 = tearoff__y - height;
+    state.o.box.y1 = tearoff__y;
+    tearoff__prevLevel->sub=t1;
+    t1->fromItem=t1->prev->selected;
+  }
+  t1->open=TRUE;
+  win_adjustBox(&(state.o));
+  wimp_open_wind(&(state.o));
+  return TRUE;
+}
+
+void tearoff_displayAt(tearoff t,void *handle,int x,int y)
+{
+  wimp_w w;
+  wimp_wstate state;
+  int height;
+
+  /* If the window is not already torn off, then create
+     the window for it */
+
+  if (w = tearoff__unTearMenu(t, TRUE), w == -1)
+  {
+    if (!t->w)
+    {
+      w = tearoff__createWindow(t);
+      if (w == -1) return;
+      win_register_event_handler(w, tearoff__windowHandler, t);
+    }
+    else
+      w=t->w;
+  }
+
+  if (handle) t->userHandle=handle;
+
+  tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
+  t->prev = NULL;
+  wimp_get_wind_state(w, &state);
+  height = state.o.box.y1 - state.o.box.y0;
+  state.o.box.x0 = x;
+  state.o.box.x1 = x + t->width;
+  state.o.box.y0 = y - height;
+  state.o.box.y1 = y;
+  tearoff__currentMenu = t;
+  tearSupport_opened(wimpt_task());
+  t->open=TRUE;
+  win_adjustBox(&(state.o));
+  wimp_open_wind(&(state.o));
+}
+
+int tearoff_height(tearoff t)
+{
+  int height=0;
+
+  height+=t->numberOfItems*44+t->dotted;
+  if (t->tearoff) height+=tearoff__HEIGHT;
+  return height;
+}
+
+/* --- Used to receive messages from TearoffSupport */
+
+static BOOL unknown_event(wimp_eventstr *e, void *handle)
+{
+  win_event_handler eh = 0;
+
+  handle = handle;
+
+  switch(e->e)
+  {
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+    switch (e->data.msg.hdr.action)
+    {
+      case wimp_MMODECHANGE:
+        if (tearoff__oldHandle)
+          tearoff__cleanUp();
+        return FALSE;
+
+      case 0x4a340:
+
+        /* Button pressed message - close any transient menus
+           iff button click was not in one of my menus */
+
+        if (e->data.msg.data.helprequest.m.w == tearoff__currentDbox)
+          return TRUE;
+        win_read_eventhandler(e->data.msg.data.helprequest.m.w,
+                              &eh,
+                              &handle);
+        if (eh != tearoff__windowHandler)
+          tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
+        return TRUE;
+
+      case 0x4a341:
+
+        /* A close menu message - close menus regardless.
+           eg. escape pressed or wimp menu opened */
+
+        tearoff__closeMenuStructure(tearoff__currentMenu,NULL);
+
+        return TRUE;
+    }
+  }
+return FALSE;
+}
+
+/* --- Some Functions the give functionality to user of library */
+
+void tearoff_closeMenu(tearoff t)
+{
+  if (t->open)
+  {
+    if (!t->tornoff)
+      tearoff__closeMenuStructure(t,NULL);
+    else
+      tearoff__closeTornoff(t,FALSE);
+  }
+}
+
+static void tearoff__defaultmidb(wimp_w w,
+                          int made,
+                          void *handlea,
+                          void *handleb,
+                          void *handlec)
+{
+  if (w==win_ICONBAR)
+  {
+    wimp_mousestr m;
+
+    wimp_get_point_info(&m);
+    tearoff_displayAt((tearoff)handlea,
+                      0,
+                     m.x-64,
+                     96+tearoff_height((tearoff)handlea));
+  }
+  else
+    tearoff_displayMenu((tearoff)handlea,0);
+}
+
+BOOL tearoff_attachMenu(wimp_w w,tearoff t,void *handle)
+{
+  if (handle) t->userHandle=handle;
+  return (event_attachMidbHandler(w,
+                                 tearoff__defaultmidb,
+                                 TRUE,
+                                 (void *)t,
+                                 NULL,
+                                 NULL
+                                 ));
+}
+
+void tearoff_init(void)
+{
+  static BOOL initialised=FALSE;
+
+  if (initialised) return;
+  tearSupport_init();
+  riscos3=(wimpt_getVersion()>=300);
+  win_add_unknown_event_processor(unknown_event, 0);
+  dbox__rms(tearoff__finder,tearoff__wasSubmenu,tearoff__openDbox);
+  alarm_init();
+  tearoff__alm.item=-1;
+  initialised=TRUE;
+}
diff --git a/StraySrc/Libraries/Steel/c/template b/StraySrc/Libraries/Steel/c/template
new file mode 100644 (file)
index 0000000..847c7a9
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ * template.c
+ *
+ * Loading and manipulation of window templates
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "os.h"
+#include "wimp.h"
+#include "utils.h"
+#include "template.h"
+#include "dll.h"
+#include "mem.h"
+#include "font.h"
+#include "msgs.h"
+#include "werr.h"
+#include "res.h"
+#include "resspr.h"
+
+/*----- Note to the reader ------------------------------------------------*
+ *
+ * This code makes no use of Wimp_LoadTemplate at all.  It's modified from
+ * the Glass template loading code, which as we all know is no slouch.
+ */
+
+/*----- Variables ---------------------------------------------------------*/
+
+static template *template__all;
+static char template__fonts[256];
+static BOOL template__usingFonts;
+
+/*----- Main code ---------------------------------------------------------*/
+
+#ifndef _dll_NODLL
+  extern void _dllEntry(template__exit)(void);
+#endif
+
+/*
+ * int template__cmp(char *a,char *b)
+ *
+ * Use
+ *  Compares two strings of length 12 or less.
+ */
+
+static int template__cmp(char *a,char *b)
+{
+  int i;
+  for (i=0;i<12;i++)
+  {
+    if (*a<32 && *b<32)
+      return (0);
+    if (*a!=*b)
+      return (*a-*b);
+    a++;
+    b++;
+  }
+  return (0);
+}
+
+/*
+ * template *template_copy(template *from)
+ *
+ * Use
+ *  Copies a template field-for-field and fixes up new indirected data for
+ *  it.
+ */
+
+template *template_copy(template *from)
+{
+  template *t;
+  wimp_icon *ic;
+  int i;
+  int size=sizeof(template)+from->window.nicons*sizeof(wimp_icon);
+
+  /* --- Allocate a new template block and copy --- */
+
+  t=mem_alloc(size);
+  if (!t)
+    return (0);
+  memcpy(t,from,size);
+
+  /* --- Allocate a new indirected space block and copy that too --- */
+
+  if (!from->workspace)
+    return(t);
+
+  t->workspace=mem_alloc(t->workspacesize);
+  if (!t->workspace)
+  {
+    mem_free(t);
+    return (0);
+  }
+  memcpy(t->workspace,from->workspace,t->workspacesize);
+
+  /* --- Fix up all the indirected pointers --- */
+
+  if (t->window.titleflags & wimp_INDIRECT)
+  {
+    t->window.title.indirecttext.buffer+=t->workspace-from->workspace;
+    if (t->window.titleflags & wimp_ITEXT &&
+        t->window.title.indirecttext.validstring!=(char *)-1)
+      t->window.title.indirecttext.validstring+=t->workspace-from->workspace;
+  }
+
+  /* --- And for the icons --- */
+
+  ic=(wimp_icon *)(t+1);
+  for (i=0;i<t->window.nicons;i++)
+  {
+    if (ic->flags & wimp_INDIRECT)
+    {
+      ic->data.indirecttext.buffer+=t->workspace-from->workspace;
+      if (ic->flags & wimp_ITEXT &&
+          ic->data.indirecttext.validstring!=(char *)-1)
+        ic->data.indirecttext.validstring+=t->workspace-from->workspace;
+    }
+    ic++;
+  }
+
+  return (t);
+}
+
+/*
+ * void template__exit(void)
+ *
+ * Use
+ *  Closes down all the fonts loaded with templates
+ */
+
+_dll_static void template__exit(void)
+{
+  int i,j;
+  for (i=0;i<256;i++)
+  {
+    for (j=0;j<template__fonts[i];j++)
+      font_lose(i);
+  }
+}
+
+/*
+ * BOOL template_readfile(char *name)
+ *
+ * Use
+ *  Loads the template file named into memory, and sorts out all its
+ *  indirected data.
+ *
+ *  Template entries with strange identifiers are ignored.  Other entry
+ *  types may be supported later.
+ *
+ * Parameters
+ *  char *name == the name of the template file to load (a resource file)
+ *
+ * Returns
+ *  FALSE if the file contained no sprite icons.  No, I don't understand
+ *  the use of this either.  It's not my problem though.  I just write the
+ *  code.
+ */
+
+/* --- Macros from Glass's gStruct.h to help read the structure --- */
+
+#define intptr(flex,offset) \
+  ((int *)(((char *)(flex))+(offset)))
+#define charptr(flex,offset) \
+  (((char *)(flex))+(offset))
+#define _ptr(type,flex,offset) \
+  ((type *)(((char *)(flex))+(offset)))
+
+BOOL template_readfile(char *file)
+{
+  /* --- Variables for loading the file --- */
+
+  char *filebuf;
+  os_filestr f;
+
+  /* --- Variables for mangling the file in memory --- */
+
+  int fontData;                  /* Offset of font ata from start of file  */
+  template *w;                   /* For each window we come across         */
+  int datasize;                  /* Size of indirected data for the window */
+  char *p=0;                     /* Offset in indirected data for next item*/
+  char *q;                       /* Pointer to an indirected string        */
+  int index;                     /* Current index entry we're looking at   */
+  char name[13];                 /* For the name of the template           */
+  int objoff;                    /* Offset of window we're looking at      */
+  wimp_icon *iconptr;            /* Offset of icon we're looking at        */
+  wimp_iconflags icf;            /* Icon flags for something or other      */
+  int objtype;                   /* Type of current template entry         */
+  int numicons;                  /* Number of icons in a window            */
+  int i;                         /* A loop counter                         */
+  int pass;                      /* We take two passes at each window      */
+
+  /* --- Font handling --- */
+
+  int fheight;                   /* Height of a font required              */
+  int fwidth;                    /* Width of a font required               */
+  int fhandle;                   /* Font handle                            */
+  int fptr;                      /* Offset of font name                    */
+  BOOL fquiet=FALSE;             /* Shut up about font failures.           */
+
+  /* --- Load the file into memory --- */
+
+  f.action=17;
+  f.name=file;
+  if (utils_complain(os_file(&f),
+      msgs_lookup("templateELF:Error loading template file: '%s'")))
+  {
+    exit(1);
+  }
+
+  filebuf=mem_alloc(f.start);
+  if (!f.start)
+  {
+    werr(FALSE,msgs_lookup("templateNEM:Not enough memory "
+                           "to load template file."));
+    exit(1);
+  }
+
+  f.action=16;
+  f.loadaddr=(int)filebuf;
+  f.execaddr=0;
+  if (utils_complain(os_file(&f),
+      msgs_lookup("templateELF:Error loading template file: '%s'")))
+  {
+    exit(1);
+  }
+
+  /* --- Now start parsing up the file structure --- */
+
+  fontData=*intptr(filebuf,0);
+
+  /* --- Loop through each index entry in turn --- */
+
+  for (index=16;*intptr(filebuf,index);index+=24)
+  {
+    /* --- Find this entry's location in the file --- */
+
+    objoff=*intptr(filebuf,index);
+    objtype=*intptr(filebuf,index+8);
+
+    /* --- Mangle it according to its type --- */
+
+    switch (objtype)
+    {
+      case 1:
+
+        /* --- Find the name of the window and its number of icons --- */
+
+        memcpy(name,charptr(filebuf,index+12),12);
+        name[12]=0;
+        utils_ctermToNterm(name);
+        memcpy(&numicons,intptr(filebuf,objoff+84),sizeof(int));
+
+        /* --- Allocate a template block for it --- */
+
+        datasize=sizeof(template)+numicons*sizeof(wimp_icon);
+        w=mem_alloc(datasize);
+        if (!w)
+        {
+          werr(FALSE,msgs_lookup("templateNEM:Not enough memory "
+                                 "to load template file."));
+          exit(1);
+        }
+
+        /* --- Copy the template data into this block --- */
+
+        memcpy(&w->window,
+               _ptr(void,filebuf,objoff),
+               sizeof(wimp_wind)+numicons*sizeof(wimp_icon));
+
+        /* --- Set up the window's sprite area --- */
+
+        w->window.spritearea=resspr_area();
+
+        /* --- Now perform the two passes on the window data --- */
+
+        datasize=0;
+        for (pass=1;pass<=2;pass++)
+        {
+          icf=w->window.titleflags;
+
+          /* --- Handle title indirected data --- */
+
+          if (icf & wimp_INDIRECT)
+          {
+            if (pass==1)
+            {
+              /* --- Pass 1 just counts the size we need --- */
+
+              q=(int)w->window.title.indirecttext.buffer+filebuf+objoff;
+              utils_ctermToNterm(q);
+              datasize+=w->window.title.indirecttext.bufflen;
+              if (icf & wimp_ITEXT &&
+                  w->window.title.indirecttext.validstring!=(char *)-1)
+              {
+                q=(int)w->window.title.indirecttext.validstring+
+                  filebuf+
+                  objoff;
+                utils_ctermToNterm(q);
+                datasize+=strlen(q)+1;
+              }
+            }
+            else
+            {
+              q=(int)w->window.title.indirecttext.buffer+filebuf+objoff;
+              memcpy(p,q,w->window.title.indirecttext.bufflen);
+              w->window.title.indirecttext.buffer=p;
+              p+=w->window.title.indirecttext.bufflen;
+              if (icf & wimp_ITEXT &&
+                  w->window.title.indirecttext.validstring!=(char *)-1)
+              {
+                q=(int)w->window.title.indirecttext.validstring+
+                  filebuf+
+                  objoff;
+                strcpy(p,q);
+                w->window.title.indirecttext.validstring=p;
+                p+=strlen(q)+1;
+              }
+            }
+          }
+
+          /* --- Cope with antialiasing on the second pass --- */
+
+          if ((icf & wimp_IFONT) && pass==2)
+          {
+            /* --- Get the font handle --- */
+
+            fhandle=(icf & 0xff000000) >> 24;
+
+            /* --- Find information about the font --- */
+
+            fptr=fontData+(fhandle-1)*48;
+            memcpy(&fwidth,intptr(filebuf,fptr)+0,sizeof(int));
+            memcpy(&fheight,intptr(filebuf,fptr)+1,sizeof(int));
+            utils_ctermToNterm(charptr(filebuf,fptr+8));
+
+            /* --- Get a real font like this --- */
+
+            if (font_find(charptr(filebuf,fptr+8),
+                          fwidth,
+                          fheight,
+                          0,0,
+                          &fhandle))
+            {
+              if (!fquiet)
+              {
+                werr(FALSE,msgs_lookup("templateCFF:Some fonts used in this "
+                                       "template file could not be found.  "
+                                       "Icons with such fonts will not be "
+                                       "anti-aliased."));
+                fquiet=TRUE;
+              }
+              icf&=~wimp_IFONT;
+            }
+            else
+            {
+              icf=(icf & 0x00ffffff) | (fhandle << 24);
+              template__fonts[fhandle]++;
+              if (!template__usingFonts)
+              {
+                atexit(_dllEntry(template__exit));
+                template__usingFonts=TRUE;
+              }
+            }
+            w->window.titleflags=icf;
+          }
+
+          /* --- Now handle each icon in turn like this --- */
+
+          iconptr=(wimp_icon *)(w+1);
+          for (i=0;i<numicons;i++)
+          {
+            icf=iconptr->flags;
+
+            /* --- Handle title indirected data --- */
+
+            if (icf & wimp_INDIRECT)
+            {
+              if (pass==1)
+              {
+                /* --- Pass 1 just counts the size we need --- */
+
+                q=(int)iconptr->data.indirecttext.buffer+filebuf+objoff;
+                utils_ctermToNterm(q);
+                datasize+=iconptr->data.indirecttext.bufflen;
+                if (icf & wimp_ITEXT &&
+                    iconptr->data.indirecttext.validstring!=(char *)-1)
+                {
+                  q=(int)iconptr->data.indirecttext.validstring+
+                    filebuf+
+                    objoff;
+                  utils_ctermToNterm(q);
+                  datasize+=strlen(q)+1;
+                }
+              }
+              else
+              {
+                q=(int)iconptr->data.indirecttext.buffer+filebuf+objoff;
+                memcpy(p,q,iconptr->data.indirecttext.bufflen);
+                iconptr->data.indirecttext.buffer=p;
+                p+=iconptr->data.indirecttext.bufflen;
+                if (icf & wimp_ITEXT &&
+                    iconptr->data.indirecttext.validstring!=(char *)-1)
+                {
+                  q=(int)iconptr->data.indirecttext.validstring+
+                    filebuf+
+                    objoff;
+                  strcpy(p,q);
+                  iconptr->data.indirecttext.validstring=p;
+                  p+=strlen(q)+1;
+                }
+              }
+            }
+
+            /* --- Cope with antialiasing on the second pass --- */
+
+            if ((icf & wimp_IFONT) && pass==2)
+            {
+              /* --- Get the font handle --- */
+
+              fhandle=(icf & 0xff000000) >> 24;
+
+              /* --- Find information about the font --- */
+
+              fptr=fontData+(fhandle-1)*48;
+              memcpy(&fwidth,intptr(filebuf,fptr)+0,sizeof(int));
+              memcpy(&fheight,intptr(filebuf,fptr)+1,sizeof(int));
+              utils_ctermToNterm(charptr(filebuf,fptr+8));
+
+              /* --- Get a real font like this --- */
+
+              if (font_find(charptr(filebuf,fptr+8),
+                            fwidth,
+                            fheight,
+                            0,0,
+                            &fhandle))
+              {
+                if (!fquiet)
+                {
+                  werr(FALSE,msgs_lookup("templateCFF:Some fonts used in "
+                                         "this template file could not be "
+                                         "found.  Icons with such fonts "
+                                         "will not be anti-aliased."));
+                  fquiet=TRUE;
+                }
+                icf&=~wimp_IFONT;
+              }
+              else
+              {
+                icf=(icf & 0x00ffffff) | (fhandle << 24);
+                template__fonts[fhandle]++;
+                if (!template__usingFonts)
+                {
+                  atexit(_dllEntry(template__exit));
+                  template__usingFonts=TRUE;
+                }
+              }
+              iconptr->flags=icf;
+            }
+            iconptr++;
+          }
+
+          /* --- Finish off the pass properly now --- */
+
+          if (pass==1)
+          {
+            /* --- Allocate the right amount of indirected space --- */
+
+            w->workspacesize=datasize;
+            if (datasize)
+            {
+              w->workspace=mem_alloc(datasize);
+              if (!w->workspace)
+              {
+                werr(FALSE,msgs_lookup("templateNEM:Not enough memory "
+                                       "to load template file."));
+                exit(1);
+              }
+            }
+            else
+              w->workspace=0;
+            p=w->workspace;
+          }
+          else
+          {
+            /* --- Link the filled in structure into the list --- */
+
+            w->next=template__all;
+            template__all=w;
+
+            /* --- Fill in the name of the template --- */
+
+            memcpy(w->name,name,12);
+          }
+        }
+        break;
+    }
+  }
+
+  /* --- Finished -- return to the user --- */
+
+  mem_free(filebuf);
+  return (TRUE);                     /* It can't do any harm, now, can it? */
+}
+
+/*
+ * void template_init(void)
+ *
+ * Use
+ *  Loads the application's `Templates' file.
+ */
+
+void template_init(void)
+{
+  template_readfile(res_name("Templates"));
+}
+
+/*
+ * void template_use_fancyfonts(void)
+ *
+ * Use
+ *  Does absolutely nothing at all.  Fancy font support happens anyway.
+ */
+
+void template_use_fancyfonts(void)
+{
+  /* Do absolutely nothing at all :-) */
+}
+
+/*
+ * BOOL template_exists(char *name)
+ *
+ * Use
+ *  Returns TRUE if the named template is known at the moment, or FALSE
+ *  otherwise
+ */
+
+BOOL template_exists(char *name)
+{
+  template *t=template__all;
+  while (t)
+  {
+    if (!template__cmp(name,t->name))
+      return (TRUE);
+    t=t->next;
+  }
+  return (FALSE);
+}
+
+/*
+ * template *template_find(char *name)
+ *
+ * Use
+ *  Locates a named template and returns a pointer to it
+ */
+
+template *template_find(char *name)
+{
+  template *t=template__all;
+  while (t)
+  {
+    if (!template__cmp(name,t->name))
+      return (t);
+    t=t->next;
+  }
+  werr(TRUE,msgs_lookup("templateNF:Template '%s' not found"),name);
+  return (0); /* FWIW */
+}
+
+/*
+ * wimp_wind *template_syshandle(char *name)
+ *
+ * Use
+ *  Not very much, if the truth be known.  It returns a pointer to a named
+ *  window definition.
+ */
+
+wimp_wind *template_syshandle(char *name)
+{
+  return (&template_find(name)->window);
+}
+
+/*
+ * BOOL template_loaded(void)
+ *
+ * Use
+ *  Returns TRUE if we have templates on board.
+ */
+
+BOOL template_loaded(void)
+{
+  return (template__all ? TRUE : FALSE);
+}
diff --git a/StraySrc/Libraries/Steel/c/utils b/StraySrc/Libraries/Steel/c/utils
new file mode 100644 (file)
index 0000000..c63833f
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * utils
+ *
+ * Various miscellaneous (and largely non-WIMP) utility routines
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "stdio.h"
+#include "string.h"
+#include "ctype.h"
+#include "utils.h"
+#include "os.h"
+#include "werr.h"
+#include "wimpt.h"
+#include "swiv.h"
+#include "swis.h"
+#include "buffer.h"
+
+/*
+ * int utils_caselessCmp(const char *s1,const char *s2)
+ *
+ * Use
+ *  Caseless comparison between string 1 and string 2
+ *
+ * Parameters
+ *  const char *s1 == source string
+ *  const char *s2 == target string
+ *
+ * Returns
+ *  0 if the strings are equal, >0 if s1>s2, or <0 if s1<s2.
+ */
+
+int utils_caselessCmp(const char *s1,const char *s2)
+{
+  if (wimpt_getVersion()>=300)
+    return (_swi(Territory_Collate, _inr(0,3)+_return(0), -1,s1,s2,3));
+  else
+  {
+    char c1;
+    char c2;
+    while (*s1!='\0' || *s2!='\0')
+    {
+      c1=tolower(*(s1++));
+      c2=tolower(*(s2++));
+      if (c1!=c2)
+        return (c1-c2);
+    }
+    return (0);
+  }
+}
+
+/*
+ * char *utils_ctermToNterm(char *s)
+ *
+ * Use
+ *  Changes a control-terminated string into a null-terminated string.
+ *
+ * Parameters
+ *  char *s == the string to change
+ *
+ * Returns
+ *  A pointer to the string.
+ */
+
+char *utils_ctermToNterm(char *s)
+{
+  char *p;
+  for (p=s;*p>31;p++)
+    /* blank loop - all in for statement */;
+  *p=0;
+  return (s);
+}
+
+/*
+ * char *utils_leafname(char *filename)
+ *
+ * Use
+ *  Returns the leafname of the file whose full pathname is given in
+ *  filename.
+ *
+ * Parameters
+ *  char *filename == pointer to full filename string
+ *
+ * Returns
+ *  Pointer to character after last '.' of string.
+ */
+
+char *utils_leafname(char *filename)
+{
+  char *p=filename;
+  while (*filename)
+  {
+    if (*(filename++)=='.')
+      p=filename;
+  }
+  return (p);
+}
+
+/*
+ * os_error *utils_complain(os error *e,char *string)
+ *
+ * Use
+ *  If e is an error (i.e. not NULL) then the routine calls werr() with
+ *  parameters (string,e->errmess).  Ths string must contain a '%s' at some
+ *  point.
+ *
+ * Parameters
+ *  os_error *e == either NULL or a pointer to a standard system
+ *    error structure.
+ *  char *string == a string containing one %s, for which the error
+ *    message from the structure passed above will be substituted.
+ *
+ * Returns
+ *  The error pointer.
+ */
+
+os_error *utils_complain(os_error *e,char *string)
+{
+  if (e)
+    werr(FALSE,string,e->errmess);
+  return (e);
+}
+
+/*
+ * char *utils_cvtSize(int size)
+ *
+ * Use
+ *  Converts a size in bytes into a string suitable to display the size to
+ *  a user.  It uses OS_ConvertFileSize to do he translation, although this
+ *  is not guaranteed for future versions.
+ *
+ * Parameters
+ *  int size == the size in bytes
+ *
+ * Returns
+ *  A pointer to the result (read-only)
+ */
+
+char *utils_cvtSize(int size)
+{
+  char *buff=buffer_find();
+  _swix(XOS_ConvertFileSize,_inr(0,2),size,buff,16);
+  return (buff);
+}
diff --git a/StraySrc/Libraries/Steel/c/viewer b/StraySrc/Libraries/Steel/c/viewer
new file mode 100644 (file)
index 0000000..f60aac6
--- /dev/null
@@ -0,0 +1,2030 @@
+/*
+ * viewer
+ *  Allows creation of Filer-like windows which rearrange themselves.
+ *
+ * v. 1.00 (13 August 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "wimp.h"
+#include "wimpt.h"
+#include "win.h"
+#include "viewer.h"
+#include "msgs.h"
+#include "bbc.h"
+#include "werr.h"
+#include "os.h"
+#include "xfersend.h"
+#include "mem.h"
+#include "coords.h"
+#include "utils.h"
+#include "help.h"
+#include "fileicon.h"
+#include "buffer.h"
+#include "swis.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "dll.h"
+
+#ifndef _dll_NODLL
+  extern void _dllEntry(viewer__events)(wimp_eventstr *e,void *handle);
+#endif
+
+/*
+ * A structure of information about a viewer icon.
+ */
+
+typedef struct viewer__iconstr
+{
+  viewer_icon next;
+  viewer_icon last;
+  char *text;
+  char sprite[15];
+  void *handle;
+  int filetype;
+  BOOL selected;
+  viewer v;
+}
+viewer__iconstr;
+
+/*
+ * A structure of information about a viewer window.
+ */
+
+typedef struct viewer__viewerstr
+{
+  wimp_w wind;
+  int icons;
+  viewer_eventhandler events;
+  void *closeHandle;
+  viewer_raweventhandler rawEvents;
+  void *rawHandle;
+  viewer_redrawhandler rdr;
+  void *rdrHandle;
+  viewer_compare cmp;
+  sprite_area *spr;
+  int width;
+  int height;
+  int across;
+  int down;
+  int selected;
+  char banner[50];
+  char title[256];
+  viewer_icon iconlist;
+  viewer_icon menuSel;
+  wimp_openstr oldSize;
+}
+viewer__viewerstr;
+
+/*
+ * Some constants for the things
+ */
+
+#define viewer__MINWIDTH 380
+#define viewer__MINHEIGHT 160
+#define viewer__GAP 16
+#define viewer__BANNERHEIGHT 48
+
+static viewer_saveproc viewer__usersave;
+static viewer_sendproc viewer__usersend;
+static viewer_printproc viewer__userprint;
+static viewer_icon viewer__currentIcon;
+static viewer viewer__currentViewer;
+static int viewer__filetype;
+
+#define max(x,y) ((x)>(y) ? (x) : (y))
+#define min(x,y) ((x)<(y) ? (x) : (y))
+
+/*
+ * void viewer__resize(viewer v)
+ *
+ * Use
+ *  Resizes the viewer nicely, altering the extent if necessary.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ */
+
+static void viewer__resize(viewer v)
+{
+  wimp_wstate s;
+  int w;
+  int across;
+  int down;
+  int minw;
+  int scw;
+  int maxacc;
+  wimp_redrawstr r;
+  wimpt_noerr(wimp_get_wind_state(v->wind,&s));
+  w=s.o.box.x1-s.o.box.x0;
+  scw=wimpt_scwidth()-40;
+  across=w/(v->width+viewer__GAP);
+  maxacc=scw/(v->width+viewer__GAP);
+  if (across>v->icons)
+    across=v->icons;
+  if (maxacc>v->icons)
+    maxacc=v->icons;
+  if (across>maxacc)
+    across=maxacc;
+  if (across==0)
+    across=1;
+  down=v->icons/across;
+  if (v->icons%across!=0)
+    down++;
+  if (down==0)
+    down=1;
+  if (v->across==across && v->down==down && (s.flags & wimp_WOPEN))
+    return;
+  minw=wimpt_stringWidth(v->title)+164;
+  if (v->banner[0]!='\0')
+  {
+    int l=wimpt_stringWidth(v->banner)+64;
+    if (l>minw)
+      minw=l;
+  }
+  if (minw<viewer__MINWIDTH)
+    minw=viewer__MINWIDTH;
+  r.w=v->wind;
+  r.box.x0=0;
+  r.box.y0=-(v->height+viewer__GAP)*down;
+  if (v->banner[0]!='\0')
+    r.box.y0-=viewer__BANNERHEIGHT;
+  if (r.box.y0>-viewer__MINHEIGHT)
+    r.box.y0=-viewer__MINHEIGHT;
+  r.box.x1=(v->width+viewer__GAP)*maxacc;
+  if (r.box.x1<minw)
+    r.box.x1=minw;
+  r.box.y1=0;
+  wimpt_noerr(wimp_set_extent(&r));
+
+  /* --- Acorn-approved hack --- *
+   *
+   * We have problems with the Wimp fiddling our extent after we've set it,
+   * so we just redraw lots and lots.
+   */
+
+  r.box.x0=r.box.y0=-0xFFFFFF;
+  r.box.x1=r.box.y1=0xFFFFFF;
+  wimpt_noerr(wimp_force_redraw(&r));
+
+  if (s.flags & wimp_WOPEN)
+    wimpt_noerr(wimp_open_wind(&s.o));
+  v->across=across;
+  v->down=down;
+}
+
+/*
+ * void viewer__redrawicon(wimp_redrawstr *r,viewer_icon icn,wimp_box *box)
+ *
+ * Use
+ *  Redraws an icon in the box specified.
+ *
+ * Parameters
+ *  viewer_icon icn == the icon to redraw
+ *  wimp_box *box == the box to draw it in
+ */
+
+static void viewer__redrawicon
+(
+  wimp_redrawstr *r,
+  viewer_icon icn,
+  wimp_box *box
+)
+{
+  wimp_icon i;
+  char valid[256];
+  viewer v=icn->v;
+  if (v->rdr)
+  {
+    (v->rdr)(icn,r,box,icn->text,icn->sprite,icn->selected,v->rdrHandle);
+    return;
+  }
+  i.box=*box;
+  if (icn->text!=0 && icn->sprite[0]!='\0')
+  {
+    i.flags=wimp_ITEXT|wimp_ISPRITE|wimp_INDIRECT|wimp_IHCENTRE;
+    sprintf(valid,"S%s",icn->sprite);
+    i.data.indirecttext.buffer=icn->text;
+    i.data.indirecttext.validstring=valid;
+    i.data.indirecttext.bufflen=1;
+  }
+  else if (icn->text!=0)
+  {
+    i.flags=wimp_ITEXT|wimp_INDIRECT|wimp_IHCENTRE|wimp_IVCENTRE;
+    i.data.indirecttext.buffer=icn->text;
+    i.data.indirecttext.validstring=(char *)-1;
+    i.data.indirecttext.bufflen=1;
+  }
+  else
+  {
+    i.flags=wimp_ISPRITE|wimp_INDIRECT|wimp_IHCENTRE|wimp_IVCENTRE;
+    i.data.indirectsprite.name=icn->sprite;
+    i.data.indirectsprite.spritearea=v->spr;
+    i.data.indirectsprite.nameisname=TRUE;
+  }
+  i.flags|=0x17000000;
+  if (icn->selected)
+    i.flags|=wimp_ISELECTED;
+  wimpt_noerr(wimp_ploticon(&i));
+}
+
+/*
+ * void viewer_drawFileIcons
+ * (
+ *   viewer_icon icn,
+ *   wimp_redrawstr *r,
+ *   wimp_box *box,
+ *   char *text,
+ *   char *sprite,
+ *   BOOL selected,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Redraw handler which takes into account filetypes of icons.  The icons
+ *  automatically get new sprites if the sprites for their filetypes change.
+ *  For applications, the text is considered to be a filename.  Register
+ *  this function using viewer_redrawHandler().
+ *
+ * Parameters
+ *  viewer_icon icn == the icon to paint
+ *  wimp_redrawstr *r == information about this redraw
+ *  wimp_box *box == the box to draw the icon in
+ *  char *text == the text to display
+ *  char *sprite == the sprite to display
+ *  BOOL selected == is the icon selected?
+ *  void *handle == a caller defined handle (ignored)
+ */
+
+void viewer_drawFileIcons
+(
+  viewer_icon icn,
+  wimp_redrawstr *r,
+  wimp_box *box,
+  char *text,
+  char *sprite,
+  BOOL selected,
+  void *handle
+)
+{
+  wimp_icon i;
+  char valid[256];
+  handle=handle;
+  r=r;
+  i.box=*box;
+  i.flags=wimp_ITEXT|wimp_ISPRITE|wimp_INDIRECT|wimp_IHCENTRE;
+  if (icn->filetype!=-1)
+    sprintf(valid,"S%s",fileicon_spriteName(icn->filetype,text));
+  else
+    sprintf(valid,"S%s",sprite);
+  i.data.indirecttext.buffer=text;
+  i.data.indirecttext.validstring=valid;
+  i.data.indirecttext.bufflen=1;
+  i.flags|=0x17000000;
+  if (selected)
+    i.flags|=wimp_ISELECTED;
+  wimpt_noerr(wimp_ploticon(&i));
+}
+
+/*
+ * viewer__redraw(wimp_redrawstr *r,void *handle)
+ *
+ * Use
+ *  Redraws a viewer window
+ *
+ * Parameters
+ *  wimp_redrawstr *r == the bit to redraw
+ *  void *handle == the viewer
+ */
+
+static void viewer__redraw(wimp_redrawstr *r,void *handle)
+{
+  viewer v=(viewer)handle;
+  viewer_icon icn=v->iconlist;
+  int oy=r->box.y1-r->scy;
+  int x=viewer__GAP/2;
+  int y=-viewer__GAP/2;
+  wimp_box box;
+  coords_cvtstr c;
+  wimp_box g;
+  int cnt=0;
+  wimp_icon banicn={28,-48,1000,0,0x037000131};
+  c.box=r->box;
+  c.scx=r->scx;
+  c.scy=r->scy;
+  g=r->g;
+  coords_box_toworkarea(&g,&c);
+  wimp_setcolour(0x81);
+  bbc_clg();
+  if (v->banner[0]!='\0')
+  {
+    if (g.y1>-viewer__BANNERHEIGHT)
+    {
+      wimp_setcolour(3);
+      bbc_rectanglefill
+      (
+        r->g.x0,
+        oy-viewer__BANNERHEIGHT,
+        r->g.x1-r->g.x0,
+        viewer__BANNERHEIGHT
+      );
+      wimp_setcolour(7);
+      banicn.box.x1=100+wimpt_stringWidth(v->banner);
+      banicn.data.indirecttext.buffer=v->banner;
+      banicn.data.indirecttext.validstring=(char *)-1;
+      wimpt_noerr(wimp_ploticon(&banicn));
+    }
+    y-=viewer__BANNERHEIGHT;
+  }
+  while (icn)
+  {
+    box.x0=x;
+    box.x1=x+v->width;
+    box.y1=y;
+    box.y0=y-v->height;
+    if (coords_boxesoverlap(&box,&g))
+      viewer__redrawicon(r,icn,&box);
+    icn=icn->next;
+    if ((++cnt)==v->across)
+    {
+      x=viewer__GAP/2;
+      y-=viewer__GAP+v->height;
+      cnt=0;
+    }
+    else
+      x+=viewer__GAP+v->width;
+  }
+}
+
+/*
+ * void viewer__events(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Window event handler for the viewer.
+ *
+ * Parameters
+ *  wimp_eventstr *e == the wimp event structure
+ *  void *handle == my data (i.e. a 'this' pointer to my viewer__viewerstr)
+ */
+
+_dll_static void viewer__events(wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  viewer v=(viewer)handle;
+  wimp_wstate s;
+  if (v->rawEvents)
+    handled=(v->rawEvents)(v,e,v->rawHandle);
+  if (handled)
+    return;
+  switch (e->e)
+  {
+    case wimp_EREDRAW:
+      wimpt_redraw(viewer__redraw,v);
+      break;
+    case wimp_EOPEN:
+      if (wimpt_justChangedMode())
+        viewer_settitle(v,0);
+      wimpt_noerr(wimp_get_wind_state(v->wind,&s));
+      wimpt_noerr(wimp_open_wind(&e->data.o));
+      viewer__resize(v);
+      if (s.flags & wimp_WCLICK_TOGGLE)
+      {
+        if (s.flags & wimp_WFULL)
+        {
+          e->data.o.box=v->oldSize.box;
+          e->data.o.x=v->oldSize.x;
+          e->data.o.y=v->oldSize.y;
+          wimpt_noerr(wimp_open_wind(&e->data.o));
+        }
+        else
+          v->oldSize=s.o;
+      }
+      break;
+    case wimp_ECLOSE:
+      if (v->events)
+        (v->events)(v,viewer_CLOSE,(wimp_bbits)0,v->closeHandle,0);
+      break;
+    case wimp_EBUT:
+      {
+        viewer_icon i=viewer_iconFromCoords
+        (
+          v,
+          e->data.but.m.x,
+          e->data.but.m.y
+        );
+        if (v->events)
+        {
+          (v->events)
+          (
+            v,
+            i,
+            e->data.but.m.bbits,
+            v->closeHandle,
+            (i!=viewer_NOICON) ? i->handle : 0
+          );
+        }
+      }
+      break;
+    case wimp_EKEY:
+      wimpt_noerr(wimp_processkey(e->data.key.chcode));
+      break;
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MHELPREQUEST:
+          {
+            viewer_icon i=viewer_iconFromCoords
+            (
+              v,
+              e->data.msg.data.helprequest.m.x,
+              e->data.msg.data.helprequest.m.y
+            );
+            if (v->events)
+            {
+              (v->events)
+              (
+                v,
+                viewer_HELP,
+                0,
+                v->closeHandle,
+                (i!=viewer_NOICON) ? i->handle : 0
+              );
+            }
+          }
+          break;
+      }
+      break;
+  }
+}
+
+/*
+ * viewer viewer_create
+ * (
+ *   int x,
+ *   int y,
+ *   int width,
+ *   int height,
+ *   sprite_area *spr,
+ *   char *title,
+ *   char *banner
+ * )
+ *
+ * Use
+ *  Creates a viewer window.  Note that viewer windows don't need templates,
+ *  and don't contain real wimp icons, just yer normal redrawn-by-
+ *  application things (which can be handled by a caller-defined function if
+ *  necessary).  The banner along the top is optional - if a null pointer is
+ *  passed, no banner is included.  The sprite area passed applies to all
+ *  the icons in the window, although if  you want to, you can use your own
+ *  redraw routine to handle different sprite areas for them.
+ *
+ * Parameters
+ *  int x,int y == the coordinates of the top-left corner of the window
+ *    (file windows for editors need good positioning here).
+ *  int width == the width of an icon
+ *  int height == the height of an icon
+ *  sprite_area *spr == the sprite area for the window
+ *  char *title == the title of the window
+ *  char *banner == the banner heading along the top (like 'Sprite file
+ *    window' or something)
+ *
+ * Returns
+ *  A handle to the viewer window.  As usual, a NULL pointer indicates
+ *   something went wrong.
+ */
+
+viewer viewer_create
+(
+  int x,
+  int y,
+  int width,
+  int height,
+  sprite_area *spr,
+  char *title,
+  char *banner
+)
+{
+  viewer v=(viewer)mem_alloc(sizeof(viewer__viewerstr));
+  wimp_wind w=
+  {
+    {0,0,0,0},
+    0,0,
+    -1,
+    (
+      wimp_WMOVEABLE |
+      wimp_WBACK |
+      wimp_WQUIT |
+      wimp_WTITLE |
+      wimp_WTOGGLE |
+      wimp_WVSCR |
+      wimp_WSIZE |
+      wimp_WNEW
+    ),
+    {7,2,7,255,3,1,12,0},
+    {0,0,0,0},
+    wimp_ITEXT|wimp_IHCENTRE|wimp_INDIRECT,
+    wimp_IBTYPE*wimp_BCLICKDRAGDOUBLE,
+    0,
+    1,
+    "Yay",
+    0
+  };
+  w.box.x0=x;
+  w.box.x1=x+900-(900%(width+viewer__GAP));
+  if (w.box.x1==x)
+    w.box.x1=x+width+viewer__GAP;
+  w.box.y0=y-500+(500%(height+viewer__GAP));
+  if (w.box.y0==y)
+    w.box.y0=y-height+viewer__GAP;
+  w.box.y1=y;
+  w.spritearea=(void *)spr;
+  if (!v)
+  {
+    werr(FALSE,msgs_lookup("viewerNEM:Not enough room to create viewer."));
+    return (0);
+  }
+  w.title.indirecttext.buffer=v->title;
+  w.title.indirecttext.validstring=(char *)-1;
+  w.title.indirecttext.bufflen=256;
+  strcpy(v->title,title);
+  if (banner)
+  {
+    strcpy(v->banner,banner);
+    w.box.y0-=viewer__BANNERHEIGHT;
+  }
+  else
+    v->banner[0]='\0';
+  v->icons=0;
+  v->events=0;
+  v->rawEvents=0;
+  v->rdr=0;
+  v->cmp=0;
+  v->iconlist=0;
+  v->width=width;
+  v->height=height;
+  v->spr=spr;
+  v->across=-1;
+  v->selected=0;
+  v->menuSel=viewer_NOICON;
+  v->oldSize.box=w.box;
+  v->oldSize.x=w.scx;
+  v->oldSize.y=w.scy;
+  if (wimp_create_wind(&w,&v->wind))
+  {
+    werr
+    (
+      FALSE,
+      msgs_lookup("viewerTMW:Too many windows - "
+                                            "%s could not create viewer."),
+      wimpt_programname()
+    );
+    mem_free(v);
+    return (0);
+  }
+  win_register_event_handler(v->wind,_dllEntry(viewer__events),v);
+  win_activeinc();
+  return (v);
+}
+
+/*
+ * void viewer_display(viewer v)
+ *
+ * Use
+ *  Displays a viewer on the screen.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ */
+
+void viewer_display(viewer v)
+{
+  wimp_wstate state;
+  viewer__resize(v);
+  wimpt_noerr(wimp_get_wind_state(v->wind,&state));
+  state.o.behind=-1;
+  wimpt_noerr(wimp_open_wind(&state.o));
+}
+
+/*
+ * void viewer_hide(viewer v)
+ *
+ * Use
+ *  Hides an open viewer.
+ *
+ * Parameters
+ *  viewer v == the handle
+ */
+
+void viewer_hide(viewer v)
+{
+  wimpt_noerr(wimp_close_wind(v->wind));
+}
+
+/*
+ * void viewer_delete(viewer v,void (*freeProc)(void *handle))
+ *
+ * Use
+ *  Zaps a viewer and everything in it.  The function you pass to this
+ *  routine is called with every icon handle the viewer has associated with
+ *  it, so you don't need to link all the structures together - I've already
+ *  done that here!
+ *
+ * Parameters
+ *  viewer v == the viewer to destroy
+ *  void (*freeProc)(void *handle) == a function to free one of the caller-
+ *    defined viewer icon structures.
+ */
+
+void viewer_delete(viewer v,void (*freeProc)(void *handle))
+{
+  viewer_icon icn=v->iconlist;
+  viewer_icon i;
+  while (icn)
+  {
+    if (icn->handle && freeProc)
+      freeProc(icn->handle);
+    i=icn;
+    icn=i->next;
+    mem_free(i->text);
+    mem_free(i);
+  }
+  win_register_event_handler(v->wind,0,0);
+  win_activedec();
+  wimpt_noerr(wimp_delete_wind(v->wind));
+  mem_free(v);
+}
+
+/*
+ * void viewer_eventHandler(viewer v,viewer_eventhandler proc,void *handle)
+ *
+ * Use
+ *  Attaches an event handler to the viewer.  The handle passed to this
+ *  function is only used for close events, so you can take appropriate
+ *  action at the other end.  Otherwise, the handle for the icon concerned
+ *  is used.  Suggested code:
+ *
+ * void user_viewer(viewer v,viewer_icon i,wimp_bbits b,void *handle)
+ * {
+ *   user_fileStructure *file=(user_fileStructure *)handle;
+ *   user_itemStructure *item=(user_itemStructure *)handle;
+ *   switch ((int)i)
+ *   {
+ *     case (int)viewer_CLOSE:
+ *       ... use 'file' for this bit of code ...
+ *       break;
+ *     case viewer_NOICON:
+ *       ... use 'file' for this bit as well ...
+ *       break;
+ *     default:
+ *       ... use 'item' for this bit of code ...
+ *       break;
+ *   }
+ * }
+ *
+ * Parameters
+ *  viewer v == the viewer to attach the handler to
+ *  viewer_eventhandler proc == the event handler
+ *  void *handle == the handle
+ */
+
+void viewer_eventHandler(viewer v,viewer_eventhandler proc,void *handle)
+{
+  v->events=proc;
+  v->closeHandle=handle;
+}
+
+/*
+ * void viewer_rawEventHandler
+ * (
+ *   viewer v,
+ *   viewer_raweventhandler proc,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Attaches a raw event handler to a viewer.  Same as always, this one.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  viewer_raweventhandler proc == the handler routine
+ *  void *handle == the handle for the user's data
+ */
+
+void viewer_rawEventHandler
+(
+  viewer v,
+  viewer_raweventhandler proc,
+  void *handle
+)
+{
+  v->rawEvents=proc;
+  v->rawHandle=handle;
+}
+
+/*
+ * void viewer_redrawHandler(viewer v,viewer_redrawhandler proc,void *handle)
+ *
+ * Use
+ *  Adds in a user-defined routine for redrawing icons in the window.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  viewer_redrawhandler proc == the routine for doing the redraw
+ *  void *handle == a handle to be passed to the routine (a sprite area or
+ *    something)
+ */
+
+void viewer_redrawHandler(viewer v,viewer_redrawhandler proc,void *handle)
+{
+  v->rdr=proc;
+  v->rdrHandle=handle;
+}
+
+/*
+ * void viewer_setIconSize(viewer v,int width,int height)
+ *
+ * Use
+ *  Sets a new icon size for the viewer.  This would normally be
+ *  accompanied by a chnge in redraw handler.  It would be used e.g. when
+ *  using a menu option giving a choice between 'Large icons' and 'Small
+ *  icons'.
+ *
+ * Parameters
+ *  viewer v == the viewer which is to receive this change
+ *  int width == the new width
+ *  int height == the new height
+ */
+
+void viewer_setIconSize(viewer v,int width,int height)
+{
+  v->width=width;
+  v->height=height;
+  v->across=-1;
+  viewer__resize(v);
+}
+
+/*
+ * void viewer_setCompare(viewer v,viewer_compare cmp)
+ *
+ * Use
+ *  Registers a compare function for the viewer specified.  The function
+ *  is passed the caller-defined handles of two icons.  The function must
+ *  return <0 if a<b, >0 if a>b, or ==0 if a==b (like strcmp does).  The
+ *  viewer's icons are then resorted.  Pass 0 to use the default sorting
+ *  system (a caseless compare on the icon text)
+ *
+ *  The resorting algorithm is the link mergesort, originally implemented
+ *  in the Sapphire linklist manager.
+ *
+ * Parameters
+ *  viewer v == the viewer we're going to set the comparer up for
+ *  viewer_compare cmp == the function to do comparing
+ */
+
+void viewer_setCompare(viewer v,viewer_compare cmp)
+{
+  v->cmp=cmp;
+  if (!v->icons)
+    return;
+  v->across=-1;
+  viewer__resize(v);
+
+  /* --- Now we have to resort the list --- *
+   *
+   * This code is pretty much based on the mergesort code printed in
+   * Sedgewick's Algorithms.
+   */
+
+  #define next(p) ((p) ? (p)->next : (p))
+
+  {
+    viewer_icon a,b,c,t,todo,x,y;
+    int i,n,more;
+
+    n=1;
+    c=v->iconlist;
+
+    do
+    {
+      todo=v->iconlist;
+      more=FALSE;
+      c=(viewer_icon)&v->iconlist;
+      while (todo)
+      {
+        t=todo;
+        a=t;
+        if (a!=v->iconlist)
+          more=TRUE;
+        for (i=1;i<n;i++)
+          t=next(t);
+        b=next(t);
+        x=b;
+        t=b;
+        for (i=1;i<n;i++)
+          t=next(t);
+        t=next(t);
+        y=t;
+        todo=t;
+
+        /* --- Now we have to do the actual merge --- *
+         *
+         * This is made a little bit more difficult since we have null-
+         * terminated lists rather than a weird node which points to itself.
+         */
+
+        while (a!=x || b!=y)
+        {
+          if (a==x)
+            i=1;
+          else if (b==y)
+            i=-1;
+          else if (v->cmp)
+            i=(v->cmp)(a->handle,b->handle);
+          else
+            i=utils_caselessCmp(a->text,b->text);
+
+          if (i<=0)
+          {
+            c->next=a;
+            c=a;
+            a=next(a);
+          }
+          else
+          {
+            c->next=b;
+            c=b;
+            b=next(b);
+          }
+        }
+
+      }
+      c->next=0;
+      n*=2;
+    }
+    while (more);
+  }
+
+  #undef next
+
+  /* --- Now we have to sort out the back links --- */
+
+  {
+    viewer_icon a=v->iconlist;
+
+    a->last=0;
+    while (a->next)
+    {
+      a->next->last=a;
+      a=a->next;
+    }
+  }
+}
+
+/*
+ * viewer_icon viewer_addIcon
+ * (
+ *   viewer v,
+ *   char *text,
+ *   char *sprite,
+ *   BOOL inOrder,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Adds a new icon to a viewer window.
+ *
+ * Parameters
+ *  viewer v == the handle of the viewer to use.
+ *  char *text == the text to put under the icon (may be null)
+ *  char *sprite == the sprite to use (may be null)
+ *  BOOL inOrder == whether you want the icons sorted into order according
+ *   to the text fields
+ *  void *handle == the handle you want to pass to the event handler routine
+ *
+ * Returns
+ *  A handle to the icon.  If this is NULL, something went majorly wrong
+ *  (sorry, John)
+ */
+
+viewer_icon viewer_addIcon
+(
+  viewer v,
+  char *text,
+  char *sprite,
+  BOOL inOrder,
+  void *handle
+)
+{
+  viewer_icon icn=(viewer_icon)&(v->iconlist);
+  viewer_icon new=(viewer_icon)mem_alloc(sizeof(viewer__iconstr));
+  if (!new)
+  {
+    werr(FALSE,msgs_lookup("viewerCCI:Not enough room to create new icon."));
+    return (0);
+  }
+  if (text)
+  {
+    if (new->text=mem_alloc(strlen(text)+1),!new->text)
+    {
+      mem_free(new);
+      werr
+      (
+        FALSE,
+        msgs_lookup("viewerCCI:Not enough room to create new icon.")
+      );
+      return (0);
+    }
+    strcpy(new->text,text);
+  }
+  else
+    new->text=0;
+  if (sprite)
+    strcpy(new->sprite,sprite);
+  else
+    new->sprite[0]='\0';
+  while (icn->next)
+  {
+    if (v->cmp)
+    {
+      if ((v->cmp)(icn->next->handle,handle)>0 && inOrder==TRUE)
+        break;
+    }
+    else
+    {
+      if (utils_caselessCmp(icn->next->text,text)>0 && inOrder==TRUE)
+        break;
+    }
+    icn=icn->next;
+  }
+  new->next=icn->next;
+  new->last=icn;
+  icn->next=new;
+  if (new->next)
+    new->next->last=new;
+  new->handle=handle;
+  new->v=v;
+  new->selected=FALSE;
+  new->filetype=-1;
+  v->icons++;
+  v->across=-1;
+  viewer__resize(v);
+  return (new);
+}
+
+/*
+ * void viewer_setFiletype(viewer_icon i,int type)
+ *
+ * Use
+ *  Sets the filetype of the icon - useful for bins and things.  This
+ *  filetype overrides the setting given to viewer_exportSelected().  It can
+ *  also be used to display the correct icon in the viewer by changing the
+ *  redraw handler to viewer_drawFileIcons().
+ *
+ * Parameters
+ *  viewer_icon i == the icon to change
+ *  int type == the filetype to give it (any valid WIMP filetype will do)
+ */
+
+void viewer_setFiletype(viewer_icon i,int type)
+{
+  i->filetype=type;
+}
+
+/*
+ * int viewer_readFiletype(viewer_icon i)
+ *
+ * Use
+ *  Returns the filetype attached to an icon.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *
+ * Returns
+ *  The type attached using viewer_setFiletype(), or -1 if none.
+ */
+
+int viewer_readFiletype(viewer_icon i)
+{
+  return (i->filetype);
+}
+
+/*
+ * viewer_icon viewer_findIcon(viewer v,char *text)
+ *
+ * Use
+ *  Searches through a viewer to find an icon with the same text as 'text'.
+ *  The search is case-insensitive.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  char *text == text to search for
+ *
+ * Returns
+ *  The icon handle, or viewer_NOICON if unsuccessful.
+ */
+
+viewer_icon viewer_findIcon(viewer v,char *text)
+{
+  viewer_icon i=v->iconlist;
+  while (i)
+  {
+    if (utils_caselessCmp(text,i->text)==0)
+      return (i);
+    i=i->next;
+  }
+  return (viewer_NOICON);
+}
+
+/*
+ * void viewer_removeIcon(viewer_icon i)
+ *
+ * Use
+ *  Removes the icon specified.  This routine is real easy!
+ *
+ * Parameters
+ *  viewer_icon i == the icon to remove (they ALL have unique handles, so
+ *    this is OK)
+ */
+
+void viewer_removeIcon(viewer_icon i)
+{
+  viewer v=i->v;
+  if (i->selected)
+    v->selected--;
+  if (i->last)
+    i->last->next=i->next;
+  else
+    v->iconlist=i->next;
+  if (i->next)
+    i->next->last=i->last;
+  mem_free(i->text);
+  mem_free(i);
+  v->icons--;
+  v->across=-1;
+  v->menuSel=viewer_NOICON;
+  viewer__resize(v);
+}
+
+/*
+ * wimp_w viewer_syshandle(viewer v)
+ *
+ * Use
+ *  Returns the WIMP window handle used for the viewer (and much use may it
+ *  do you!)
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *
+ * Returns
+ *  The wimp_w window handle
+ */
+
+wimp_w viewer_syshandle(viewer v)
+{
+  return (v->wind);
+}
+
+/*
+ * viewer_icon viewer_iconFromCoords(viewer v,int x,int y)
+ *
+ * Use
+ *  Given a set of (absolute) coordinates, this returns the icon in the
+ *  viewer specified that the point is on.  This is mainly useful for menu
+ *  maker routines, which will want to be able to select items and so on.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  int x == the x-coordinate of the point
+ *  int y == the y-coordinate of the point
+ *
+ * Returns
+ *  The icon handle, or viewer__NOICON if there isn't one.
+ */
+
+viewer_icon viewer_iconFromCoords(viewer v,int x,int y)
+{
+  wimp_wstate s;
+  int ix,iy;
+  int i;
+  int cnt;
+  viewer_icon icn=v->iconlist;
+  wimpt_noerr(wimp_get_wind_state(v->wind,&s));
+  x-=(s.o.box.x0-s.o.x);
+  y-=(s.o.box.y1-s.o.y);
+  y=-y;
+  if (v->banner[0]!='\0')
+    y-=viewer__BANNERHEIGHT;
+  ix=x/(v->width+viewer__GAP);
+  x-=(v->width+viewer__GAP)*ix;
+  if (x<viewer__GAP/2 || x-viewer__GAP/2>v->width || ix>=v->across)
+    return (viewer_NOICON);
+  iy=y/(v->height+viewer__GAP);
+  y-=(v->height+viewer__GAP)*iy;
+  if (y<viewer__GAP/2 || y-viewer__GAP/2>v->height || iy>=v->down)
+    return (viewer_NOICON);
+  i=ix+iy*v->across;
+  if (i>=v->icons)
+    return (viewer_NOICON);
+  for (cnt=0;cnt<i;cnt++)
+  {
+    if (icn==0)
+      return (viewer_NOICON);
+    icn=icn->next;
+  }
+  return (icn);
+}
+
+/*
+ * void viewer_iconToCoords(viewer_icon i,wimp_box *box)
+ *
+ * Use
+ *  Calculates the bounding box of the icon given.  If there is an error,
+ *  nothing is written in the block.
+ *
+ * Parameters
+ *  viewer_icon i == the icon we're interested in
+ *  wimp_box *box == where to store the coordinates
+ */
+
+void viewer_iconToCoords(viewer_icon i,wimp_box *box)
+{
+  int x,y;
+  viewer v=i->v;
+  BOOL end=FALSE;
+  viewer_icon icn=v->iconlist;
+  wimp_wstate s;
+  wimpt_noerr(wimp_get_wind_state(v->wind,&s));
+  x=y=0;
+  while (!end)
+  {
+    if (icn==0)
+      return;
+    if (icn==i)
+      end=TRUE;
+    else
+    {
+      if ((++x)==v->across)
+      {
+        x=0;
+        y++;
+      }
+    }
+    icn=icn->next;
+  }
+  box->x0=s.o.box.x0-s.o.x+viewer__GAP/2+(viewer__GAP+v->width)*x;
+  box->x1=box->x0+v->width;
+  box->y1=s.o.box.y1-s.o.y-viewer__GAP/2-(viewer__GAP+v->height)*y;
+  if (v->banner[0]!='\0')
+    box->y1-=viewer__BANNERHEIGHT;
+  box->y0=box->y1-v->height;
+}
+
+/*
+ * BOOL viewer_isSelected(viewer_icon i)
+ *
+ * Use
+ *  Returns whether an icon is selected or not.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *
+ * Returns
+ *  TRUE if the icon is selected, or FALSE otherwise.
+ */
+
+BOOL viewer_isSelected(viewer_icon i)
+{
+  return (i->selected);
+}
+
+/*
+ * void viewer_selectIcon(viewer_icon i,BOOL onOrOff)
+ *
+ * Use
+ *  Selects or deselects the icon specified.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *  BOOL onOrOff == TRUE to select, FALSE to deselect
+ */
+
+void viewer_selectIcon(viewer_icon i,BOOL onOrOff)
+{
+  wimp_redrawstr r;
+  viewer v;
+  wimp_wstate s;
+  int ox,oy;
+  wimp_box box;
+  BOOL more;
+  if (i==viewer_NOICON)
+    return;
+  v=i->v;
+  if (i->selected!=onOrOff)
+  {
+    if (onOrOff)
+      v->selected++;
+    else
+      v->selected--;
+  }
+  else
+    return;
+  i->selected=onOrOff;
+  r.w=v->wind;
+  viewer_iconToCoords(i,&box);
+  wimpt_noerr(wimp_get_wind_state(v->wind,&s));
+  ox=s.o.box.x0-s.o.x;
+  oy=s.o.box.y1-s.o.y;
+  box.x0-=ox;
+  box.y0-=oy;
+  box.x1-=ox;
+  box.y1-=oy;
+  r.box=box;
+  wimpt_noerr(wimp_update_wind(&r,&more));
+  while (more)
+  {
+    viewer__redrawicon(&r,i,&box);
+    wimpt_noerr(wimp_get_rectangle(&r,&more));
+  }
+}
+
+/*
+ * viewer viewer_iconToViewer(viewer_icon i)
+ *
+ * Use
+ *  Returns the viewer in which an icon is contained.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *
+ * Returns
+ *  The viewer handle.
+ */
+
+viewer viewer_iconToViewer(viewer_icon i)
+{
+  return (i->v);
+}
+
+/*
+ * void *viewer_iconHandle(viewer_icon i)
+ *
+ * Use
+ *  Returns the handle attached to the icon when it was created
+ *
+ * Parameters
+ *  viewer_icon i == the icon in question
+ *
+ * Returns
+ *  The handle attached
+ */
+
+void *viewer_iconHandle(viewer_icon i)
+{
+  return (i->handle);
+}
+
+/*
+ * char *viewer_textOfIcon(viewer_icon i)
+ *
+ * Use
+ *  Returns the text of the icon given.
+ *
+ * Parameters
+ *  viewer_icon i == the icon
+ *
+ * Returns
+ *  Pointer to the string (read only!).
+ */
+
+char *viewer_textOfIcon(viewer_icon i)
+{
+  return (i->text);
+}
+
+/*
+ * int viewer_selected(viewer v)
+ *
+ * Use
+ *  Informs caller how many icons are selected.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *
+ * Returns
+ *  The number of icons selected.
+ */
+
+int viewer_selected(viewer v)
+{
+  return (v->selected);
+}
+
+/*
+ * int viewer_icons(viewer v)
+ *
+ * Use
+ *  Returns the number of icons in a viewer.
+ *
+ * Parameters
+ *  viewer v == the viewer
+ *
+ * Returns
+ *  The number of icons.
+ */
+
+int viewer_icons(viewer v)
+{
+  return (v->icons);
+}
+
+/*
+ * void viewer_doForIcons
+ * (
+ *   viewer v,
+ *   BOOL onlySelected,
+ *   void (*proc)(viewer_icon i,void *handle)
+ * )
+ *
+ * Use
+ *  Does the same thing for either all the icons in a viewer, or just the
+ *  selected ones.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  BOOL onlySelected == whether you want to handle just the selected ones,
+ *    or the whole lot.
+ *  void (*proc)(viewer_icon i,void *handle) == the routine to do whatever
+ *    it is you want to do.
+ */
+
+void viewer_doForIcons
+(
+  viewer v,
+  BOOL onlySelected,
+  void (*proc)(viewer_icon i,void *handle)
+)
+{
+  viewer_icon i=v->iconlist;
+  viewer_icon next;
+  while (i)
+  {
+    next=i->next;
+    if (i->selected || !onlySelected)
+      proc(i,i->handle);
+    i=next;
+  }
+}
+
+/*
+ * void viewer__select(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Selects an icon.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *  void *handle == a handle (ignored)
+ */
+
+static void viewer__select(viewer_icon i,void *handle)
+{
+  handle=handle;
+  viewer_selectIcon(i,TRUE);
+}
+
+/*
+ * void viewer__deselect(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Deselects an icon.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *  void *handle == a handle (ignored)
+ */
+
+static void viewer__deselect(viewer_icon i,void *handle)
+{
+  handle=handle;
+  viewer_selectIcon(i,FALSE);
+}
+
+/*
+ * void viewer_selectAll(viewer v,BOOL onOrOff)
+ *
+ * Use
+ *  Selects or deselects all the icons in a viewer.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  BOOL onOrOff == whether you want the icons to be on or off
+ */
+
+void viewer_selectAll(viewer v,BOOL onOrOff)
+{
+  viewer_doForIcons(v,FALSE,onOrOff ? viewer__select : viewer__deselect);
+  v->menuSel=viewer_NOICON;
+}
+
+/*
+ * BOOL viewer__selectUnknowns(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Selects the icons inside the rubber-band box created, RISC OS 3-like.
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event that I might be interested in
+ *  void *handle == a (useless) handle
+ *
+ * Returns
+ *  TRUE if the event was interesting.
+ */
+
+static BOOL viewer__selectUnknowns(wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  wimp_box b;
+  wimp_wstate s;
+  coords_cvtstr c;
+  viewer v=viewer__currentViewer;
+  wimp_box vib;
+  int i;
+  int x,y;
+  viewer_icon icn=v->iconlist;
+  handle=handle;
+  switch (e->e)
+  {
+    case wimp_EUSERDRAG:
+      wimpt_noerr(wimp_get_wind_state(v->wind,&s));
+      c.box=s.o.box;
+      c.scx=s.o.x;
+      c.scy=s.o.y;
+      b.x0=min(e->data.dragbox.x0,e->data.dragbox.x1);
+      b.y0=min(e->data.dragbox.y0,e->data.dragbox.y1);
+      b.x1=max(e->data.dragbox.x0,e->data.dragbox.x1);
+      b.y1=max(e->data.dragbox.y0,e->data.dragbox.y1);
+      b.x0+=viewer__GAP/2;
+      b.x1-=viewer__GAP/2;
+      b.y0+=viewer__GAP/2;
+      b.y1-=viewer__GAP/2;
+      coords_box_toworkarea(&b,&c);
+      if (v->banner[0]!='\0')
+        coords_offsetbox(&b,0,viewer__BANNERHEIGHT,&b);
+      vib.x0=b.x0/(v->width+viewer__GAP);
+      vib.y0=(-b.y1)/(v->height+viewer__GAP);
+      vib.x1=b.x1/(v->width+viewer__GAP);
+      vib.y1=(-b.y0)/(v->height+viewer__GAP);
+      if (b.y1>0)
+        vib.y0=-1;
+      if (b.y0>0)
+        vib.y1=-1;
+      handled=TRUE;
+      win_remove_unknown_event_processor(viewer__selectUnknowns,0);
+      for (i=0;icn!=0;i++,icn=icn->next)
+      {
+        x=i%(v->across);
+        y=i/(v->across);
+        if (x>=vib.x0 && x<=vib.x1 && y>=vib.y0 && y<=vib.y1)
+          viewer_selectIcon(icn,TRUE);
+      }
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void viewer_clickSelect(viewer v,viewer_icon i,wimp_bbits b)
+ *
+ * Use
+ *  Handles a click on an icon just like clicks in Filer windows.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  viewer_icon i == the icon that was clicked
+ *  wimp_bbits b == the mouse button status
+ */
+
+void viewer_clickSelect(viewer v,viewer_icon i,wimp_bbits b)
+{
+  viewer_icon icn=v->iconlist;
+  switch (b)
+  {
+    case wimp_BCLICKRIGHT:
+      if (i!=viewer_NOICON)
+      {
+        viewer_selectIcon(v->menuSel,FALSE);
+        v->menuSel=viewer_NOICON;
+        viewer_selectIcon(i,!(i->selected));
+      }
+      break;
+    case wimp_BCLICKLEFT:
+      v->menuSel=viewer_NOICON;
+      if (i->selected==FALSE || i==viewer_NOICON)
+      {
+        while (icn)
+        {
+          if (icn->selected)
+            viewer_selectIcon(icn,FALSE);
+          icn=icn->next;
+        }
+        viewer_selectIcon(i,TRUE);
+      }
+      break;
+    case wimp_BDRAGLEFT:
+    case wimp_BDRAGRIGHT:
+      if (i==viewer_NOICON)
+      {
+        wimp_mousestr m;
+        wimp_wstate s;
+        wimp_dragstr d;
+        wimpt_noerr(wimp_get_point_info(&m));
+        wimpt_noerr(wimp_get_wind_state(v->wind,&s));
+        d.window=v->wind;
+        d.type=wimp_USER_RUBBER;
+        d.box.x0=m.x;
+        d.box.y0=m.y;
+        d.box.x1=m.x+wimpt_dx();
+        d.box.y1=m.y+wimpt_dy();
+        d.parent=s.o.box;
+        wimpt_noerr(wimp_drag_box(&d));
+        viewer__currentViewer=v;
+        win_add_unknown_event_processor(viewer__selectUnknowns,0);
+      }
+      else
+      {
+        v->menuSel=viewer_NOICON;
+        viewer_selectIcon(i,TRUE);
+      }
+      break;
+    case wimp_BMID:
+      if ((v->menuSel!=viewer_NOICON || v->selected==0) && v->menuSel!=i)
+      {
+        viewer_selectIcon(v->menuSel,FALSE);
+        v->menuSel=i;
+        viewer_selectIcon(v->menuSel,TRUE);
+      }
+  }
+}
+
+/*
+ * char *viewer_menuItem(viewer v,char *header)
+ *
+ * Use
+ *  Returns a menu item of the form either "~<header> ''",
+ *  "<header> '<icon name>'", or "Selection", for inclusion in a menu
+ *  string.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  char *header == the header for the menu item
+ *
+ * Returns
+ *  A pointer to a read-only string.
+ */
+
+char *viewer_menuItem(viewer v,char *header)
+{
+  char *buffer=buffer_find();
+  char *ret;
+  switch (v->selected)
+  {
+    case 0:
+      sprintf(buffer,"~%s ''",header);
+      ret=buffer;
+      break;
+    case 1:
+      {
+        viewer_icon i=v->iconlist;
+        while (i->selected==FALSE)
+        {
+          i=i->next;
+        }
+        sprintf(buffer,"%s '%s'",header,i->text);
+        ret=buffer;
+      }
+      break;
+    default:
+      strcpy(buffer,msgs_lookup("viewerMIS:Selection"));
+      ret=buffer;
+      break;
+  }
+  return (ret);
+}
+
+/*
+ * void viewer_setupMenu(viewer v,char *header,menu m,int i,char *buff)
+ *
+ * Use
+ *  Writes a menu item out as for the previous routine, but implants it
+ *  directly into the menu, so you don't need to fiddle about with things
+ *  like that, and also means that the menu pointer changes.  The menu item
+ *  must have been previously set up with menu_redirectItem.  This call will
+ *  also set the menu to the correct width.  However, ensure that you call
+ *  menu_minWidth(m,0) before fiddling with the width!
+ *
+ * Parameters
+ *  viewer v == the viewer handle pertaining to this request
+ *  menu m == the menu to doctor
+ *  int i == the menu item
+ *  char *buff == where the menu item wants the data
+ */
+
+void viewer_setupMenu(viewer v,char *header,menu m,int i,char *buff)
+{
+  char *t=viewer_menuItem(v,header);
+  if (*t=='~')
+  {
+    t++;
+    menu_setflags(m,i,FALSE,TRUE);
+  }
+  else
+    menu_setflags(m,i,FALSE,FALSE);
+  strcpy(buff,t);
+  menu_minWidth(m,strlen(buff));
+}
+
+/*
+ * viewer_icon viewer_firstSelected(viewer v)
+ *
+ * Use
+ *  Returns the handle of the first selected icon.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *
+ * Returns
+ *  A handle to the first one, or viewer_NOICON.
+ */
+
+viewer_icon viewer_firstSelected(viewer v)
+{
+  viewer_icon i=v->iconlist;
+  while (i)
+  {
+    if (i->selected)
+      return (i);
+    i=i->next;
+  }
+  return (viewer_NOICON);
+}
+
+/*
+ * void viewer_settitle(viewer v,char *title)
+ *
+ * Use
+ *  Changes a viewer's title, so that the extent is updated as well.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  char *title == the new title string
+ *     (internal: may be 0 to indicate just to resize the viewer)
+ */
+
+void viewer_settitle(viewer v,char *title)
+{
+  wimp_wstate s;
+  int minw;
+  int scw;
+  int maxacc;
+  wimp_redrawstr r;
+  if (title)
+    win_settitle(v->wind,"%s",title);
+  wimpt_noerr(wimp_get_wind_state(v->wind,&s));
+  scw=wimpt_scwidth();
+  maxacc=scw/(v->width+viewer__GAP);
+  if (maxacc>v->icons)
+    maxacc=v->icons;
+  minw=wimpt_stringWidth(v->title)+164;
+  if (v->banner[0]!='\0')  /* Bug fix */
+  {
+    int l=wimpt_stringWidth(v->banner)+64;
+    if (l>minw)
+      minw=l;
+  }
+  if (minw<viewer__MINWIDTH)
+    minw=viewer__MINWIDTH;
+  r.w=v->wind;
+  r.box.x0=0;
+  r.box.y0=-(v->height+viewer__GAP)*v->down;
+  if (v->banner[0]!='\0')
+    r.box.y0-=viewer__BANNERHEIGHT;
+  if (r.box.y0>-viewer__MINHEIGHT)
+    r.box.y0=-viewer__MINHEIGHT;
+  r.box.x1=(v->width+viewer__GAP)*maxacc;
+  if (r.box.x1<minw)
+    r.box.x1=minw;
+  r.box.y1=0;
+  wimpt_noerr(wimp_set_extent(&r));
+  if (s.flags & wimp_WOPEN)
+    wimpt_noerr(wimp_open_wind(&s.o));
+}
+
+/*
+ * void viewer_dragSelected(viewer_icon icn,wimp_bbits b)
+ *
+ * Use
+ *  Drags a set of icons around a window.
+ *
+ * Parameters
+ *  viewer_icon icn == the viewer icon handle
+ *  wimp_bbits b == the button types that started this lot off
+ */
+
+void viewer_dragSelected(viewer_icon icn,wimp_bbits b)
+{
+  wimp_box box;
+  wimp_dragstr d;
+  wimp_mousestr m;
+  BOOL started=FALSE;
+  viewer v;
+  viewer_icon i;
+  os_regset r;
+  int scWidth=wimpt_scwidth();
+  int scHeight=wimpt_scheight();
+  sprite_id sid;
+  if (icn==viewer_NOICON)
+    return;
+  if (b!=wimp_BDRAGLEFT && b!=wimp_BDRAGRIGHT)
+    return;
+  viewer_selectIcon(icn,TRUE);
+  v=icn->v;
+  wimpt_noerr(wimp_get_point_info(&m));
+  r.r[0]=161;
+  r.r[1]=28;
+  wimpt_noerr(os_swix(XOS_Byte,&r)); /* Support DragASprite? */
+  if (wimpt_getVersion()>=300 && (r.r[2] & 2))
+  {
+    r.r[0]=0xC5;
+    d.box.x0=m.x-50;
+    d.box.x1=m.x+50;
+    d.box.y0=m.y-50;
+    d.box.y1=m.y+50;
+    if (v->selected==1)
+    {
+      if (icn->filetype==-1)
+      {
+        r.r[2]=(int)icn->sprite;
+        r.r[1]=(int)v->spr;
+      }
+      else
+      {
+        r.r[2]=(int)fileicon_spriteName(icn->filetype,icn->text);
+        r.r[1]=1;
+      }
+    }
+    else
+    {
+      r.r[2]=(int)"package";
+      r.r[1]=1;
+      if ((int)v->spr>1)
+      {
+        sid.s.name="package";
+        sid.tag=0;
+        if (!sprite_select(v->spr,&sid))
+          r.r[1]=(int)v->spr;
+      }
+    }
+    r.r[3]=(int)&d.box;
+    wimpt_noerr(os_swix(XDragASprite_Start,&r));
+    return;
+  }
+  i=v->iconlist;
+  while (i)
+  {
+    if (i->selected==TRUE)
+    {
+      viewer_iconToCoords(i,&box);
+      if (started)
+      {
+        if (d.box.x0>box.x0)
+          d.box.x0=box.x0;
+        if (d.box.y0>box.y0)
+          d.box.y0=box.y0;
+        if (d.box.x1<box.x1)
+          d.box.x1=box.x1;
+        if (d.box.y1<box.y1)
+          d.box.y1=box.y1;
+      }
+      else
+      {
+        d.box=box;
+        started=TRUE;
+      }
+    }
+    i=i->next;
+  }
+  d.box.x0-=viewer__GAP/2;
+  d.box.y0-=viewer__GAP/2;
+  d.box.x1+=viewer__GAP/2;
+  d.box.y1+=viewer__GAP/2;
+  d.window=0;
+  d.type=wimp_USER_FIXED;
+  d.parent.x0=d.box.x0-m.x;
+  d.parent.y0=d.box.y0-m.y;
+  d.parent.x1=scWidth-m.x+d.box.x1;
+  d.parent.y1=scHeight-m.y+d.box.y1;
+  wimpt_noerr(wimp_drag_box(&d));
+}
+
+/*
+ * The routines for the data transfer.
+ */
+
+static BOOL viewer__save(char *name,void *handle)
+{
+  handle=handle;
+  return
+  (
+    viewer__usersave(viewer__currentIcon,name,viewer__currentIcon->handle)
+  );
+}
+
+static BOOL viewer__send(void *handle,int *maxbuf)
+{
+  handle=handle;
+  return
+  (
+    viewer__usersend(viewer__currentIcon,viewer__currentIcon->handle,maxbuf)
+  );
+}
+
+static int viewer__print(char *filename,void *handle)
+{
+  handle=handle;
+  return
+  (
+    viewer__userprint
+    (
+      viewer__currentIcon,
+      filename,
+      viewer__currentIcon->handle
+    )
+  );
+}
+
+/*
+ * void viewer__export(viewer_icon i,void *handle)
+ *
+ * Use
+ *  Exports each icon in turn.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *  void *handle == a handle to the user's data (ignored)
+ */
+
+static void viewer__export(viewer_icon i,void *handle)
+{
+  wimp_eventstr e;
+  handle=handle;
+  viewer__currentIcon=i;
+  e.e=wimp_EUSERDRAG;
+  wimpt_fake_event(&e);
+  xfersend
+  (
+    i->filetype==-1 ? viewer__filetype : i->filetype,
+    i->text,
+    1,
+    viewer__usersave==0 ? 0 : viewer__save,
+    viewer__usersend==0 ? 0 : viewer__send,
+    viewer__userprint==0 ? 0 : viewer__print,
+    &e,
+    0
+  );
+}
+
+/*
+ * BOOL viewer__unknowns(wimp_eventstr *e,void *handle)
+ *
+ * Use
+ *  Unknown event processor - handles the end of the drag operation.
+ *
+ * Parameters
+ *  wimp_eventstr *e == a pointer to the event.
+ *  void *handle == a handle to some data (ignored).
+ *
+ * Returns
+ *  Whether the event was interesting.
+ */
+
+static BOOL viewer__exportUnknowns(wimp_eventstr *e,void *handle)
+{
+  BOOL handled=FALSE;
+  wimp_mousestr m;
+  handle=handle;
+  switch (e->e)
+  {
+    case wimp_EUSERDRAG:
+      wimpt_noerr(wimp_get_point_info(&m));
+      if (m.w!=viewer__currentViewer->wind)
+        viewer_doForIcons(viewer__currentViewer,TRUE,viewer__export);
+      handled=TRUE;
+      win_remove_unknown_event_processor(viewer__exportUnknowns,0);
+      break;
+  }
+  return (handled);
+}
+
+/*
+ * void viewer_exportSelected
+ * (
+ *   viewer_icon icn,
+ *   wimp_bbits b,
+ *   int filetype,
+ *   viewer_saveproc save,
+ *   viewer_sendproc send,
+ *   viewer_printproc print
+ * )
+ *
+ * Use
+ *  Allows you to export the data connected with each selected icon to
+ *  another application.  The filename used is the icon's text.
+ *
+ * Parameters
+ *  viewer_icon icn == the icon on which the user clicked to start the drag
+ *    operation.
+ *  wimp_bbits b == the mouse buttons which started this up.
+ *  int filetype == the filetype of the data.
+ *  viewer_saveproc save == the save routine (saving and <Wimp$Scrap>
+ *    transfer.
+ *  viewer_sendproc send == the send routine (RAM transfer).
+ *  viewer_printproc print == the print routine (printing etc.)
+ */
+
+void viewer_exportSelected
+(
+  viewer_icon icn,
+  wimp_bbits b,
+  int filetype,
+  viewer_saveproc save,
+  viewer_sendproc send,
+  viewer_printproc print
+)
+{
+  if (icn==viewer_NOICON)
+    return;
+  if (b!=wimp_BDRAGLEFT && b!=wimp_BDRAGRIGHT)
+    return;
+  viewer_dragSelected(icn,b);
+  viewer__filetype=filetype;
+  viewer__usersave=save;
+  viewer__usersend=send;
+  viewer__userprint=print;
+  viewer__currentViewer=icn->v;
+  win_add_unknown_event_processor(viewer__exportUnknowns,0);
+}
+
+/*
+ * viewer_icon viewer_helpIcon(viewer v)
+ *
+ * Use
+ *  Informs the caller which icon the Help system is interested in.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *
+ * Returns
+ *  The icon's handle (or maybe viewer_NOICON)
+ */
+
+viewer_icon viewer_helpIcon(viewer v)
+{
+  wimp_eventstr *e=wimpt_last_event();
+  if (help_wasHelp())
+    return
+    (
+      viewer_iconFromCoords
+      (
+        v,
+        e->data.msg.data.helprequest.m.x,
+        e->data.msg.data.helprequest.m.y
+      )
+    );
+  else
+    werr(TRUE,msgs_lookup("viewerVIE:(viewer_helpIcon, caller fault): "
+                                      "Not called on HELPREQUEST event."));
+  return (0);
+}
diff --git a/StraySrc/Libraries/Steel/c/visdelay b/StraySrc/Libraries/Steel/c/visdelay
new file mode 100644 (file)
index 0000000..b419766
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * videlay
+ *
+ * Provides a bit more control than the original version
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "visdelay.h"
+#include "os.h"
+#include "swiv.h"
+#include "swis.h"
+#include "wimpt.h"
+#include <stdlib.h>
+
+#include "dll.h"
+
+#ifndef _dll_NODLL
+  extern void _dllEntry(visdelay__exitHandler)(void);
+#endif
+
+static visdelay_state visdelay__state={0,-1};
+static BOOL visdelay__exit;
+
+/*
+ * void visdelay__exitHandler(void)
+ *
+ * Use
+ *  Shuts the hourglass off if we've used it
+ */
+
+_dll_static void visdelay__exitHandler(void)
+{
+  if (visdelay__state.count)
+    wimpt_noerr(_swix(XHourglass_Off,0));
+}
+
+/*
+ * void visdelay_begin(void)
+ *
+ * Use
+ *  Starts the hourglass.
+ */
+
+void visdelay_begin(void)
+{
+  if (!visdelay__state.count)
+  {
+    wimpt_noerr(_swix(XHourglass_On,0));
+    visdelay__state.percent=-1;
+  }
+  visdelay__state.count++;
+  if (!visdelay__exit)
+  {
+    atexit(_dllEntry(visdelay__exitHandler));
+    visdelay__exit=TRUE;
+  }
+}
+
+/*
+ * void visdelay_end(void)
+ *
+ * Use
+ *  Turns off the hourglass.  Note that calls to visdelay_begin() and
+ *  visdelay_end() must be matched.
+ */
+
+void visdelay_end(void)
+{
+  if (visdelay__state.count)
+  {
+    visdelay__state.count--;
+    wimpt_noerr(_swix(XHourglass_Off,0));
+  }
+}
+
+/*
+ * void visdelay_percent(int percent)
+ *
+ * Use
+ *  Puts up the little percentage indicator on the hourglass.
+ *
+ * Parameters
+ *  int percent == the percentage number to indicate.
+ */
+
+void visdelay_percent(int percent)
+{
+  wimpt_noerr(_swix(XHourglass_Percentage,_in(0),percent));
+  visdelay__state.percent=percent;
+}
+
+/*
+ * visdelay_state visdelay_suspend(void)
+ *
+ * Use
+ *  Turns the hourglass right off.  It also returns information about the
+ *  current state of the hourglass so that it can be resumed.
+ *
+ * Returns
+ *  State information recorded in an undefined manner.
+ */
+
+visdelay_state visdelay_suspend(void)
+{
+  visdelay_state c=visdelay__state;
+  wimpt_noerr(_swix(XHourglass_Off,0));
+  visdelay__state.count=0;
+  return (c);
+}
+
+/*
+ * void visdelay_resume(visdelay_state state)
+ *
+ * Use
+ *  Returns the hourglass to the state it was in when the last
+ *  visdelay_suspend() call was made.
+ *
+ * Parameters
+ *  visdelay_state state == the hourglass state as returned by
+ *  visdelay_suspend().
+ */
+
+void visdelay_resume(visdelay_state state)
+{
+  visdelay__state=state;
+  if (visdelay__state.count)
+  {
+    wimpt_noerr(_swix(XHourglass_On,0));
+    wimpt_noerr(_swix(XHourglass_Percentage,_in(0),visdelay__state.percent));
+  }
+}
diff --git a/StraySrc/Libraries/Steel/c/vsscanf b/StraySrc/Libraries/Steel/c/vsscanf
new file mode 100644 (file)
index 0000000..136a58a
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * vsscanf
+ *
+ * the function that ANSI forgot...
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "vsscanf.h"
+
+#ifndef BOOL
+  #define BOOL int
+  #define TRUE 1
+  #define FALSE 0
+#endif
+
+typedef enum
+{
+  vsscanf__DEFAULT,
+  vsscanf__SHORT,
+  vsscanf__LONG,
+  vsscanf__VERY_LONG
+}
+vsscanf__length;
+
+/* This union type is to avoid problems with converting between signed and
+   unsigned longs. */
+
+typedef union
+{
+  unsigned long ul;
+  signed long l;
+}
+vsscanf__genlongu;
+
+static int vsscanf__getWidth(char **p)
+{
+  char *q=(*p);
+  for (;isdigit(**p);(*p)++)
+    /* blank loop */;
+  return (atoi(q));
+}
+
+static void vsscanf__skipSpace(char **p)
+{
+  while (isspace(**p))
+    (*p)++;
+}
+
+static void vsscanf__readFloat
+(
+  char **p,
+  BOOL ignore,
+  int *processed,
+  vsscanf__length length,
+  va_list ap
+)
+{
+
+/*-------------------------------------------------------------------------*/
+/* Note: this code relies on the fact that long double and double are      */
+/* identical on this architecture.  This can't be chacked at compile time, */
+/* and it is pointless checking at run-time.  The reason for this is that  */
+/* I don't have a function for turning a string into a long double.        */
+/*-------------------------------------------------------------------------*/
+
+  double result;
+  vsscanf__skipSpace(p);
+  result=strtod(*p,p);
+  if (!ignore)
+  {
+    switch (length)
+    {
+      case vsscanf__DEFAULT:
+      case vsscanf__SHORT:
+        *va_arg(ap,float *)=(float)result;
+        break;
+      case vsscanf__LONG:
+      case vsscanf__VERY_LONG:
+        *va_arg(ap,double *)=(double)result;
+        break;
+    }
+    (*processed)++;
+  }
+}
+
+static void vsscanf__readScanset
+(
+  char **p,
+  char **q,
+  int width,
+  BOOL ignore,
+  int *processed,
+  va_list ap
+)
+{
+  char trans[256];          /* A trt (translate and test) table            */
+  int i;
+  BOOL reversed;
+  int done=0;
+  BOOL finished=FALSE;
+  char *dest=0;
+  for (i=0;i<256;i++)
+    trans[i]=FALSE;
+  (*q)++;                   /* Move past the opening '['                   */
+  if (**q=='^')
+  {
+    reversed=TRUE;
+    (*q)++;
+  }
+  else 
+    reversed=FALSE;
+  if (**q==']')
+  {
+    trans[']']=TRUE;        /* euch using a char as an index, but it works */
+    (*q)++;
+  }
+  while (**q!=']' && **q!=0)/* results of incorrect syntax are 'undefined' */
+  {
+    trans[**q]=TRUE;
+    (*q)++;
+  }
+  if (!ignore)
+    dest=va_arg(ap,char *);
+  while (!finished)
+  {
+    if (**p!=0 && (width==-1 || width!=done) && (trans[**p] ^ reversed))
+    {
+      if (!ignore)
+        *dest=**p;
+      (*p)++;
+      dest++;
+      done++;
+    }
+    else
+      finished=TRUE;
+  }
+  if (!ignore)
+    *dest=0;
+  if (done && !ignore)
+    (*processed)++;
+}
+
+static void vsscanf__readString
+(
+  char **p,
+  int width,
+  BOOL ignore,
+  BOOL chars,
+  int *processed,
+  va_list ap
+)
+{
+  char *dest=0;
+  int done=0;
+  BOOL finished=FALSE;
+  if (!ignore)
+    dest=va_arg(ap,char *);
+  if (!chars)
+    vsscanf__skipSpace(p);
+  else
+  {
+    if (width==-1)
+      width=1;
+  }
+  while (!finished)
+  {
+    if ((!isspace(**p) || chars) && **p && (done!=width || width==-1))
+    {
+      if (!ignore)
+        *dest=**p;
+      (*p)++;
+      dest++;
+      done++;
+    }
+    else
+      finished=TRUE;
+  }
+  if (!ignore && !chars)
+    *dest=0;                /* Finish off the string                       */
+  if (done && !ignore)
+    (*processed)++;
+}
+
+static void vsscanf__readInteger
+(
+  char **p,
+  BOOL ignore,
+  int *processed,
+  BOOL isSigned,
+  int base,
+  vsscanf__length length,
+  va_list ap
+)
+{
+  char *start;
+  vsscanf__genlongu result;
+  vsscanf__skipSpace(p);
+  start=*p;
+  if (base==0)
+  {
+    if (**p=='0')
+    {
+      if (tolower(*(++(*p)))=='x')
+      {
+        base=16;
+        (*p)++;
+      }
+      else
+        base=8;
+    }
+    else
+      base=10;
+  }
+  if (isSigned)
+    result.l=strtol(start,p,base);
+  else
+    result.ul=strtoul(start,p,base);
+  if (!ignore)
+  {
+    switch (length)
+    {
+      case vsscanf__DEFAULT:
+      case vsscanf__VERY_LONG:                /* Ignore silly option */
+        *va_arg(ap,int *)=(int)result.l;
+        break;
+      case vsscanf__LONG:
+        *va_arg(ap,long *)=(long)result.l;
+/* This is machine dependant - r.r[2] is an int, but longs are the same    */
+/* width                                                                   */
+        break;
+      case vsscanf__SHORT:
+        *va_arg(ap,short *)=(short)result.l;          
+                       /* If the number is too big, the results are wierd. */
+        break;
+    }
+    (*processed)++;
+  }
+}
+
+static BOOL vsscanf__processFormat
+(
+  char **p,
+  char **q,
+  int *processed,
+  va_list ap
+)
+{
+  BOOL ignore=FALSE;
+  vsscanf__length length=vsscanf__DEFAULT;
+  int width=-1;
+  if (**q=='*')
+  {
+    ignore=TRUE;
+    (*q)++;
+  }
+  if (isdigit(**q))
+    width=vsscanf__getWidth(q);
+  if (**q=='h')
+  {
+    length=vsscanf__SHORT;
+    (*q)++;
+  }
+  else if (**q=='l')
+  {
+    length=vsscanf__LONG;
+    (*q)++;
+  }
+  else if (**q=='L')
+  {
+    length=vsscanf__VERY_LONG;
+    (*q)++;
+  }
+  /* Right - now we come to the business end of the thing.  **q is the     */
+  /* actual format specifier.                                              */
+  switch (**q)
+  {
+    case 'n':
+      if (!ignore)
+        *(va_arg(ap,int *))=*processed;
+      (*q)++;
+      break;
+    case 's':
+      vsscanf__readString(p,width,ignore,FALSE,processed,ap);
+      (*q)++;
+      break;
+    case 'c':
+      vsscanf__readString(p,width,ignore,TRUE,processed,ap);
+      (*q)++;
+      break;
+    case 'd':
+      vsscanf__readInteger(p,ignore,processed,TRUE,10,length,ap);
+      (*q)++;
+      break;
+    case 'x':
+    case 'X':
+    case 'p':                   /* Flat memory model - pointer==hex number */
+      vsscanf__readInteger(p,ignore,processed,FALSE,16,length,ap);
+      (*q)++;
+      break;
+    case 'o':
+      vsscanf__readInteger(p,ignore,processed,FALSE,8,length,ap);
+      (*q)++;
+      break;
+    case 'u':
+      vsscanf__readInteger(p,ignore,processed,FALSE,10,length,ap);
+      (*q)++;
+      break;
+    case 'i':
+      vsscanf__readInteger(p,ignore,processed,TRUE,0,length,ap);
+      (*q)++;
+      break;
+    case 'e':
+    case 'f':
+    case 'g':
+      vsscanf__readFloat(p,ignore,processed,length,ap);
+      (*q)++;
+      break;
+    case '[':
+      vsscanf__readScanset(p,q,width,ignore,processed,ap);
+      (*q)++;
+      break;
+    default:
+      vsscanf__skipSpace(p);
+      if (*((*q)++)!=*((*p)++))
+        return (TRUE);
+  }
+  return (FALSE);
+}
+
+int vsscanf(char *string,char *format,va_list ap)
+{
+  char *p=string;
+  char *q=format;
+  int processed=0;
+  char c;
+  while (c=*(q++),c)
+  {
+    if (isspace(c))               /* Skip whitespace in format and source  */
+    {
+      vsscanf__skipSpace(&p);
+      vsscanf__skipSpace(&q);
+    }
+    else if (c=='%')              /* A format specifier                    */
+    {
+      if (vsscanf__processFormat(&p,&q,&processed,ap))
+        return (processed);
+    }
+    else                          /* R&D (Read and Discard)                */
+    {
+      vsscanf__skipSpace(&p);
+      if (c!=*(p++))
+        return (processed);
+    }
+    if (*p==0)                    /* This is the dreaded EOF (well, EOL)   */
+    {
+      if (!processed)
+        return (EOF);
+      else
+        return (processed);
+    }
+  }
+  return (processed);
+}
diff --git a/StraySrc/Libraries/Steel/c/werr b/StraySrc/Libraries/Steel/c/werr
new file mode 100644 (file)
index 0000000..d55eb1e
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * werr
+ *  Just like the old one, only nicer.
+ *
+ * v. 1.00 (8 Aug 1993)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "werr.h"
+#include "dbox.h"
+#include "template.h"
+#include "nopoll.h"
+#include "bbc.h"
+#include "wimp.h"
+#include "wimpt.h"
+#include "win.h"
+#include "msgs.h"
+#include "kernel.h"
+#include "swiv.h"
+#include "swis.h"
+#include "exception.h"
+#include "calltrace.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+
+#define werr__TITLE 0
+#define werr__OK 3
+#define werr__CANCEL 6
+#define werr__ERROR 4
+#define werr__BACKTRACE 7
+
+static dbox werr__errorBox;
+static BOOL werr__initialised;
+
+/*
+ * void werr_bleepy(void)
+ *
+ * Use
+ *  Bleeps if and only if the appropriate WimpFlags bit is right for
+ *  bleeping.
+ */
+
+void werr_bleepy(void)
+{
+  int bleepy=_kernel_osbyte(161,197,0);
+  if (bleepy>0)
+  {
+    if ((bleepy&4096)==0)
+      bbc_vdu(7);
+  }
+}
+
+/*
+ * void werr_init(void)
+ *
+ * Use
+ *  Sets up the werr system ready for action.
+ */
+
+void werr_init(void)
+{
+  char *title=template_syshandle("error")->title.indirecttext.buffer;
+  if (!win_anyWindows())
+  {
+    werr(FALSE,msgs_lookup("werrSEM:Could not initialise."));
+    exit(0);
+  }
+  sprintf(title,"Error from %s",wimpt_programname());
+  werr__errorBox=dbox_create("error");
+  werr__initialised=TRUE;
+}
+
+/*
+ * wimp_icon *werr__idef(wimp_wind *w,wimp_i i)
+ *
+ * Use
+ *  Vaguely similar to the dbox version, only different.  Returns a pointer
+ *  to the icon, at any rate.
+ *
+ * Parameters
+ *  wimp_wind *w == the window definition.
+ *  wimp_i i == the icon number
+ *
+ * Returns
+ *  Pointer to the icon definition.
+ */
+
+static wimp_icon *werr__idef(wimp_wind *w,wimp_i i)
+{
+  return ((wimp_icon *)(w+1)+i);
+}
+
+/*
+ * int werr__wimpBox(char *string,int buttons)
+ *
+ * Use
+ *  Displays a WIMP error box to show the specified message
+ *
+ * Parameters
+ *  char *string == the error string to display
+ *  int buttons == the number of buttons to display
+ */
+
+static int werr__wimpBox(char *string,int buttons)
+{
+  os_error err;
+  static BOOL threaded;
+  int f;
+
+  /* --- If we crashed in here before, abort damned quick --- */
+
+  if (threaded)
+  {
+    _swi(Wimp_CommandWindow,_in(0),"Unrecoverable error");
+    fprintf(stderr,
+            "%s has suffered a fatal error and must quit.",
+            wimpt_programname());
+    abort();
+  }
+
+  /* --- Display the error message --- */
+
+  threaded=TRUE;
+  strcpy(err.errmess,string);
+  err.errnum=1;    /* Stop new WindowManglers thinking this is serious :-/ */
+  if (buttons==1)
+    f=wimp_EOK;
+  else
+    f=wimp_EOK | wimp_ECANCEL;
+  f=_swi(Wimp_ReportError,_inr(0,2)+_return(1),&err,f,wimpt_programname());
+  threaded=FALSE;
+
+  return (f==2 ? 0 : 1);
+}
+
+/*
+ * int werr__reportError(int buttons,char *error,va_list ap)
+ *
+ * Use
+ *  Error reporting primitive.  Called by all both the old and new werr()s.
+ *
+ * Parameters
+ *  int buttons == how many buttons we need (1 or 2)
+ *  char *error == a printf() type format string for the error text
+ *  va_list ap == the variable arg list to use.
+ *
+ * Returns
+ *  1 if OK clicked, 0 if Cancel clicked.
+ */
+
+static int werr__reportError(int buttons,char *error,va_list ap)
+{
+  wimp_wind *wind;
+  wimp_icon *ok;
+  wimp_icon *cancel;
+  wimp_icon *backtrace=(wimp_icon *)(-80);
+  int cancelButt=-1;
+  int backButt=-1;
+  int clicked;
+  char errString[256];
+  BOOL hasBacktrace;
+
+  /* --- Set up the dialogue box --- */
+
+  vsprintf(errString,error,ap);
+  if (werr__initialised==FALSE)
+    return (werr__wimpBox(errString,buttons));
+
+  /* --- Find all the definitions we need --- */
+
+  werr__initialised=FALSE;               /* Use the WIMP box if this fails */
+  wind=template_syshandle("error");
+  hasBacktrace=(wind->nicons>=werr__BACKTRACE);
+  ok=werr__idef(wind,werr__OK);
+  cancel=werr__idef(wind,werr__CANCEL);
+  if (hasBacktrace)
+    backtrace=werr__idef(wind,werr__BACKTRACE);
+  dbox_delete(werr__errorBox);
+
+  /* --- Zap any unwanted buttons --- */
+
+  if (buttons>=2)
+  {
+    cancel->flags&=~(1<<23);
+    cancelButt=werr__CANCEL;
+  }
+  else
+    cancel->flags|=(1<<23);
+
+  if (hasBacktrace)
+  {
+    if (buttons>=3)
+    {
+      backtrace->flags&=~(1<<23);
+      backButt=werr__BACKTRACE;
+    }
+    else
+      backtrace->flags|=(1<<23);
+  }
+
+  /* --- Display the error box on the screen --- */
+
+  werr__errorBox=dbox_create("error");
+  if (!werr__errorBox)
+    return (werr__wimpBox(errString,buttons));
+  if (!dbox_hasTitle(werr__errorBox))
+    dbox_setEmbeddedTitle(werr__errorBox,werr__TITLE,FALSE);
+  dbox_setfield(werr__errorBox,werr__ERROR,"%s",errString);
+
+  /* --- Display backtraces for as long we're asked to --- */
+
+  werr_bleepy();
+  do
+  {
+    clicked=nopoll_doDbox(werr__errorBox,
+                          nopoll_CENTRE,
+                          werr__OK,
+                          cancelButt,
+                          backButt);
+    if (clicked==nopoll_OTHER)
+      _calltrace();
+  }
+  while (clicked==nopoll_OTHER);
+
+  /* --- Return the result to the user --- */
+
+  werr__initialised=TRUE;                /* Use fancy box for next error   */
+  return (clicked==nopoll_OK);
+}
+
+/*
+ * void werr(int fatal,char *error,...)
+ *
+ * Use
+ *  Compatibility with the old werr segment mainly.  If the error is fatal,
+ *  a STEEL exception is generated, which eventually gets round to the
+ *  error box handlers and dumps back out to top level.
+ *
+ * Parameters
+ *  int fatal == 1 if the error is fatal, or 0 otherwise.
+ *  char *error == printf()-type format string.
+ */
+
+void werr(int fatal,char *error,...)
+{
+  va_list ap;
+  va_start(ap,error);
+  if (fatal==0)
+  {
+    werr__reportError(1,error,ap);
+    va_end(ap);
+  }
+  else
+  {
+    char buffer[256];
+    vsprintf(buffer,error,ap);
+    va_end(ap);
+    exception_generate("%s",buffer);
+  }
+}
+
+/*
+ * int werr_error(int buttons,char *error,...)
+ *
+ * Use
+ *  Reports an error.  You can have two buttons, OK and Cancel if you really
+ *  want, now.
+ *
+ * Parameters
+ *  int buttons == 1 for 1 button, 2 for 2 buttons, or anything else for an
+ *    unpredictable result.
+ *  char *error == printf()-like format string.
+ *
+ * Returns
+ *  1 for OK, 0 for cancel.
+ */
+
+int werr_error(int buttons,char *error,...)
+{
+  va_list ap;
+  int clicked;
+  va_start(ap,error);
+  clicked=werr__reportError(buttons,error,ap);
+  va_end(ap);
+  return (clicked);
+}
diff --git a/StraySrc/Libraries/Steel/c/wimpt b/StraySrc/Libraries/Steel/c/wimpt
new file mode 100644 (file)
index 0000000..c8848bf
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * wimpt.c
+ *
+ * Low level Wimp interface
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <string.h>
+#include "dll.h"
+#include "swis.h"
+#include "kernel.h"
+
+#include "os.h"
+#include "bbc.h"
+#include "wimp.h"
+#include "font.h"
+#include "wimpt.h"
+#include "wimpt.h"
+#include "werr.h"
+#include "alarm.h"
+#include "event.h"
+#include "flex.h"
+#include "msgs.h"
+#include "interface.h"
+#include "exception.h"
+#include "mem.h"
+#include "visdelay.h"
+#include "caretptr.h"
+#include "sculptrix.h"
+#include "resspr.h"
+
+/*----- Veneered internal functions ---------------------------------------*/
+
+#ifndef _dll_NODLL
+  extern void _dllEntry(wimpt__signals)(int sig);
+  extern void _dllEntry(wimpt__escapeHandler)(int sig);
+  extern void _dllEntry(wimpt__exit)(void);
+#endif
+
+/*----- Static data -------------------------------------------------------*/
+
+/* --- Event handling --- */
+
+static BOOL wimpt__fakeWaiting;
+static wimp_eventstr wimpt__fakeEvent;
+static wimp_eventstr wimpt__lastEvent;
+
+/* --- Wimp task management --- */
+
+static wimp_t wimpt__task;
+static char *wimpt__name="<Untitled>";
+static int wimpt__wimpVersion;
+static int *wimpt__messages;
+static BOOL wimpt__justChangedMode;
+static int wimpt__pollingTime=100/50;
+static int wimpt__options=wimpt_OSCULPTRIX;
+
+/* --- Mode information --- */
+
+static int wimpt__currentMode;
+static int wimpt__dx;
+static int wimpt__dy;
+static int wimpt__bpp;
+static int wimpt__xwind;
+static int wimpt__ywind;
+
+/*----- Internal functions ------------------------------------------------*/
+
+/* --- Signal handling --- */
+
+_dll_static void wimpt__escapeHandler(int sig)
+{
+  sig=sig;
+  signal(SIGINT,_dllEntry(wimpt__escapeHandler));
+}
+
+_dll_static void wimpt__signals(int sig)
+{
+  static char *errors[]=
+  {
+    "?",
+    "SIGABRT",
+    "SIGFPE",
+    "SIGILL",
+    "SIGINT",
+    "SIGSEGV",
+    "SIGTERM",
+    "SIGSTAK",
+    "SIGUSR1",
+    "SIGUSR2",
+    "SIGOSERROR"
+  };
+
+  signal(sig,_dllEntry(wimpt__signals));
+  exception_generate(msgs_lookup("wimptSIGC:%s - code=%s"),
+                     _kernel_last_oserror()->errmess,
+                     sig>0 && sig<8 ? errors[sig] : "SIGUKN");
+}
+
+/* --- Exit handler --- */
+
+_dll_static void wimpt__exit(void)
+{
+  if (wimpt__options & wimpt_OINTERFACE)
+    interface_closeDown(wimpt__task);
+  if (wimpt__options & wimpt_OWIMPEXT)
+    os_swiv(XWimpExt_CloseDown,wimpt__task);
+  wimp_taskclose(wimpt__task);
+}
+
+/*----- Screen mode information -------------------------------------------*/
+
+BOOL wimpt_checkmode(void)
+{
+  int dummy;
+  int old=wimpt__currentMode;
+  os_byte(135,&dummy,&wimpt__currentMode);
+
+  wimpt__dx=1<<bbc_vduvar(bbc_XEigFactor);
+  wimpt__dy=1<<bbc_vduvar(bbc_YEigFactor);
+  wimpt__bpp=1<<bbc_vduvar(bbc_Log2BPP);
+  wimpt__xwind=(bbc_vduvar(bbc_XWindLimit)+1)*wimpt_dx();
+  wimpt__ywind=(bbc_vduvar(bbc_YWindLimit)+1)*wimpt_dy();
+
+  return (old!=wimpt__currentMode);
+}
+
+int wimpt_dx(void)
+{
+  return (wimpt__dx);
+}
+
+int wimpt_dy(void)
+{
+  return (wimpt__dy);
+}
+
+int wimpt_bpp(void)
+{
+  return (wimpt__bpp);
+}
+
+int wimpt_scwidth(void)
+{
+  return (wimpt__xwind);
+}
+
+int wimpt_scheight(void)
+{
+  return (wimpt__ywind);
+}
+
+int wimpt_mode(void)
+{
+  return (wimpt__currentMode);
+}
+
+/*----- Redrawing things --------------------------------------------------*/
+
+void wimpt_forceredraw(void)
+{
+  wimp_redrawstr r;
+
+  r.w=-1;
+  r.box.x0=r.box.y0=0;
+  r.box.x1=wimpt__xwind;
+  r.box.y1=wimpt__ywind;
+
+  wimp_force_redraw(&r);
+}
+
+void wimpt_redraw(wimpt_redraw_proc p,void *handle)
+{
+  wimp_eventstr *e=wimpt_last_event();
+  wimp_redrawstr r;
+  BOOL more;
+
+  r.w=e->data.o.w;
+  wimpt_noerr(wimp_redraw_wind(&r,&more));
+  while (more)
+  {
+    if (p)
+      p(&r,handle);
+    if (wimpt__options & wimpt_OSCULPTRIX)
+    {
+      wimpt_noerr(sculptrix_setSpriteArea(resspr_area()));
+      wimpt_noerr(sculptrix_redrawWindow(&r));
+    }
+    if (wimpt__options & wimpt_OINTERFACE)
+      wimpt_noerr(interface_render3dWindow(&r));
+    if (wimpt__options & wimpt_OWIMPEXT)
+      wimpt_noerr(os_swiv(XWimpExt_Redraw,0,&r));
+    wimpt_noerr(wimp_get_rectangle(&r,&more));
+  }
+}
+
+/*----- Initialisation ----------------------------------------------------*/
+
+void wimpt_setOptions(int eor,int bic)
+{
+  wimpt__options=(wimpt__options & ~bic) ^ eor;
+}
+
+int wimpt_options(void)
+{
+  return (wimpt__options);
+}
+
+void wimpt_setMessages(int msg,...)
+{
+  int i=0;
+  int sz=0;
+  va_list ap;
+
+  if (!msg)
+    return;
+
+  if (wimpt__messages=mem_alloc(256*sizeof(int)),!wimpt__messages)
+  {
+    fprintf(stderr,
+            msgs_lookup("wimptNEMI:Not enough memory to initialise."));
+    exit(1);
+  }
+
+  sz=256;
+  wimpt__messages[i++]=msg;
+  va_start(ap,msg);
+  while (msg)
+  {
+    msg=va_arg(ap,int);
+    if (i==sz)
+    {
+      sz+=64;
+      if (wimpt__messages=mem_reAlloc(wimpt__messages,sz*sizeof(int)),
+          !wimpt__messages)
+      {
+        fprintf(stderr,
+                msgs_lookup("wimptNEMI:Not enough memory to initialise."));
+        exit(1);
+      }
+    }
+    wimpt__messages[i++]=msg;
+  }
+  va_end(ap);
+
+  if (wimpt__wimpVersion<300)
+    wimpt__wimpVersion=300;
+}
+
+void wimpt_wimpversion(int version)
+{
+  wimpt__wimpVersion=version;
+}
+
+int wimpt_getVersion(void)
+{
+  return (wimpt__wimpVersion);
+}
+
+void wimpt_init(char *progname)
+{
+  os_error *e;
+
+  signal(SIGABRT, _dllEntry(wimpt__signals));
+  signal(SIGFPE, _dllEntry(wimpt__signals));
+  signal(SIGILL, _dllEntry(wimpt__signals));
+  signal(SIGINT, _dllEntry(wimpt__escapeHandler));
+  signal(SIGSEGV, _dllEntry(wimpt__signals));
+  signal(SIGTERM, _dllEntry(wimpt__signals));
+  signal(SIGOSERROR, _dllEntry(wimpt__signals));
+
+  wimpt__name=progname;
+
+  if (!wimpt__wimpVersion)
+  {
+    /* --- Guess the current WIMP version --- */
+
+    switch (bbc_inkey(0xFF00))
+    {
+      case 0xA0:   /* Arthur */
+        fprintf(stderr,
+                msgs_lookup("wimptARTH:Operating system too old.  Try "
+                                      "upgrading to RISC OS!\n"));
+        exit(1);
+        break;
+      case 0xA1:   /* OS 2.00 */
+      case 0xA2:   /* OS 2.01 */
+        wimpt__wimpVersion=200;
+        break;
+      case 0xA3:   /* OS 3.00 */
+        wimpt__wimpVersion=300;
+        break;
+      case 0xA4:   /* OS 3.10 */
+      default:     /* Anything later */
+        wimpt__wimpVersion=310;
+        break;
+    }
+  }
+
+  if (wimpt__wimpVersion==300 && !wimpt__messages)
+  {
+    /* Set up some sensible default messages for brain-damaged OS */
+    wimpt_setMessages(1,2,3,4,5,6,7,8,9,10,
+                      0x502,0x503,
+                      0x400c0,0x400c1,0x400c9,
+                      0x80140,0x80145,0x80147,
+                      0);
+  }
+
+  if (e=wimp_taskinit(progname,
+                      &wimpt__wimpVersion,
+                      &wimpt__task,
+                      wimpt__messages ?
+                        wimpt__messages :
+                        (int *)-1),
+      e)
+  {
+    fprintf(stderr,
+            msgs_lookup("wimptFTI:Failed to initialise: '%s'"),
+            e->errmess);
+    fprintf(stderr,"\n");
+    exit(1);
+  }
+
+  wimpt_checkmode();
+  atexit(_dllEntry(wimpt__exit));
+
+  /* --- Initialise any extensions --- */
+
+  if (wimpt__options & wimpt_OINTERFACE)
+    wimpt_noerr(interface_initialise(wimpt__task));
+
+  /* --- Handle WimpExtension with care... --- *
+   *
+   * If WimpExtension isn't initialised yet, it will start up its Wimp task,
+   * corrupting the application handle in the process, causing a bad crash
+   * when we return through app__epilogue.
+   */
+
+  if (wimpt__options & wimpt_OWIMPEXT)
+  {
+    #ifndef _dll_NODLL
+      int handle;
+      os_error *err;
+
+      dll_saveHandle(&handle);
+      err=os_swiv(XWimpExt_Initialise,16,wimpt__task,0);
+      dll_restoreHandle(&handle);
+      wimpt_noerr(err);
+    #else
+      wimpt_noerr(os_swiv(XWimpExt_Initialise,16,wimpt__task,0));
+    #endif
+  }
+}
+
+char *wimpt_programname(void)
+{
+  return (wimpt__name);
+}
+
+wimp_t wimpt_task(void)
+{
+  return (wimpt__task);
+}
+
+/*----- Error handling ----------------------------------------------------*/
+
+os_error *wimpt_complain(os_error *e)
+{
+  if (e)
+    werr_error(1,"%s",e->errmess);
+  return (e);
+}
+
+void wimpt_noerr(os_error *e)
+{
+  if (e)
+    exception_generate("%s",e->errmess);
+}
+
+void wimpt_reporterror(os_error *e, wimp_errflags f)
+{
+  werr_error((f & 3==3) ? 2 : 1,"%s",e->errmess);
+}
+
+/*----- Polling the WIMP --------------------------------------------------*/
+
+os_error *wimpt_poll(wimp_emask mask,wimp_eventstr *result)
+{
+  visdelay_state vs;
+  os_error *e=0;
+  int nextAlarm;
+  BOOL alarming;
+  int timeNow;
+
+  if (wimpt__fakeWaiting /* && !(mask & (1<<wimpt__fakeEvent.e)) */ )
+  {
+    *result=wimpt__fakeEvent;
+    wimpt__fakeWaiting=0;
+    wimpt__lastEvent=wimpt__fakeEvent;
+    return (0);
+  }
+
+  alarming=alarm_next(&nextAlarm);
+
+  if (wimpt__options & wimpt_OWIMPEXT)
+    os_swiv(XWimpExt_PrePoll);
+
+  vs=visdelay_suspend();
+
+  if (alarming && (mask & wimp_EMNULL))
+    e=wimp_pollidle(mask & ~wimp_EMNULL,result,nextAlarm);
+  else
+  {
+    if ((mask & wimp_EMNULL) || !wimpt__pollingTime)
+      e=wimp_poll(mask,result);
+    else
+    {
+      timeNow=alarm_timenow()+wimpt__pollingTime;
+      if (alarming && nextAlarm<timeNow)
+        timeNow=nextAlarm;
+      e=wimp_pollidle(mask,result,timeNow);
+    }
+  }
+
+  visdelay_resume(vs);
+  flex_reduce();
+
+  if (wimpt__options & wimpt_OWIMPEXT)
+  {
+    wimpt_noerr(os_swi3r(XWimpExt_Action,wimpt__task,
+                                         (int)&result->data,
+                                         result->e,
+                                         (int *)&result->e,0,0));
+  }
+  if (wimpt__options & wimpt_OINTERFACE)
+    interface_poll(result,wimpt__task);
+
+  wimpt__lastEvent=*result;
+
+  switch (result->e)
+  {
+    case wimp_ESEND:
+    case wimp_ESENDWANTACK:
+      if (result->data.msg.hdr.action==0x400C1)
+      {
+        wimpt__justChangedMode=TRUE;
+        wimpt_checkmode();
+      }
+      else
+        wimpt__justChangedMode=FALSE;
+      break;
+    case wimp_EOPEN:
+      /* Could be part of the mode change */
+      break;
+    case wimp_EPTRLEAVE:
+      caretPtr__pointer(FALSE);
+      wimpt__justChangedMode=FALSE;
+      break;
+    case wimp_EPTRENTER:
+      caretPtr__pointer(TRUE);
+      wimpt__justChangedMode=FALSE;
+      break;
+    default:
+      wimpt__justChangedMode=FALSE;
+      break;
+  }
+  return(e);
+}
+
+BOOL wimpt_justChangedMode(void)
+{
+  return (wimpt__justChangedMode);
+}
+
+int wimpt_pollingTime(int new)
+{
+  int temp=wimpt__pollingTime;
+  if (new>=0)
+    wimpt__pollingTime=new;
+  return (temp);
+}
+
+void wimpt_fake_event(wimp_eventstr * e)
+{
+  if (!wimpt__fakeWaiting)
+  {
+    wimpt__fakeWaiting=TRUE;
+    wimpt__fakeEvent=*e;
+  }
+}
+
+wimp_eventstr *wimpt_last_event(void)
+{
+  return (&wimpt__lastEvent);
+}
+
+int wimpt_last_event_was_a_key(void)
+{
+  return (wimpt__lastEvent.e == wimp_EKEY);
+}
+
+/*----- String width ------------------------------------------------------*/
+
+/*
+ * int wimpt_stringWidth(char *s)
+ *
+ * Use
+ *  Determines the width of a string in OS units, taking into account the
+ *  fact that it may be represented in a WIMP anti-aliased font.
+ *
+ * Parameters
+ *  char *s == pointer to the string to font the length of
+ *
+ * Returns
+ *  The width of the string in OS units
+ */
+
+int wimpt_stringWidth(char *s)
+{
+  font f;
+  font_string fs;
+
+  if (wimp_readsysinfo(wimp_IFONTHANDLE,&f) || !f)
+    return (strlen(s)*16);
+
+  font_setfont(f);
+  fs.s=s;
+  font_converttopoints(1000,1000,&fs.x,&fs.y);
+  fs.split=0;
+  fs.term=strlen(s)+1;
+  font_strwidth(&fs);
+  font_converttoos(fs.x,0,&fs.x,&fs.y);
+  return (fs.x);
+}
diff --git a/StraySrc/Libraries/Steel/c/win b/StraySrc/Libraries/Steel/c/win
new file mode 100644 (file)
index 0000000..85d59f7
--- /dev/null
@@ -0,0 +1,653 @@
+/* Title: -> c.win
+ * Purpose: central control of window sytem events.
+ *
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "trace.h"
+#include "os.h"
+#include "wimp.h"
+#include "werr.h"
+#include "wimpt.h"
+#include "event.h"
+#include "msgs.h"
+#include "mem.h"
+#include "bbc.h"
+#include "swis.h"
+#include "menu.h"
+
+#include "win.h"
+
+/* -------- Keeping Track of All Windows. -------- */
+
+typedef struct win__str {
+  struct win__str *next;
+  struct win__str *prev;
+  wimp_w w;
+  win_event_handler proc;
+  void *handle;
+  void *menuh;
+} win__str;
+
+#define DUD (-1)
+
+static win__str *win__allwindows;
+
+static win__str *win__find(wimp_w w)
+{
+  win__str *ws=win__allwindows;
+  while (ws)
+  {
+    if (ws->w==w)
+      return (ws);
+    ws=ws->next;
+  }
+  return (0);
+}
+
+static void win__register(wimp_w w, win_event_handler proc, void *handle)
+{
+  BOOL new=FALSE;
+  win__str *ws=win__find(w);
+  if (ws==0)
+  {
+    new=TRUE;
+    if (ws=(win__str *)mem_alloc(sizeof(win__str)),ws==0)
+    {
+      werr
+      (
+        FALSE,
+        msgs_lookup("winNEM:Not enough memory for new event handler.")
+      );
+      return;
+    }
+    ws->next=win__allwindows;
+    ws->prev=0;
+    if (win__allwindows)
+      win__allwindows->prev=ws;
+    win__allwindows=ws;
+    ws->w=w;
+  }
+  ws->proc=proc;
+  ws->handle=handle;
+  if (new)
+    ws->menuh=0;
+}
+
+static void win__discard(wimp_w w)
+{
+  win__str *ws=win__find(w);
+  if (ws)
+  {
+    if (ws->menuh)
+      menu_attach(w,0,0,0,0); /* Try to free the menu */
+    if (ws->prev)
+      ws->prev->next=ws->next;
+    else
+      win__allwindows=ws->next;
+    if (ws->next)
+      ws->next->prev=ws->prev;
+    mem_free(ws);
+  }
+}
+
+BOOL win_read_eventhandler(wimp_w w,win_event_handler *p,void **handle)
+{
+  win__str *ws=win__find(w);
+  if (ws)
+  {
+    *p=ws->proc;
+    *handle=ws->handle;
+  }
+  return (!!ws);
+}
+
+/* -------- Claiming Events. -------- */
+
+void win_register_event_handler(
+  wimp_w w, win_event_handler proc, void *handle)
+{
+  if (proc == 0) {
+    win__discard(w);
+  } else {
+    win__register(w, proc, handle);
+  };
+}
+
+typedef struct unknown_previewer
+{
+ struct unknown_previewer *link ;
+ win_unknown_event_processor proc ;
+ void *handle ;
+} unknown_previewer ;
+
+typedef struct idle_receiver
+{
+  struct idle_receiver *next;
+  win_idle_claimer proc;
+  int speed;
+  void *handle;
+}
+idle_receiver;
+
+static wimp_w win__idle = DUD;
+#define win__unknown_flag (('U'<<24)+('N'<<16)+('K'<<8)+'N')
+
+static wimp_w win__unknown = DUD;
+static unknown_previewer *win__unknown_previewer_list;
+static idle_receiver *idleList;
+static int win__minPoll=2;
+
+static void win__setPollingSpeed(void)
+{
+  int s=win__minPoll;
+  idle_receiver *p=idleList;
+  while (p)
+  {
+    if (p->speed<s && p->speed!=win_DONTCARE)
+      s=p->speed;
+    p=p->next;
+  }
+  wimpt_pollingTime(s);
+}
+
+void win_idleTime(int time)
+{
+  win__minPoll=time;
+  win__setPollingSpeed();
+}
+
+void win_addIdleClaimer(win_idle_claimer proc,int speed,void *handle)
+{
+  idle_receiver *new=(idle_receiver *)mem_alloc(sizeof(idle_receiver));
+  if (new)
+  {
+    new->proc=proc;
+    new->handle=handle;
+    new->next=idleList;
+    new->speed=speed;
+    idleList=new;
+  }
+  win__setPollingSpeed();
+}
+
+BOOL win_any_idles(void)
+{
+  return (!!idleList);
+}
+
+void win_remove_idle_claimer(win_idle_claimer proc,void *handle)
+{
+ idle_receiver *block ;
+ for (block = (idle_receiver *) &idleList ;
+      block->next != 0 && (block->next->proc != proc || block->next->handle != handle) ;
+      block = block->next) ;
+ if (block->next != 0)
+ {
+  idle_receiver *b2 = block->next ;
+  block->next = b2->next ;
+  mem_free(b2) ;
+  win__setPollingSpeed();
+ }
+}
+
+void win_claim_idle_events(wimp_w w)
+{
+  tracef1("idle events -> %d\n",w) ;
+  win__idle = w;
+}
+
+wimp_w win_idle_event_claimer(void)
+{
+  return(win__idle);
+}
+
+void win_claim_unknown_events(wimp_w w)
+{
+  win__unknown = w;
+}
+
+wimp_w win_unknown_event_claimer(void)
+{
+  return win__unknown;
+}
+
+void win_add_unknown_event_processor(win_unknown_event_processor p,
+                                     void *h)
+{
+ unknown_previewer *block = mem_alloc(sizeof(unknown_previewer)) ;
+ if (block != 0)
+ {
+  block->link = win__unknown_previewer_list ;
+  block->proc = p ;
+  block->handle = h ;
+  win__unknown_previewer_list = block ;
+ }
+}
+
+void win_remove_unknown_event_processor(win_unknown_event_processor p,
+                                        void *h)
+{
+ unknown_previewer *block ;
+ for (block = (unknown_previewer *) &win__unknown_previewer_list ;
+      block != 0 && (block->link->proc != p || block->link->handle != h) ;
+      block = block->link) ;
+ if (block != 0)
+ {
+  unknown_previewer *b2 = block->link ;
+  block->link = b2->link ;
+  mem_free(b2) ;
+ }
+}
+
+/* -------- Menus. -------- */
+
+void win_setmenuh(wimp_w w, void *handle)
+{
+  win__str *p = win__find(w);
+  if (p != 0) {p->menuh = handle;};
+}
+
+void *win_getmenuh(wimp_w w) /* 0 if not set */
+{
+  win__str *p = win__find(w);
+  return(p==0 ? 0 : p->menuh);
+}
+
+/* -------- Processing Events. -------- */
+
+/*
+ * void win_broadcast(wimp_eventstr *e)
+ *
+ * Use
+ *  Broadcasts the given event to ALL windows currently active.  Note: this
+ *  works in a similar way to module service calls - a broadcast can be
+ *  'claimed' by changing it to a null event.  This is most useful for
+ *  informing other windows about events (such as a parent window being
+ *  closed), and thus message broadcasts should be used.
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event to broadcast.
+ */
+
+void win_broadcast(wimp_eventstr *e)
+{
+  win__str *p=win__allwindows;
+  win__str *q;
+  while (p)
+  {
+    q=p;
+    p=p->next;
+    (q->proc)(e,q->handle);
+  }
+}
+
+BOOL win_processevent(wimp_eventstr *e)
+{
+  /* --- Houston, we have a problem --- *
+   *
+   * Event handlers can continue over several polls, unlike Sapphire where
+   * this sort of convolution is limited to coroutines.  Our lists of
+   * handlers can become `stale' by the time the previous one finishes,
+   * if we're not careful.  We bodge around the problem (bloody Acorn :-( )
+   * by keeping a static serial number, and a local copy.  If the two don't
+   * match, we declare `stale!' and refuse to process any more events.
+   */
+
+
+  static int serial;
+  int cserial=++serial;
+
+  wimp_w w;
+  win__str *p;
+  os_regset r;
+  wimp_wstate s;
+  tracef1("win_processevent %i.\n", e->e);
+  switch (e->e) {
+  case wimp_ENULL:
+    {
+      idle_receiver *idles=idleList;
+      idle_receiver *next;
+      while (idles && cserial==serial) /* Avoid staleness of lists */
+      {
+        next=idles->next;
+        (idles->proc)(idles->handle);
+        idles=next;
+      }
+    }
+    w = win__idle;
+    break;
+  case wimp_EUSERDRAG:
+    w = win__unknown_flag ;
+    if (wimpt_getVersion()>=300)
+      os_swix(XDragASprite_Stop,&r);
+    break;
+  case wimp_EOPEN:
+    wimpt_noerr(wimp_get_wind_state(e->data.o.w,&s));
+    if (wimpt_justChangedMode() || (s.flags & wimp_WCLICK_TOGGLE))
+      win_adjustBox(&e->data.o);
+    /* And continue... */
+  case wimp_EREDRAW: case wimp_ECLOSE:
+  case wimp_EPTRLEAVE: case wimp_EPTRENTER: case wimp_EKEY:
+  case wimp_ESCROLL:
+    w = e->data.o.w;
+    break;
+  case wimp_EBUT:
+    w = e->data.but.m.w;
+    if (w <= (wimp_w) -1) w = win_ICONBAR;
+    if (wimpt_options() & wimpt_ONOWIMPSHADE)
+    {
+      wimp_icon icn;
+      wimpt_noerr(wimp_get_icon_info(e->data.but.m.w,e->data.but.m.i,&icn));
+      if ((icn.flags & 0x001f0000) == 0x001f0000)
+        e->data.but.m.i=-1;
+    }
+    break;
+  case wimp_ESEND:
+  case wimp_ESENDWANTACK:
+    switch (e->data.msg.hdr.action) {
+    case wimp_MCLOSEDOWN:
+      tracef0("closedown message\n");
+      exit(0);
+    case wimp_MDATALOAD:
+    case wimp_MDATASAVE:
+      tracef1("data %s message arriving.\n",
+             (int) (e->data.msg.hdr.action==wimp_MDATASAVE ? "save" : "load"));
+      if (e->data.msg.data.dataload.w < 0)
+      {
+        tracef0("data message to the icon bar.\n");
+        w = win_ICONBARLOAD ;
+      } else {
+        w = e->data.msg.data.dataload.w;
+      };
+      break;
+    case wimp_MHELPREQUEST:
+      tracef1("help request for window %i.\n", e->data.msg.data.helprequest.m.w);
+      w = e->data.msg.data.helprequest.m.w;
+      if (w < 0) w = win_ICONBARLOAD;
+      break;
+    default:
+      tracef1("unknown message type %i arriving.\n", e->data.msg.hdr.action);
+      w = win__unknown_flag;
+      if (w < 0) w = win_ICONBARLOAD;
+    };
+    break;
+  default:
+    w = win__unknown_flag;
+  };
+
+  if (w==win__unknown_flag || win__find(w) == 0)
+  {
+   unknown_previewer *pr=win__unknown_previewer_list;
+   unknown_previewer *next;
+   while (pr != 0 && cserial==serial)  /* Avoid staleness of lists */
+   {
+    next=pr->link;
+    if (pr->proc(e, pr->handle)) return TRUE ;
+    pr=next;
+   }
+   w = win__unknown ;
+  }
+
+  p = (w == DUD ? 0 : win__find(w));
+  if (p != 0) {
+    p->proc(e, p->handle);
+    return TRUE;
+  } else {
+    return FALSE;
+  };
+}
+
+/* -------- Termination. -------- */
+
+static int win__active;
+
+void win_activeinc(void)
+{
+  win__active++;
+}
+
+void win_activedec(void)
+{
+  win__active--;
+}
+
+int win_activeno(void)
+{
+  return win__active;
+}
+
+/* -------- Giving away the caret. -------- */
+
+void win_give_away_caret(void)
+{
+  win__str *ws=win__allwindows;
+  while (ws) {
+    if (ws->w != DUD) { /* found a window */
+      wimp_wstate s;
+      wimp_eventstr e;
+      tracef1("get state of window %i.", ws->w);
+      (void) wimp_get_wind_state(ws->w, &s);
+      tracef2("behind=%i flags=%i.\n", s.o.behind, s.flags);
+      if (s.o.behind == DUD && (s.flags & wimp_WOPEN) != 0) {
+        /* w is the top window */
+        /* if it wants the caret, it will grab it. */
+        tracef0("Opening it.\n");
+        e.e = wimp_EOPEN;
+        e.data.o = s.o;
+        wimpt_fake_event(&e);
+        break;
+      };
+    };
+    ws=ws->next;
+  };
+}
+
+/* ----------- setting a window title ------------ */
+
+void win_settitle(wimp_w w, char *newtitle,...)
+{
+  wimp_redrawstr r;
+  va_list ap;
+  wimp_winfo *winfo;
+
+  va_start(ap,newtitle);
+  if((winfo = mem_alloc(sizeof(wimp_wind) + 200*sizeof(wimp_icon))) == 0)
+  {
+    werr(FALSE, msgs_lookup("win2:Not enough memory to change window title."));
+    va_end(ap);
+    return;
+  }
+
+tracef1("New title is %s\n", (int)newtitle);
+  /* --- get the window's details --- */
+    winfo->w = w;
+    wimpt_noerr(wimp_get_wind_info(winfo));
+
+  /* --- put the new title string in the title icon's buffer --- */
+tracef1("Lib buffer is at %d\n", (int)winfo->info.title.indirecttext.buffer);
+    vsprintf(winfo->info.title.indirecttext.buffer, newtitle, ap);
+    va_end(ap);
+
+  /* --- invalidate the title bar in absolute coords --- */
+    if (winfo->info.flags & wimp_WOPEN)
+    {
+      r.w = (wimp_w) -1;    /* absolute screen coords */
+      r.box = winfo->info.box;
+      r.box.y1 += 36;            /* yuk - tweaky */
+      r.box.y0 = r.box.y1 - 36;
+      wimpt_noerr(wimp_force_redraw(&r));
+    }
+
+  /* --- free space used to window info --- */
+    mem_free(winfo);
+}
+
+/*
+ * void win_gadgetWidths(wimp_wflags f,wimp_box *b)
+ *
+ * Use
+ *  Returns a box giving the width of the system area around a window with
+ *  window flags f.
+ */
+
+void win_gadgetWidths(wimp_wflags f,wimp_box *b)
+{
+  wimp_wind w=
+  {
+    {-500,-500,-300,-300},0,0,-1,
+    0,
+    {7,2,7,1,3,1,12},
+    {0,0,100,100},
+    0,
+    0,
+    (void *)1,
+    0,
+    {"anywindow"},
+    0
+  };
+  wimp_w temp;
+  wimp_wstate s;
+  wimp_redrawstr r;
+
+  w.flags=f | wimp_WTRESPASS;
+  if (wimp_create_wind(&w,&temp))
+  {
+    b->x0=0;
+    b->x1=(f & wimp_WHSCR) ? 40 : 0;
+    b->y0=(f & wimp_WVSCR) ? 40 : 0;
+    b->y1=(f & wimp_WTITLE) ? 40 : 0;
+  }
+  else
+  {
+    wimpt_noerr(wimp_get_wind_state(temp,&s));
+    wimpt_noerr(wimp_open_wind(&s.o));
+    wimpt_noerr(wimp_get_wind_state(temp,&s));
+    r.w=temp;
+    wimpt_noerr(wimp_getwindowoutline(&r));
+    b->x0=s.o.box.x0-r.box.x0;
+    b->x1=r.box.x1-s.o.box.x1;
+    b->y1=r.box.y1-s.o.box.y1;
+    b->y0=s.o.box.y0-r.box.y0;
+    wimpt_noerr(wimp_delete_wind(temp));
+  }
+}
+
+/*
+ * void win_adjustBox(wimp_openstr *o)
+ *
+ * Use
+ *  Adjusts a window so that it fits on the screen.
+ *
+ * Parameters
+ *  wimp_openstr *o == pointer to the block to fiddle
+ */
+
+void win_adjustBox(wimp_openstr *o)
+{
+  int scx=wimpt_scwidth();
+  int scy=wimpt_scheight();
+  int w=o->box.x1-o->box.x0;
+  int h=o->box.y1-o->box.y0;
+  wimp_box b;
+  wimp_wstate s;
+  wimpt_noerr(wimp_get_wind_state(o->w,&s));
+  win_gadgetWidths(s.flags,&b);
+
+  if (o->box.x1-o->box.x0>scx-b.x0-b.x1)
+  {
+    o->box.x0=b.x0;
+    o->box.x1=scx-b.x1;
+  }
+  else if (o->box.x1>scx-b.x1)
+  {
+    o->box.x1=scx-b.x1;
+    o->box.x0=scx-b.x1-w;
+  }
+  else if (o->box.x0<b.x0)
+  {
+    o->box.x0=b.x0;
+    o->box.x1=b.x0+w;
+  }
+
+  if (o->box.y1-o->box.y0>scy-b.y0-b.y1)
+  {
+    o->box.y0=b.y0;
+    o->box.y1=scy-b.y1;
+  }
+  else if (o->box.y1>scy-b.y1)
+  {
+    o->box.y1=scy-b.y1;
+    o->box.y0=scy-b.y1-h;
+  }
+  else if (o->box.y0<b.y0)
+  {
+    o->box.y0=b.y0;
+    o->box.y1=b.y0+h;
+  }
+}
+
+/*
+ * BOOL win_anyWindows(void)
+ *
+ * Use
+ *  Informs the caller if there are any windows left.
+ *
+ * Returns
+ *  TRUE if there are.
+ */
+
+BOOL win_anyWindows(void)
+{
+  wimp_wind w=
+  {
+    {0,0,10,10},0,0,-1,
+    0,
+    {7,2,7,1,3,1,12},
+    {0,0,10,10},
+    0,
+    0,
+    (void *)1,
+    0,
+    {"anywindow"},
+    0
+  };
+  os_error *err;
+  wimp_w handle;
+  err=wimp_create_wind(&w,&handle);
+  if (err)
+    return (FALSE);
+  else
+  {
+    wimp_delete_wind(handle);
+    return (TRUE);
+  }
+}
+
+/* end */
diff --git a/StraySrc/Libraries/Steel/c/xferrecv b/StraySrc/Libraries/Steel/c/xferrecv
new file mode 100644 (file)
index 0000000..caa386c
--- /dev/null
@@ -0,0 +1,394 @@
+/* Title: -> c.xferrecv
+ * Purpose: general purpose import of data by dragging icon
+ * Requires:
+ *  BOOL
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+#include "trace.h"
+#include "os.h"
+#include "bbc.h"
+#include "wimp.h"
+#include "wimpt.h"
+#include "win.h"
+#include "dbox.h"
+#include "typdat.h"
+#include "xfersend.h"
+#include "fileicon.h"
+#include "werr.h"
+#include "menu.h"
+#include "event.h"
+#include "xferrecv.h"
+#include "msgs.h"
+
+#define XOS_ReadVarVal 0x20023
+
+typedef enum
+{
+ xferrecv_state_Ask,
+ xferrecv_state_Talk,
+ xferrecv_state_Done,
+ xferrecv_state_Broken
+} xferrecv_stateval ;
+
+
+static wimp_t xferrecv_sendertask ;
+static wimp_msgstr xferrecv_ack ;
+
+static xferrecv_buffer_processor xferrecv_processbuff ;
+static char *xferrecv_buffer ;
+static int xferrecv_buffersize ;
+static int xferrecv_state ;
+static int xferrecv_msgid ;
+
+static flex_ptr xferrecv__flex;
+static int xferrecv__returnBlockSize;
+
+static char xferrecv__nameToImport[256];
+
+static int scrap_ref;
+static int xferrecv__fileissafe ;
+
+int xferrecv_checkinsert(char **filename)
+{
+
+ wimp_eventstr *e = wimpt_last_event();
+
+ if ((e->e==wimp_ESENDWANTACK || e->e == wimp_ESEND) &&
+     (e->data.msg.hdr.action == wimp_MDATALOAD ||
+      e->data.msg.hdr.action == wimp_MDATAOPEN))
+ {
+  tracef4("xferrecv_checkinsert returning filetype %x: %d %d %d\n",
+           e->data.msg.data.dataload.type,
+           scrap_ref,e->data.msg.hdr.your_ref,e->data.msg.hdr.my_ref) ;
+  xferrecv__fileissafe = e->data.msg.hdr.your_ref != scrap_ref ||
+                         scrap_ref==0 ;
+  xferrecv_ack.hdr.action = wimp_MDATALOADOK ;
+  xferrecv_ack.hdr.size = sizeof(wimp_msghdr) ;
+  xferrecv_sendertask = e->data.msg.hdr.task ;
+  xferrecv_ack.hdr.your_ref = e->data.msg.hdr.my_ref ;
+  *filename = e->data.msg.data.dataload.name ;
+  if (xferrecv__fileissafe)
+    strcpy(xferrecv__nameToImport,*filename);
+  return e->data.msg.data.dataload.type ;
+ }
+ else return -1 ;
+}
+
+void xferrecv_insertfileok(void)
+{
+/* An insert has been completed successfully. This sends an acknowledge back
+   to the original application. */
+
+ tracef0("xferrecv_insertfileok\n") ;
+
+ if (!xferrecv__fileissafe)
+ {
+  tracef0("Must delete scrap file\n") ;
+  os_cli("%remove <Wimp$Scrap>") ;
+ }
+ scrap_ref = 0 ;
+ (void) wimp_sendmessage(wimp_ESEND, &xferrecv_ack, xferrecv_sendertask);
+}
+
+int xferrecv_checkprint(char **filename)
+{
+ wimp_eventstr *e = wimpt_last_event();
+
+ if ((e->e==wimp_ESENDWANTACK || e->e == wimp_ESEND) &&
+     (e->data.msg.hdr.action == wimp_MPrintTypeOdd))
+ {
+  tracef4("xferrecv_checkprint returning filetype %x: %d %d %d\n",
+           e->data.msg.data.print.type,
+           scrap_ref,e->data.msg.hdr.your_ref,e->data.msg.hdr.my_ref) ;
+
+  xferrecv__fileissafe = 0 ;
+  xferrecv_ack.hdr.action = wimp_MPrintTypeKnown ;
+  xferrecv_ack.hdr.size = sizeof(wimp_msghdr)+sizeof(wimp_msgprint) ;
+  xferrecv_sendertask = e->data.msg.hdr.task ;
+  xferrecv_ack.hdr.your_ref = e->data.msg.hdr.my_ref ;
+  *filename = e->data.msg.data.print.name ;
+  return e->data.msg.data.print.type ;
+ }
+ else return -1 ;
+}
+
+
+void xferrecv_printfileok(int type)
+{
+ xferrecv_ack.data.print.type = type ;
+ (void) wimp_sendmessage(wimp_ESEND, &xferrecv_ack, xferrecv_sendertask);
+}
+
+int xferrecv_checkimport(int *estsize)
+{
+ wimp_eventstr *e = wimpt_last_event();
+
+ if ((e->e==wimp_ESENDWANTACK || e->e == wimp_ESEND) &&
+     e->data.msg.hdr.action == wimp_MDATASAVE)
+ {
+  xferrecv_ack.hdr.size = sizeof(wimp_msghdr) + sizeof(wimp_msgdatasaveok) ;
+  xferrecv_sendertask = e->data.msg.hdr.task ;
+  xferrecv_ack.hdr.your_ref = e->data.msg.hdr.my_ref ;
+  xferrecv_ack.hdr.action = wimp_MDATASAVEOK ;
+  xferrecv_ack.data.datasaveok.w = e->data.msg.data.datasave.w ;
+  xferrecv_ack.data.datasaveok.i = e->data.msg.data.datasave.i ;
+  xferrecv_ack.data.datasaveok.x = e->data.msg.data.datasave.x ;
+  xferrecv_ack.data.datasaveok.y = e->data.msg.data.datasave.y ;
+  xferrecv_ack.data.datasaveok.type = e->data.msg.data.datasave.type ;
+  *estsize = xferrecv_ack.data.datasaveok.estsize
+           = e->data.msg.data.datasave.estsize ;
+  strcpy(xferrecv__nameToImport,e->data.msg.data.datasave.leaf);
+  tracef2("xferrecv_checkimport returning filetype %x from %d\n",
+           e->data.msg.data.datasave.type,xferrecv_sendertask) ;
+
+  return  xferrecv_ack.data.datasaveok.type = e->data.msg.data.datasave.type ;
+ }
+ else return -1 ;
+}
+
+/*
+ * char *xferrecv_nameToImport(void)
+ *
+ * Use
+ *  Returns the name of the file to import (full pathname if available).
+ *
+ * Returns
+ *  A pointer to a read-only string.
+ */
+
+char *xferrecv_nameToImport(void)
+{
+  return (xferrecv__nameToImport);
+}
+
+static void  xferrecv_sendRAMFETCH(void)
+{
+ char *addr = xferrecv_ack.data.ramfetch.addr ;
+ int size = xferrecv_ack.data.ramfetch.nbytes ;
+ int action = xferrecv_ack.hdr.action ;
+
+ tracef2("xferrecv_sendRAMFETCH with buffer %x, size %d :",
+          (int) xferrecv_buffer,xferrecv_buffersize) ;
+
+ xferrecv_ack.hdr.action = wimp_MRAMFETCH ;
+ xferrecv_ack.data.ramfetch.addr = xferrecv_buffer ;
+ xferrecv_ack.data.ramfetch.nbytes = xferrecv_buffersize ;
+ (void) wimp_sendmessage(wimp_ESENDWANTACK,
+                         &xferrecv_ack,
+                         xferrecv_sendertask);
+ xferrecv_msgid = xferrecv_ack.hdr.my_ref ;
+
+ tracef1(" ramfetch msg id %d\n",xferrecv_msgid) ;
+
+ xferrecv_ack.data.ramfetch.addr=addr ;
+ xferrecv_ack.data.ramfetch.nbytes=size ;
+ xferrecv_ack.hdr.action = action ;
+}
+
+static BOOL xferrecv_unknown_events(wimp_eventstr *e, void *handle)
+{
+ handle = handle ;
+
+#if TRACE
+ tracef("xferrecv_unknown_events %d %d %d %d %d\n",e->e,
+         e->data.msg.hdr.action,e->data.msg.hdr.my_ref,
+         e->data.msg.hdr.your_ref,xferrecv_msgid) ;
+#endif
+
+ if ((e->e == wimp_ESEND || e->e == wimp_ESENDWANTACK) &&
+     e->data.msg.hdr.your_ref == xferrecv_msgid &&
+     e->data.msg.hdr.action == wimp_MRAMTRANSMIT)
+ {
+  tracef2("xferrecv got ramtransmit of %d into %d\n",
+          e->data.msg.data.ramtransmit.nbyteswritten,xferrecv_buffersize) ;
+  if (e->data.msg.data.ramtransmit.nbyteswritten == xferrecv_buffersize)
+  {
+   /* other end has filled our buffer; better try and allocate some more
+      space */
+   if (xferrecv_processbuff(&xferrecv_buffer, &xferrecv_buffersize))
+   {
+    /* can go on */
+    tracef2("users buffer processor set buffer %x, size %d\n",
+             (int) xferrecv_buffer, xferrecv_buffersize) ;
+
+    xferrecv_ack.hdr.your_ref = e->data.msg.hdr.my_ref ;
+    xferrecv_sendRAMFETCH() ;
+    xferrecv_state = xferrecv_state_Talk ;
+   }
+   else
+   {
+    tracef0("users buffer processor failed: break down\n") ;
+    xferrecv_state = xferrecv_state_Broken ;
+   }
+  }
+  else
+  {
+   tracef0("xferrecv had final ramtransmit; set done state\n") ;
+   xferrecv_state = xferrecv_state_Done ;
+   xferrecv_buffersize=e->data.msg.data.ramtransmit.nbyteswritten;
+   if (xferrecv_buffersize!=0)
+   {
+     if (!xferrecv_processbuff(&xferrecv_buffer, &xferrecv_buffersize))
+       xferrecv_state = xferrecv_state_Broken ;
+   }
+   xferrecv_buffersize = e->data.msg.data.ramtransmit.nbyteswritten ;
+  }
+ }
+ else if (e->e == wimp_EACK && e->data.msg.hdr.my_ref == xferrecv_msgid)
+ {
+  tracef0("xferrecv ramfetch bounced: ") ;
+  /* got our message back */
+  if (xferrecv_state == xferrecv_state_Ask)
+    xferrecv_importByScrap();
+  else
+  {
+   tracef0("tell the user the protocol fell down\n") ;
+   werr(0, msgs_lookup("xferrecv2:Data transfer failed.")) ;
+  }
+  xferrecv_state = xferrecv_state_Broken ;
+ }
+ else return FALSE ;
+
+ return TRUE ;
+}
+
+/*
+ * void xferrecv_importByScrap(void)
+ *
+ * Use
+ *  Tells xferrecv not to bother with RAM transfer, but to use the
+ *  <Wimp$Scrap> file instead.  It checks that the system variables and
+ *  everything are set up right beforehand.
+ */
+
+void xferrecv_importByScrap(void)
+{
+  os_regset r ;
+  tracef0("ask for Wimp$Scrap transfer\n") ;
+
+  /* first check that variable exists */
+  r.r[0] = (int) "Wimp$Scrap" ;
+  r.r[1] = NULL ;
+  r.r[2] = -1 ;
+  r.r[3] = 0 ;
+  r.r[4] = 3 ;
+  os_swix(XOS_ReadVarVal, &r) ;
+
+  if (r.r[2]==0)
+    werr(0,msgs_lookup("xferrecv1:Can't transfer file (use *Set Wimp$Scrap <filename>)")) ;
+  else
+  {
+    strcpy(xferrecv_ack.data.datasaveok.name, "<Wimp$Scrap>") ;
+    xferrecv_ack.data.datasaveok.estsize = -1 ; /* file is not safe with us */
+    (void) wimp_sendmessage(wimp_ESEND, &xferrecv_ack, xferrecv_sendertask);
+    scrap_ref = xferrecv_ack.hdr.my_ref ;
+  }
+}
+
+int xferrecv_doimport(char *buf, int size, xferrecv_buffer_processor p)
+{
+
+/* Receives data into the buffer; calls the buffer processor if the buffer
+   given becomes full. Returns TRUE if the transaction completed sucessfully.
+ */
+
+ win_add_unknown_event_processor(xferrecv_unknown_events, 0) ;
+
+ tracef0("xferrecv_doimport entered\n") ;
+ xferrecv_processbuff = p ;
+ xferrecv_buffer = buf ;
+ xferrecv_buffersize = size ;
+ xferrecv_sendRAMFETCH() ;
+ xferrecv_state = xferrecv_state_Ask ;
+ xferrecv__fileissafe = FALSE ;
+
+ do
+ {
+  event_process() ;
+ } while (xferrecv_state < xferrecv_state_Done) ;
+
+ win_remove_unknown_event_processor(xferrecv_unknown_events, 0) ;
+
+ return (xferrecv_state == xferrecv_state_Done ? xferrecv_buffersize : -1 ) ;
+}
+
+/*
+ * BOOL xferrecv__returnBlockBuffProcessor(char **buff,int *size)
+ *
+ * Use
+ *  Buffer processor for xferrecv_returnImportedBlock.
+ */
+
+static BOOL xferrecv__returnBlockBuffProcessor(char **buff,int *size)
+{
+  if (!flex_extend(xferrecv__flex,xferrecv__returnBlockSize+8192))
+    return (FALSE);
+  xferrecv__returnBlockSize+=8192;
+  *buff+=*size;
+  *size=8192;
+  return (TRUE);
+}
+
+/*
+ * int xferrecv_returnImportedBlock(flex_ptr p)
+ *
+ * Use
+ *  Performs the data import if possible, and returns with the block filled
+ *  with *ALL* the imported data i.e. it obviates the need of any work on
+ *  your part for the data transfer.  This is the life, huh?  If anything
+ *  went wrong, it returns -1 as for xferrecv_doimport
+ *
+ * Parameters
+ *  flex_ptr p == flex pointer to nothing in particular (certainly not a
+ *    flex block - one is allocated for you).  Remember to free it after
+ *    you've read all the data!  Also ensure that flex has been initialised.
+ *    If there is no data to import (i.e. the import failed) then p is freed
+ *    of any data that may have been stored there.
+ *
+ * Returns
+ *  -1 for failure, or the total size of the imported data for success
+ */
+
+int xferrecv_returnImportedBlock(flex_ptr p)
+{
+  xferrecv__flex=p;
+  if (!flex_alloc(p,xferrecv_ack.data.datasaveok.estsize))
+    return (-1);
+  xferrecv__returnBlockSize=xferrecv_ack.data.datasaveok.estsize;
+  if (xferrecv_doimport(*p,xferrecv_ack.data.datasaveok.estsize,
+                                     xferrecv__returnBlockBuffProcessor)==-1)
+  {
+    flex_free(p);
+    return (-1);
+  }
+  return (xferrecv__returnBlockSize);
+}
+
+BOOL xferrecv_file_is_safe()
+{
+ return xferrecv__fileissafe ;
+}
+
+/* end */
diff --git a/StraySrc/Libraries/Steel/c/xfersend b/StraySrc/Libraries/Steel/c/xfersend
new file mode 100644 (file)
index 0000000..5d15655
--- /dev/null
@@ -0,0 +1,531 @@
+/* Title: -> c.xfersend
+ * Purpose: generalised data transfer to a concurrent wimp program.
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "trace.h"
+#include "os.h"
+#include "bbc.h"
+#include "wimp.h"
+#include "wimpt.h"
+#include "win.h"
+#include "dbox.h"
+#include "xfersend.h"
+#include "fileicon.h"
+#include "werr.h"
+#include "menu.h"
+#include "event.h"
+#include "msgs.h"
+#include "swis.h"
+
+static int rcvbufsize ;
+static int xfersend__msgid;
+static xfersend_saveproc xfersend__saveproc;
+static xfersend_sendproc xfersend__sendproc;
+static xfersend_printproc xfersend__printproc;
+static int xfersend__filetype;
+static void *xfersend__savehandle;
+static int xfersend__estsize;
+static wimp_t xfersend__receiver ;
+static BOOL xfersend__fileissafe ;
+static char xfersend__filename[256];
+
+static wimp_mousestr xfersend__mousestr;
+static wimp_msgstr xfersend__msg;
+static BOOL xfersend__close;
+static wimp_w xfersend__w;
+static wimp_i xfersend__i;
+
+static BOOL xfersend__finishedXfer;
+
+static void xfersend__iconDel(wimp_w w,wimp_i i,BOOL del)
+{
+  if (wimpt_options() & wimpt_OREMSAVEICON)
+  {
+    if (del)
+      wimp_set_icon_state(w,i,(1<<23)+(1<<7),(1<<23)+(1<<7));
+    else
+      wimp_set_icon_state(w,i,0,(1<<23)+(1<<7));
+  }
+}
+
+void xfersend_close_on_xfer(BOOL do_we_close, wimp_w w)
+{
+  xfersend__close = do_we_close;
+  xfersend__w = w;
+}
+
+static void xfersend__winclose(void)
+{
+  wimp_eventdata e;
+  e.o.w = xfersend__w;
+  wimpt_noerr(wimp_sendwmessage(wimp_ECLOSE, (wimp_msgstr*) &e, e.o.w, -1));
+}
+
+
+static BOOL xfersend__unknowns(wimp_eventstr *e, void *handle) {
+  handle = handle ;
+  tracef1("xfersend raw event %i.\n", e->e);
+  switch (e->e) {
+  case wimp_EUSERDRAG:
+    tracef0("drag event received.\n");
+    {
+      wimp_get_point_info(&xfersend__mousestr);
+      if (xfersend__mousestr.w == -1) {
+        tracef0("drag to no window: has no effect.\n");
+        xfersend__finishedXfer=TRUE;
+        /* do nothing */
+      } else {
+        wimp_msgstr msg;
+
+        tracef1("drag to window %i: offer data.\n", xfersend__mousestr.w);
+        /* msg.hdr.size = sizeof(wimp_msghdr) + sizeof(wimp_msgdatasave); */
+        msg.hdr.task = xfersend__mousestr.w;
+        msg.hdr.your_ref = 0;
+        msg.hdr.action = wimp_MDATASAVE;
+        msg.data.datasave.w = xfersend__mousestr.w;
+        msg.data.datasave.i = xfersend__mousestr.i;
+        msg.data.datasave.x = xfersend__mousestr.x;
+        msg.data.datasave.y = xfersend__mousestr.y;
+        msg.data.datasave.type = xfersend__filetype;
+        msg.data.datasave.estsize = xfersend__estsize;
+        {
+          int  tail;
+          char name[256];
+          strncpy(name,xfersend__filename,  256);
+          tail = strlen(name); /* point at the zero */
+          while (tail > 0 && name[tail-1] != '.' && name[tail-1] != ':')
+               tail--;
+
+         strncpy(msg.data.datasave.leaf, name + tail, 210);
+         msg.data.dataload.name[211] = 0; /* Avoid boundcheck warning */
+         msg.hdr.size = (48+strlen(msg.data.datasave.leaf)) & ~3;
+          tracef1("suggest leaf '%s'.\n", (int) &msg.data.datasave.leaf[0]);
+        };
+        wimpt_noerr(wimp_sendwmessage(
+           wimp_ESENDWANTACK, &msg, xfersend__mousestr.w, xfersend__mousestr.i));
+        xfersend__msgid = msg.hdr.my_ref; /* filled in by wimp. */
+        /* We still get unknown events, so we'll get the reply sometime. */
+      };
+    };
+    return TRUE;
+
+  case wimp_ESEND:
+  case wimp_ESENDWANTACK:
+
+#if TRACE
+    tracef("xfersend msg %x received: %i %i.\n",
+            e->data.msg.hdr.action,e->data.msg.hdr.your_ref,xfersend__msgid);
+#endif
+
+    if (e->data.msg.hdr.your_ref == xfersend__msgid)
+     switch (e->data.msg.hdr.action)
+     {
+      case wimp_MRAMFETCH:
+       if (xfersend__sendproc != 0)
+       {
+        xfersend__fileissafe = FALSE ;
+
+        /* He wants to do an in-core transfer, and we can do this. */
+        /* Note that this can't be other than the first response, as others
+           are grabbed by sendbuf */
+
+        tracef0("ram transfer starting.\n");
+
+        /* Prepare the reply record. */
+        xfersend__msg = e->data.msg;
+        xfersend__msg.hdr.your_ref = xfersend__msg.hdr.my_ref;
+        xfersend__msg.hdr.action = wimp_MRAMTRANSMIT;
+        xfersend__msg.data.ramtransmit.addr = e->data.msg.data.ramfetch.addr;
+        xfersend__msg.data.ramtransmit.nbyteswritten = 0; /* so far. */
+        rcvbufsize = e->data.msg.data.ramfetch.nbytes;
+
+        xfersend__receiver = e->data.msg.hdr.task ;
+        /* the copy in xfersend__msg.hdr.task is overwritten by the Wimp
+           message sending */
+
+        if (xfersend__sendproc(xfersend__savehandle, &rcvbufsize))
+        {
+         /* See sendbuf for all the real work for this case... */
+         tracef0("The send succeeded; send final RAMTRANSMIT.\n");
+
+         /* We may have transferred some data but not yet told the
+         other end about it. xfersend__msg contains a final RAMTRANSMIT,
+         which does not quite fill his buffer (or we'd have sent it already)
+         thus signalling to him that the transfer is over. */
+
+         wimpt_noerr(wimp_sendmessage(
+           wimp_ESEND,
+           &xfersend__msg,
+           xfersend__receiver));
+         xfersend__finishedXfer=TRUE;
+         if(xfersend__close) xfersend__winclose();
+         else xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
+        }
+        else
+        {
+          tracef0("the send failed.\n");
+          xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
+          xfersend__finishedXfer=TRUE;
+        };
+        return TRUE;
+       }
+       else
+       {
+         if (getenv("Wimp$Scrap")==0)
+           xfersend__finishedXfer=TRUE;
+      /*** The other application reports an error, and I don't get my ***
+       *** no-acknowledgement  message to tell me to abort  the  data ***
+       *** transfer.                                                  ***/
+       }
+       break ;
+
+      case wimp_MPrintFile:       /* was dropped on a printer application */
+       if (xfersend__printproc != 0)
+       {
+        int res ;
+
+        tracef0("print request acceptable\n");
+        xfersend__fileissafe = FALSE ;
+
+        res = xfersend__printproc(&e->data.msg.data.print.name[0],
+                                      xfersend__savehandle) ;
+
+        xfersend__msg = e->data.msg;
+        xfersend__msg.hdr.your_ref = xfersend__msg.hdr.my_ref;
+        xfersend__msg.hdr.action =
+           res >= 0 ? wimp_MDATALOAD : wimp_MWillPrint;
+        xfersend__msg.data.print.type = res ;  /* in case it's been saved */
+        wimpt_noerr(wimp_sendmessage(
+           wimp_ESENDWANTACK,
+           &xfersend__msg,
+           xfersend__receiver));
+        xfersend__msgid=xfersend__msg.hdr.my_ref;
+        if (res==xfersend_printPrinted)
+        {
+          xfersend__finishedXfer=TRUE;
+          if(xfersend__close) xfersend__winclose();
+          else xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
+        }
+        else if (res==xfersend_printFailed)
+          xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
+        return TRUE;
+       }
+       break ;
+
+      case wimp_MDATALOADOK:
+        xfersend__finishedXfer=TRUE;
+        if(xfersend__close) xfersend__winclose();
+        else xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
+        return (TRUE);
+        break;
+
+      case wimp_MDATASAVEOK:
+      {
+        tracef4("datasaveok %i %i %i %i.\n",
+          e->data.msg.hdr.size,
+          e->data.msg.hdr.task,
+          e->data.msg.hdr.your_ref,
+          e->data.msg.hdr.my_ref);
+        tracef4("datasaveok %x %x %x %x.\n",
+          e->data.msg.data.words[0],
+          e->data.msg.data.words[1],
+          e->data.msg.data.words[2],
+          e->data.msg.data.words[3]);
+        tracef1("it's the datasaveok, to file '%s'.\n",
+                 (int) &e->data.msg.data.datasaveok.name[0]);
+
+        tracef1("save to filename '%s'.\n",
+                (int) &e->data.msg.data.datasaveok.name[0]);
+
+        xfersend__fileissafe = e->data.msg.data.datasaveok.estsize >= 0 ;
+
+        if (xfersend__saveproc(&e->data.msg.data.datasaveok.name[0],
+                             xfersend__savehandle))
+        {
+          tracef0("the save succeeded: send dataload\n");
+
+          xfersend__msg = e->data.msg;
+                                 /* sets hdr.size, data.w,i,x,y, size, name */
+          xfersend__msg.hdr.your_ref = e->data.msg.hdr.my_ref;
+          xfersend__msg.hdr.action = wimp_MDATALOAD;
+          xfersend__msg.data.dataload.type = xfersend__filetype ;
+          wimpt_noerr(wimp_sendmessage(
+            wimp_ESENDWANTACK,
+            &xfersend__msg,
+            e->data.msg.hdr.task));
+          xfersend__msgid=xfersend__msg.hdr.my_ref;
+
+        } else
+        {
+          /* he has already reported the error: nothing more to do. */
+          tracef0("save was not successful.\n");
+          xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
+          xfersend__finishedXfer=TRUE;
+        };
+        return TRUE;
+      }
+     }
+    return FALSE ;      /* unknown not dealt with */
+
+  case wimp_EACK:
+    if (e->data.msg.hdr.my_ref == xfersend__msgid)
+    {
+      switch (e->data.msg.hdr.action)
+      {
+        case wimp_MDATALOAD:
+          {
+            /* It looks as if he hasn't acknowledged my DATALOAD acknowledge:
+               thus it may be a loose scrap file, and must be deleted. */
+            char a[256];
+            tracef0("he hasn't ack'd our data load of temp file, so delete the file.\n");
+            werr(FALSE, msgs_lookup("xfersend1:Bad data transfer, receiver dead."));
+            sprintf(a, "%%delete %s", &xfersend__msg.data.dataload.name[0]);
+            os_cli(a) ;
+            xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
+            xfersend__finishedXfer=TRUE;
+          }
+          break;
+        case wimp_MDATASAVE:
+          xfersend__finishedXfer=TRUE;
+          xfersend__iconDel(xfersend__w,xfersend__i,FALSE);
+          break;
+      }
+    };
+    return TRUE;
+  default:
+    return FALSE ;
+  };
+}
+
+
+static int sendbuf__state ;
+
+static BOOL sendbuf__unknowns(wimp_eventstr *e, void *h)
+{
+ h = h ;
+
+ tracef4("sendbuf__unknowns %d %d %d %d\n",
+          e->data.msg.hdr.my_ref, e->data.msg.hdr.your_ref,
+          xfersend__msg.hdr.your_ref, xfersend__msg.hdr.my_ref) ;
+
+ if ((e->e == wimp_ESENDWANTACK || e->e == wimp_ESEND) &&
+     e->data.msg.hdr.your_ref == xfersend__msg.hdr.my_ref &&
+     e->data.msg.hdr.action == wimp_MRAMFETCH)
+ {
+  /* Prepare xfersend__msg as the next RAMTRANSMIT. Most of
+  the fields are already set up. */
+
+  xfersend__msg.data.ramtransmit.addr = e->data.msg.data.ramfetch.addr;
+  xfersend__msg.data.ramtransmit.nbyteswritten = 0;
+  xfersend__msg.hdr.your_ref = e->data.msg.hdr.my_ref ;
+  rcvbufsize = e->data.msg.data.ramfetch.nbytes;
+
+  tracef2("RAMFETCH received: continue with buffer at %x, size %d\n",
+           (int) xfersend__msg.data.ramtransmit.addr, rcvbufsize) ;
+
+  sendbuf__state = 1 ;
+  return TRUE ;      /* We've had another RAMFETCH: off we go again */
+ }
+
+ if (e->e == wimp_EACK &&
+    e->data.msg.hdr.my_ref == xfersend__msg.hdr.my_ref)
+ {
+  sendbuf__state = 2 ;
+  tracef0("xfersend RAMTRANSMIT bounced; set failed state\n") ;
+  return TRUE ;/* our message bounced back; give up */
+ }
+
+ return FALSE ;    /* we don't want it */
+}
+
+
+BOOL xfersend_sendbuf(char *buffer, int size)
+{
+
+/* Called by his sendproc when sending things in memory. The
+reply record is in xfersend__msg. */
+
+ tracef2("xfersend_sendbuf %i %i\n", (int) buffer, size);
+
+ /* Make the data transfer */
+ tracef3("transfer block of %d from %x to %x\n", size, (int) buffer,
+           (int) (xfersend__msg.data.ramtransmit.addr +
+            xfersend__msg.data.ramtransmit.nbyteswritten)) ;
+
+ wimpt_noerr(wimp_transferblock(
+      wimpt_task(),
+      buffer,
+      xfersend__receiver,
+      xfersend__msg.data.ramtransmit.addr +
+        xfersend__msg.data.ramtransmit.nbyteswritten,
+      size));
+
+ /* record bytes to be sent to the other end */
+ xfersend__msg.data.ramtransmit.nbyteswritten += size;
+ rcvbufsize -= size ;
+
+ /* if size != 0, there are still bytes to send. */
+
+  if (rcvbufsize > 0) return TRUE;
+
+ tracef1("xfersend message has put %d into buffer\n",size) ;
+ /* Tell him that you've done it */
+ wimpt_noerr(wimp_sendmessage(
+      wimp_ESENDWANTACK,
+      &xfersend__msg,
+      xfersend__receiver));
+
+  /* Get his reply. Poll and despatch events until get nack or message */
+
+ sendbuf__state = 0 ;
+
+ win_add_unknown_event_processor(sendbuf__unknowns, 0) ;
+ do { event_process() ; } while (sendbuf__state == 0) ;
+ win_remove_unknown_event_processor(sendbuf__unknowns, 0) ;
+
+  /* This exit happens in the cases where the buffers at each end
+      are of identical size. So, return for another call to sendbuf, or
+      so that the sendbuf procedure can return. */
+
+ return sendbuf__state != 2 ;  /* OK unless state = broken */
+}
+
+BOOL xfersend(int filetype, char *filename, int estsize,
+                     xfersend_saveproc saver,
+                     xfersend_sendproc sender,
+                     xfersend_printproc printer,
+                     wimp_eventstr *e, void *handle)
+{
+      wimp_dragstr dr;
+      wimp_wstate wstate;
+      wimp_icon icon;
+      wimp_w w = e->data.but.m.w;
+      os_regset r;
+      xfersend__saveproc = saver;
+      xfersend__sendproc = sender;
+      xfersend__printproc = printer;
+      xfersend__filetype = filetype;
+      xfersend__estsize = estsize;
+      xfersend__savehandle = handle;
+      if(filename == 0)
+        strcpy(xfersend__filename, msgs_lookup("xfersend2:Selection"));
+      else
+        strncpy(xfersend__filename,filename,256);
+      if (e->e==wimp_EBUT)
+      {
+        xfersend__w = e->data.but.m.w;
+        xfersend__i = e->data.but.m.i;
+        tracef0("Initiate a drag.\n");
+        r.r[0]=161; /* Read CMOS */
+        r.r[1]=0x1c; /* Support DragASrite? */
+        wimpt_noerr(os_swix(XOS_Byte,&r));
+        wimp_get_wind_state(w, &wstate);
+        wimp_get_icon_info(w, e->data.but.m.i, &icon);
+        dr.box.x0 = wstate.o.box.x0 - wstate.o.x + icon.box.x0;
+        dr.box.y0 = wstate.o.box.y1 - wstate.o.y + icon.box.y0;
+        dr.box.x1 = wstate.o.box.x0 - wstate.o.x + icon.box.x1;
+        dr.box.y1 = wstate.o.box.y1 - wstate.o.y + icon.box.y1;
+        if ((r.r[2] & 2) && wimpt_getVersion()>=300)
+        {
+          r.r[0]=0xC5; /* Centre, whole-screen, drop-shadow */
+          r.r[1]=1;
+          r.r[2]=(int)fileicon_spriteName(filetype,filename);
+          r.r[3]=(int)&dr.box;
+          xfersend__iconDel(xfersend__w,xfersend__i,TRUE);
+          wimpt_noerr(os_swix(XDragASprite_Start,&r));
+        }
+        else
+        {
+          /* Pedestrian drag-box */
+          dr.window = w; /* not relevant. */
+          dr.type = wimp_USER_FIXED;
+          dr.parent.x0 = 0;
+          dr.parent.y0 = 0;
+          dr.parent.x1 = wimpt_scwidth();
+          dr.parent.y1 = wimpt_scheight();
+          wimp_drag_box(&dr);
+        }
+      }
+      win_add_unknown_event_processor(xfersend__unknowns, 0);
+      xfersend__finishedXfer=FALSE;
+      while (xfersend__finishedXfer==FALSE)
+        event_process();
+      win_remove_unknown_event_processor(xfersend__unknowns, 0);
+      xfersend__w=0;
+      return TRUE;
+}
+
+
+BOOL xfersend_file_is_safe()
+{
+ return xfersend__fileissafe ;
+}
+
+void xfersend_set_fileissafe(BOOL value)
+{
+  xfersend__fileissafe = value;
+}
+
+/*
+ * BOOL xfersend_sendBlock(void *block,size_t length,int *maxbuf)
+ *
+ * Use
+ *  Sends a block to xfersend_sendbuf() a chunk at a time.
+ *
+ * Parameters
+ *  void *block == pointer to the block
+ *  size_t length == length of block
+ *  int *maxbuf == pointer to the length of the destination task's buffer
+ *
+ * Returns
+ *  TRUE if successful, FALSE if it failed.  If this returns FALSE, you must
+ *  return FALSE immediately.
+ */
+
+BOOL xfersend_sendBlock(void *block,int length,int *maxbuf)
+{
+  char *p=(char *)block;
+  int left=length;
+  int send;
+  while (left)
+  {
+    if (left<=(*maxbuf))
+      send=left;
+    else
+      send=*maxbuf;
+    if (xfersend_sendbuf(p,send)==FALSE)
+      return (FALSE);
+    left-=send;
+    p+=send;
+  }
+  return (TRUE);
+}
+
+/* end xfersend.c */
diff --git a/StraySrc/Libraries/Steel/c/xproginfo b/StraySrc/Libraries/Steel/c/xproginfo
new file mode 100644 (file)
index 0000000..65c4e4c
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * xproginfo.c
+ *
+ * Fancy scrolling message in a proginfo box
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define _CORE
+#define _STDAPP
+
+#include "steel.h"
+#include "scroller.h"
+#include "xproginfo.h"
+
+#define xprogInfo__TITLE 0
+#define xprogInfo__NAME 7
+#define xprogInfo__PURPOSE 5
+#define xprogInfo__AUTHOR 3
+#define xprogInfo__VERSION 1
+#define xprogInfo__SCROLLER 9
+
+typedef struct
+{
+  dbox d;
+  scroller s;
+  BOOL hasTitle;
+}
+xprogInfo__str;
+
+static void xprogInfo__redraw(wimp_redrawstr *r,void *handle)
+{
+  xprogInfo__str *s=handle;
+  if (!s->hasTitle)
+    dbox_drawEmbeddedTitle(r,s->d);
+  scroller_redraw(s->s,r);
+}
+
+static BOOL xprogInfo__raw(dbox d,wimp_eventstr *e,void *handle)
+{
+  xprogInfo__str *s=handle;
+  BOOL handled=FALSE;
+  switch (e->e)
+  {
+    case wimp_EREDRAW:
+      wimpt_redraw(xprogInfo__redraw,s);
+      handled=TRUE;
+      break;
+    case wimp_ECLOSE:
+      scroller_destroy(s->s);
+      dbox_delete(s->d);
+      mem_free(s);
+      handled=TRUE;
+      break;
+  }
+  return (handled);
+}
+
+void xprogInfo(char *name,
+               char *purpose,
+               char *author,
+               int version,
+               char *date,
+               char *scrolltext,
+               char *initText,
+               int delay)
+{
+  xprogInfo__str *s=mem_alloc(sizeof(xprogInfo__str));
+  if (!s)
+    return;
+  s->d=dbox_create("progInfo");
+  if (!s->d)
+  {
+    mem_free(s);
+    return;
+  }
+  s->s=scroller_create(s->d,xprogInfo__SCROLLER,scrolltext,initText,delay);
+  if (!s->s)
+  {
+    dbox_delete(s->d);
+    mem_free(s);
+    return;
+  }
+  if (s->hasTitle=dbox_hasTitle(s->d),!s->hasTitle)
+    dbox_setEmbeddedTitle(s->d,xprogInfo__TITLE,TRUE);
+  dbox_setfield(s->d,xprogInfo__NAME,"%s",name);
+  dbox_setfield(s->d,xprogInfo__PURPOSE,"%s",purpose);
+  dbox_setfield(s->d,xprogInfo__AUTHOR,"%s",author);
+  dbox_setfield
+  (
+    s->d,
+    xprogInfo__VERSION,
+    "%i.%02i (%s)",
+    version/100,
+    version%100,
+    date
+  );
+
+  dbox_rawEventHandler(s->d,xprogInfo__raw,s);
+  dbox_display(s->d,dbox_MENU_OVERPTR);
+  scroller_go(s->s);
+}
diff --git a/StraySrc/Libraries/Steel/def/steel b/StraySrc/Libraries/Steel/def/steel
new file mode 100644 (file)
index 0000000..77e1365
--- /dev/null
@@ -0,0 +1,875 @@
+;
+; cdll definition file for Steel
+;
+
+name "Steel"
+  version 1.00
+  author "© %ce%yr Straylight (%zdy %mo %ce%yr)"
+
+; --- Exported symbols ---
+
+exports {                              ; Next = 651
+
+  ; --- akbd ---
+
+  akbd_checkInternalKey                        = 0
+  akbd_pollctl                         = 1
+  akbd_pollkey                         = 2
+  akbd_pollsh                          = 3
+  akbd_translate                       = 4
+
+  ; --- alarm ---
+
+  alarm_anypending                     = 5
+  alarm_callnext                       = 6
+  alarm_init                           = 7
+  alarm_next                           = 8
+  alarm_remove                         = 9
+  alarm_removeall                      = 10
+  alarm_set                            = 11
+  alarm_timedifference                 = 12
+  alarm_timenow                                = 13
+
+  ; --- baricon (obsolete) ---
+
+  baricon                              = 14
+  baricon_left                         = 15
+  baricon_newsprite                    = 16
+  baricon_newtext                      = 17
+  baricon_textandsprite                        = 18
+  baricon_textandsprite_left           = 19
+
+  ; --- bbc ---
+
+  bbc_adval                            = 20
+  bbc_circle                           = 21
+  bbc_circlefill                       = 22
+  bbc_clg                              = 23
+  bbc_cls                              = 24
+  bbc_colour                           = 25
+  bbc_cursor                           = 26
+  bbc_draw                             = 27
+  bbc_drawby                           = 28
+  bbc_fill                             = 29
+  bbc_gcol                             = 30
+  bbc_get                              = 31
+  bbc_getbeat                          = 32
+  bbc_getbeats                         = 33
+  bbc_gettempo                         = 34
+  bbc_gwindow                          = 35
+  bbc_inkey                            = 36
+  bbc_mode                             = 37
+  bbc_modevar                          = 38
+  bbc_mouse                            = 39
+  bbc_mouserect                                = 40
+  bbc_move                             = 41
+  bbc_moveby                           = 42
+  bbc_origin                           = 43
+  bbc_palette                          = 44
+  bbc_plot                             = 45
+  bbc_point                            = 46
+  bbc_pos                              = 47
+  bbc_rectangle                                = 48
+  bbc_rectanglefill                    = 49
+  bbc_setbeats                         = 50
+  bbc_settempo                         = 51
+  bbc_sound                            = 52
+  bbc_soundoff                         = 53
+  bbc_soundon                          = 54
+  bbc_stereo                           = 55
+  bbc_stringprint                      = 56
+  bbc_tab                              = 57
+  bbc_tint                             = 58
+  bbc_vdu                              = 59
+  bbc_vduq                             = 60
+  bbc_vduvar                           = 61
+  bbc_vduvars                          = 62
+  bbc_vduw                             = 63
+  bbc_voices                           = 64
+  bbc_vpos                             = 65
+
+  ; --- blinkc ---
+
+  blinkCursor                          = 66
+  blink_init                           = 67
+
+  ; --- buffer ---
+
+  buffer_find                          = 631
+
+  ; --- buttons ---
+
+  buttons_arrow                                = 68
+  buttons_arrowClick                   = 69
+  buttons_insertChar                   = 70
+  buttons_redrawColourButton           = 71
+  buttons_redrawSlider                 = 72
+  buttons_slideSlider                  = 73
+  buttons_updateColourButton           = 74
+  buttons_updateSlider                 = 75
+
+  ; --- calltrace ---
+
+  _calltrace                           = 76
+
+  ; --- caretptr ---
+
+  caretPtr__pointer                    = 77
+  caretPtr                             = 78
+  caretPtrOff                          = 79
+
+  ; --- choices ---
+
+  choices_name                         = 80
+  choices_setName                      = 81
+
+  ; --- colourtran ---
+
+  colourtran_GCOL_tocolournumber       = 82
+  colourtran_colournumbertoGCOL                = 83
+  colourtran_convert_device_colour     = 84
+  colourtran_invalidate_cache          = 85
+  colourtran_returnGCOL                        = 86
+  colourtran_return_GCOLformode                = 87
+  colourtran_return_OppGCOL            = 88
+  colourtran_return_OppGCOLformode     = 89
+  colourtran_return_Oppcolourformode   = 90
+  colourtran_return_Oppcolournumber    = 91
+  colourtran_return_colourformode      = 92
+  colourtran_return_colournumber       = 93
+  colourtran_returnfontcolours         = 94
+  colourtran_select_GCOLtable          = 95
+  colourtran_select_table              = 96
+  colourtran_setGCOL                   = 97
+  colourtran_setOppGCOL                        = 98
+  colourtran_setfontcolours            = 99
+
+  ; --- coords ---
+
+  coords_box_toscreen                  = 100
+  coords_box_toworkarea                        = 101
+  coords_boxesoverlap                  = 102
+  coords_intersects                    = 103
+  coords_offsetbox                     = 104
+  coords_point_toscreen                        = 105
+  coords_point_toworkarea              = 106
+  coords_withinbox                     = 107
+  coords_x_toscreen                    = 108
+  coords_x_toworkarea                  = 109
+  coords_y_toscreen                    = 110
+  coords_y_toworkarea                  = 111
+
+  ; --- dbox ---
+
+  dbox__rms                            = 112
+  dbox__eventProcess                   = 113
+  dbox_clickicon                       = 114
+  dbox_create                          = 115
+  dbox_delete                          = 116
+  dbox_deleteNoUpdate                  = 117
+  dbox_display                         = 118
+  dbox_drawEmbeddedTitle               = 119
+  dbox_eventHandler                    = 120
+  dbox_fillin                          = 121
+  dbox_getNumeric                      = 122
+  dbox_getfield                                = 123
+  dbox_hasTitle                                = 124
+  dbox_helpField                       = 125
+  dbox_hide                            = 126
+  dbox_openDisplaced                   = 127
+  dbox_rawEventHandler                 = 128
+  dbox_scanfield                       = 129
+  dbox_selecticon                      = 130
+  dbox_setEmbeddedTitle                        = 131
+  dbox_setNumeric                      = 132
+  dbox_setfield                                = 133
+  dbox_shadeicon                       = 134
+  dbox_syshandle                       = 135
+  dbox_unclick                         = 136
+  dbox_unclickAll                      = 137
+  dbox_updatePosition                  = 138
+  dbox_wasAdjustClick                  = 139
+
+  ; --- event ---
+
+  event__process                       = 140
+  event_anywindows                     = 141
+  event_attachMidbHandler              = 142
+  event_attachedMenu                   = 143
+  event_attachmenu                     = 144
+  event_attachmenumaker                        = 145
+  event_clear_current_menu             = 146
+  event_getmask                                = 147
+  event_is_menu_being_recreated                = 148
+  event_makeIconbarMenu                        = 149
+  event_makeMenu                       = 150
+  event_openIconbarMenu                        = 151
+  event_openMenu                       = 152
+  event_process                                = 153
+  event_returnMenuHelp                 = 154
+  event_setmask                                = 155
+  event_whyMenuEvent                   = 156
+
+  ; --- exception ---
+
+  exception__registerHandler           = 157
+  exception_generate                   = 158
+
+  ; --- fileicon ---
+
+  fileicon                             = 159
+  fileicon_spriteName                  = 160
+
+  ; --- flex ---
+
+  flex_alloc                           = 161
+  flex_budge                           = 162
+  flex_compact                         = 163
+  flex_dont_budge                      = 164
+  flex_die                             = 632
+  flex_dinit                           = 633
+  flex_extend                          = 165
+  flex_free                            = 166
+  flex_init                            = 167
+  flex_midextend                       = 168
+  flex_reduce                          = 169
+  flex_size                            = 170
+
+  ; --- font ---
+
+  font_cacheaddress                    = 171
+  font_caret                           = 172
+  font_charbbox                                = 173
+  font_converttoos                     = 174
+  font_converttopoints                 = 175
+  font_current                         = 176
+  font_find                            = 177
+  font_findcaret                       = 178
+  font_findcaretj                      = 179
+  font_future                          = 180
+  font_list                            = 181
+  font_lose                            = 182
+  font_output_size                     = 183
+  font_output_to_buffer                        = 184
+  font_output_to_null                  = 185
+  font_output_to_screen                        = 186
+  font_paint                           = 187
+  font_readdef                         = 188
+  font_readinfo                                = 189
+  font_readscalefactor                 = 190
+  font_readthresholds                  = 191
+  font_setcolour                       = 192
+  font_setfont                         = 193
+  font_setpalette                      = 194
+  font_setscalefactor                  = 195
+  font_setthresholds                   = 196
+  font_stringbbox                      = 197
+  font_strwidth                                = 198
+
+  ; --- fontmenu ---
+
+  fontMenu                             = 199
+  fontMenu_createFontMenu              = 200
+  fontMenu_findFont                    = 201
+  fontMenu_fontname                    = 202
+  fontMenu_submenu                     = 203
+  fontMenu_tick                                = 204
+  fontMenu_tickGivenName               = 205
+
+  ; --- heap ---
+
+  heap_alloc                           = 206
+  heap_free                            = 207
+  heap_info                            = 208
+  heap_init                            = 209
+  heap_realloc                         = 210
+
+  ; --- help ---
+
+  help_addLine                         = 211
+  help_endHelp                         = 212
+  help_readFromIcon                    = 213
+  help_readFromMenu                    = 214
+  help_startHelp                       = 215
+  help_wasHelp                         = 216
+
+  ; --- ibicon ---
+
+  ibicon_attachMenu                    = 217
+  ibicon_attachMenuMaker               = 218
+  ibicon_changeSprite                  = 219
+  ibicon_changeText                    = 220
+  ibicon_create                                = 221
+  ibicon_eventHandler                  = 222
+  ibicon_find                          = 223
+  ibicon_rawEventHandler               = 224
+  ibicon_removeIcon                    = 225
+  ibicon_setPriority                   = 226
+  ibicon_syshandle                     = 227
+
+  ; --- interface ---
+
+  interface_closeDown                  = 228
+  interface_initialise                 = 229
+  interface_poll                       = 230
+  interface_removeWorkareaPointer      = 231
+  interface_render3dWindow             = 232
+  interface_setWorkareaPointer         = 233
+  interface_slabButton                 = 234
+  interface_spritearea                 = 235
+
+  ; --- keystring ---
+
+  keyString                            = 236
+
+  ; --- listbox ---
+
+  list_addItem                         = 237
+  list_addToSelection                  = 238
+  list_attachData                      = 239
+  list_create                          = 240
+  list_delete                          = 241
+  list_display                         = 242
+  list_doForItems                      = 243
+  list_doForSelected                   = 244
+  list_eventHandler                    = 245
+  list_findItem                                = 246
+  list_getData                         = 247
+  list_helpItem                                = 248
+  list_hide                            = 249
+  list_indexToItem                     = 250
+  list_isPane                          = 251
+  list_itemData                                = 252
+  list_itemToIndex                     = 253
+  list_items                           = 254
+  list_link                            = 255
+  list_multipleSelection               = 256
+  list_numSelected                     = 257
+  list_openDisplaced                   = 258
+  list_rawEventHandler                 = 259
+  list_redrawHandler                   = 260
+  list_removeItem                      = 261
+  list_selectAll                       = 262
+  list_selectItem                      = 263
+  list_selected                                = 264
+  list_setItemHeight                   = 265
+  list_syshandle                       = 266
+  list_unlink                          = 267
+  list_unlinkNoUpdate                  = 268
+  list_updatePosition                  = 269
+  list_widthAdd                                = 270
+
+  ; --- mem ---
+
+  mem_RMAalloc                         = 271
+  mem_RMAfree                          = 272
+  mem_alloc                            = 273
+  mem_allowFlexBudge                   = 274
+  mem_flexInit                         = 275
+  mem_flexdInit                                = 634
+  mem_free                             = 276
+  mem_heapInit                         = 277
+  mem_reAlloc                          = 278
+  mem_sizeOfBlock                      = 279
+  mem_useHeap                          = 280
+  mem_useMalloc                                = 281
+  mem_useRMA                           = 282
+  mem_useUser                          = 283
+
+  ; --- menu ---
+
+  menu_attach                          = 284
+  menu_attachMaker                     = 285
+  menu_dispose                         = 286
+  menu_extend                          = 287
+  menu_make                            = 288
+  menu_make_sprite                     = 289
+  menu_make_writeable                  = 290
+  menu_minWidth                                = 291
+  menu_new                             = 292
+  menu_open                            = 293
+  menu_redirectItem                    = 294
+  menu_restoreHandler                  = 295
+  menu_saveHandler                     = 296
+  menu_setflags                                = 297
+  menu_settitle                                = 298
+  menu_submenu                         = 299
+  menu_syshandle                       = 300
+
+  ; --- msgs ---
+
+  msgs_init                            = 301
+  msgs_delete                          = 302
+  msgs_lookup                          = 303
+  msgs_readfile                                = 304
+
+  ; --- nopoll ---
+
+  nopoll_doDbox                                = 305
+  nopoll_showDbox                      = 306
+
+  ; --- os ---
+
+  os_args                              = 307
+  os_byte                              = 308
+  os_cli                               = 309
+  os_file                              = 310
+  os_find                              = 311
+  os_gbpb                              = 312
+  os_read_var_val                      = 313
+  os_swi                               = 314
+  os_swi0                              = 315
+  os_swi1                              = 316
+  os_swi1r                             = 317
+  os_swi2                              = 318
+  os_swi2r                             = 319
+  os_swi3                              = 320
+  os_swi3r                             = 321
+  os_swi4                              = 322
+  os_swi4r                             = 323
+  os_swi5                              = 324
+  os_swi5r                             = 325
+  os_swi6                              = 326
+  os_swi6r                             = 327
+  os_swiv                              = 328
+  os_swivr                             = 329
+  os_swix                              = 330
+  os_word                              = 331
+
+  ; --- pointer ---
+
+  pointer_reset_shape                  = 332
+  pointer_set_shape                    = 333
+
+  ; --- print ---
+
+  print_abortjob                       = 334
+  print_canceljob                      = 335
+  print_checkfeatures                  = 336
+  print_currentjob                     = 337
+  print_drawpage                       = 338
+  print_endjob                         = 339
+  print_getrectangle                   = 340
+  print_giverectangle                  = 341
+  print_info                           = 342
+  print_pagesize                       = 343
+  print_reset                          = 344
+  print_screendump                     = 345
+  print_selectillustration             = 346
+  print_selectjob                      = 347
+  print_setinfo                                = 348
+  print_setpagesize                    = 349
+
+  ; --- pane ---
+
+  pane_addListbox                      = 350
+  pane_addPane                         = 351
+  pane_close                           = 352
+  pane_create                          = 353
+  pane_delete                          = 354
+  pane_front                           = 355
+  pane_moved                           = 356
+  pane_removePane                      = 357
+  pane_updatePanes                     = 358
+
+  ; --- prefs ---
+
+  prefs_preferences                    = 359
+  prefs_read                           = 360
+  prefs_readBoolean                    = 361
+  prefs_readNumeric                    = 362
+  prefs_readString                     = 363
+  prefs_write                          = 364
+  prefs_writeBoolean                   = 365
+  prefs_writeNumeric                   = 366
+  prefs_writeString                    = 367
+
+  ; --- res ---
+
+  res_fileExists                       = 368
+  res_findname                         = 369
+  res_init                             = 370
+  res_name                             = 371
+  res_openfile                         = 372
+  res_setPrefix                                = 373
+
+  ; --- resspr ---
+
+  resspr_area                          = 374
+  resspr_init                          = 375
+
+  ; --- saveas ---
+
+  saveas                               = 376
+  saveas_file_is_safe                  = 377
+
+  ; --- sculptrix ---
+
+  sculptrix_boundingBox                        = 378
+  sculptrix_doSlab                     = 379
+  sculptrix_plotIcon                   = 380
+  sculptrix_redrawWindow               = 381
+  sculptrix_setSpriteArea              = 382
+  sculptrix_slabColour                 = 383
+  sculptrix_slabIcon                   = 384
+  sculptrix_unslabIcon                 = 385
+  sculptrix_updateIcon                 = 386
+
+  ; --- sprite ---
+
+  sprite_area_initialise               = 387
+  sprite_area_load                     = 388
+  sprite_area_merge                    = 389
+  sprite_area_readinfo                 = 390
+  sprite_area_reinit                   = 391
+  sprite_area_save                     = 392
+  sprite_change_size                   = 393
+  sprite_copy                          = 394
+  sprite_create                                = 395
+  sprite_create_mask                   = 396
+  sprite_create_rp                     = 397
+  sprite_delete                                = 398
+  sprite_delete_column                 = 399
+  sprite_delete_row                    = 400
+  sprite_flip_x                                = 401
+  sprite_flip_y                                = 402
+  sprite_get                           = 403
+  sprite_get_given                     = 404
+  sprite_get_given_rp                  = 405
+  sprite_get_rp                                = 406
+  sprite_getname                       = 407
+  sprite_insert_column                 = 408
+  sprite_insert_row                    = 409
+  sprite_outputtomask                  = 410
+  sprite_outputtoscreen                        = 411
+  sprite_outputtosprite                        = 412
+  sprite_put                           = 413
+  sprite_put_char_scaled               = 414
+  sprite_put_given                     = 415
+  sprite_put_greyscaled                        = 416
+  sprite_put_mask                      = 417
+  sprite_put_mask_given                        = 418
+  sprite_put_mask_pgm                  = 419
+  sprite_put_mask_scaled               = 420
+  sprite_put_mask_trans                        = 421
+  sprite_put_pgm                       = 422
+  sprite_put_scaled                    = 423
+  sprite_put_trans                     = 424
+  sprite_readinfo                      = 425
+  sprite_readmask                      = 426
+  sprite_readpixel                     = 427
+  sprite_readsize                      = 428
+  sprite_remove_mask                   = 429
+  sprite_removewastage                 = 430
+  sprite_rename                                = 431
+  sprite_restorestate                  = 432
+  sprite_screenload                    = 433
+  sprite_screensave                    = 434
+  sprite_select                                = 435
+  sprite_select_rp                     = 436
+  sprite_sizeof_screencontext          = 437
+  sprite_sizeof_spritecontext          = 438
+  sprite_writemask                     = 439
+  sprite_writepixel                    = 440
+
+  ; --- stddbox ---
+
+  note                                 = 441
+  mbox                                 = 442
+  progInfo                             = 443
+  saveWarn                             = 444
+  warning                              = 445
+  writable                             = 446
+
+  ; --- tcol ---
+
+  tcol                                 = 447
+
+  ; --- tearoff ---
+
+  tearoff_attachMenu                   = 635
+  tearoff_attachSubMenu                        = 636
+  tearoff_changeItemText               = 637
+  tearoff_changeTitle                  = 638
+  tearoff_closeMenu                    = 639
+  tearoff_create                       = 640
+  tearoff_destroy                      = 641
+  tearoff_displayAt                    = 642
+  tearoff_displayMenu                  = 643
+  tearoff_extendMenu                   = 644
+  tearoff_height                       = 645
+  tearoff_howSelected                  = 646
+  tearoff_init                         = 647
+  tearoff_isShaded                     = 648
+  tearoff_selectItem                   = 649
+  tearoff_shadeItem                    = 650
+
+  ; --- template ---
+
+  template_copy                                = 448
+  template_find                                = 449
+  template_init                                = 450
+  template_loaded                      = 451
+  template_readfile                    = 452
+  template_syshandle                   = 453
+  template_use_fancyfonts              = 454
+
+  ; --- utils ---
+
+  utils_caselessCmp                    = 455
+  utils_complain                       = 456
+  utils_ctermToNterm                   = 457
+  utils_cvtSize                                = 458
+  utils_leafname                       = 459
+
+  ; --- viewer ---
+
+  viewer_addIcon                       = 460
+  viewer_clickSelect                   = 461
+  viewer_create                                = 462
+  viewer_delete                                = 463
+  viewer_display                       = 464
+  viewer_doForIcons                    = 465
+  viewer_dragSelected                  = 466
+  viewer_drawFileIcons                 = 467
+  viewer_eventHandler                  = 468
+  viewer_exportSelected                        = 469
+  viewer_findIcon                      = 470
+  viewer_firstSelected                 = 471
+  viewer_helpIcon                      = 472
+  viewer_hide                          = 473
+  viewer_iconFromCoords                        = 474
+  viewer_iconHandle                    = 475
+  viewer_iconToCoords                  = 476
+  viewer_iconToViewer                  = 477
+  viewer_icons                         = 478
+  viewer_isSelected                    = 479
+  viewer_menuItem                      = 480
+  viewer_rawEventHandler               = 481
+  viewer_readFiletype                  = 482
+  viewer_redrawHandler                 = 483
+  viewer_removeIcon                    = 484
+  viewer_selectAll                     = 485
+  viewer_selectIcon                    = 486
+  viewer_selected                      = 487
+  viewer_setCompare                    = 488
+  viewer_setFiletype                   = 489
+  viewer_setIconSize                   = 490
+  viewer_settitle                      = 491
+  viewer_setupMenu                     = 492
+  viewer_syshandle                     = 493
+  viewer_textOfIcon                    = 494
+
+  ; --- visdelay ---
+
+  visdelay_begin                       = 495
+  visdelay_end                         = 496
+  visdelay_percent                     = 497
+  visdelay_resume                      = 498
+  visdelay_suspend                     = 499
+
+  ; --- vsscanf ---
+
+  vsscanf                              = 500
+
+  ; --- werr ---
+
+  werr                                 = 501
+  werr_bleepy                          = 502
+  werr_error                           = 503
+  werr_init                            = 504
+
+  ; --- wimp ---
+
+  wimp_addmessages                     = 505
+  wimp_baseofsprites                   = 506
+  wimp_blockcopy                       = 507
+  wimp_close_template                  = 508
+  wimp_close_wind                      = 509
+  wimp_closedown                       = 510
+  wimp_commandwindow                   = 511
+  wimp_corrupt_fp_state_on_poll                = 512
+  wimp_create_icon                     = 513
+  wimp_create_menu                     = 514
+  wimp_create_submenu                  = 515
+  wimp_create_wind                     = 516
+  wimp_decode_menu                     = 517
+  wimp_delete_icon                     = 518
+  wimp_delete_wind                     = 519
+  wimp_drag_box                                = 520
+  wimp_force_redraw                    = 521
+  wimp_get_caret_pos                   = 522
+  wimp_get_icon_info                   = 523
+  wimp_get_point_info                  = 524
+  wimp_get_rectangle                   = 525
+  wimp_get_wind_info                   = 526
+  wimp_get_wind_state                  = 527
+  wimp_getmenustate                    = 528
+  wimp_getwindowoutline                        = 529
+  wimp_initialise                      = 530
+  wimp_load_template                   = 531
+  wimp_open_template                   = 532
+  wimp_open_wind                       = 533
+  wimp_ploticon                                = 534
+  wimp_poll                            = 535
+  wimp_pollidle                                = 536
+  wimp_processkey                      = 537
+  wimp_readpalette                     = 538
+  wimp_readpixtrans                    = 539
+  wimp_readsysinfo                     = 540
+  wimp_redraw_wind                     = 541
+  wimp_removemessages                  = 542
+  wimp_reporterror                     = 543
+  wimp_save_fp_state_on_poll           = 544
+  wimp_sendmessage                     = 545
+  wimp_sendwmessage                    = 546
+  wimp_set_caret_pos                   = 547
+  wimp_set_extent                      = 548
+  wimp_set_icon_state                  = 549
+  wimp_set_point_shape                 = 550
+  wimp_setcolour                       = 551
+  wimp_setfontcolours                  = 552
+  wimp_setmode                         = 553
+  wimp_setpalette                      = 554
+  wimp_slotsize                                = 555
+  wimp_spriteop                                = 556
+  wimp_spriteop_full                   = 557
+  wimp_starttask                       = 558
+  wimp_taskclose                       = 559
+  wimp_taskinit                                = 560
+  wimp_textcolour                      = 561
+  wimp_transferblock                   = 562
+  wimp_update_wind                     = 563
+  wimp_which_icon                      = 564
+
+  ; --- wimpt ---
+
+  wimpt_bpp                            = 565
+  wimpt_checkmode                      = 566
+  wimpt_complain                       = 567
+  wimpt_dx                             = 568
+  wimpt_dy                             = 569
+  wimpt_fake_event                     = 570
+  wimpt_forceredraw                    = 571
+  wimpt_getVersion                     = 572
+  wimpt_init                           = 573
+  wimpt_justChangedMode                        = 574
+  wimpt_last_event                     = 575
+  wimpt_last_event_was_a_key           = 576
+  wimpt_mode                           = 577
+  wimpt_noerr                          = 578
+  wimpt_options                                = 579
+  wimpt_poll                           = 580
+  wimpt_pollingTime                    = 581
+  wimpt_programname                    = 582
+  wimpt_redraw                         = 583
+  wimpt_reporterror                    = 584
+  wimpt_scwidth                                = 585
+  wimpt_scheight                       = 586
+  wimpt_setMessages                    = 587
+  wimpt_setOptions                     = 588
+  wimpt_stringWidth                    = 589
+  wimpt_task                           = 590
+  wimpt_wimpversion                    = 591
+
+  ; --- win ---
+
+  win_activedec                                = 592
+  win_activeinc                                = 593
+  win_activeno                         = 594
+  win_addIdleClaimer                   = 595
+  win_add_unknown_event_processor      = 596
+  win_adjustBox                                = 597
+  win_anyWindows                       = 598
+  win_any_idles                                = 599
+  win_broadcast                                = 600
+  win_claim_idle_events                        = 601
+  win_claim_unknown_events             = 602
+  win_getmenuh                         = 603
+  win_give_away_caret                  = 604
+  win_idleTime                         = 605
+  win_idle_event_claimer               = 606
+  win_processevent                     = 607
+  win_read_eventhandler                        = 608
+  win_register_event_handler           = 609
+  win_removeIdleClaimer                        = 610
+  win_remove_unknown_event_processor   = 611
+  win_setmenuh                         = 612
+  win_settitle                         = 613
+  win_unknown_event_claimer            = 614
+
+  ; --- xferrecv_checkimport ---
+
+  xferrecv_checkimport                 = 615
+  xferrecv_checkinsert                 = 616
+  xferrecv_checkprint                  = 617
+  xferrecv_doimport                    = 618
+  xferrecv_file_is_safe                        = 619
+  xferrecv_importByScrap               = 620
+  xferrecv_insertfileok                        = 621
+  xferrecv_nameToImport                        = 622
+  xferrecv_printfileok                 = 623
+  xferrecv_returnImportedBlock         = 624
+
+  ; --- xfersend ---
+
+  xfersend                             = 625
+  xfersend_close_on_xfer               = 626
+  xfersend_file_is_safe                        = 627
+  xfersend_sendBlock                   = 628
+  xfersend_sendbuf                     = 629
+  xfersend_set_fileissafe              = 630
+}
+
+extentry {
+
+  ; --- blinkc ---
+
+  blink__doBlink
+  blink__exit
+
+  ; --- dbox ---
+
+  dbox__eventhandler
+  dbox__menuDboxWindow
+
+  ; --- ibicon ---
+
+  ibicon__events
+  ibicon__menuhandler
+  ibicon__menuhelphandler
+  ibicon__menumaker
+
+  ; --- listbox ---
+
+  list__events
+
+  ; --- menu ---
+
+  menu__menumaker
+  menu__menuproc
+
+  ; --- template ---
+
+  template__exit
+
+  ; --- viewer ---
+
+  viewer__events
+
+  ; --- visdelay ---
+
+  visdelay__exitHandler
+
+  ; --- wimpt ---
+
+  wimpt__escapeHandler
+  wimpt__exit
+  wimpt__signals
+}
+
+; --- Object files ---
+
+objects {
+  do.steel
+}
diff --git a/StraySrc/Libraries/Steel/h/akbd b/StraySrc/Libraries/Steel/h/akbd
new file mode 100644 (file)
index 0000000..7142136
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * akbd.h
+ *
+ * Really good keyboard handling
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __akbd_h
+#define __akbd_h
+
+/*----- Make sure we have BOOL defined ------------------------------------*/
+
+#ifndef BOOL
+  #define BOOL int
+  #define TRUE 1
+  #define FALSE 0
+#endif
+
+/*----- Old-style macros for keypresses -----------------------------------*/
+
+#define akbd_Fn (256 + 128)
+#define akbd_Sh (16)
+#define akbd_Ctl (32)
+#define akbd_TabK (akbd_Fn + 10)
+#define akbd_CopyK (akbd_Fn + 11)
+#define akbd_LeftK (akbd_Fn + 12)
+#define akbd_RightK (akbd_Fn + 13)
+#define akbd_DownK (akbd_Fn + 14)
+#define akbd_UpK (akbd_Fn + 15)
+#define akbd_Fn10 (0x1CA)
+#define akbd_Fn11 (0x1CB)
+#define akbd_Fn12 (0x1CC)
+#define akbd_InsertK (0x1CD)
+#define akbd_PrintK (akbd_Fn+0)
+#define akbd_PageUpK (akbd_Sh+akbd_UpK)
+#define akbd_PageDownK (akbd_Sh+akbd_DownK)
+
+/*----- Constant names for the STEEL extended keyset ----------------------*
+ *
+ * Due to buggy compilers, we can't put these into an enumeration, so 
+ * we put the load onto the preprocessor instead...
+ */
+
+#define key_cA         0x001
+#define key_cB         0x002
+#define key_cC         0x003
+#define key_cD         0x004
+#define key_cE         0x005
+#define key_cF         0x006
+#define key_cG         0x007
+#define key_cH         0x008
+#define key_cI         0x009
+#define key_cJ         0x00A
+#define key_cK         0x00B
+#define key_cL         0x00C
+#define key_cM         0x00D
+#define key_cN         0x00E
+#define key_cO         0x00F
+#define key_cP         0x010
+#define key_cQ         0x011
+#define key_cR         0x012
+#define key_cS         0x013
+#define key_cT         0x014
+#define key_cU         0x015
+#define key_cV         0x016
+#define key_cW         0x017
+#define key_cX         0x018
+#define key_cY         0x019
+#define key_cZ         0x01A
+                            
+#define key_scA                0x101
+#define key_scB                0x102
+#define key_scC                0x103
+#define key_scD                0x104
+#define key_scE                0x105
+#define key_scF                0x106
+#define key_scG                0x107
+#define key_scH                0x108
+#define key_scI                0x109
+#define key_scJ                0x10A
+#define key_scK                0x10B
+#define key_scL                0x10C
+#define key_scM                0x10D
+#define key_scN                0x10E
+#define key_scO                0x10F
+#define key_scP                0x110
+#define key_scQ                0x111
+#define key_scR                0x112
+#define key_scS                0x113
+#define key_scT                0x114
+#define key_scU                0x115
+#define key_scV                0x116
+#define key_scW                0x117
+#define key_scX                0x118
+#define key_scY                0x119
+#define key_scZ                0x11A
+                            
+#define key_Esc                0x01B
+#define key_sEsc       0x11B
+#define key_cEsc       0x13B
+#define key_scEsc      0x15B
+
+#define key_Backspace  0x01C
+#define key_sBackspace 0x11C
+#define key_cBackspace 0x13C
+#define key_scBackspace        0x15C
+
+#define key_Return     0x01D
+#define key_sReturn    0x11D
+#define key_cReturn    0x13D
+#define key_scReturn   0x15D
+
+#define key_Insert     0x1CD
+#define key_sInsert    0x1DD
+#define key_cInsert    0x1ED
+#define key_scInsert   0x1FD
+
+#define key_Home       0x01E
+#define key_sHome      0x11E
+#define key_cHome      0x13E
+#define key_scHome     0x15E
+
+#define key_Delete     0x07F
+#define key_sDelete    0x17F
+#define key_cDelete    0x01F
+#define key_scDelete   0x11F
+
+#define key_Copy       0x18B
+#define key_sCopy      0x19B
+#define key_cCopy      0x1AB
+#define key_scCopy     0x1BB
+
+#define key_Tab                0x18A
+#define key_sTab       0x19A
+#define key_cTab       0x1AA
+#define key_scTab      0x1BA
+
+#define key_Space      0x020
+#define key_sSpace     0x120
+#define key_cSpace     0x000
+#define key_scSpace    0x100
+
+#define key_c0         0x130
+#define key_c1         0x131
+#define key_c2         0x132
+#define key_c3         0x133
+#define key_c4         0x134
+#define key_c5         0x135
+#define key_c6         0x136
+#define key_c7         0x137
+#define key_c8         0x138
+#define key_c9         0x139
+
+#define key_sc0                0x150
+#define key_sc1                0x151
+#define key_sc2                0x152
+#define key_sc3                0x153
+#define key_sc4                0x154
+#define key_sc5                0x155
+#define key_sc6                0x156
+#define key_sc7                0x157
+#define key_sc8                0x158
+#define key_sc9                0x159
+
+#define key_k0         0x1C0
+#define key_k1         0x1C1
+#define key_k2         0x1C2
+#define key_k3         0x1C3
+#define key_k4         0x1C4
+#define key_k5         0x1C5
+#define key_k6         0x1C6
+#define key_k7         0x1C7
+#define key_k8         0x1C8
+#define key_k9         0x1C9
+
+#define key_sk0                0x1D0
+#define key_sk1                0x1D1
+#define key_sk2                0x1D2
+#define key_sk3                0x1D3
+#define key_sk4                0x1D4
+#define key_sk5                0x1D5
+#define key_sk6                0x1D6
+#define key_sk7                0x1D7
+#define key_sk8                0x1D8
+#define key_sk9                0x1D9
+
+#define key_ck0                0x1E0
+#define key_ck1                0x1E1
+#define key_ck2                0x1E2
+#define key_ck3                0x1E3
+#define key_ck4                0x1E4
+#define key_ck5                0x1E5
+#define key_ck6                0x1E6
+#define key_ck7                0x1E7
+#define key_ck8                0x1E8
+#define key_ck9                0x1E9
+
+#define key_sck0       0x1F0
+#define key_sck1       0x1F1
+#define key_sck2       0x1F2
+#define key_sck3       0x1F3
+#define key_sck4       0x1F4
+#define key_sck5       0x1F5
+#define key_sck6       0x1F6
+#define key_sck7       0x1F7
+#define key_sck8       0x1F8
+#define key_sck9       0x1F9
+
+#define key_cLSquare   0x12B
+#define key_scLSquare  0x14B
+
+#define key_cRSquare   0x12D
+#define key_scRSquare  0x14D
+
+#define key_cBackslash 0x12C
+#define key_scBackslash        0x14C
+
+#define key_cMinus     0x12F
+#define key_scMinus    0x14F
+
+#define key_kSlash     0x161
+#define key_kStar      0x162
+#define key_kHash      0x163
+#define key_kMinus     0x164
+#define key_kPlus      0x165
+#define key_kEnter     0x166
+#define key_kDot       0x167
+
+#define key_skSlash    0x171
+#define key_skStar     0x172
+#define key_skHash     0x173
+#define key_skMinus    0x174
+#define key_skPlus     0x175
+#define key_skEnter    0x176
+#define key_skDot      0x177
+                            
+#define key_ckSlash    0x121
+#define key_ckStar     0x122
+#define key_ckHash     0x123
+#define key_ckMinus    0x124
+#define key_ckPlus     0x125
+#define key_ckEnter    0x126
+#define key_ckDot      0x127
+
+#define key_sckSlash   0x141
+#define key_sckStar    0x142
+#define key_sckHash    0x143
+#define key_sckMinus   0x144
+#define key_sckPlus    0x145
+#define key_sckEnter   0x146
+#define key_sckDot     0x147
+
+#define key_Print      0x180
+#define key_F1         0x181
+#define key_F2         0x182
+#define key_F3         0x183
+#define key_F4         0x184
+#define key_F5         0x185
+#define key_F6         0x186
+#define key_F7         0x187
+#define key_F8         0x188
+#define key_F9         0x189
+#define key_F10                0x1CA
+#define key_F11                0x1CB
+#define key_F12                0x1CC
+
+#define key_sPrint     0x190
+#define key_sF1                0x191
+#define key_sF2                0x192
+#define key_sF3                0x193
+#define key_sF4                0x194
+#define key_sF5                0x195
+#define key_sF6                0x196
+#define key_sF7                0x197
+#define key_sF8                0x198
+#define key_sF9                0x199
+#define key_sF10       0x1DA
+#define key_sF11       0x1DB
+#define key_sF12       0x1DC
+
+#define key_cPrint     0x1A0
+#define key_cF1                0x1A1
+#define key_cF2                0x1A2
+#define key_cF3                0x1A3
+#define key_cF4                0x1A4
+#define key_cF5                0x1A5
+#define key_cF6                0x1A6
+#define key_cF7                0x1A7
+#define key_cF8                0x1A8
+#define key_cF9                0x1A9
+#define key_cF10       0x1EA
+#define key_cF11       0x1EB
+#define key_cF12       0x1EC
+
+#define key_scPrint    0x1B0
+#define key_scF1       0x1B1
+#define key_scF2       0x1B2
+#define key_scF3       0x1B3
+#define key_scF4       0x1B4
+#define key_scF5       0x1B5
+#define key_scF6       0x1B6
+#define key_scF7       0x1B7
+#define key_scF8       0x1B8
+#define key_scF9       0x1B9
+#define key_scF10      0x1FA
+#define key_scF11      0x1FB
+#define key_scF12      0x1FC
+
+#define key_Left       0x18C
+#define key_Right      0x18D
+#define key_Down       0x18E
+#define key_Up         0x18F
+#define key_PageDown   0x19E
+#define key_PageUp     0x19F
+
+#define key_sLeft      0x19C
+#define key_sRight     0x19D
+#define key_sDown      0x19E
+#define key_sUp                0x19F
+#define key_sPageDown  0x18E
+#define key_sPageUp    0x18F
+
+#define key_cLeft      0x1AC
+#define key_cRight     0x1AD
+#define key_cDown      0x1AE
+#define key_cUp                0x1AF
+#define key_cPageDown  0x1BE
+#define key_cPageUp    0x1BF
+
+#define key_scLeft     0x1BC
+#define key_scRight    0x1BD
+#define key_scDown     0x1BE
+#define key_scUp       0x1BF
+#define key_scPageDown 0x1AE
+#define key_scPageUp   0x1AF
+
+/*----- Functions ---------------------------------------------------------*/
+
+/*
+ * BOOL akbd_checkInternalKey(int ikey)
+ *
+ * Use
+ *  Checks whether a given key is being pressed at the moment.
+ *
+ * Parameters
+ *  int ikey == the internal key number of the key to check, as shown on page
+ *    1-849 of the RISC OS 3 Programmer's Reference Manual.
+ */
+
+BOOL akbd_checkInternalKey(int ikey);
+
+/*
+ * int akbd_translate(int chcode)
+ *
+ * Use
+ *  Translates the given WIMP-type key number, as returned in a Key_Pressed
+ *  (wimp_EKEY) event into a STEEL extended key number, which should
+ *  distinguish almost every keypress available.
+ *
+ * Parameters
+ *  int chcode == a WIMP-type keypress number
+ *
+ * Returns
+ *  An extended keycode
+ */
+
+int akbd_translate(int chcode);
+
+/*
+ * BOOL akbd_pollsh(void)
+ *
+ * Use
+ *  Returns whether the Shift key is pressed
+ */
+
+BOOL akbd_pollsh(void);
+
+/*
+ * BOOL akbd_pollctl(void)
+ *
+ * Use
+ *  Returns whether the Control key is pressed
+ */
+
+BOOL akbd_pollctl(void);
+
+/*
+ * BOOL akbd_pollkey(int *code)
+ *
+ * Use
+ *  Reports whether the user has typed ahead, and if so what the keypress
+ *  was.  Note that the keypresses returned are WIMP-type, not STEEL extended
+ *  ones so you will have to use akbd_translate if you need the extended
+ *  type.
+ *
+ *  This call could be used to allow buffering of keypresses: on a
+ *  Key_Pressed event you would call this routine until it returns FALSE
+ *  and store the codes it returns in a buffer along with the code from the
+ *  event.
+ */
+
+BOOL akbd_pollkey(int *code);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/alarm b/StraySrc/Libraries/Steel/h/alarm
new file mode 100644 (file)
index 0000000..1c35705
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * alarm.h
+ *
+ * Calling routines at set times
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __alarm_h
+#define __alarm_h
+
+#ifndef BOOL
+  #define BOOL int
+  #define TRUE 1
+  #define FALSE 0
+#endif
+
+typedef void (*alarm_handler)(int at,void *handle);
+
+/*
+ * void alarm_init(void)
+ *
+ * Use
+ *  None at all
+ */
+
+void alarm_init(void);
+
+/*
+ * int alarm_timenow(void)
+ *
+ * Use
+ *  Reports the time right now
+ */
+
+int alarm_timenow(void);
+
+/*
+ * int alarm_timedifference(int t1,int t2)
+ *
+ * Use
+ *  Tells you the difference between two times.  t2 is considered to be later
+ *  than t1.
+ */
+
+int alarm_timedifference(int t1,int t2);
+
+/*
+ * void alarm_set(int at,alarm_handler proc,void *handle)
+ *
+ * Use
+ *  Sets up `proc' to be called at time `at', being passed `handle'.
+ */
+
+void alarm_set(int at,alarm_handler proc,void *handle);
+
+/*
+ * void alarm_remove(int at,void *handle)
+ *
+ * Use
+ *  Removes an alarm identified by a time and a handle
+ */
+
+void alarm_remove(int at,void *handle);
+
+/*
+ * void alarm_removeall(void *handle)
+ *
+ * Use
+ *  Removes all alarms for the given handle
+ */
+
+void alarm_removeall(void *handle);
+
+/*
+ * BOOL alarm_anypending(void *handle)
+ *
+ * Use
+ *  Returns TRUE if there are alarms for the given handle
+ */
+
+BOOL alarm_anypending(void *handle);
+
+/*
+ * BOOL alarm_next(int *when)
+ *
+ * Use
+ *  Informs the caller (a) if there are any alarms waiting, and (b) when
+ *  the next one is.
+ *
+ * Parameters
+ *  int *when == where to put the next time for an alarm (unchanged if no
+ *    alarm is set)
+ *
+ * Returns
+ *  TRUE if there are any alarms left
+ */
+
+BOOL alarm_next(int *when);
+
+/*
+ * void alarm_callnext(void)
+ *
+ * Use
+ *  Calls the next alarm and removes it from the list
+ */
+
+void alarm_callnext(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/baricon b/StraySrc/Libraries/Steel/h/baricon
new file mode 100644 (file)
index 0000000..ea90034
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * baricon.h
+ *
+ * Icon bar handling stuff
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __baricon_h
+#define __baricon_h
+
+#ifndef __ibicon_h
+  #include "ibicon.h"
+#endif
+
+#ifndef __wimp_h
+  #include "wimp.h"
+#endif
+
+/*-------------------------------------------------------
+  This is a collection of macros that interface with 
+  ibicon.
+-------------------------------------------------------*/
+
+/*
+ * Some types
+ */
+
+typedef void (*baricon_clickproc)(wimp_i);
+
+wimp_i baricon(char *,int,baricon_clickproc);
+wimp_i baricon_left(char *,int,baricon_clickproc);
+wimp_i baricon_textandsprite(char *,char *,int,int,baricon_clickproc);
+wimp_i baricon_textandsprite_left(char *,char *,int,int,baricon_clickproc);
+wimp_i baricon_newsprite(char *);
+wimp_i baricon_newtext(char *);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/bbc b/StraySrc/Libraries/Steel/h/bbc
new file mode 100644 (file)
index 0000000..ff94c16
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * bbc.h
+ *
+ * Interface to various vaguely BBC-like bits of the OS
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __bbc_h
+#define __bbc_h
+
+#ifndef __os_h
+  #include "os.h"
+#endif
+
+/*----- VDU driver interface ----------------------------------------------*
+ *
+ * It's highly unlikely that any of these calls will return an error unless
+ * you're trying to use them from a print loop.
+ */
+
+/* --- bbc_vdu --- *
+ *
+ * Write character c to the VDU drivers
+ */
+
+typedef enum
+{
+  bbc_Null=0,
+  bbc_CharToPrinter,
+  bbc_EnablePrinter,
+  bbc_DisablePrinter,
+  bbc_TextToText,
+  bbc_TextToGraph,
+  bbc_EnableVDU,
+  bbc_Bell,
+  bbc_MoveOneBack,
+  bbc_MoveOneOn,
+  bbc_MoveDownOne,
+  bbc_MoveUpOne,
+  bbc_ClearText,
+  bbc_MoveToStart,
+  bbc_PageOn,
+  bbc_PageOff,
+  bbc_ClearGraph,
+  bbc_DefTextColour,
+  bbc_DefGraphColour,
+  bbc_DefLogical,
+  bbc_RestoreLogical,
+  bbc_DisableVDU,
+  bbc_ScreenMode,
+  bbc_MultiPurpose,
+  bbc_DefGraphWindow,
+  bbc_PlotCommand,
+  bbc_DefaultWindow,
+  bbc_DoesntDoAnything,
+  bbc_DefTextWindow,
+  bbc_DefGraphOrigin,
+  bbc_HomeText,
+  bbc_MoveText
+}
+bbc_vduCode;
+
+os_error *bbc_vdu(bbc_vduCode c);
+
+/* --- bbc_vduw --- *
+ *
+ * Write halfword hw to the VDU drivers (e.g. for coordinates)
+ */
+
+os_error *bbc_vduw(int hw);
+
+/* --- bbc_vduq --- *
+ *
+ * Write a stream of characters to the VDU drivers.  The correct number of
+ * characters for the VDU command given in the first character is expected:
+ * strange things may happen if you don't give the right number.
+ */
+
+os_error *bbc_vduq(bbc_vduCode c,...);
+
+/* --- bbc_stringprint --- *
+ *
+ * Writes a null-terminated string pointed to by p to the VDU drivers
+ */
+
+os_error *bbc_stringprint(const char *p);
+
+/* --- bbc_cls --- *
+ *
+ * Clears the screen
+ */
+
+os_error *bbc_cls(void);
+
+/* --- bbc_colour --- *
+ *
+ * Sets the text colour to be col.  Set bit 7 of col to set the background
+ * colour.
+ */
+
+os_error *bbc_colour(int col);
+
+/* --- bbc_pos and bbc_vpos --- *
+ *
+ * Return the x or y position of the text cursor respectively.
+ */
+
+int bbc_pos(void);
+int bbc_vpos(void);
+
+/* --- bbc_tab --- *
+ *
+ * Moves the text cursor to a specified position on the screen.
+ */
+
+os_error *bbc_tab(int x,int y);
+
+/*----- Graphics interface ------------------------------------------------*/
+
+/* --- bbc_plot --- *
+ *
+ * Plots something specified by action at position x,y
+ */
+
+typedef enum
+{
+  bbc_SolidBoth=0x00,
+  bbc_SolidExFinal=0x08,
+  bbc_DottedBoth=0x10,
+  bbc_DottedExFinal=0x18,
+  bbc_SolidExInit=0x20,
+  bbc_SolidExBoth=0x28,
+  bbc_DottedExInit=0x30,
+  bbc_DottedExBoth=0x38,
+  bbc_Point=0x40,
+  bbc_HorizLineFillNB=0x48,
+  bbc_TriangleFill=0x50,
+  bbc_HorizLineFillB=0x58,
+  bbc_RectangleFill=0x60,
+  bbc_HorizLineFillF=0x68,
+  bbc_ParallelFill=0x70,
+  bbc_HorizLineFillNF=0x78,
+  bbc_FloodToBack=0x80,
+  bbc_FloodToFore=0x88,
+  bbc_Circle=0x90,
+  bbc_CircleFill=0x98,
+  bbc_CircleArc=0xA0,
+  bbc_Segment=0xA8,
+  bbc_Sector=0xB0,
+  bbc_Block=0xB8,
+  bbc_Ellipse=0xC0,
+  bbc_EllipseFill=0xC8,
+  bbc_GraphicsChar=0xD0,
+  bbc_SpritePlot=0xE8
+}
+bbc_plotAction;
+
+typedef enum
+{
+  bbc_MoveCursorRel,
+  bbc_DrawRelFore,
+  bbc_DrawRelInverse,
+  bbc_DrawRelBack,
+  bbc_MoveCursorAbs,
+  bbc_DrawAbsFore,
+  bbc_DrawAbsInverse,
+  bbc_DrawAbsBack
+}
+bbc_plotType;
+
+os_error *bbc_plot(int action,int x,int y);
+
+/* --- bbc_move --- *
+ *
+ * Moves the graphics cursor to x,y
+ */
+
+os_error *bbc_move(int x,int y);
+
+/* --- bbc_moveby --- *
+ *
+ * Translates the graphics cursor by x,y
+ */
+
+os_error *bbc_moveby(int x,int y);
+
+/* --- bbc_draw --- *
+ *
+ * Draws a line from the graphics cursor position to x,y
+ */
+
+os_error *bbc_draw(int x,int y);
+
+/* --- bbc_drawby --- *
+ *
+ * Draws a line from the graphics cursor position to the point x to the 
+ * right of and y above the graphics cursor position
+ */
+
+os_error *bbc_drawby(int x,int y);
+
+/* --- bbc_rectangle --- *
+ *
+ * Draws a rectangle with bottom left point at x,y, width w and height h
+ */
+
+os_error *bbc_rectangle(int x,int y,int w,int h);
+
+/* --- bbc_rectanglefill --- *
+ *
+ * Draws a filled rectangle with bottom left point at x,y, width w and
+ * height h
+ */
+
+os_error *bbc_rectanglefill(int x,int y,int w,int h);
+
+/* --- bbc_circle --- *
+ *
+ * Draws a circle, centre at x,y with radius r
+ */
+
+os_error *bbc_circle(int x,int y,int r);
+
+/* --- bbc_circlefill --- *
+ *
+ * Draws a filled in circle, centre at x,y with radius r
+ */
+
+os_error *bbc_circlefill(int x,int y,int r);
+
+/* --- bbc_origin --- *
+ *
+ * Sets the graphics origin to the point x,y (relative to the bottom left
+ * corner of the screen)
+ */
+
+os_error *bbc_origin(int x,int y);
+
+/* --- bbc_gwindow --- *
+ *
+ * Sets the graphics clipping window to the rectangle whose bottom left and
+ * top right corners are x0,y0 and x1,y1
+ */
+
+os_error *bbc_gwindow(int x0,int y0,int x1,int y1);
+
+/* --- bbc_clg --- *
+ *
+ * Clears the graphics clipping window
+ */
+
+os_error *bbc_clg(void);
+
+/* --- bbc_fill --- *
+ *
+ * Flood fills the area containing the point x,y to the current foreground
+ * colour.  The area is expected to currently be coloured in the current
+ * background colour
+ */
+
+os_error *bbc_fill(int x,int y);
+
+/* --- bbc_gcol --- *
+ *
+ * Sets the current GCOL action to action and the current graphics colour to
+ * col.  Set bit 7 of col to choose the background colour.
+ */
+
+os_error *bbc_gcol(int action,int col);
+
+/* --- bbc_tint --- *
+ *
+ * Sets the current tint (if in a 256-colour mode) to tint specified.  Note
+ * that tint values should be between 0 and 3, not 0x00 to 0xC0.
+ */
+
+typedef enum
+{
+  bbc_TextForegroundTint,
+  bbc_TextBackgroundTint,
+  bbc_GraphicsForegroundTint,
+  bbc_GraphicsBackgroundTint
+}
+bbc_tintAction;
+
+os_error *bbc_tint(bbc_tintAction action,int col);
+
+/* --- bbc_palette --- *
+ *
+ * Sets logical colour col to be `physical' colour mode, or to the palette
+ * entry red,green,blue.
+ */
+
+typedef enum
+{
+  /* --- BBC-style solid colours --- */
+
+  bbc_palBlack,
+  bbc_palRed,
+  bbc_palGreen,
+  bbc_palYellow,
+  bbc_palBlue,
+  bbc_palMagenta,
+  bbc_palCyan,
+  bbc_palWhite,
+
+  /* --- BBC-style really yukky flashing colours --- */
+
+  bbc_palFlashBlackWhite,
+  bbc_palFlashRedCyan,
+  bbc_palFlashGreenMagenta,
+  bbc_palFlashYellowBlue,
+  bbc_palFlashBlueYellow,
+  bbc_palFlashMagentaGreen,
+  bbc_palFlashCyanRed,
+  bbc_palFlashWhiteBack,
+
+  /* --- Other special values (use red,green,blue values) --- */
+
+  bbc_palSolidRGB,
+  bbc_palFirstFlashRGB,
+  bbc_palSecondFlashRGB,
+  bbc_palBorderRGB,
+  bbc_palMouseRGB,
+
+  /* --- Special flags to OR in --- */
+
+  bbc_palSupremacy
+}
+bbc_palMode;
+
+os_error *bbc_palette(int col,bbc_palMode mode,int red,int green,int blue);
+
+/* --- bbc_point --- *
+ *
+ * Returns the logical colour of the point at position x,y.  Doesn't return
+ * the tint in 256-colour modes.  Returns 255 if the point is offscreen or
+ * an error occurred.
+ */
+
+int bbc_point(int x,int y);
+
+/*----- Screen mode handling ----------------------------------------------*/
+
+/* --- bbc_mode --- *
+ *
+ * Sets the screen mode to mode
+ */
+
+os_error *bbc_mode(int mode);
+
+/* --- bbc_vduvar --- *
+ *
+ * Reads the value of the VDU variable var and returns it
+ */
+
+typedef enum
+{
+  bbc_GWLCol=128,
+  bbc_GWBRow,
+  bbc_GWRCol,
+  bbc_GWTRow,
+  bbc_TWLCol,
+  bbc_TWBRow,
+  bbc_TWRCol,
+  bbc_TWTRow,
+  bbc_OrgX,
+  bbc_OrgY,
+  bbc_GCsX,
+  bbc_GCsY,
+  bbc_OlderCsX,
+  bbc_OlderCsY,
+  bbc_OldCsX,
+  bbc_OldCsY,
+  bbc_GCsIX,
+  bbc_GCsIY,
+  bbc_NewPtX,
+  bbc_NewPtY,
+  bbc_ScreenStart,
+  bbc_DisplayStart,
+  bbc_TotalScreenSize,
+  bbc_GPLFMD,
+  bbc_CPLBMD,
+  bbc_GFCOL,
+  bbc_GBCOL,
+  bbc_TForeCol,
+  bbc_TBackCol,
+  bbc_GFTint,
+  bbc_GBTint,
+  bbc_TFTint,
+  bbc_TBTint,
+  bbc_MaxMode,
+  bbc_GCharSizeX,
+  bbc_GCharSizeY,
+  bbc_GCharSpaceX,
+  bbc_GCharSpaceY,
+  bbc_HLineAddr,
+  bbc_TCharSizeX,
+  bbc_TCharSizeY,
+  bbc_TCharSpaceX,
+  bbc_TCharSpaceY
+}
+bbc_vduvariable;
+
+typedef enum
+{
+  bbc_ModeFlags,
+  bbc_ScrRCol,
+  bbc_ScrBCol,
+  bbc_NColour,
+  bbc_XEigFactor,
+  bbc_YEigFactor,
+  bbc_LineLength,
+  bbc_ScreenSize,
+  bbc_YShftFactor,
+  bbc_Log2BPP,
+  bbc_Log2BPC,
+  bbc_XWindLimit,
+  bbc_YWindLimit
+}
+bbc_modevariable;
+
+int bbc_vduvar(int var);
+
+/* --- bbc_vduvars --- *
+ *
+ * Reads a collection of VDU variables into an array.  The variables to be
+ * read are held in the `in' array, which is terminated by a -1 entry.  The
+ * values are stored in the same order in the `out' array.
+ */
+
+os_error *bbc_vduvars(int in[],int out[]);
+
+/* --- bbc_modevar --- *
+ *
+ * Returns the value of mode variable var for mode m
+ */
+
+int bbc_modevar(int m,int var);
+
+/*----- Keyboard and cursor handling --------------------------------------*/
+
+/* --- bbc_get --- *
+ *
+ * Waits for a keypress and returns the ASCII code.  Returns 0x1?? if Escape
+ * was pressed.
+ */
+
+int bbc_get(void);
+
+/* --- bbc_inkey --- *
+ *
+ * Return value depends on action:
+ *
+ * action == 0xFF00: Return OS version identifier
+ * action == 0xFFkk: Return whether key with internal code kk ^ 255 is
+ *                   pressed
+ * action == 0xtttt: Wait tttt centiseconds for a keypress and return ASCII
+ *                   code
+ */
+
+int bbc_inkey(int action);
+
+/* --- bbc_cursor --- *
+ *
+ * Sets cursor mode according to value of action:
+ *
+ * action == 0: Turn cursor off
+ * action == 1: Turn cursor on
+ * action == 2: Make cursor steady
+ * action == 3: Make cursor flash
+ */
+
+os_error *bbc_cursor(int action);
+
+/*----- Mouse control -----------------------------------------------------*/
+
+/* --- bbc_mouse --- *
+ *
+ * Reads the mouse coordinates into *x,*y, button status int *b and time of
+ * mouse event into *t.  Any of these may be 0 to indicate `don't care'.
+ */
+
+os_error *bbc_mouse(int *x,int *y,int *b,int *t);
+
+/* --- bbc_mouserect --- *
+ *
+ * Sets the mouse bounding rectangle to have bottom left coordinate x0,y0
+ * and top right coordinate x1,y1
+ */
+
+os_error *bbc_mouserect(int x0,int y0,int x1,int y1);
+
+/*----- Strangeness -------------------------------------------------------*/
+
+/* --- bbc_adval --- *
+ *
+ * If I knew, I wouldn't be here.
+ */
+
+int bbc_adval(int);
+
+/*----- Sound calls -------------------------------------------------------*/
+
+/* --- bbc_getbeat --- *
+ *
+ * Reads the beat counter
+ */
+
+int bbc_getbeat(void);
+
+/* --- bbc_getbeats --- *
+ *
+ * Reads the length of a bar in beats
+ */
+
+int bbc_getbeats(void);
+
+/* --- bbc_setbeats --- *
+ *
+ * Sets the bar length
+ */
+
+os_error *bbc_setbeats(int beats);
+
+/* --- bbc_gettempo --- *
+ *
+ * Reads the beat speed
+ */
+
+int bbc_gettempo(void);
+
+/* --- bbc_settempo --- *
+ *
+ * Sets the beat speed
+ */
+
+os_error *bbc_settempo(int tempo);
+
+/* --- bbc_sound --- *
+ *
+ * Makes a sound on channel chan with amplitude a, pitch p and duration d
+ * at time t.  t==-2 for `right now'.  Doesn't return an error.
+ */
+
+os_error *bbc_sound(int chan,int a,int p,int d,int t);
+
+/* --- bbc_soundoff and bbc_soundon --- *
+ *
+ * Disable and enable the sound system
+ */
+
+os_error *bbc_soundoff(void);
+os_error *bbc_soundon(void);
+
+/* --- bbc_stereo --- *
+ *
+ * Sets the stereo position of channel chan to pos
+ */
+
+os_error *bbc_stereo(int chan,int pos);
+
+/* --- bbc_voices --- *
+ *
+ * Sets the number of voices (channels ) to be n
+ */
+
+os_error *bbc_voices(int n);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/blinkC b/StraySrc/Libraries/Steel/h/blinkC
new file mode 100644 (file)
index 0000000..e7bf10f
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * BlinkCursor
+ *  A nice blinky caret routine for your progs
+ *
+ * v. 1.00 (23 July 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __blinkCursor_h
+#define __blinkCursor_h
+
+#ifndef TRUE
+#define BOOL int;
+#define TRUE 1
+#define FALSE 0
+#endif
+
+/*
+ * void blinkCursor(BOOL onOrOff)
+ *
+ * Use
+ *  Turns the blinkingness of the cursor on or off.  You must call
+ *  alarm_init() before this function, or all hell breaks loose.
+ *
+ * Parameters
+ *  BOOL onOrOff == whether you want to turn blinking cursor on or off
+ */
+
+void blinkCursor(BOOL onOrOff);
+
+/*
+ * void blink_init(void)
+ *
+ * Use
+ *  Sets everything up nicely.
+ */
+
+void blink_init(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/buffer b/StraySrc/Libraries/Steel/h/buffer
new file mode 100644 (file)
index 0000000..4900a72
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * buffer.h
+ *
+ * Two buffers for building strings in
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __buffer_h
+#define __buffer_h
+
+/*
+ * char *buffer_find(void)
+ *
+ * Use
+ *  Returns a pointer to a 256-byte buffer.  There are two buffers, which are
+ *  returned alternately.
+ */
+
+char *buffer_find(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/buttons b/StraySrc/Libraries/Steel/h/buttons
new file mode 100644 (file)
index 0000000..8008975
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * Buttons
+ *  provides handling for clever buttons and things.
+ *
+ * v. 1.00 (23 July 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __buttons_h
+#define __buttons_h
+
+#ifndef __wimp_h
+#include "wimp.h"
+#endif
+
+#ifndef __dbox_h
+#include "dbox.h"
+#endif
+
+typedef void (*buttons_arrowProc)(dbox d,dbox_field f,int diff,void *handle);
+
+typedef struct
+{
+  int min,max;
+  BOOL wrap;
+}
+buttons_simpleArrow;
+
+/*
+ * A function to handle the update of a slider.
+ */
+typedef void (*buttons_sliderHandler)(dbox d,wimp_i i,int val,void *handle);
+
+/*
+ * void buttons_arrowClick
+ * (
+ *   dbox d,
+ *   dbox_field f,
+ *   int min,
+ *   int max,
+ *   int increment,
+ *   BOOL wrap
+ * )
+ *
+ * Use
+ *  Increases (or decreases) the value in a writable box.  If the last event
+ *  was a click with the adjust button, the increment is made negative (i.e.
+ *  1 becomes -1, and -1 becomes 1), following the standard convention.  The
+ *  value will not be allowed to exceed the limits passed.  If you don't
+ *  want limits, make max and min the same.  Optionally, you can make the
+ *  field's value 'wrap around' if it goes out of range.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field number
+ *  int min == the lowest allowable value for the field
+ *  int max == the highest allowable value for the field
+ *  int increment == what to add to the value.  This may be negative.
+ *  BOOL wrap == wrap around or not
+ */
+
+void buttons_arrowClick
+(
+  dbox d,
+  dbox_field f,
+  int min,
+  int max,
+  int increment,
+  BOOL wrap
+);
+
+/*
+ * void buttons_arrow(dbox d,
+ *                    dbox_field f,
+ *                    dbox wd,
+ *                    dbox_field wf,
+ *                    buttons_arrowProc p,
+ *                    int diff,
+ *                    void *handle)
+ *
+ * Use
+ *  Handles a click on an arrow button.  It constrains the mouse pointer
+ *  so it doesn't drift away annoyingly, and presses the icon in (by
+ *  selecting it, so set up the sprites properly) while it's being clicked,
+ *  with nary a flicker in sight.  It simulates auto-repeat on the button,
+ *  so don't use real auto-repeat buttons.
+ *
+ * Parameters
+ *  dbox d,dbox_field f == the icon that was clicked
+ *  dbox wd,dbox_field wf == the (writable) icon that is passed to p
+ *  buttons_arrowProc p == a procedure to call for each `click' on the
+ *   button.  It may call buttons_arrowClick to bump the field.  If you pass
+ *   0, a default function is called which just bumps the icon.  handle must
+ *   point to a buttons_simpleArrow structure filled in correctly.
+ *  int diff == the difference to add to the icon (passed to p).  The sign
+ *   is toggled if the click was with the adjust button.
+ *  void *handle == a handle to pass to p
+ */
+
+void buttons_arrow(dbox d,
+                   dbox_field f,
+                   dbox wd,
+                   dbox_field wf,
+                   buttons_arrowProc p,
+                   int diff,
+                   void *handle);
+
+/*
+ * BOOL buttons_insertChar(dbox d,int chcode,char min,char max)
+ *
+ * Use
+ *  This function inserts the character specified into the writable field
+ *  containing the caret.  Useful if you want to handle input yourself so
+ *  you can update things (such as sliders) in deending on the input.  It
+ *  will insure that the character is within the limits given (invalid
+ *  limits will cause a default of 32-255 to be used).
+ *
+ * Parameters
+ *  dbox d == dbox handle
+ *  int chcode == the character, as returned from dbox_eventProcess().
+ *  char min == minimum character allowable.
+ *  char max == maximum character allowable.
+ *
+ * Returns
+ *  Whether it inserted the character or not.
+ */
+
+BOOL buttons_insertChar(dbox d,int chcode,char min,char max);
+
+/*
+ * void buttons_redrawSlider
+ * (
+ *   dbox d,
+ *   wimp_i i,
+ *   int max,
+ *   int val,
+ *   int colour,
+ *   BOOL isVertical
+ * )
+ *
+ * Use
+ *  Draws a slider in the specified icon
+ *
+ * Parameters
+ *  dbox d == dbox handle
+ *  wimp_i icon == the icon we're dealing with
+ *  int max == the maximum value you want
+ *  int val == the current value of the slider
+ *  int colour == the WIMP colour for the slider
+ *  BOOL isVertical == TRUE if the slider is vertical
+ */
+
+void buttons_redrawSlider
+(
+  dbox d,
+  wimp_i i,
+  int max,
+  int val,
+  int colour,
+  BOOL isVertical
+);
+
+/*
+ * void buttons_updateSlider
+ * (
+ *   dbox d,
+ *   wimp_i i,
+ *   int max,
+ *   int val,
+ *   int colour,
+ *   BOOL isVertical
+ * )
+ *
+ * Use
+ *  Redraws a slider in the specified icon
+ *
+ * Parameters
+ *  dbox d == dbox handle
+ *  wimp_i icon == the icon we're dealing with
+ *  int max == the maximum value you want
+ *  int val == the current value of the slider
+ *  int colour == the WIMP colour for the slider
+ *  BOOL isVertical == TRUE if the slider is vertical
+ */
+
+void buttons_updateSlider
+(
+  dbox d,
+  wimp_i i,
+  int max,
+  int val,
+  int colour,
+  BOOL isVertical
+);
+
+/*
+ * void buttons_slideSlider
+ * (
+ *   dbox d,
+ *   wimp_i i,
+ *   int max,
+ *   int *val,
+ *   int colour,
+ *   BOOL isVertical,
+ *   buttons_sliderHandler proc,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  This routine just neatly handles the slider totally.  Just pass it the
+ *  parameters it needs, and let it get on with it.
+ *
+ * Parameters
+ *  dbox d == the dbox
+ *  wimp_i i == the icon number
+ *  int max == the maximum slider value
+ *  int *val == a pointer to the slider value (updated as we go along)
+ *  int colour == the colour for the slider
+ *  BOOL isVertical == whether the slider is vertical
+ *  buttons_sliderHandler proc == a slider handler, which can update, say a
+ *   a writable field as the drag takes place
+ *  void *handle == a handle to pass the routine
+ */
+
+void buttons_slideSlider
+(
+  dbox d,
+  wimp_i i,
+  int max,
+  int *val,
+  int colour,
+  BOOL isVertical,
+  buttons_sliderHandler proc,
+  void *handle
+);
+
+/*
+ * void buttons_redrawColourButton(dbox d,wimp_i i,buttons_colourstr *c)
+ *
+ * Use
+ *  Redraws a true-colour button.
+ *
+ * Parameters
+ *  dbox d == the dbox
+ *  wimp_i i == icon number
+ *  buttons_colourstr == the colour we're intersted in
+ */
+
+void buttons_redrawColourButton(dbox d,wimp_i i,wimp_paletteword c);
+
+/*
+ * buttons_updateColourButton(dbox d,wimp_i i,wimp_paletteword c)
+ *
+ * Use
+ *  This routine redraws a colour button.
+ *
+ * Parameters
+ *  dbox d ==  the dbox
+ *  wimp_i == the icon number
+ *  wimp_paletteword c == the colour number
+ */
+
+void buttons_updateColourButton(dbox d,wimp_i i,wimp_paletteword c);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/calltrace b/StraySrc/Libraries/Steel/h/calltrace
new file mode 100644 (file)
index 0000000..cfd99be
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * calltrace.h
+ *
+ * Display a stack backtrace
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __calltrace_h
+#define __calltrace_h
+
+void _calltrace(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/caretptr b/StraySrc/Libraries/Steel/h/caretptr
new file mode 100644 (file)
index 0000000..3a6a00c
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * CaretPtr
+ *  handles a 'caret pointer' - one that changes to a 'I' shape if over a
+ *  writable icon.
+ *
+ * v. 1.00 (25 July 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __caretptr_h
+#define __caretptr_h
+
+#ifndef __pointer_h
+#include "pointer.h"
+#endif
+
+/*
+ * void caretPtr(char *name,sprite_area *area,int x,int y)
+ *
+ * Use
+ *  Turns the caret pointer on
+ *
+ * Parameters
+ *  char *name == the name of the sprite to use
+ *  sprite_area *area == pointer to sprite area
+ *  int x == x position of hotspot
+ *  int y == y position of hotspot
+ */
+
+void caretPtr(char *name,sprite_area *area,int x,int y);
+
+/*
+ * void caretPtrOff(void)
+ *
+ * Use
+ *  Turns the caretPtr off.
+ */
+
+void caretPtrOff(void);
+
+void caretPtr__pointer(BOOL ownIt);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/choices b/StraySrc/Libraries/Steel/h/choices
new file mode 100644 (file)
index 0000000..6cd2da5
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * choices.h
+ *
+ * Handling the global choices repository
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __choices_h
+#define __choices_h
+
+#ifndef BOOL
+  #define BOOL int
+  #define TRUE 1
+  #define FALSE 0
+#endif
+
+/*
+ * void choices_setName(char *progname)
+ *
+ * Use
+ *  Sets the name of the application as used by choices.  The name is
+ *  truncated to 10 characters if necessary.  If no name is specified (i.e.
+ *  you don't call this routine) then the name of the application (as passed
+ *  to wimpt_init) is assumed.
+ */
+
+void choices_setName(char *progname);
+
+/*
+ * char *choices_name(char *leaf,BOOL writable)
+ *
+ * Use
+ *  Locates the name of the specified resource.  If you want to open a file
+ *  for writing, you should set the writable flag.  Otherwise, this routine
+ *  will try to find the name of a file which already exists.
+ *
+ *  If you only want to read a file, this routine will first look at
+ *  <Choices$Dir>.leaf, and then at <resPrefix>.leaf, and return whichever
+ *  is found first.  If neither exists, a name is returned as for the
+ *  writable case.
+ *
+ *  If you want to write a file, then <Choices$Dir>.leaf is returned, unless
+ *  Choices$Dir is unset, in which case <resPrefix>.leaf is returned.
+ *
+ *  resPrefix is the prefix passed to res through res_init or res_setPrefix.
+ */
+
+char *choices_name(char *leaf,BOOL writable);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/colourtran b/StraySrc/Libraries/Steel/h/colourtran
new file mode 100644 (file)
index 0000000..840cc99
--- /dev/null
@@ -0,0 +1,343 @@
+/****************************************************************************
+ * This source file was written by Acorn Computers Limited. It is part of   *
+ * the RISCOS library for writing applications in C for RISC OS. It may be  *
+ * used freely in the creation of programs for Archimedes. It should be     *
+ * used with Acorn's C Compiler Release 3 or later.                         *
+ *                                                                          *
+ ***************************************************************************/
+
+/*
+ * Title:  colourtran.h
+ * Purpose: C interface to the ColourTrans SWIs
+ *
+ */
+
+#ifndef __colourtran_h
+#define __colourtran_h
+
+#ifndef __os_h
+#include "os.h"
+#endif
+
+#ifndef __wimp_h
+#include "wimp.h"
+#endif
+
+#ifndef __font_h
+#include "font.h"
+#endif
+
+
+/* ----------------------- colourtran_select_table -------------------------
+ * Description:   Sets up a translation table in a buffer, given a source
+ *                mode and palette, and a destination mode and palette.
+ *
+ * Parameters:    int source_mode -- source mode
+ *                wimp_paletteword *source_palette -- source palette
+ *                int dest_mode -- destination mode
+ *                wimp_paletteword *dest_palette -- destination palette
+ *                void *buffer -- pointer to store for the table.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_select_table (int source_mode, 
+                                   wimp_paletteword *source_palette,
+                                   int dest_mode,
+                                   wimp_paletteword *dest_palette,
+                                   void *buffer);
+
+
+/* ---------------------- colourtran_select_GCOLtable ----------------------
+ * Description:   Sets up a list of GCOLs in a buffer, given a source
+ *                mode and palette, and a destination mode and palette.
+ *
+ * Parameters:    int source_mode -- source mode
+ *                wimp_paletteword *source_palette -- source palette
+ *                int dest_mode -- destination mode
+ *                wimp_paletteword *dest_palette -- destination palette
+ *                void *buffer -- pointer to store for the list of GCOLs.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_select_GCOLtable (int source_mode, 
+                                       wimp_paletteword *source_palette,
+                                       int dest_mode,
+                                       wimp_paletteword *dest_palette,
+                                       void *buffer);
+
+
+/* ------------------------- colourtran_returnGCOL -------------------------
+ * Description:   Informs caller of the closest GCOL in the current mode
+ *                to a given palette entry.
+ *
+ * Parameters:    wimp_paletteword entry -- the palette entry
+ *                int *gcol -- returned GCOL value.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_returnGCOL (wimp_paletteword entry, int *gcol);
+
+
+/* ------------------------ colourtran_setGCOL -----------------------------
+ * Description:   Informs caller of the closest GCOL in the current mode
+ *                to a given palette entry, and also sets the GCOL.
+ *
+ * Parameters:    wimp_paletteword entry -- the palette entry
+ *                int fore_back -- set to 0 for foreground, 
+ *                                 set to 128 for background
+ *                int gcol_in -- GCOL action
+ *                int *gcol_out -- returned closest GCOL.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_setGCOL (wimp_paletteword entry, int fore_back,
+                              int gcol_in, int *gcol_out);
+
+
+/* ---------------------- colourtran_return_colournumber -------------------
+ * Description:   Informs caller of the closeset colour number to a given
+ *                palette entry, in the current mode and palette
+ *
+ * Parameters:    wimp_paletteword entry -- the palette entry
+ *                int *col -- returned colour number.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+os_error *colourtran_return_colournumber (wimp_paletteword entry, int *col);
+
+
+/* --------------------- colourtran_return_GCOLformode ---------------------
+ * Description:   Informs caller of the closest GCOL to a given palette
+ *                entry, destination mode and destination palette.
+ *
+ * Parameters:    wimp_paletteword entry -- the palette entry
+ *                int dest_mode -- destination mode
+ *                wimp_paletteword *dest_palette -- destination palette
+ *                int *gcol -- returned closest GCOL.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+os_error *colourtran_return_GCOLformode (wimp_paletteword entry,
+                                         int dest_mode,
+                                         wimp_paletteword *dest_palette,
+                                         int *gcol);
+
+
+/* ------------------ colourtran_return_colourformode ----------------------
+ * Description:   Informs caller of the closest colour number to a given
+ *                palette entry, destination mode and destination palette.
+ *
+ * Parameters:    wimp_paletteword entry -- the palette entry
+ *                int dest_mode -- destination mode
+ *                wimp_paletteword *dest_palette -- destination palette
+ *                int *col -- returned closest colour number.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_return_colourformode (wimp_paletteword entry,
+                                           int dest_mode,
+                                           wimp_paletteword *dest_palette,
+                                           int *col);
+
+
+/* ----------------------- colourtran_return_OppGCOL -----------------------
+ * Description:   Informs caller of the furthest GCOL in the current mode
+ *                from a given palette entry.
+ *
+ * Parameters:    wimp_paletteword entry -- the palette entry
+ *                int *gcol -- returned GCOL value.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_return_OppGCOL (wimp_paletteword entry, int *gcol);
+
+
+/* ------------------------ colourtran_setOppGCOL --------------------------
+ * Description:   Informs caller of the furthest GCOL in the current mode
+ *                from a given palette entry, and also sets the GCOL.
+ *
+ * Parameters:    wimp_paletteword entry -- the palette entry
+ *                int fore_back -- set to 0 for foreground,
+ *                                 set to 128 for background
+ *                int gcol_in -- GCOL action
+ *                int *gcol_out -- returned furthest GCOL.
+ * Returns:       possible error condition.
+ * Other Info:    none. 
+ *
+ */
+
+os_error *colourtran_setOppGCOL (wimp_paletteword entry, int fore_back,
+                                int gcol_in, int *gcol_out);
+
+
+/* ---------------------- colourtran_return_Oppcolournumber ----------------
+ * Description:   Informs caller of the furthest colour number from a given
+ *                palette entry, in the current mode and palette
+ *
+ * Parameters:    wimp_paletteword -- the palette entry
+ *                int *col -- returned colour number.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_return_Oppcolournumber (wimp_paletteword entry,
+                                             int *col);
+
+
+/* --------------------- colourtran_return_OppGCOLformode ------------------
+ * Description:   Informs caller of the furthest GCOL from a given palette
+ *                entry, destination mode and destination palette.
+ *
+ * Parameters:    wimp_paletteword entry -- the palette entry
+ *                int dest_mode -- destination mode
+ *                wimp_paletteword *dest_palette -- destination palette
+ *                int *gcol -- returned furthest GCOL.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_return_OppGCOLformode (wimp_paletteword entry,
+                                            int dest_mode,
+                                            wimp_paletteword *dest_palette,
+                                            int *gcol);
+
+
+/* ------------------ colourtran_return_Oppcolourformode -------------------
+ * Description:   Informs caller of the furthest colour number from a given
+ *                palette entry, destination mode and destination palette.
+ *
+ * Parameters:    wimp_paletteword entry -- the palette entry
+ *                int dest_mode -- destination mode
+ *                wimp_paletteword *dest_palette -- destination palette
+ *                int *col -- returned furthest colour number.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_return_Oppcolourformode (wimp_paletteword entry,
+                                              int dest_mode,
+                                              wimp_paletteword *dest_palette,
+                                              int *col);
+
+
+/* ---------------------- colourtran_GCOL_tocolournumber -------------------
+ * Description:   Translates a GCOL to a colournumber (assuming 256-colour
+ *                mode).
+ *
+ * Parameters:    int gcol -- the GCOL
+ *                int *col -- returned colour number.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_GCOL_tocolournumber (int gcol, int *col);
+
+
+/* ----------------- colourtran_colournumbertoGCOL -------------------------
+ * Description:   Translates a colour number to a GCOL (assuming 256-colour
+ *                mode).
+ *
+ * Parameters:    int col -- the colour number
+ *                int *gcol -- the returned GCOL.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_colournumbertoGCOL (int col, int *gcol);
+
+
+/* ------------------ colourtran_returnfontcolours -------------------------
+ * Description:   Informs caller of font colours to match given colours.
+ *
+ * Parameters:    font *handle -- the font's handle
+ *                wimp_paletteword *backgnd -- background palette entry
+ *                wimp_paletteword *foregnd -- foreground palette entry
+ *                int *max_offset
+ * Returns:       possible error condition.
+ * Other Info:    Closest approximations to fore/background colours will be
+ *                set, and as many intermediate colours as possible (up to
+ *                a maximum of *max_offset). Values are returned through
+ *                the parameters.
+ *
+ */
+
+os_error *colourtran_returnfontcolours (font *handle, 
+                                        wimp_paletteword *backgnd,
+                                        wimp_paletteword *foregnd,
+                                        int *max_offset);
+
+
+/* -------------------- colourtran_setfontcolours --------------------------
+ * Description:   Informs caller of font colours to match given colours, and
+ *                calls font_setfontcolour() to set them.
+ *
+ * Parameters:    font *handle -- the font's handle
+ *                wimp_paletteword *backgnd -- background palette entry
+ *                wimp_paletteword *foregnd -- foreground palette entry
+ *                int *max_offset
+ * Returns:       possible error condition.
+ * Other Info:    Closest approximations to fore/background colours will be
+ *                set, and as many intermediate colours as possible (up to
+ *                a maximum of *max_offset). Values are returned through
+ *                the parameters. Font_setfontcolours() is then called with
+ *                these as parameters.
+ *
+ */
+os_error *colourtran_setfontcolours (font *handle,
+                                     wimp_paletteword *backgnd,
+                                     wimp_paletteword *foregnd,
+                                     int *max_offset);
+
+
+/* ----------------------- colourtran_invalidate_cache ---------------------
+ * Description:   To be called when the palette has changed since a call was
+ *                last made to a function in this module.
+ *
+ * Parameters:    void.
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+os_error *colourtran_invalidate_cache (void);
+
+
+/* new SWIs */
+
+/* ----------------------- colourtran_convert_device_colour ----------------
+ * Description:   Convert from a device colour to a standard RGB colour
+ *
+ * Parameters:    wimp_paletteword device colour
+                  wimp_paletteword *rgb colour
+ * Returns:       possible error condition.
+ * Other Info:    Uses the current calibration to convert from a device
+ *                colour to a standard RGB palette entry
+ *
+ */
+
+os_error *colourtran_convert_device_colour ( wimp_paletteword device,
+                                             wimp_paletteword *rgb );
+
+#endif
+/* end colourtran.h */
diff --git a/StraySrc/Libraries/Steel/h/coords b/StraySrc/Libraries/Steel/h/coords
new file mode 100644 (file)
index 0000000..6873b14
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * coords.h
+ *
+ * Miscellaneous handling of window-related geometries
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __coords_h
+#define __coords_h
+
+#ifndef __wimp
+  #include "wimp.h"
+#endif
+
+/* --- Passing window information to coords --- */
+
+typedef struct
+{
+  wimp_box box;
+  int scx;
+  int scy;
+}
+coords_cvtstr;
+
+/* --- Passing individual points --- *
+ *
+ * This is actually slightly silly, but we do it this way for compatibility
+ * with RISC_OSLib
+ */
+
+typedef struct
+{
+  int x;
+  int y;
+}
+coords_pointstr;
+
+/*
+ * int coords_x_toscreen(int x,coords_cvtstr *c)
+ * int coords_y_toscreen(int y,coords_cvtstr *c)
+ * int coords_x_toworkarea(int x,coords_cvtstr *c)
+ * int coords_y_toworkarea(int y,coords_cvtstr *c)
+ *
+ * Use
+ *  Convert x- or y-coordinates from window to screen coordinates or vice-
+ *  versa.
+ *
+ * Parameters
+ *  int x or int y == the coordinate to convert
+ *  coords_cvtstr *c == pointer to window information (e.g. cast from a
+ *    wimp_wstate or a wimp_redrawstr)
+ *
+ * Returns
+ *  The appropriate screen- or window-relative coordinate
+ */
+
+int coords_x_toscreen(int x,coords_cvtstr *c);
+int coords_y_toscreen(int y,coords_cvtstr *c);
+int coords_x_toworkarea(int x,coords_cvtstr *c);
+int coords_y_toworkarea(int y,coords_cvtstr *c);
+
+/*
+ * void coords_box_toscreen(wimp_box *b,coords_cvtstr *c)
+ * void coords_box_toworkarea(wimp_box *b,coords_cvtstr *c)
+ *
+ * Use
+ *  Converts a whole rectangle from window to screen coordinates or vice-
+ *  versa.
+ *
+ * Parameters
+ *  wimp_box *b == pointer to the rectangle to convert
+ *  coords_cvtstr *c == pointer to the window information to use
+ */
+
+void coords_box_toscreen(wimp_box *b,coords_cvtstr *c);
+void coords_box_toworkarea(wimp_box *b,coords_cvtstr *c);
+
+/*
+ * void coords_point_toscreen(coords_pointstr *p,coords_cvtstr *c)
+ * void coords_point_toworkarea(coords_pointstr *p,coords_cvtstr *c)
+ *
+ * Use
+ *  Converts a single point from window to screen coordinates or vice-versa.
+ *
+ * Parameters
+ *  coords_pointstr *p == pointer to the rectangle to convert
+ *  coords_cvtstr *c == pointer to the window information to use
+ */
+
+void coords_point_toscreen(coords_pointstr *p,coords_cvtstr *c);
+void coords_point_toworkarea(wimp_box *b,coords_cvtstr *c);
+
+/*
+ * BOOL coords_withinbox(coords_pointstr *p,wimp_box *b)
+ *
+ * Use
+ *  Returns whether the given point lies within (or on the edge of) the
+ *  specified box
+ *
+ * Parameters
+ *  coords_pointstr *p == pointer to the point
+ *  wimp_box *b == pointer to the box
+ *
+ * Returns
+ *  TRUE if the point is indeed within the box, and FALSE otherwise
+ */
+
+BOOL coords_withinbox(coords_pointstr *p,wimp_box *b);
+
+/*
+ * void coords_offsetbox(wimp_box *source,int ox,int oy,wimp_box *dest)
+ *
+ * Use
+ *  Nudges the given rectangle by adding the given offsets to the x and y
+ *  coordinates.
+ *
+ * Parameters
+ *  wimp_box *source == pointer to the rectangle to nudge
+ *  int ox == amount to nudge the x-coordinates of the box
+ *  int oy == amount to nudge the y-coordinates of the box
+ *  wimp_box *dest == pointer to where to put the nudged rectangle (may be
+ *    the same as source)
+ */
+
+void coords_offsetbox(wimp_box *source,int ox,int oy,wimp_box *dest);
+
+/*
+ * BOOL coords_intersects(wimp_box *line,wimp_box *box,int width)
+ *
+ * Use
+ *  Returns FALSE only if the line specified does not intersect the specified
+ *  box.  The line is considered to have a thickness of width.  The method
+ *  used is very approximate, and false positives may occur.
+ *
+ * Parameters
+ *  wimp_box *line == pointer to the coordinates of the line
+ *  wimp_box *box == pointer to the coordinates of the box
+ *
+ * Returns
+ *  FALSE if the line does not intersect the box
+ */
+
+BOOL coords_intersects(wimp_box *line,wimp_box *box,int width);
+
+/*
+ * BOOL coords_boxesoverlap(wimp_box *a,wimp_box *b)
+ *
+ * Use
+ *  Determines whether two boxes overlap at all (useful for checking whether
+ *  to redraw something).
+ *
+ * Parameters
+ *  wimp_box *a == pointer to one of the rectangles to test
+ *  wimp_box *b == pointer to the other rectangle
+ *
+ * Returns
+ *  TRUE if the boxes overlap, or FALSE if they don't
+ */
+
+BOOL coords_boxesoverlap(wimp_box *a,wimp_box *b);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/crc b/StraySrc/Libraries/Steel/h/crc
new file mode 100644 (file)
index 0000000..bcc7a7a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * crc
+ *  Checks CRC values for resource files
+ *
+ * v. 1.00 (24 August 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __crc_h
+#define __crc_h
+
+/*
+ * long crc(char *filename)
+ *
+ * Use
+ *  Calculates the CRC value for the file specified.  Uses the same method
+ *  as WindowEd etc.
+ *
+ * Parameters
+ *  char *filename == the filename of the file to check (leaf only - it's
+ *    passed through res_findname()).  Note that CRC-checking the
+ *    '!RunImage' file is rather silly.
+ *
+ * Returns
+ *  A 4-byte CRC value
+ */
+
+long crc(char *filename);
+
+/*
+ * void crc_check(char *filename,long check)
+ *
+ * Use
+ *  Checks a CRC value for a file and reports a fatal error if the check
+ *  fails.
+ *
+ * Parameters
+ *  char *filename == the leafname of the file
+ *  long check == the CRC number to check with
+ */
+
+void crc_check(char *filename,long check);
+
+/*
+ * void crc_checkRunImage(void)
+ *
+ * Use
+ *  Corruption-checks the main !RunImage file.  It must have been passed
+ *  through CodeScr first, to install the CRC into the code.
+ */
+
+void crc_checkRunImage(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/crc32 b/StraySrc/Libraries/Steel/h/crc32
new file mode 100644 (file)
index 0000000..94d832c
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * crc32.c
+ *
+ * Calculates 32-bit CRCs (Cyclic Redundancy Checks)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __crc32_h
+#define __crc32_h
+
+#ifndef __stddef_h
+  #include <stddef.h>
+#endif
+
+/*
+ * long crc32(long seed,void *data,size_t size,int diff)
+ *
+ * Use
+ *  Calculates the CRC for a block of data.  The system has been designed to
+ *  allow a CRC calculation to be carried out in stages, the result of 
+ *  previous calculations being used for continuation.
+ *
+ * Parameters
+ *  long seed == 0 to start a calculation, or the result from the previous
+ *    one to continue.
+ *  void *data == pointer to the data to check
+ *  size_t size == size (in bytes) of the data (just this block)
+ *  int diff == the address difference between bytes to check (normally one,
+ *    for all bytes).
+ *
+ * Returns
+ *   The CRC for all the data checked so far.
+ */
+
+long crc32(long seed,void *data,size_t size,int diff);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/dbox b/StraySrc/Libraries/Steel/h/dbox
new file mode 100644 (file)
index 0000000..bf4c4e7
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * dbox.h
+ *  further dialogue box routines for Straylight apps
+ *
+ * v. 1.00 (23 July 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ *
+ * Conventions from the old C library supported by this one
+ *
+ *  1. Use of field 0 as default action button
+ *
+ * New conventions
+ *
+ *  1. Field 1 is Cancel action button (it is activated when Esc is pressed)
+ *
+ */
+
+#ifndef __dbox_h
+#define __dbox_h
+
+#ifndef __wimp_h
+#include "wimp.h"
+#endif
+
+#ifndef __event_h
+#include "event.h"
+#endif
+
+typedef wimp_i dbox_field;
+typedef struct dbox__dboxstr *dbox;
+typedef void (*dbox_eventhandler)(dbox d,dbox_field clicked,void *handle);
+typedef BOOL (*dbox_raweventhandler)(dbox d,wimp_eventstr *e,void *handle);
+
+typedef enum
+{
+  dbox_RESETSTATE,
+  dbox_SETSTATE,
+  dbox_READSTATE,
+  dbox_TOGGLESTATE
+}
+dbox_action;
+
+typedef enum
+{
+  dbox_MENU_OVERPTR,              /* Menu dbox, opened over pointer        */
+  dbox_STATIC_LASTPOS,            /* Static dbox, opened in last position  */
+  dbox_MENU_LASTPOS,              /* Menu dbox, opened in last stored pos  */
+  dbox_STATIC_OVERPTR,            /* Static dbox, opened over pointer      */
+  dbox_MENU_CENTRE,               /* Menu dbox, centred on screen          */
+  dbox_STATIC_CENTRE              /* Static dbox, centred on screen        */
+}
+dbox_openType;
+
+#define dbox_CLOSE (dbox_field)-1
+#define dbox_HELP (dbox_field)-2
+#define dbox_ENDFILLIN (dbox_field)-3
+
+/*----- Private external interfaces ---------------------------------------*
+ *
+ * Some parts of dbox are better left alone...
+ */
+
+#ifdef dbox__INTERNALS
+
+typedef void (*dbox__mf)(int *x,int *y);
+typedef BOOL (*dbox__esm)(void);
+typedef void (*dbox__ddb)(wimp_openstr *o);
+void dbox__rms(dbox__mf mf,dbox__esm esm,dbox__ddb ddb);
+
+wimp_w dbox__menuDboxWindow(void);
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * BOOL dbox_wasSubmenu(void)
+ *
+ * Use
+ *  Returns whether the current menu hit was due to a submenu request or an
+ *  actual Menu_Selection event.
+ *
+ * Returns
+ *  TRUE if event was submenu warning
+ *  FALSE otherwise
+ *  Exits with error if neither (i.e. it was not called from a menu handler)
+ */
+
+#define dbox_wasSubmenu(x) (event_whyMenuEvent()==event_MENUSUBMENU)
+
+/*
+ * BOOL wasAdjustClick(void)
+ *
+ * Use
+ *  Returns whether the last event was caused by a mouse click with the
+ *  adjust mouse button.  Useful for deciding whether you want to bump a
+ *  value up or down, or for keeping a dbox on-screen.
+ *
+ * Returns
+ *  TRUE if the last event WAS caused by an adjust click.
+ */
+
+BOOL dbox_wasAdjustClick(void);
+
+/*
+ * dbox dbox_create(char *template)
+ *
+ * Use
+ *  Creates a dbox from a template and returns a handle to it.  It calls
+ *  werr() sensibly with nice messages if it failed.
+ *
+ * Parameters
+ *  char *name == name of template to use
+ *
+ * Returns
+ *  Abstract handle to dbox or NULL if the dbox could not be
+ *  created
+ */
+
+dbox dbox_create(char *name);
+
+/*
+ * void dbox_display(dbox d,dbox_openType how)
+ *
+ * Use
+ *  Displays a dbox on the screen.  The new dbox_openType is compatible with
+ *  the old TRUE/FALSE system.  Note that is the event was a submenu, then
+ *  the dbox will be opened as a submenu regardless of how you want it done.
+ *
+ *  If the dbox conatins a writable icon, then the caret is placed within
+ *  the first one.  This is handled automatically by the WIMP for submenu
+ *  dboxes, but not (unfortunately) for static ones.
+ *
+ * Parameters
+ *  dbox d == dbox handle
+ *  dbox_openType how == how you want the dbox opened
+ */
+
+void dbox_display(dbox d,dbox_openType how);
+
+/*
+ * void dbox_openDisplaced(dbox d)
+ *
+ * Use
+ *  Displaces the dbox from its original height by the statutory 48 OS
+ *  units.  If it would overlap the icon bar, it gets moved up to a sensible
+ *  height.  The dbox must be opened by this call once only.  It must be
+ *  closed using dbox_deleteNoUpdate().  The dbox is opened as a static
+ *  dbox, of course.
+ *
+ * Parameters
+ *  dbox d == the dbox
+ */
+
+void dbox_openDisplaced(dbox d);
+
+/*
+ * void dbox_hide(dbox d)
+ *
+ * Use
+ *  Closes the dbox specified in whatever manner necessary to stop it being
+ *  seen.  The window can still be created real easy.
+ *
+ * Parameters
+ *  dbox d == dialogue box handle
+ */
+
+void dbox_hide(dbox d);
+
+/*
+ * void dbox_deleteNoUpdate(dbox d)
+ *
+ * Use
+ *  Zaps a dbox without storing the thing's position away, so it reappears
+ *  where you want it.
+ *
+ * Parameters
+ *  dbox d == the handle
+ */
+
+void dbox_deleteNoUpdate(dbox d);
+
+/*
+ * void dbox_updatePosition(dbox d)
+ *
+ * Use
+ *  Stores the position of the dialogue box away, so that next time a dbox
+ *  using the same template is opened, it goes to that place.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ */
+
+void dbox_updatePosition(dbox d);
+
+/*
+ * void dbox_delete(dbox d)
+ *
+ * Use
+ *  Utterly zaps the dialogue box specified.  Updates the template, so it's
+ *  right next time around, though.  The window is deleted, and the dbox's
+ *  space is freed.
+ *
+ * Parameters
+ *  dbox d == dialogue box handle
+ */
+
+void dbox_delete(dbox d);
+
+/*
+ * void dbox_eventHandler(dbox d,dbox_eventhandler proc,void *handle)
+ *
+ * Use
+ *  This routine attaches an event handler to a dbox.  Pass 0 as the pointer
+ *  to the procedure if you want to remove the handler. Event handers are an
+ *  alternative to using dbox_fillin().
+ *
+ * Parameters
+ *  dbox d == the dbox you want to attach a handler to.
+ *  dbox_eventhandler proc == the hander procedure.
+ *  void *handle == up to you.  It gets passed to the procedure, though.
+ */
+
+void dbox_eventHandler(dbox d,dbox_eventhandler proc,void *handle);
+
+/*
+ * void dbox_rawEventHandler(dbox d,dbox_raweventhandler proc,void *handle)
+ *
+ * Use
+ *  This routine attaches a raw event handler to a dbox.  Pass 0 as the
+ *  pointer to the procedure if you want to remove the handler.  A raw event
+ *  handler gets passed all the WIMP events received by the dbox.  It should
+ *  return FALSE if it could not process the event itself, or TRUE if it
+ *  did.
+ *
+ * Parameters
+ *  dbox d == the dbox you want to attach a handler to.
+ *  dbox_eventhandler proc == the hander procedure.
+ *  void *handle == up to you.  It gets passed to the procedure, though.
+ */
+
+void dbox_rawEventHandler(dbox d,dbox_raweventhandler proc,void *handle);
+
+/*
+ * dbox_field dbox_fillin(dbox d)
+ *
+ * Use
+ *  This is a nice simple way of handling a dbox.  It means you can handle
+ *  everything from an in-line point of view. Functions can easily return
+ *  the results they need (like dbox_query()).  Unfortunately, it will only
+ *  work with menu dboxes, and will complain bitterly at you if you try and
+ *  do anything different.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *
+ * Returns
+ *  The field number that was clicked.
+ */
+
+dbox_field dbox_fillin(dbox d);
+
+/*
+ * void dbox__eventProcess(void)
+ *
+ * Use
+ *  Part of a private interface.  Do not use this function.
+ */
+
+void dbox__eventProcess(void);
+
+/*
+ * void dbox_eventProcess(void)
+ *
+ * Use
+ *  Compatibility with old programs.
+ */
+
+#define dbox_eventProcess(x) event_process()
+
+/*
+ * void dbox_setfield(dbox d,dbox_field f,char *string,...)
+ *
+ * Use
+ *  This routine will write the string into the field specified, if and only
+ *  if the field's data is indirected.  No checking is performed whatsoever,
+ *  though, so watch out!
+ *
+ * Parameters
+ *  dbox d == the dbox
+ *  dbox_field f == the field
+ *  char *string == a printf-style format string
+ */
+
+void dbox_setfield(dbox d,dbox_field f,char *string,...);
+
+/*
+ * void dbox_clickicon(dbox d,dbox_field f)
+ *
+ * Use
+ *  This routine neatly calls Interface, telling it to handle a click on the
+ *  field specified.  The clicks are handled in a stack-like manner.
+ *
+ * Parameters
+ *  dbox d == the dbox
+ *  dbox_field f == the field
+ */
+
+void dbox_clickicon(dbox d,dbox_field f);
+
+/*
+ * void dbox_unclick(void)
+ *
+ * Use
+ *  This routine declicks the last icon to be 'dbox_clickicon'ed.  If you
+ *  intend to delete the dbox after the click, you should use code like
+ *  this:
+ *
+ *    dbox_hide(d);
+ *    dbox_unclick();
+ *    dbox_delete(d);
+ */
+
+void dbox_unclick(void);
+
+/*
+ * void dbox_unclickAll(void)
+ *
+ * Use
+ *  This call dbox_unclick()s all the 'dbox_clickicon'ed icons in the dbox.
+ *  You shouldn't really need to use it.  It's mainly there for consistency
+ *  with Straylight's WimpLib v. 3.00.
+ */
+
+void dbox_unclickAll(void);
+
+/*
+ * void dbox_getfield(dbox d,dbox_field f,char *buffer,int size)
+ *
+ * Use
+ *  This is the same routine as in RISC_OSlib.  It returns the contents of
+ *  the icon text in the buffer.
+ */
+
+void dbox_getfield(dbox d, dbox_field f, char *buffer, int size);
+
+/*
+ * void dbox_scanfield(dbox d,dbox_field f,char *format,...)
+ *
+ * Use
+ *  Reads in scanf()-style the contents of a field.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field number
+ *  char *format == a scanf() style format string
+ */
+
+void dbox_scanfield(dbox d,dbox_field f,char *format,...);
+
+/*
+ * BOOL dbox_selecticon(dbox d,dbox_field f,dbox_action a)
+ *
+ * Use
+ *  This call will read the icon's state of selection and return it, and
+ *  optionally alter it as specified in the dbox_action parameter.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field you're interested in
+ *  dbox_action a == what you want to do with it
+ */
+
+BOOL dbox_selecticon(dbox d,dbox_field f,dbox_action a);
+
+/*
+ * BOOL dbox_shadeicon(dbox d,dbox_field f,dbox_action a)
+ *
+ * Use
+ *  This call will read the icon's state of shading and return it, and
+ *  optionally alter it as specified in the dbox_action parameter.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field you're interested in
+ *  dbox_action a == what you want to do with it
+ */
+
+BOOL dbox_shadeicon(dbox d,dbox_field f,dbox_action a);
+
+/*
+ * wimp_w dbox_syshandle(dbox d)
+ *
+ * Use
+ *  Returns the window handle used by the dbox specified, because your poor
+ *  underprivileged code can't access my nice data structure.  This is for
+ *  setting up things like calls to event_attachmenu and suchlike, which
+ *  don't know about cunning things like dboxes.
+ *
+ * Parameters
+ *  dbox d == the dbox you're interested in
+ *
+ * Returns
+ *  The window handle, which is a wimp_w
+ */
+
+wimp_w dbox_syshandle(dbox d);
+
+/*
+ * int dbox_getNumeric(dbox d,dbox_field f)
+ *
+ * Use
+ *  Reads an integer from a field.  If there is no semblance to a valid
+ *  integer, 0 is returned.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field to read from
+ */
+
+int dbox_getNumeric(dbox d,dbox_field f);
+
+/*
+ * void dbox_setNumeric(dbox d,dbox_field f,int val)
+ *
+ * Use
+ *  Writes the integer value specified into the field.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  dbox_field f == the field to set
+ *  int val == the integer value to write
+ */
+
+void dbox_setNumeric(dbox d,dbox_field f,int val);
+
+/*
+ * dbox_field dbox_helpField(void)
+ *
+ * Use
+ *  Returns field number that Help is interested in.
+ *
+ * Returns
+ *  Field number.
+ */
+
+dbox_field dbox_helpField(void);
+
+/*
+ * void dbox_setEmbeddedTitle(dbox d,dbox_field icon,BOOL moveDrag)
+ *
+ * Use
+ *  Gives the specified dialogue box an inbuilt title (in a group box, round
+ *  the outside, as seen in Elite).  This is drawn automatically normally,
+ *  but raw event handlers might want to do extra drawing, so the entry
+ *  point to the redraw code is also supplied.
+ *
+ * Parameters
+ *  dbox d == the dialogue box to do this to
+ *  dbox_field icon == the icon around which the title is to be drawn
+ *  BOOL moveDrag == allow a click on any of the dialogue box to move it
+ */
+
+void dbox_setEmbeddedTitle(dbox d,dbox_field icon,BOOL moveDrag);
+
+/*
+ * void dbox_drawEmbeddedTitle(wimp_redrawstr *r,void *handle)
+ *
+ * Use
+ *  Redraws an embedded title (as seen in Elite).  This is for the use of
+ *  raw event handlers, which might want to do this sort of thing, because
+ *  the redraw is normally handled automatically.
+ *
+ * Parameters
+ *  wimp_redrawstr *r == the redraw information I need
+ *  void *handle == a dbox, really.  This is for passing to wimpt_redraw.
+ */
+
+void dbox_drawEmbeddedTitle(wimp_redrawstr *r,void *handle);
+
+/*
+ * BOOL dbox_hasTitle(dbox d)
+ *
+ * Use
+ *  Returns TRUE if the given dialogue box has a window title bar.
+ *
+ * Parameters
+ *  dbox d == the dialogue box to check
+ *
+ * Returns
+ *  TRUE if the dialogue box has a title bar
+ */
+
+BOOL dbox_hasTitle(dbox d);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/event b/StraySrc/Libraries/Steel/h/event
new file mode 100644 (file)
index 0000000..f40fc20
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * event.h
+ *
+ * Handling and dispatching events
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __event_h
+#define __event_h
+
+/*----- Required headers --------------------------------------------------*/
+
+#ifndef __wimp_h
+  #include "wimp.h"
+#endif
+
+#ifndef __menu_h
+  typedef struct menu__menustr *menu;
+  typedef menu (*event_menu_maker)(void *handle);
+  typedef void (*event_menu_proc)(void *handle,char* hit);
+  #include "menu.h"
+#endif
+
+/*----- Type definitions --------------------------------------------------*/
+
+typedef enum
+{
+  event_MENUSELECT,
+  event_MENUSUBMENU,
+  event_MENUDELETE,
+  event_MENUHELP
+}
+event_menuPurpose;
+
+typedef void (*event_midbhandler)(wimp_w w,
+                                  int gadget,
+                                  void *handlea,
+                                  void *handleb,
+                                  void *handlec);
+
+/*----- Exported functions ------------------------------------------------*/
+
+void event__process(void);
+void event_process(void);
+#define event_process(x) dbox__eventProcess()
+
+event_menuPurpose event_whyMenuEvent(void);
+void event_returnMenuHelp(BOOL doit);
+
+/*
+ * BOOL event_attachMidbHandler(wimp_w w,
+ *                              event_midbhandler proc,
+ *                              int gadget,
+ *                              void *handlea,
+ *                              void *handleb,
+ *                              void *handlec)
+ *
+ * Use
+ *  Registers a function to be called by event when a menu button event is
+ *  received by a particular window.  Typically, this handler will display a
+ *  menu at the mouse coordinates, although you can do anything you want.
+ *
+ *  You shouldn't need to call this function very much.  It's really for
+ *  allowing other systems to supply menu attachment functions like event_-
+ *  attachmenu etc.
+ *
+ * Parameters
+ *  wimp_w == the window to which to attach the function
+ *  event_midbhandler proc == the function to call when a menu button event
+ *    is received for the window
+ *  others == arguments to be passed (unprocessed) to proc when it's called.
+ *
+ * Returns
+ *  TRUE if the attachment succeeded.
+ */
+
+BOOL event_attachMidbHandler(wimp_w w,
+                             event_midbhandler proc,
+                             int gadget,
+                             void *handlea,
+                             void *handleb,
+                             void *handlec);
+
+void event_attachedMenu(wimp_w w,
+                        menu *m,
+                        event_menu_maker *mk,
+                        event_menu_proc *proc,
+                        void **handle);
+
+/*
+ * void event_openMenu(menu it,event_menu_proc proc,void *handle)
+ * void event_makeMenu(event_menu_maker it,event_menu_proc proc,void *handle)
+ * void event_openIconbarMenu(...)
+ * void event_makeIconbarMenu(...)
+ *
+ * Use
+ *  Opens a menu onto the screen and tells your routine when it's finished.
+ *
+ * Parameters
+ *  menu it == the menu or menu maker procedure
+ *  event_menu_proc proc == the menu handler function
+ *  void *handle == it's jolly old handle
+ */
+
+void event_openMenu(menu it,event_menu_proc proc,void *handle);
+void event_makeMenu(event_menu_maker maker,
+                    event_menu_proc proc,
+                    void *handle);
+void event_openIconbarMenu(menu it,event_menu_proc proc,void *handle);
+void event_makeIconbarMenu(event_menu_maker maker,
+                           event_menu_proc proc,
+                           void *handle);
+
+/*
+ * void event_attachmenu(wimp_w w,menu m,event_menu_proc p,void *handle)
+ *
+ * Use
+ *  Attaches a menu to a window so that it opens when you click menu on it.
+ *
+ * Parameters
+ *  wimp_w w == the window to attach to
+ *  menu m == the menu to attach to it
+ *  event_menu_proc p == what to do when a menu item is chosen
+ *  void *handle == something else to send to p
+ */
+
+BOOL event_attachmenu(wimp_w w,menu m,event_menu_proc p,void *handle);
+
+/*
+ * void event_attachmenumaker(wimp_w w,
+ *                            event_menu_maker m,
+ *                            event_menu_proc p,
+ *                            void *handle)
+ *
+ * Use
+ *  Attaches a menu to a window so that it opens when you click menu on it.
+ *
+ * Parameters
+ *  wimp_w w == the window to attach to
+ *  event_menu_maker m == how to create the menu
+ *  event_menu_proc p == what to do when a menu item is chosen
+ *  void *handle == something else to send to p
+ */
+
+BOOL event_attachmenumaker(wimp_w w,
+                           event_menu_maker m,
+                           event_menu_proc p,
+                           void *handle);
+
+BOOL event_anywindows(void);
+
+BOOL event_is_menu_being_recreated(void);
+
+void event_clear_current_menu(void);
+
+void event_setmask (wimp_emask mask);
+
+wimp_emask event_getmask (void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/exception b/StraySrc/Libraries/Steel/h/exception
new file mode 100644 (file)
index 0000000..0f9e3c4
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Exception
+ *  Handles odd errors in Steel programs
+ *
+ * 1.00 (24 September 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __exception_h
+#define __exception_h
+
+#ifndef __setjmp_h
+#include <setjmp.h>
+#endif
+
+#ifndef __dll_h
+  #include "dll.h"
+#endif
+
+typedef struct
+{
+  jmp_buf j;
+  int sp;
+}
+exception_handler;
+
+/*
+ * int exception_registerHandler(exception_handler env)
+ *
+ * Use
+ *  Registers the current point as being a sensible place to go after an
+ *  exception.  This is implemented as a macro for the simple reason that 
+ *  things tend to go a tad wrong if you define your jmp_bufs in a function
+ *  and then return.
+ *
+ * Parameters
+ *  exception_handler env == an undefined variable of the type jmp_buf.
+ */
+
+#ifndef exception_registerHandler
+#define exception_registerHandler(exc)                                     \
+  (                                                                        \
+    ( exc.sp=_dll_setjmp() ),                                              \
+    ( exception__registerHandler((exc.j),setjmp(exc.j)) ?                  \
+      (_dll_longjmped(exc.sp),1) :                                         \
+      0)                                                                  \
+  )
+#endif
+
+
+/*
+ * void exception_generate(char *message,...)
+ *
+ * Use
+ *  Generates an ArmenLib exception, to be handled in an appropriate manner.
+ *
+ * Parameters
+ *  char *message == printf()-type format string
+ */
+
+void exception_generate(char *message,...);
+
+
+/*
+ * int exception__registerHandler(jmp_buf handler)
+ *
+ * Use
+ *  This routine is for the use of exception segment only, and should not
+ *  be called from your code.
+ */
+
+int exception__registerHandler(jmp_buf handler,int result);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/fileicon b/StraySrc/Libraries/Steel/h/fileicon
new file mode 100644 (file)
index 0000000..80f6e59
--- /dev/null
@@ -0,0 +1,80 @@
+/****************************************************************************
+ * This source file was written by Acorn Computers Limited. It is part of   *
+ * the RISCOS library for writing applications in C for RISC OS. It may be  *
+ * used freely in the creation of programs for Archimedes. It should be     *
+ * used with Acorn's C Compiler Release 3 or later.                         *
+ *                                                                          *
+ ***************************************************************************/
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Title:   fileicon.h
+ * Purpose: general display of a file icon in a window.
+ *
+ */
+
+# ifndef __fileicon_h
+# define __fileicon_h
+
+# ifndef __wimp_h 
+# include "wimp.h"
+# endif
+
+/*
+ * char *fileicon_spriteName(int filetype,char *name)
+ *
+ * Use
+ *  Returns the name of the sprite required to display the file whose name is given.
+ *
+ * Parameters
+ *  int filetype == the type of the file
+ *  char *name == the name of the file (may be full pathname)
+ *
+ * Returns
+ *  Pointer to read-only string.
+ */
+
+char *fileicon_spriteName(int filetype,char *name);
+
+/* ------------------------------ fileicon ---------------------------------
+ * Description:   Display an icon representing a file, in a given window
+ *
+ * Parameters:    wimp_w -- the given window's handle
+ *                wimp_i -- an existing icon
+ *                int filetype -- RISC OS file type (eg. 0x0ffe)
+ *                char *name -- the name of the file (may be pathname)
+ * Returns:       void.
+ * Other Info:    If you want a file icon in a dialogue box then pass that
+ *                dialogue box's window handle through first parameter,
+ *                    eg fileicon((wimp_w)dbox_syshandle(d),........)
+ *                The second parameter is the icon number of the required
+ *                icon, within the template set up using FormEd
+ *                For an example see the fileInfo template for !Edit.
+ *
+ */ 
+void fileicon(wimp_w, wimp_i, int filetype,char *name);
+
+#endif
+
+/* end fileicon.h */
+
+
diff --git a/StraySrc/Libraries/Steel/h/flex b/StraySrc/Libraries/Steel/h/flex
new file mode 100644 (file)
index 0000000..dee4e65
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * flex.h
+ *
+ * A shifting heap for RISC OS applications [APCS edition]
+ *
+ * © 1996-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Foreword: what are all those funny symbols in the comments? -------*
+ *
+ * This file has been marked up so that `lgrind' can process it to produce
+ * a pretty typeset listing.  Text enclosed by at signs is typeset like
+ * normal code.  There are some other neat things, but you get the idea.
+ * Note that you'll need a hacked version of lgrind.sty to get the rows
+ * of dashes typeset properly: they'll just look odd otherwise.
+ *
+ * Quite a lot of work has been put into this header file recently to make
+ * the descriptions of the routines clear and complete.  As a result, they
+ * probably read like excerpts from ISO 9899 (Computer Languages -- C).
+ */
+
+/* --- Standard-ish preamble --- *
+ *
+ * If I understand the compiler properly, then use special magic to prevent
+ * wasted cycles reading this file more than once.  The normal #ifndef
+ * stuff should keep GNU C happy because it's particularly intelligent like
+ * that; Norcroft C would rather have some magic pragmae specified.  The
+ * usual protection is added to stop compilers of the brain-damaged version
+ * of C invented by Bjarne Stroutrup generating duff linker symbols.
+ */
+
+#ifdef __CC_NORCROFT
+  #pragma force_top_level
+  #pragma include_only_once
+#endif
+
+#ifndef __flex_h
+#define __flex_h
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- How it all works --------------------------------------------------*
+ *
+ * In order to allow the blocks to move around, you need to tell flex where
+ * your pointer to each block is.  You do this with an anchor pointer (i.e.
+ * it points at your anchor for the block).  Flex is quite at liberty to
+ * change your anchors at any time it wants to, so if you don't want your
+ * blocks to move, don't call flex.  You must ensure that you always access
+ * data in flex blocks through the anchor, unless you're really sure the
+ * block won't move.
+ *
+ * Unlike older (Acorn) versions, Straylight flex doesn't ensure that the
+ * heap is always as compact as possible.  Instead, calling @flex_reduce@
+ * will attempt to compact the heap a little bit, so if you call it a lot,
+ * the heap will eventually become very compact.  It is envisaged that you
+ * call @flex_reduce@ every Wimp_Poll.  STEEL's @wimpt_poll@ does this for
+ * you.
+ *
+ * There is another call, @flex_compact@, which will compact the heap fully.
+ * This isn't terribly useful most of the time, since flex compacts itself
+ * if it runs out of memory.
+ *
+ * @flex_budge@ is not currently supported.  If there is a demand for it,
+ * it may be added in later, but probably not, because in the author's
+ * opinion it's just a request for unpredictable crashes.
+ */
+
+/* --- A flex anchor pointer --- *
+ *
+ * Due to Acorn brain-damage, this is a void ** instead of a void *, meaning
+ * that you end up with typecasts all over the shop.  Strictly speaking,
+ * such typecasts invoke undefined behaviour, although it works under all
+ * known ARM compilers, and if nyone tries to use this code on any other
+ * platform they get what they deserve, because the code's written in
+ * assembler ;-).
+ */
+
+typedef void **flex_ptr;
+
+/* --- @flex_init@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Initialises flex.  It doesn't bother to check that any
+ *             memory is available.
+ *
+ *             This is now just a macro which calls the @flex_dinit@
+ *             routine with a null pointer argument, forcing the heap to
+ *             be created in the task;s WimpSlot.
+ */
+
+#define flex_init(x) flex_dinit(0, 0);
+
+/* --- @flex_dinit@ --- *
+ *
+ * Arguments:  @const char *name@ = name of dynamic area to create, or null
+ *             @long max@ = maximum size of the area
+ *
+ * Returns:    ---
+ *
+ * Use:                Initialises flex and creates a (zero-sized) initial heap.
+ *             If the @name@ argument is not a null pointer, and the
+ *             current operating system is RISC OS 3.50 or later, then an
+ *             attempt is made to create the heap in a dynamic area.  If
+ *             this fails, or the attempt wasn't made, then the heap is
+ *             created in the task's wimpslot instead.
+ *
+ *             The author strongly urges you not to use the dynamic area
+ *             option without good reason.  Dynamic areas are limited to
+ *             16MB, to avoid problems with address space fragmentation
+ *             on machines with large quantities of real memory.
+ *
+ *             It is your responsibility to remove the dynamic area when
+ *             your program quits.  Usually you will do this by calling
+ *             @atexit(flex_die)@ just after initialisation of the heap,
+ *             although some other method may be necessary if you're not
+ *             using the complete C library for some reason.
+ */
+
+extern void flex_dinit(const char */* name */, long /* max */);
+
+/* --- @flex_die@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Tidies up anything as required when the program end.  It is
+ *             recommended that this be done via the C library's @atexit@
+ *             mechanism or some equivalent for freestanding applications.
+ *             This is only necessary when flex has created a dynamic area
+ *             for this application, although provided flex has initialised
+ *             it is never wrong to register this routine as a closedown
+ *             function.
+ */
+
+extern void flex_die(void);
+
+/* --- @flex_alloc@ --- *
+ *
+ * Arguments:  @flex_ptr anchor@ = address of the anchor for this block
+ *             @unsigned long size@ = size of the block required
+ *
+ * Returns:    Nonzero if the block was successfuly allocated, zero if
+ *             there wasn't enough memory.
+ *
+ * Use:                Allocates a shifting heap block.  The address is stored in
+ *             the pointer variable whose address was passed in @anchor@.
+ *             This pointer will be updated automatically when the block is
+ *             moved during compaction.  The size of the allocated block
+ *             will be at least @size@ bytes.
+ *
+ *             If there is not enough memory currently available in the
+ *             heap, flex may attempt to reclaim space by compacting the
+ *             heap.  As a result, other heap blocks may be moved; this was
+ *             not possible under the Acorn implementation.  The new block
+ *             will always be placed at the end of the heap.
+ *
+ *             During compaction, blocks only move to lower addresses.
+ *             When a block is grown, blocks above it move to higher
+ *             addresses.  As a consequence of this, a block at the base
+ *             of the heap will never be moved by flex.  This fact may be
+ *             useful, for example if you want to create a resizing non-
+ *             shifting heap.
+ */
+
+extern int flex_alloc(flex_ptr /* anchor*/, unsigned long /* size */);
+
+/* --- @flex_free@ --- *
+ *
+ * Arguments;  @flex_ptr@ anchor = address of the anchor for this block
+ *
+ * Returns:    ---
+ *
+ * Use:                Frees the memory occupied by the block whose anchor address
+ *             is given in @anchor@.  The memory is marked as unoccupied
+ *             and reclaimed during compaction later.  Therefore freeing
+ *             blocks is an extremely cheap operation, as it should be.
+ */
+
+extern void flex_free(flex_ptr /* anchor */);
+
+/* --- @flex_extend@ --- *
+ *
+ * Arguments:  @flex_ptr anchor@ = address of the anchor for the block
+ *             @unsigned long size@ = new size for the block
+ *
+ * Returns:    Nonzero if the resize was successful, or zero if there
+ *             wasn't enough memory.
+ *
+ * Use:                Changes the size of the block whose anchor address is given
+ *             by @anchor@; the new size will be at least @size@ bytes.
+ *
+ *             If @size@ is less than or equal to the current size of the
+ *             block, this operation cannot fail; any space at the end of
+ *             the block which is no longer required is marked as unused
+ *             and reclaimed later during compaction.  No blocks are moved.
+ *
+ *             If @size@ is greater than the current size of the block,
+ *             this operation might fail.  Also, flex might compact the
+ *             heap in an attempt to obtain enough free memory, so all
+ *             blocks might move.  Blocks above the one being grown will
+ *             move anyway; blocks below the one being resized did not
+ *             move in this way under the Acorn implementation.
+ */
+
+extern int flex_extend(flex_ptr /* anchor */, unsigned long /* newsize */);
+
+/* --- @flex_midextend@ --- *
+ *
+ * Arguments:  @flex_ptr anchor@ = address of the anchor for the block
+ *             @unsigned long at@ = index at which to insert or remove bytes
+ *             @long by@ = number of bytes to insert or remove
+ *
+ * Returns:    Nonzero if the resize was successful, or zero if there
+ *             wasn't enough memory.
+ *
+ * Use:                Changes the size of the block whose anchor address is given
+ *             by @anchor@.  Bytes are inserted or removed at the given
+ *             offset @at@, which must be between 0 and @flex_size(anchor)@
+ *             inclusive.  If @by@ is positive, then @by@ bytes are
+ *             inserted before the indexed byte; if it is negative, then
+ *             @-by@ bytes are deleted from just before @at@.  Always,
+ *             the data which was at offset @at@ is now at offset @at + by@.
+ *             The value of @by@ must be at least @-flex_size(anchor)@.
+ *
+ *             If @by@ is negative, this operation cannot fail; the bytes
+ *             are deleted by calling @memmove@, and any space at the end of
+ *             the block which is no longer required is marked as unused
+ *             and reclaimed later during compaction.  No blocks are moved.
+ *
+ *             If @by@ is positive, this operation might fail.  Also, flex
+ *             might compact the heap in an attempt to obtain enough free
+ *             memory, so all blocks might move.  Blocks above the one
+ *             being extended will move anyway; blocks below the one being
+ *             resized did not move in this way under the Acorn
+ *             implementation.  If the block was resized successfully, bytes
+ *             with undefined values are inserted at the correct place by
+ *             calling @memmove@.  This does not occur if the operation
+ *             failed.
+ */
+
+extern int flex_midextend(flex_ptr /* anchor */,
+                          unsigned long /* at */ , long /* by */);
+
+/* --- @flex_size@ --- *
+ *
+ * Arguments:  @flex_ptr anchor@ = address of the anchor for the block
+ *
+ * Returns:    The size of the block.  This is returned as a @signed int@
+ *             for historical reasons: old versions of flex returned this
+ *             value, and it's likely that old code will generate large
+ *             numbers of annoying and useless `implicit narrowing cast'
+ *             if I change the return type to @unsigned long@.  However,
+ *             if you read the value as an @unsigned long@ you won't get
+ *             get any warnings, and you'll also get the correct value.
+ *
+ * Use:                Returns the current size of the block in bytes.  This is
+ *             the `conceptual' size: the actual amount of memory occupied
+ *             by the block depends on unspecified bookkeeping overhead and
+ *             alignment applied to this value.  The size returned is the
+ *             @size@ argument passed to the most recent @flex_alloc@ or
+ *             @flex_extend@ call referring to this block, added to the
+ *             sum of all the @by@ arguments passed to @flex_midextend@
+ *             since then.
+ */
+
+extern int flex_size(flex_ptr /* anchor */);
+
+/* --- @flex_reduce@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Performs a small part of the compaction process.  Calling
+ *             @flex_reduce@ enough times will result in the heap becoming
+ *             compacted; further calls will have no effect.
+ *
+ *             The idea is that you call @flex_reduce@ periodically, e.g.,
+ *             when you receive a null event code.
+ */
+
+extern void flex_reduce(void);
+
+/* --- @flex_compact@ --- *
+ *
+ * Arguments:  ---
+ *
+ * Returns:    ---
+ *
+ * Use:                Fully compacts the heap.  This might be useful if you've
+ *             just done a lot of freeing and compaction by normal
+ *             processes takes too long.
+ */
+
+extern void flex_compact(void);
+
+/* --- kernel slot extension functions --- *
+ *
+ * Only @flex_dont_budge@ is supported at the moment.  Note that the
+ * interfaces as defined here are broken, because the size should really
+ * be an unsigned type.  However, since both routines simply do @return (0)@
+ * this isn't too much of a problem.
+ */
+
+extern int flex_dont_budge(int /* n */, void **/* p */);
+extern int flex_budge(int /* n */, void **/* p */);
+
+#ifdef __cplusplus
+  }
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/font b/StraySrc/Libraries/Steel/h/font
new file mode 100644 (file)
index 0000000..ef2fca5
--- /dev/null
@@ -0,0 +1,475 @@
+/****************************************************************************
+ * This source file was written by Acorn Computers Limited. It is part of   *
+ * the RISCOS library for writing applications in C for RISC OS. It may be  *
+ * used freely in the creation of programs for Archimedes. It should be     *
+ * used with Acorn's C Compiler Release 3 or later.                         *
+ *                                                                          *
+ ***************************************************************************/
+
+/*
+ * Title  : font.h
+ * Purpose: access to RISC OS font facilities
+ *
+ */
+
+# ifndef __font_h
+# define __font_h
+
+# ifndef __os_h
+# include "os.h"
+# endif
+
+# include "drawmod.h"
+
+typedef int font; /* abstract font handle */
+
+
+/* ---------------------------- font_cacheaddress --------------------------
+ * Description:   Informs caller of font cache used and font cache size.
+ *
+ * Parameters:    int *version -- version number
+ *                int *cacheused -- amount of font cache used (in bytes)
+ *                int *cachesize -- total size of font cache (in bytes)
+ * Returns:       os_error* -- possible error condition
+ * Other Info:    Version number is *100, so v.1.07 would be returned as 107.
+ *
+ */
+
+extern os_error * font_cacheaddress(int *version, int *cacheused, int *cachesize);
+
+
+/* ------------------------------- font_find -------------------------------
+ * Description:   Gives caller a handle to font, given its name.
+ *
+ * Parameters:    char *name -- the font name
+ *                int xsize, ysize -- x/y point size (in 16ths of a point)
+ *                int xres, yres -- x/y resolution in dots per inch
+ *                font* -- the returned font handle
+ * Returns:       Possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+extern os_error * font_find(
+  char* name,
+  int xsize, int ysize,    /* in 16ths of a point */
+  int xres, int yres,      /* dots per inch of resolution: 0->use default */
+  font*);                  /* result */
+
+
+/* ------------------------------- font_lose -------------------------------
+ * Description:   Informs font manager that a font is no longer needed
+ *
+ * Parameters:    font f -- the font
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+extern os_error * font_lose(font f);
+
+typedef struct font_def {
+    char name[16];
+    int xsize, ysize, xres, yres; /* as above */
+    int usage, age;
+} font_def;
+
+
+/* ------------------------------ font_readdef -----------------------------
+ * Description:   Get details about a font, given its handle.
+ * 
+ * Parameters:    font -- the font handle
+ *                font_def* -- pointer to buffer to hold returned details
+ * Returns:       possible error condition.
+ * Other Info:    This function fills in details re: font, into the supplied
+ *                buffer(a variable of type 'font_def').
+ *                fields of this buffer are as follows:
+ *                          name -- font name
+ *                          xsize, ysize -- x/y point size * 16
+ *                          xres, yres -- x/y resolution (dots per inch)
+ *                          usage -- number of times Font_FindFont has found
+ *                                   the font minus number of times 
+ *                                   Font_LoseFont has been used on it
+ *                          age -- number of font accesses made since this
+ *                                 one was last accessed.
+ *
+ */
+
+extern os_error * font_readdef(font, font_def*);
+
+typedef struct font_info {
+    int minx, miny, maxx, maxy;
+} font_info;
+
+
+/* ------------------------------- font_readinfo ---------------------------
+ * Description:   Informs caller of minimal area covering any character in
+ *                the font bounding box.
+ *
+ * Parameters:    font -- the font handle
+ *                font_info* -- pointer to buffer to hold returned details
+ * Returns:       possible error condition.
+ * Other Info:    Fills in details re: font in supplied buffer (variable of
+ *                type 'font_info').
+ *                fields of this buffer are as follows:
+ *                       minx -- min x coord in pixels (inclusive)
+ *                       maxx -- max x coord in pixels (inclusive)
+ *                       miny -- min y coord in pixels (exclusive)
+ *                       maxy -- max y coord in pixels (exclusive).
+ *
+ */
+
+extern os_error * font_readinfo(font, font_info*);
+
+
+typedef struct font_string {
+
+    char* s;
+    int x;                /* inout, in 1/72000 inch */
+    int y;                /* inout, in 1/72000 inch */
+    int split;            /* inout: space char, or -1 */
+                          /* on exit, = count of space or printable */
+    int term;             /* inout, index into s */
+
+    } font_string;
+
+
+/* -------------------------------- font_strwidth --------------------------
+ * Description:   Determine 'width' of string.
+ *
+ * Parameters:    font_string *fs -- the string, with fields:
+ *                              s -- string itself
+ *                              x -- max x offset before termination
+ *                              y -- max y offset before termination
+ *                          split -- string split character
+ *                           term -- index of char to terminate by
+ * Returns:       possible error condition.
+ * Other Info:    On exit fs fields hold:
+ *                              s -- unchanged
+ *                              x -- x offset after printing string
+ *                              y -- y offset after printing string
+ *                          split -- no. of split chars found
+ *                                   no. of printable chars if split was -1
+ *                           term -- index into string at which terminated.
+ *
+ */
+
+extern os_error * font_strwidth(font_string *fs);
+
+
+/* paint options */
+#define font_JUSTIFY 0x01   /* justify text */
+#define font_RUBOUT  0x02   /* rub-out box required */
+#define font_ABS     0x04   /* absolute co-ordinates */
+        /* 8 not used */
+#define font_OSCOORDS 0x10  /* os coords supplied (otherwise 1/72000 inch) */
+
+
+/* ------------------------------- font_paint -----------------------------
+ * Description:   Paint the given string at coords x,y.
+ * 
+ * Parameters:    char * -- the string
+ *                int options -- set using "paint options" defined above
+ *                int x, y -- coords (either os or 1/72000 inch)
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+  
+extern os_error * font_paint(char*, int options, int x, int y);
+
+
+/* ------------------------------- font_caret -----------------------------
+ * Description:   Set colour, size and position of the caret.
+ *
+ * Parameters:    int colour -- EORed onto screen
+ *                int height -- in OS coordinates
+ *                int flags -- bit 4 set ==> OS coords, else 1/72000 inch
+ *                int x,y   -- x/y coords
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+extern os_error *font_caret(int colour, int height, int flags, int x, int y);
+
+
+/* ---------------------------- font_converttoos ---------------------------
+ * Description:   Converts coords in 1/72000 inch to OS units.
+ *
+ * Parameters:    int x_inch, y_inch -- x/y coords in 1/72000 inch
+ *                int *x_os, *y_os -- x/y coords in OS units
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+extern os_error *font_converttoos(int x_inch, int y_inch, int *x_os, int *y_os);
+
+
+/* --------------------------- font_converttopoints ------------------------
+ * Description:   Converts OS units to 1/72000 inch.
+ *
+ * Parameters:    int x_os, y_os -- x/y coords in OS units
+ *                int *x_inch, *y_inch -- x/y coords in 1/72000 inch
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+extern os_error *font_converttopoints(int x_os, int y_os, int *x_inch, int *y_inch);
+
+
+/* ------------------------------- font_setfont ----------------------------
+ * Description:   Sets up font used for subsequent painting or size-requests.
+ *
+ * Parameters:    font -- the font handle
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+extern os_error * font_setfont(font);
+
+
+typedef struct font_state {
+
+       font f;
+       int back_colour;
+       int fore_colour;
+       int offset;
+
+       } font_state;
+
+
+/* --------------------------------- font_current --------------------------
+ * Description:   Informs caller of current font state.
+ *
+ * Parameters:    font_state *f -- pointer to buffer to hold font state
+ * Returns:       possible error condition.
+ * Other Info:    returned buffer(into variable of type 'font_state'):
+ *                         font f -- handle of current font
+ *                         int back_colour -- current background colour
+ *                         int fore_colour -- current foreground colour
+ *                         int offset -- foreground colour offset.
+ *
+ */
+
+extern os_error *font_current(font_state *f);
+
+
+/* -------------------------------- font_future ----------------------------
+ * Description:   Informs caller of font characteristics after a future
+ *                font_paint.
+ *
+ * Parameters:    font_state *f -- pointer to buffer to hold font state
+ * Returns:       possible error condition.
+ * Other Info:    buffer contents:
+ *                          font f -- handle of font which would be selected
+ *                          int back_colour -- future background colour
+ *                          int fore_colour -- future foreground colour
+ *                          int offset -- foreground colour offset.
+ *
+ */
+
+extern os_error *font_future(font_state *f);
+
+
+/* ------------------------------- font_findcaret --------------------------
+ * Description:   Informs caller of nearest point in a string to the caret
+ *                position.
+ *
+ * Parameters:    font_string *fs -- the string
+ *                         fields:  char *s -- the string itself
+ *                                  int x,y -- x/y coords of caret
+ * Returns:       possible error condition.
+ * Other Info:    returned fields of fs as in font_strwidth.
+ *
+ */
+
+extern os_error *font_findcaret(font_string *fs);
+
+
+/* ----------------------------- font_charbbox -----------------------------
+ * Description:   Informs caller of bounding box of char in given font.
+ *
+ * Parameters:    font -- the font handle
+ *                char -- the ASCII character
+ *                int options -- only relevant option if font_OSCOORDS
+ *                font_info * -- pointer to buffer to hold font info
+ * Returns:       possible error condition.
+ * Other Info:    if OS coords are used and font has been scaled, box may
+ *                be surrounded by area of blank pixels.
+ *
+ */
+
+extern os_error * font_charbbox(font, char, int options, font_info*);
+
+
+/* -------------------------- font_readscalefactor -------------------------
+ * Description:   Informs caller of x and y scale factors used by font.
+ *                manager for converting between OS coords and 1/72000 inch
+ *
+ * Parameters:    int *x, *y -- returned scale factors
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+extern os_error *font_readscalefactor(int *x, int *y);
+
+
+/* ---------------------------- font_setscalefactor -----------------------
+ * Description:   Sets the scale factors used by font manager.
+ *
+ * Parameters:    int x,y -- the new scale factors
+ * Returns:       possible error condition.
+ * Other Info:    scale factors may have been changed by another application
+ *                well-behaved applications save and restore scale factors.
+ *
+ */
+
+extern os_error *font_setscalefactor(int x, int y);
+
+
+/* ------------------------------- font_list -------------------------------
+ * Description:   Gives name of an available font.
+ *
+ * Parameters:    char* -- pointer to buffer to hold font name
+ *                int*  -- count of fonts found (0 on first call)
+ * Returns:       possible error condition.
+ * Other Info:    count is -1 if no more names
+ *                typically used in loop until count == -1.
+ *
+ */
+
+extern os_error * font_list(char*, int*);
+
+                 
+/* ------------------------------ font_setcolour ---------------------------
+ * Description:   Sets the current font(optionally), changes foreground
+ *                and background colours, and offset for that font.
+ * 
+ * Parameters:    font -- the font handle (0 for current font)
+ *                int background, foreground -- back/foreground colours
+ *                int offset -- foreground offset colour (-14 to +14) 
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+extern os_error * font_setcolour(font, int background, int foreground, int offset);
+
+
+#define font_BlueGun  0x01000000 /* 8-bit field: phsical colour blue gun.  */
+#define font_GreenGun 0x00010000 /* 8-bit field: phsical colour green gun. */
+#define font_RedGun   0x00000100 /* 8-bit field: phsical colour red gun.   */
+
+
+/* --------------------------- font_setpalette -----------------------------
+ * Description:   Sets the anti-alias palette
+ *
+ * Parameters:    int background -- logical background colour
+ *                int foreground -- logical foreground colour
+ *                int offset -- foreground colour offset
+ *                int physical_back -- physical background colour
+ *                int physical_fore -- physical foreground colour
+ * Returns:       possible error condition.
+ * Other Info:    physical_back and physical_fore are of the form:
+ *                        0xBBGGRR00 (see #defines above).
+ *
+ */
+
+extern os_error *font_setpalette(int background, int foreground, int offset, 
+                          int physical_back, int physical_fore);
+
+typedef struct font_threshold {
+
+     char offset;
+     char thresholds[15];
+
+     } font_threshold;
+                                        
+
+/* ------------------------- font_readthresholds ---------------------------
+ * Description:   Reads the list of threshold values that the font manager
+ *                uses when painting characters.
+ *
+ * Parameters:    font_theshold *th -- pointer to result buffer
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+extern os_error *font_readthresholds(font_threshold *th);
+
+
+/* ------------------------- font_setthresholds ----------------------------
+ * Description:   Sets up threshold values for painting colours.
+ *
+ * Parameters:    font_threshold *th -- pointer to a threshold table
+ * Returns:       possible error condition.
+ * Other Info:    none.
+ *
+ */
+
+extern os_error *font_setthresholds(font_threshold *th);
+
+
+/* ------------------------- font_findcaretj -------------------------------
+ * Description:   Finds nearest point where the caret can go (using
+ *                justification offsets).
+ *
+ * Parameters:    font_string *fs -- the string (set up as in font_findcaret)
+ *                int offset_x, offset-y -- the justification offsets
+ * Returns:       possible error condition.
+ * Other Info:    if offsets are both zero then same as font_findcaret.
+ *
+ */
+
+extern os_error *font_findcaretj(font_string *fs, int offset_x, int offset_y);
+
+
+/* ------------------------ font_stringbbox --------------------------------
+ * Description:   Measures the size of a string (without printing it).
+ *
+ * Parameters:    char *s -- the string
+ *                font_info *fi -- pointer to buffer to hold font info
+ * Returns:       possible error condition.
+ * Other Info:    fields returned in fi are:
+ *                    minx, miny -- bounding box min x/y
+ *                    maxx, maxy -- bounding box min x/y.
+ *
+ */
+   
+extern os_error *font_stringbbox(char *s, font_info *fi);
+
+/* new SWIS */
+
+/*---------------------------------------------------------------------------*/
+/*Routines to create a draw module path object from calls to font_paint*/
+
+typedef enum {font_CONVERT, font_IGNORE, font_ERROR} font_action_on_bitmap;
+
+extern os_error
+   *font_output_to_null
+   (  BOOL add_hints,
+      BOOL output_skeleton,
+      font_action_on_bitmap action_on_bitmap
+   );
+
+extern os_error *font_output_size (size_t *size);
+
+extern os_error
+   *font_output_to_buffer
+   (  drawmod_buffer *buff_ptr,
+      BOOL add_hints,
+      BOOL output_skeleton,
+      font_action_on_bitmap action_on_bitmap
+   );
+
+extern os_error *font_output_to_screen (void);
+
+# endif
+
+/* end font.h */
diff --git a/StraySrc/Libraries/Steel/h/fontMenu b/StraySrc/Libraries/Steel/h/fontMenu
new file mode 100644 (file)
index 0000000..b1eb081
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * fontMenu
+ *  creates (and handles) a hierarchical font menu
+ *
+ * v. 1.00 (22 August 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __fontMenu_h
+#define __fontMenu_h
+
+#ifndef __menu_h
+#include "menu.h"
+#endif
+
+#ifndef __event_h
+#include "event.h"
+#endif
+
+/*
+ * menu fontMenu_createFontMenu(BOOL includeSystem)
+ *
+ * Use
+ *  Creates a hierarchical font menu and returns a handle.  If the menu is
+ *  out-of-date it will be recreated, if not the old handle will be
+ *  returned.  You must call this before using routines such as
+ *  fontMenu_make() (so that the system knows whether you want to use a
+ *  menu containing the system font or not).  The returned pointer will be
+ *  NULL if there are no fonts.  
+ *
+ * Parameters
+ *  BOOL includeSystem == whether you want to include a 'System font' item
+ *
+ * Returns
+ *  A menu handle for the menu.
+ */
+
+menu fontMenu_createFontMenu(BOOL includeSystem);
+
+/*
+ * menu fontMenu(BOOL includeSystem)
+ *
+ * Use
+ *  Compatibility.  Don't use this function.
+ */
+
+menu fontMenu(BOOL includeSystem);
+
+/*
+ * char *fontMenu_fontname(int item1,int item2)
+ *
+ * Use
+ *  Returns the font name given by the the menu hit passed.  Example code:
+ *
+ *  switch (hit[n])
+ *  {
+ *    ...
+ *    case FONTMENU:
+ *      {
+ *        char *fontname=fontMenu_fontname(hit[n+1],hit[n+2]);
+ *        ...
+ *      }
+ *      break;
+ *    ...
+ *  }
+ *
+ *  Type promotion does the rest!  If the hits give a silly result, then a
+ *  null string (not a null pointer!) is returned.
+ *
+ *  You should check for the system font yourself (hit[n+1]==1).
+ *
+ * Parameters
+ *  int item1 == the item number in the main menu
+ *  int item2 == the item number in the submenu
+ *
+ * Returns
+ *  A pointer to a read-only string.
+ */
+
+char *fontMenu_fontname(int item1,int item2);
+
+/*
+ * void fontMenu_submenu(BOOL includeSystem)
+ *
+ * Use
+ *  Opens a font menu as the submenu of another menu.
+ *
+ * Parameters
+ *  BOOL includeSystem == whether we need to include a system font item.
+ */
+
+void fontMenu_submenu(BOOL includeSystem);
+
+/*
+ * void fontMenu_findFont(char *name,int *item1,int *item2)
+ *
+ * Use
+ *  Finds a font in the font list.  Returns the result in two integers,
+ *  which are the menu item numbers in the main font menu and the submenu
+ *  respectively.  -1 is returned as the first item number if the font
+ *  wasn't found.
+ *
+ * Parameters
+ *  char *name == the (case sensitive) name of the font.
+ *  int *item1 == where to store the first item number.
+ *  int *item2 == where to store the second item number.
+ */
+
+void fontMenu_findFont(char *name,int *item1,int *item2);
+
+/*
+ * void fontMenu_tick(int item1,int item2)
+ *
+ * Use
+ *  Ticks the item specified.  Only one font may be ticked at a time.  If
+ *  the menu item specified is silly, no item will be ticked.  No range
+ *  checking is performed.
+ *
+ * Parameters
+ *  int item1 == the item number in the main menu
+ *  int item2 == the item number in the submenu
+ */
+
+void fontMenu_tick(int item1,int item2);
+
+/*
+ * void fontMenu_tickGivenName(char *name)
+ *
+ * Use
+ *  Ticks the item specified by it's name.  If the name is silly, no item
+ *  will be ticked.
+ *
+ * Parameters
+ *  char *name == the font name to tick
+ */
+
+void fontMenu_tickGivenName(char *name);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/heap b/StraySrc/Libraries/Steel/h/heap
new file mode 100644 (file)
index 0000000..9ed167c
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * heap
+ *
+ * A heap system in a flex block
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __heap_h
+#define __heap_h
+
+#ifndef __size_t
+#define __size_t 1
+typedef unsigned int size_t;   /* from <stddef.h> */
+#endif
+
+typedef struct heap_infostr
+{
+  int size;                                   /* Size of the whole heap    */
+  int free;                                   /* Heap space currently free */
+  int largest;                                /* Size of the largest block */
+}
+heap_infostr;
+
+/*
+ * void heap_init(void)
+ *
+ * Use
+ * Initialises the heap system for use.  This must be called before
+ *  flex_alloc to ensure that the system gets the first block and so it
+ *  doesn't move around.  heap doesn't mind this, but your data probably will
+ *  (if it doen't, why don't you use flex?).
+ */
+
+void heap_init(void);
+
+/*
+ * heap_infostr heap_info(void)
+ *
+ * Use
+ *  Describes the heap's current status.
+ *
+ * Returns
+ *  Structure type described above.
+ */
+
+heap_infostr heap_info(void);
+
+/*
+ * void *heap_alloc(size_t size)
+ *
+ * Use
+ *  Allocates a block of at least a given size from a heap.  If the heap is
+ *  not big enough, more is claimed from the operating system.  A NULL
+ *  pointer is returned if a block of suitable size could not be found.
+ *
+ * Parameters
+ *  size_t size == size of block required
+ *
+ * Returns
+ *  Pointer to block
+ */
+
+void *heap_alloc(size_t size);
+
+/*
+ * void heap_free(void *block)
+ *
+ * Use
+ *  Frees a block allocated using heap_alloc.  It tries to shrink the heap
+ *  as much as possible and to coagulate adjacent free blocks together.
+ *
+ * Parameters
+ *  void *block == pointer to the block to free
+ */
+
+void heap_free(void *block);
+
+/*
+ * void *heap_realloc(void *block,int newSize)
+ *
+ * Use
+ *  Changes the size of a heap block.  If possible, the block's position is
+ *  is unchanged, but this may not always be the case.
+ *
+ *  Note that changing a block's size to 0 is permitted.  Passing a NULL
+ *  pointer will probably result in severe heap death.
+ *
+ * Parameters
+ *  void *block == pointer to the block to change
+ *  int newSize == the new size to make the block
+ *
+ * Returns
+ *   Pointer to where the block has been moved to, or a NULL pointer if the
+ *   allocation failed.
+ */
+
+void *heap_realloc(void *block,int newSize);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/help b/StraySrc/Libraries/Steel/h/help
new file mode 100644 (file)
index 0000000..c61317e
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Help
+ *  Provides support for the !Help application
+ *
+ * v. 1.00 (25 July 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __help_h
+#define __help_h
+
+/*
+ * void help_startHelp(void)
+ *
+ * Use
+ *  This call sets up a new message to bundle off to !Help.
+ */
+
+void help_startHelp(void);
+
+/*
+ * void help_addLine(char *line,...)
+ *
+ * Use
+ *  This call adds a line of text to the current help message.  If the
+ *  message starts off blank, then the line will become the current message,
+ *  otherwise the message will have a '|m' followed by the new line appended
+ *  on the end.
+ *
+ * Parameters
+ *  char *line == a printf()-style format string for what you want to say.
+ */
+
+void help_addLine(char *line,...);
+
+/*
+ * void help_endHelp(void)
+ *
+ * Use
+ *  This call bundles off the current help message to the application.
+ */
+
+void help_endHelp(void);
+
+/*
+ * void help_readFromIcon(void)
+ *
+ * Use
+ *  This call will read a help message from the icon the help system is
+ *  interested in, and tack it on the end of the message.  The help message
+ *  should be stored in the icon's validation string with the command 'H'
+ *  (e.g. validation string == "A0-9;B3;HType a number in this icon."
+ */
+
+void help_readFromIcon(void);
+
+/*
+ * BOOL help_wasHelp(void)
+ *
+ * Use
+ *  Informs caller if the last event was a help request.
+ *
+ * Returns
+ *  TRUE if it was.
+ */
+
+BOOL help_wasHelp(void);
+
+/*
+ * void help_readFromMenu(char *prefix,int hit[])
+ *
+ * Use
+ *  Converts the menu hit structure into a message tag and then reads the
+ *  message and adds it to the help message being constructed.
+ *  The message tag is constructed from the prefix, followed by a character
+ *  for each entry in the hit structure.  The characters are in order (first
+ *  to last) 0-9,A-Z,a-z, giving 62 entries.  This WILL be enough for any
+ *  *reasonable* menu...
+ *
+ * Parameters
+ *  char *prefix == 
+ *  int hit[] == a menu hit structure as passed to a menu handler.
+ */
+
+void help_readFromMenu(char *prefix,int hit[]);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/ibicon b/StraySrc/Libraries/Steel/h/ibicon
new file mode 100644 (file)
index 0000000..e744389
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+ * ibicon
+ *  proper icon bar mangement (multiple icons, etc.)
+ *
+ * © 1992-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __ibicon_h
+#define __ibicon_h
+
+#ifndef __sprite_h
+  #include "sprite.h"
+#endif
+
+#ifndef __wimp_h
+  #include "wimp.h"
+#endif
+
+#ifndef __event_h
+  #include "event.h"
+#endif
+
+#ifndef __menu_h
+  #include "menu.h"
+#endif
+
+/*-----------------------------------------------------
+
+  DOs and DON'Ts
+
+  DO...
+
+  + only use the functions provided for manipulating your icons
+
+  DON'T...
+
+  + try and use event_attachmenu() or win_register_event_handler()
+    like you do for baricon.
+  + delete icons without these functions
+
+  baricon will be retained for compatibility, but it will use these
+  routines rather than going it alone.
+
+-----------------------------------------------------*/
+
+typedef struct ibicon__ibiconstr *ibicon;
+
+typedef enum
+{
+  ibicon_NOTHING,          /* Nothing interesting.  This is for use by     */
+                           /* ibicon, and will NOT be passed to handlers   */
+  ibicon_LEFTCLICK,        /* Click with left button                       */
+  ibicon_RIGHTCLICK,       /* Click with right button                      */
+  ibicon_LOAD,             /* Attempt to load file from disk               */
+  ibicon_SAVE,             /* Attempt to import file                       */
+  ibicon_HELP              /* Request for help about the icon              */
+}
+ibicon_eventType;
+
+typedef void (*ibicon_handler)(ibicon i,ibicon_eventType e,void *handle);
+typedef BOOL (*ibicon_rawHandler)(ibicon i,wimp_eventstr *e,void *handle);
+
+/* These are places you can put your icon */
+
+#define ibicon_LEFT -2     /* Show icon on left side (device)              */
+#define ibicon_RIGHT -1    /* Show icon on right side (application)        */
+#define ibicon_LEFTSEARCHLEFT -5
+#define ibicon_LEFTSEARCHRIGHT -6
+#define ibicon_RIGHTSEARCHLEFT -7
+#define ibicon_RIGHTSEARCHRIGHT -8
+
+/* A couple of ways of specifying odd sprite areas */
+
+#define ibicon_WIMPAREA ((sprite_area *)1)
+#define ibicon_SYSTEMAREA ((sprite_area *)0)
+
+/*
+ * ibicon ibicon_find(wimp_i icon)
+ *
+ * Use
+ *  Return the ibicon handle of an icon.
+ *
+ * Parameters
+ *  wimp_i icon == the icon to find
+ */
+
+ibicon ibicon_find(wimp_i icon);
+
+
+/*
+ * wimp_i ibicon_syshandle(ibicon i)
+ *
+ * Use
+ *  Returns the low-level WIMP handle for the icon concerned.
+ *
+ * Parameters
+ *  ibicon i == the icon whose handle is desired
+ *
+ * Returns
+ *  The WIMP icon handle for the icon
+ */
+
+wimp_i ibicon_syshandle(ibicon i);
+
+/*
+ * void ibicon_setPriority(int priority)
+ *
+ * Use
+ *  Sets the priority with which to create icons under RISC OS 3.
+ *
+ * Parameters
+ *  int priority == the new setting
+ */
+
+void ibicon_setPriority(int priority);
+
+/*
+ * ibicon ibicon_create
+ * (
+ *   int where,
+ *   char *spritename,
+ *   sprite_area *sprarea,
+ *   char *text,
+ *   int maxtext
+ * )
+ *
+ * Use
+ *  Creates an icon in the icon bar.  Where is up to you.  Specify a
+ *  sprite-only icon by passing 0 for text.  Use the macros to define where
+ *  and what area you want the sprite from.
+ *
+ * Parameters
+ *  int where == what part of the icon bar you want to put the icon in.
+ *    Macros are defined for the RISC OS 2 possibilities.  Wait for the
+ *    RISC OS 3 macros, or just pass a window handle.
+ *  char *spritename == the name of the sprite to display
+ *  sprite_area *sprarea == the area from which the sprite area comes.  Use
+ *    the macros provided for odd things like the WIMP area.  If you have
+ *    text as well, then this will be ignored anyway.
+ *  char *text == the text for the icon.  May be a NULL pointer, for no
+ *    text.
+ *  int maxtext == the max length the text entry can be.  If 0 then the
+ *    length of the text given will be used.
+ *
+ * Returns
+ *  A handle to the icon if successful, or 0 if not.
+ */
+
+ibicon ibicon_create
+(
+  int where,
+  char *spritename,
+  sprite_area *sprarea,
+  char *text,
+  int maxtext
+);
+
+/*
+ * void ibicon_changeSprite(ibicon i,char *newsprite)
+ *
+ * Use
+ *  Chnage the sprite displayed in an icon
+ *
+ * Parameters
+ *  ibicon i == the icon to change
+ *  char *newsprite == the new name
+ */
+
+void ibicon_changeSprite(ibicon i,char *newsprite);
+
+/*
+ * void ibicon_changeText(ibicon i,char *newtext)
+ *
+ * Use
+ *  Change the text of an icon.
+ *
+ * Parameters
+ *  ibicon i == the icon to change
+ *  char *text == the new text to display
+ */
+
+void ibicon_changeText(ibicon i,char *newtext);
+
+/*
+ * void ibicon_attachMenu
+ * (
+ *   ibicon i,
+ *   menu m,
+ *   menu_selectProc sel,
+ *   menu_helpProc help,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Attaches a menu to an icon in the icon bar
+ *
+ * Parameters
+ *  ibicon i == the icon to attach to
+ *  menu m == the menu to attach
+ *  menu_selectProc sel == a handler function for the menu
+ *  menu_helpProc help == a help processor for the menu
+ *  void *handle == a handle passed to the handler
+ */
+
+void ibicon_attachMenu
+(
+  ibicon i,
+  menu m,
+  menu_selectProc sel,
+  menu_helpProc help,
+  void *handle
+);
+
+
+/*
+ * void ibicon_attachMenuMaker
+ * (
+ *   ibicon i,
+ *   event_menu_maker m,
+ *   menu_selectProc sel,
+ *   menu_helpProc help,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Attaches a menu maker to an icon in the icon bar
+ *
+ * Parameters
+ *  ibicon i == the icon to attach to
+ *  event_menu_maker m == the menu maker to attach
+ *  menu_selectProc sel == a handler function for the menu
+ *  menu_helpProc help == a help processor for the menu
+ *  void *handle == a handle passed to the handler
+ */
+
+void ibicon_attachMenuMaker
+(
+  ibicon i,
+  event_menu_maker m,
+  menu_selectProc sel,
+  menu_helpProc help,
+  void *handle
+);
+
+/*
+ * void ibicon_removeIcon(ibicon i)
+ *
+ * Use
+ *  Removes an icon totally from the icon bar.
+ *
+ * Parameters
+ *  ibicon i == the icon to vape
+ */
+
+void ibicon_removeIcon(ibicon i);
+
+/*
+ * void ibicon_eventHandler(ibicon i,ibicon_handler p,void *handle)
+ *
+ * Use
+ *  Attaches the handler to an icon.
+ *
+ * Parameters
+ *  ibicon i == the icon to attach
+ *  ibicon_handler p == the handler
+ *  void *handle == a pointer to pass to the handler
+ */
+
+void ibicon_eventHandler(ibicon i,ibicon_handler p,void *handle);
+
+/*
+ * void ibicon_rawEventHandler(ibicon i,ibicon_rawHandler p,void *handle)
+ *
+ * Use
+ *  Attaches a raw event handler.  This can 'vet' events before ibicon gets
+ *  it mucky mits on them.
+ *
+ * Parameters
+ *  ibicon i == the icon to attach
+ *  ibicon_rawHandler p == the handler
+ *  void *handle == a pointer to pass to the handler
+ */
+
+void ibicon_rawEventHandler(ibicon i,ibicon_rawHandler p,void *handle);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/interface b/StraySrc/Libraries/Steel/h/interface
new file mode 100644 (file)
index 0000000..494893d
--- /dev/null
@@ -0,0 +1,74 @@
+/************************************
+
+ interface segment of Wimp routines
+
+   Controls low-level access to
+   Interface module.
+
+   Version 1.00 (29 June 1991)
+   © 1991-1998 Straylight
+
+************************************/
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __interface_h
+
+#ifndef __sprite_h
+  #include "sprite.h"
+#endif
+
+/* Structure for passing to interface_set/releaseworkareapointer(). */
+
+typedef struct
+{
+  wimp_w win;
+  wimp_box b;
+  char *ptr;
+}
+interface_pointerstr;
+
+/*
+ * void interface_spritearea(sprite_area *a)
+ *
+ * Use
+ *  Sets the sprite area for use with interface_pollpointer().
+ *
+ * Parameters
+ *  sprite_area *a == the sprite area containing all the pointers
+ */
+
+void interface_spritearea(sprite_area *a);
+
+/* These are just bindings to the SWI commands provided by the Interface module. */
+
+os_error *interface_slabButton(wimp_mousestr *mouse);
+os_error *interface_render3dWindow(wimp_redrawstr *rdr);
+os_error *interface_initialise(wimp_t task);
+os_error *interface_closeDown(wimp_t task);
+os_error *interface_poll(wimp_eventstr *evnt,wimp_t task);
+os_error *interface_setWorkareaPointer(interface_pointerstr *s);
+os_error *interface_removeWorkareaPointer(interface_pointerstr *s);
+
+#define __interface_h
+
+#endif
+
+/* End of interface.h */
diff --git a/StraySrc/Libraries/Steel/h/keyString b/StraySrc/Libraries/Steel/h/keyString
new file mode 100644 (file)
index 0000000..cea338c
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * keyString
+ *  Converts keypresses to strings
+ *
+ * © 1992-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __keyString_h
+#define __keyString_h
+
+/*
+ * char *keyString(int key)
+ *
+ * Use
+ *  Converts a keypress as returned by the WIMP into a string suitable for
+ *  displaying to the user, for example as a keyboard shortcut.  The routine
+ *  handles the following cases:
+ *
+ *  * Function keys and Print, possibly with <Shift> and/or <Ctrl>
+ *  * Alphabetic keys with <Ctrl>
+ *
+ *  Note: f12 is not trapped; neither is <Ctrl> M, since this is <Return>.
+ *
+ * Parameters
+ *  int key == the key pressed
+ *
+ * Returns
+ *  A pointer to a READ-ONLY string, or 0 if the key was invalid.
+ */
+
+char *keyString(int key);
+
+/*
+ * char *keyString_convert(int key,BOOL mnu)
+ *
+ * Use
+ *  Converts a STEEL extended keypress into a string suitable for displaying
+ *  either as a short-cut string in a dialogue box or in a menu
+ *
+ * Parameters
+ *  int key == the keypress to translate
+ *  BOOL mnu == TRUE to create menu shortcut string, FALSE for dbox
+ *
+ * Returns
+ *  A pointer to the string, or 0
+ */
+
+char *keyString_convert(int key,BOOL mnu);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/listbox b/StraySrc/Libraries/Steel/h/listbox
new file mode 100644 (file)
index 0000000..2c5e116
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+ * ListBox
+ *  Provides handling for list boxes
+ *
+ * v. 1.00 (27 July 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __listbox_h
+#define __listbox_h
+
+#ifndef __wimp_h
+#include "wimp.h"
+#endif
+
+/*
+ * Abstract listbox handle
+ */
+typedef struct list__liststr *list;
+
+#ifndef __pane_h
+#include "pane.h"
+#endif
+
+/*
+ * An abstraction for list items
+ */
+typedef struct list__item *list_item;
+
+#define list_NOITEM ((list_item)0)
+#define list_CLOSE ((list_item)-2)
+#define list_HELP ((list_item)-3)
+
+typedef void (*list_eventhandler)(list l,list_item item,void *handle);
+typedef BOOL (*list_raweventhandler)(list l,wimp_eventstr *e,void *handle);
+typedef void (*list_redrawhandler)(list l,
+                                   list_item i,
+                                   wimp_redrawstr *r,
+                                   wimp_box *b,
+                                   char *text,
+                                   BOOL selected,
+                                   void *handle);
+
+typedef enum
+{
+  list_RESETSTATE,
+  list_SETSTATE,
+  list_READSTATE,
+  list_TOGGLESTATE
+}
+list_action;
+
+/*
+ * void list_isPane(list l,pane p)
+ *
+ * Use
+ *  This routine is part of the private interface between the listbox and
+ *  pane segments.  Do *NOT* try to call it in your own code.
+ */
+
+void list_isPane(list l,pane p);
+
+/*
+ * list list_create(char *name,BOOL alterSize)
+ *
+ * Use
+ *  Creates a new list box window, and returns a handle to it.  Initially,
+ *  there are no items, and the list box is not shown.  The function returns
+ *  0 if the call fails for one reason or another (not enough windows or
+ *  memory).
+ *
+ * Parameters
+ *  char *name == the name to match in the template file
+ *  BOOL alterSize == TRUE if we are allowed to change the box's visible
+ *    size.
+ *
+ * Returns
+ *  An abstract handle for the list box.
+ */
+
+list list_create(char *name,BOOL alterSize);
+
+/*
+ * void list_selectItem(list l,list_item item)
+ *
+ * Use
+ *  Makes the item the currently selected one.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  list_item item == the item number
+ */
+
+void list_selectItem(list l,list_item item);
+
+/*
+ * list_item list_selected(list l)
+ *
+ * Use
+ *  Returns the currently selected item of the list.
+ *
+ * Parameters
+ *  list l == the list handle
+ *
+ * Returns
+ *  The item number of the currently selected item.
+ */
+
+list_item list_selected(list l);
+
+/*
+ * char *list_itemData(list l,list_item i)
+ *
+ * Use
+ *  Returns the string for an item
+ *
+ * Parameters
+ *  list l == the list handle
+ *  list_item i == the item's handle
+ *
+ * Returns
+ *  A pointer to the item's data
+ */
+
+char *list_itemData(list l,list_item i);
+
+/*
+ * list_item list_addItem(list l,char *data,BOOL inOrder)
+ *
+ * Use
+ *  Adds a new piece of data into the list.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  char *data == the data (as a char *, because most of the time you'll
+ *    want to be using character strings).
+ *
+ * Returns
+ *  A handle for the list item.
+ */
+
+list_item list_addItem(list l,char *data,BOOL inOrder);
+
+/*
+ * list_item list_findItem(list l,char *data)
+ *
+ * Use
+ *  Searches through a list and returns the item number of the item whose
+ *  data matches that given in the function.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  char *data == the data to compare with
+ *
+ * Returns
+ *  The item number of the item, or list_NOITEM if no match.
+ */
+
+list_item list_findItem(list l,char *data);
+
+/*
+ * void list_removeItem(list l,list_item i)
+ *
+ * Use
+ *  Removes an item from the list.
+ *
+ * Parameters
+ *  list l == the list's handle
+ *  list_item i == the item number
+ */
+
+void list_removeItem(list l,list_item i);
+
+/*
+ * void list_delete(list l)
+ *
+ * Use
+ *  Destroys a list totally.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_delete(list l);
+
+/*
+ * void list_updatePosition(list l)
+ *
+ * Use
+ *  Writes the position of the listbox back into the template, so any new
+ *  list boxes created from the template open at that position.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_updatePosition(list l);
+
+/*
+ * BOOL list_link(list l)
+ *
+ * Use
+ *  Links a list box to a WIMP window.  If the list is already linked,
+ *  nothing happens.  The list box is not displayed.
+ *
+ * Parameters
+ *  list l == the list handle
+ *
+ * Returns
+ *  TRUE if the link succeeded (may run out of windows!)
+ */
+
+BOOL list_link(list l);
+
+/*
+ * void list_unlink(list l)
+ *
+ * Use
+ *  Unlinks the list box from its window and deletes the window.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_unlink(list l);
+
+/*
+ * void list_unlinkNoUpdate(list l)
+ *
+ * Use
+ *  Unlinks a list from its window without storing its final position  back
+ *  in memory.  Note that list_delete() calls list_unlink(), so make sure
+ *  you call this routine before deleting the listbox it you want to prevent
+ *  the position being written back.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_unlinkNoUpdate(list l);
+
+/*
+ * void list_update(list l,BOOL really)
+ *
+ * Use
+ *  Enables or disables list updating (i.e. whether the listbox resizes and
+ *  redraws itself between every operation).  If you're going to do some
+ *  lengthy operation, it would be a good idea to turn update off first,
+ *  and then turn it on again afterwards.
+ *
+ *  Note that this is an all-or-nothing thing -- no counter is kept.
+ *
+ * Parameters
+ *  list l == the listbox which we're messing about with
+ *  BOOL really == whether to turn the update on or off
+ */
+
+void list_update(list l,BOOL really);
+
+/*
+ * void list_display(list l)
+ *
+ * Use
+ *  Displays a list box on-screen
+ *
+ * Parameters
+ *  list l == the list
+ */
+
+void list_display(list l);
+
+/*
+ * void list_openDisplaced(list l)
+ *
+ * Use
+ *  Opens the listbox on-screen displaced from its previous position by
+ *  the normal 48 OS units.  It must be unlinked using list_unlinkNoUpdate()
+ *  before deletion.
+ *
+ * Parameters
+ *  list l == the list handle.
+ */
+
+void list_openDisplaced(list l);
+
+/*
+ * void list_hide(list l)
+ *
+ * Use
+ *  Stops the list box being displayed
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_hide(list l);
+
+/*
+ * wimp_w list_syshandle(list l)
+ *
+ * Use
+ *  Returns the WIMP window handle being used for the list box.
+ *
+ * Parameters
+ *  list l == the list
+ *
+ * Returns
+ *  The window handle (a wimp_w).
+ */
+
+wimp_w list_syshandle(list l);
+
+
+/*
+ * void list_eventHandler(list l,list_eventhandler proc,void *handle)
+ *
+ * Use
+ *  Attaches an event handler to the list box.  Most won't actually need
+ *  this, just the stand-alone ones, or ones that do clever-dick things.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  list_eventhandler proc == the procedure to handle events
+ *  void *handle == the jolly olde pointer to the user-defined data
+ */
+
+void list_eventHandler(list l,list_eventhandler proc,void *handle);
+
+/*
+ * void list_rawEventHandler(list l,list_raweventhandler proc,void *handle)
+ *
+ * Use
+ *  Attaches the raw event handler procedure to the list box.  You can then
+ *  vet any events coming into the list box and have your wicked way with
+ *  them. 
+ *
+ * Parameters
+ *  list l == the list handle
+ *  list_raweventhandler proc == the raw event handler routine
+ *  void *handle == the (now-famous) caller defined handle.
+ */
+
+void list_rawEventHandler(list l,list_raweventhandler proc,void *handle);
+
+/*
+ * void list_redrawHandler(list l,list_redrawhandler rdr,void *handle)
+ *
+ * Use
+ *  Attaches a replacement redraw handler to the list box.  The new handler
+ *  redraws individual items in the list.  It must fill in the box it is
+ *  passed, because the WIMP does not fill in the background.  The part of
+ *  the list box not populated by items is filled in the window background
+ *  colour automatically.  Using this, you can achieve quite a pleasing
+ *  effect by making the background grey (colour 1) and the actual item
+ *  backgrounds white (colour 0), indicating clearly the bottom of the list.
+ *
+ *  You can also implement other things like items being shaded etc.
+ *
+ * Parameters
+ *  list l == the list to which the redraw handler is to be attached
+ *  list_redrawhandler == the replacement redraw routine (or 0 to cancel)
+ *  void *handle == a pointer to pass the redraw routine
+ */
+
+void list_redrawHandler(list l,list_redrawhandler rdr,void *handle);
+
+/* 
+ * void list_widthAdd(list l,int extra)
+ *
+ * Use
+ *  Since redraw handlers can basically do whatever they want to for each
+ *  items, the list manager no longer really has any idea about how wide an
+ *  item is.  Since the main thing displayed in lists is text, it is assumed
+ *  that the width of an item is the width of the longest piece of text plus
+ *  a constant (e.g. for a sprite on the side).  If this is not so, I'll
+ *  have to rethink this bit...
+ *
+ * Parameters
+ *  list l == the list we're setting the width of
+ *  int extra == the constant to add to each item
+ */
+
+void list_widthAdd(list l,int extra);
+
+/*
+ * void list_setItemHeight(list l,int height)
+ *
+ * Use
+ *  Sets the height of items in the specified list box.  By default, the
+ *  height is 44 OS units (the height of menu items).  This should be 
+ *  sufficient for most purposes.
+ *
+ * Parameters
+ *  list l == the list to set
+ *  int height == the new height of each item, in OS units
+ */
+
+void list_setItemHeight(list l,int height);
+
+/*
+ * int list_items(list l)
+ *
+ * Use
+ *  Informs the caller how many items there are in a list
+ *
+ * Parameters
+ *  list l == the list handle
+ *
+ * Returns
+ *  The number of items in a list
+ */
+
+int list_items(list l);
+
+/*
+ * void list_doForItems
+ * (
+ *   list l,
+ *   void (*proc)(list l,list_item i,void *handle),
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Performs an operation on all of the items in a list box.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  void (*proc)(list l,list_item i,void *handle) == the procedure to use
+ *  void *handle == a handle to pass to the procedure.
+ */
+
+void list_doForItems
+(
+  list l,
+  void (*proc)(list l,list_item i,void *handle),
+  void *handle
+);
+
+/*
+ * void list_attachData(list l,list_item i,void *data)
+ *
+ * Use
+ *  Attaches a data structure to a list item.  This is a bit of an
+ *  afterthought really.
+ *
+ * Parameters
+ *  list l == the list
+ *  list_item i == the list item
+ *  void *data == a pointer to the data structure
+ */
+
+void list_attachData(list l,list_item i,void *data);
+
+/*
+ * void *list_getData(list l,list_item i)
+ *
+ * Use
+ *  Returns the data attached to a list item.  The item number
+ *  may have changed etc. with items deleted and added.
+ *
+ * Parameters
+ *  list l == the list
+ *  list_item i == the list item number
+ *
+ * Returns
+ *  A pointer to the data structure attached using list_attachData().
+ */
+
+void *list_getData(list l,list_item i);
+
+/*
+ * void list_multipleSelection(list l)
+ *
+ * Use
+ *  Makes a list able to handle a multiple selection.
+ *
+ * Parameters
+ *  list l == the list handle
+ */
+
+void list_multipleSelection(list l);
+
+/*
+ * BOOL list_addToSelection(list l,list_item i,list_action a)
+ *
+ * Use
+ *  Adds an item to the current selection.
+ *
+ * Parameters
+ *  list l == the list
+ *  list_item i == the list item
+ *  list_action a == what to do with the state
+ *
+ * Returns
+ *  The previous state of the item
+ */
+
+BOOL list_addToSelection(list l,list_item i,list_action a);
+
+/*
+ * void list_doForSelected
+ * (
+ *   list l,
+ *   void (*proc)(list l,list_item i,void *handle),
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Performs a user-specified action for each selected list item.
+ *
+ * Parameters
+ *  list l == the list box
+ *  void (*proc)(list l,list_item i,void *handle) == the procedure to do the
+ *    thing
+ *  void *handle == a handle to pass to the routine.
+ */
+
+void list_doForSelected
+(
+  list l,
+  void (*proc)(list l,list_item i,void *handle),
+  void *handle
+);
+
+
+/*
+ * void list_selectAll(list l,list_action a)
+ *
+ * Use
+ *  Selects all the items in a list.
+ *
+ * Parameters
+ *  list l == the list
+ *  list_action a == what to do with the icons (list_READSTATE ain't all
+ *    that useful, and list_TOGGLESTATE is downright wierd).
+ */
+
+void list_selectAll(list l,list_action a);
+
+/*
+ * int list_numSelected(list l)
+ *
+ * Use
+ *  Informs the caller how many items are selected.
+ *
+ * Parameters
+ *  list l == the list handle
+ *
+ * Returns
+ *  An integer indicating the number of selected items
+ */
+
+int list_numSelected(list l);
+
+/*
+ * int list_itemToIndex(list l,list_item i)
+ *
+ * Use
+ *  Translates a list_item into the index of the item.  This avoids
+ *  assumptions about the mapping of indices to item numbers.  In the
+ *  future, for example, the list_item data type may be used as a pointer to
+ *  the list item data structure in memory.  Most of the time this will be
+ *  irrelevant anyway.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  list_item i == the list item to translate
+ *
+ * Returns
+ *  An integer giving the index of the item.  The first item has index 0, as
+ *  for C arrays.
+ */
+
+int list_itemToIndex(list l,list_item i);
+
+/*
+ * list_item list_indexToItem(list l,int index)
+ *
+ * Use
+ *  Performs the reverse operation to the previous routine.  It will
+ *  translate an index to a list_item.
+ *
+ * Parameters
+ *  list l == the list handle
+ *  int index == the index of the item required
+ *
+ * Returns
+ *  The equivalent list_item for the item.
+ */
+
+list_item list_indexToItem(list l,int index);
+
+/*
+ * list_item list_helpItem(list l)
+ *
+ * Use
+ *  Returns the item that Help is interested in.
+ *
+ * Parameters
+ *  list l == the list's handle
+ *
+ * Returns
+ *  A list_item
+ */
+
+list_item list_helpItem(list l);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/mem b/StraySrc/Libraries/Steel/h/mem
new file mode 100644 (file)
index 0000000..5dc8e7f
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * mem
+ *  Store handling for Steel
+ *
+ * version 1.00 6 September 1991
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __mem_h
+#define __mem_h
+
+#ifndef __size_t
+#define __size_t
+typedef unsigned int size_t;
+#endif
+
+typedef void *(*mem_allocProc)(size_t size);
+typedef void (*mem_freeProc)(void *ptr);
+
+/*
+ * void mem_flexdInit(void)
+ *
+ * Use
+ *  Initialises flex system.  If flex is already initialised, nothing
+ *  happens.  This call should be used in preference to flex_init().
+ */
+
+void mem_flexdInit(const char *name, long max);
+#define mem_flexInit(x) mem_flexdInit(0, 0)
+
+/*
+ * void mem_heapInit(void)
+ *
+ * Use
+ *  Initialises heap system.  If heap is already initialised, nothing
+ *  happens.  If flex is not initialised, it is initialised for you.  This
+ *  call should be used in preference to heap_init().  Note that unlike
+ *  earlier versioms, this call will NOT set up ArmenLib to use heap by
+ *  default.  This would be duplicating the functionality of mem_useHeap().
+ */
+
+void mem_heapInit(void);
+
+/*
+ * void mem_useMalloc(void)
+ *
+ * Use
+ *  Makes ArmenLib use malloc() etc. for memory allocation.
+ */
+
+void mem_useMalloc(void);
+
+/*
+ * void mem_useHeap(void)
+ *
+ * Use
+ *  Makes ArmenLib use heap_alloc() etc. for memory allocation.  It is
+ *  initialised if necessary.
+ */
+
+void mem_useHeap(void);
+
+/*
+ * void mem_useUser(mem_allocProc alloc,mem_freeProc free)
+ *
+ * Use
+ *  Makes ArmenLib use your own user-defined memory allocation procedures.
+ *
+ * Parameters
+ *  mem_allocProc alloc == a routine to allocate a block of memory.  If a
+ *    block of sufficient size cannot be allocated, return 0.  Problems
+ *    about allocating blocks of 0 size are handled before your routine is
+ *    called.
+ *  mem_freeProc free == a routine to free a block of memory.  A valid
+ *    pointer will be passed to your routine.
+ */
+
+void mem_useUser(mem_allocProc alloc,mem_freeProc free);
+
+/*
+ * void mem_useRMA(void)
+ *
+ * Use
+ *  Makes ArmenLib use the RMA for memory allocation.
+ */
+
+void mem_useRMA(void);
+
+/*
+ * void *mem_RMAalloc(size_t size)
+ *
+ * Use
+ *  Allocates a block of memory from the relocatable module area.
+ *
+ * Parameters
+ *  size_t size == the size of the block
+ *
+ * Returns
+ *  A pointer to the block (or 0)
+ */
+
+void *mem_RMAalloc(size_t size);
+
+/*
+ * void mem_RMAfree(void *ptr)
+ *
+ * Use
+ *  Frees a block allocated using RMAalloc.
+ *
+ * Parameters
+ *  void *ptr == a pointer to the block.
+ */
+
+void mem_RMAfree(void *ptr);
+
+/*
+ * void *mem_alloc(size_t size)
+ *
+ * Use
+ *  Allocates a block of memory using malloc (or heap if initialised).  If
+ *  size is zero, or allocation fails then a NULL pointer is returned.
+ *
+ * Parameters
+ *  size_t size == how big you want the block.
+ *
+ * Returns
+ *  A pointer to the block allocated.
+ */
+
+void *mem_alloc(size_t size);
+
+/*
+ * void mem_free(void *ptr)
+ *
+ * Purpose
+ *  Frees a block of memory.  It must have been allocated using mem_alloc().
+ *  If ptr is NULL, then mem_free() does nothing.
+ *
+ * Parameters
+ *  void *ptr == the pointer returned by mem_alloc()
+ */
+
+void mem_free(void *ptr);
+
+/*
+ * size_t mem_sizeOfBlock(void *ptr)
+ *
+ * Use
+ *  Returns the allocated size of the block.
+ *
+ * Parameters
+ *  void *ptr == the pointer to the block
+ *
+ * Returns
+ *  The size of the block.
+ */
+
+size_t mem_sizeOfBlock(void *ptr);
+
+/*
+ * void *mem_reAlloc(void *ptr,size_t newSize)
+ *
+ * Use
+ *  Alters the size of the block given.  If the block could not be resized,
+ *  its contents are unchanged.  Note that the block may move as a result of
+ *  this call.
+ *
+ * Parameters
+ *  void *ptr == a pointer to the block.  This may be NULL, in which case,
+ *    this call behaves exactly like mem_alloc().
+ *  size_t newSize == the new size to make the block.  This may be zero, in
+ *    which case the block is freed.
+ *
+ * Returns
+ *  A pointer to the block.
+ */
+
+void *mem_reAlloc(void *ptr,size_t newSize);
+
+/*
+ * void mem_allowFlexBudge(BOOL allow)
+ *
+ * Use
+ *  A slightly more sensible way to allow flex store to be shunted around.
+ *
+ * Parameters
+ *  BOOL allow == whether you want flex store to be shifted around willy-
+ *    nilly.
+ */
+
+void mem_allowFlexBudge(BOOL allow);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/menu b/StraySrc/Libraries/Steel/h/menu
new file mode 100644 (file)
index 0000000..2c68f3b
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * menu
+ *
+ *  A working menu system
+ *
+ * © 1992-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __menu_h
+#define __menu_h
+
+#ifndef __wimp_h
+#include "wimp.h"
+#endif
+
+#ifndef __event_h
+typedef struct menu__menustr *menu;
+typedef menu (*event_menu_maker)(void *handle);
+typedef void (*event_menu_proc)(void *handle, char* hit);
+#include "event.h"
+#endif
+
+typedef void (*menu_selectProc)(int hits[],void *handle);
+typedef void (*menu_helpProc)(int hits[],void *handle);
+
+/*---------------------------------------------------------------------------
+
+  The syntax of menu strings is an extension of the system used by the
+  RISC_OSlib menu segment:
+
+    menu_description ::= <flags> <item> <sep> { <flags> <item> <sep> }
+    flags ::= '!' | '~' | '>' | ' ' | '+'
+    sep ::= ',' | '|'
+    item ::= <a bunch of other characters>
+
+  flags have meanings as follows:
+
+    ' ' has no effect
+    '~' shades the item
+    '>' item has a menu dbox attached
+    '!' item is ticked
+    '+' open submenu even if item is shaded
+
+---------------------------------------------------------------------------*/
+
+/*
+ * menu menu_new(char *title,char *items)
+ *
+ * Use
+ *  Creates a menu as per the old RISC_OSlib system.
+ *
+ * Parameters
+ *  char *title == the menu title (truncated to 12 chars if necessary)
+ *  char *items == the menu item text.  Data is indirected where required.
+ *
+ * Returns
+ *  A pointer to the menu if successful, or a NULL pointer if not.
+ */
+
+menu menu_new(char *title,char *items);
+
+/*
+ * void menu_submenu(menu main,int item,menu submenu)
+ *
+ * Use
+ *  Attaches a menu as a submenu, but it will put in a submenu warning flag,
+ *  so the user-friendly too-many-windows messages come up right!
+ *
+ * Parameters
+ *  menu main == the main menu
+ *  int item == the menu item number
+ *  menu submenu == the submenu
+ */
+
+void menu_submenu(menu main,int item,menu submenu);
+
+/*
+ * void menu_dispose(menu *m,BOOL recurse)
+ *
+ * Use
+ *  Kill off a menu or menu tree.  Won't work on submenus.
+ *
+ * Parameters
+ *  menu *m == pointer to menu to Domestos-ise.
+ *  BOOL recurse == do we want to kill its submenus too?
+ */
+
+void menu_dispose(menu *m,BOOL recurse);
+
+/*
+ * wimp_menustr *menu_syshandle(menu m)
+ *
+ * Use
+ *  Returns pointer to actual menu structure.
+ *
+ * Parameters
+ *  menu m == menu handle for which structure is required.
+ *
+ * Returns
+ *  A pointer to the WIMP menu structure.
+ */
+
+wimp_menustr *menu_syshandle(menu m);
+
+/*
+ * void menu_extend(menu m,char *items)
+ *
+ * Use
+ *  Extend the given menu by a bit.
+ *
+ * Parameters
+ *  menu m == the menu to extend
+ *  char *items == the items to tag on the end
+ */
+
+void menu_extend(menu m,char *items);
+
+/*
+ * void menu_setflags(menu m,int i,BOOL tick,BOOL shade)
+ *
+ * Use
+ *  Changes menu item properties.
+ *
+ * Parameters
+ *  menu m == menu to change
+ *  int i == menu item to change
+ *  BOOL tick == tick the item
+ *  BOOL shade == shade the item
+ */
+
+void menu_setflags(menu m,int i,BOOL tick,BOOL shade);
+
+/*
+ * void menu_make_writeable(menu m,int i,char *buff,int bufflen,char *valid)
+ *
+ * Use
+ *  Makes a menu entry writable (sorry about the spelling - it's Acorn's
+ *  fault).
+ *
+ * Parameters
+ *  menu m == the menu in question
+ *  int i == the item to be handled
+ *  char *buff == where the data is to reside
+ *  int bufflen == max length of data that can be crammed into buff
+ *  char *valid == validation string (0 for none)
+ */
+
+void menu_make_writeable(menu m,int i,char *buff,int bufflen,char *valid);
+
+/*
+ * void menu_make_sprite(menu m,int i,char *name)
+ *
+ * Use
+ *  Turns a menu entry into a sprite.  Utterly useless, but there you go...
+ *
+ * Parameters
+ *  menu m == the menu we're dealing with
+ *  int i == the item to sprite-ise
+ *  char *name == the sprite name
+ */
+
+void menu_make_sprite(menu m,int i,char *name);
+
+/*
+ * void menu_redirectItem(menu m,int i,char *buff,int bufflen,char *valid)
+ *
+ * Use
+ *  Allows you to make a menu item's data point to your workspace, so you
+ *  can change the text of an item at any time.  The buffer length isn't
+ *  important.
+ *
+ * Parameters
+ *  menu m == the menu in question
+ *  int i == the item to be handled
+ *  char *buff == where the data is to reside
+ *  int bufflen == max length of data that can be crammed into buff
+ *  char *valid == validation string (0 for none)
+ */
+
+void menu_redirectItem(menu m,int i,char *buff,int bufflen,char *valid);
+
+/*
+ * void menu_minWidth(menu m,int min)
+ *
+ * Use
+ *  Sets the minimum permissable width of a menu (in characters).  Note that
+ *  this call will not make the menu thinner than the width calculated
+ *  during menu_new or menu_extend.
+ *
+ * Parameters
+ *  menu m == the menu to change
+ *  int min == the minumum allowable width fro the menu in characters.  If
+ *    0 is passed, the width reverts to the calculated width.
+ */
+
+void menu_minWidth(menu m,int min);
+
+/*
+ * void menu_settitle(menu m,char *title)
+ *
+ * Use
+ *  Change a menu title.
+ *
+ * Parameters
+ *  menu m == the menu to change
+ *  char *title == the new title
+ */
+
+void menu_settitle(menu m,char *title);
+
+/*
+ * void menu_attach
+ * (
+ *   wimp_w w,
+ *   menu m,
+ *   menu_selectProc sel,
+ *   menu_helpProc help,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Basically equivalent to event_attachmenu, only it handles help requests
+ *  neatly etc.  Source code compatibility *cannot* be assured, because I
+ *  want to be able to expand this routine to cater for later changes.  I
+ *  will try to soften the blow (if any) by supplying macros that will work
+ *  with older programs, but I can't guarantee anything.
+ *
+ * Parameters
+ *  wimp_w w == the window to attach to
+ *  menu m == the menu to attach
+ *  menu_selectProc sel == procedure to handle most selection-type events
+ *  menu_helpProc help == procedure to handle help requests for the menu
+ */
+
+void menu_attach
+(
+  wimp_w w,
+  menu m,
+  menu_selectProc sel,
+  menu_helpProc help,
+  void *handle
+);
+
+/*
+ * void menu_attachMaker
+ * (
+ *   wimp_w w,
+ *   event_menu_maker m,
+ *   menu_selectProc sel,
+ *   menu_helpProc help,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  This routine deals with event_attachmenumaker as menu_attach deals with
+ *  event_attachmenu.
+ *
+ * Parameters
+ *  wimp_w w == the window to attach to
+ *  menu m == the menu to attach
+ *  menu_selectProc sel == procedure to handle most selection-type events
+ *  menu_helpProc help == procedure to handle help requests for the menu
+ */
+
+void menu_attachMaker
+(
+  wimp_w w,
+  event_menu_maker m,
+  menu_selectProc sel,
+  menu_helpProc help,
+  void *handle
+);
+
+/*
+ * void menu_open(menu m,menu_selectProc sel,menu_helpProc help,void *handle)
+ *
+ * Use
+ *  Analagous to event_openMenu().
+ *
+ * Parameters
+ *  As above.
+ */
+
+void menu_open(menu m,menu_selectProc sel,menu_helpProc help,void *handle);
+
+/*
+ * void menu_make(event_menu_maker m,menu_selectProc sel,menu_helpProc help,void *handle)
+ *
+ * Use
+ *  Analagous to event_makeMenu().
+ *
+ * Parameters
+ *  As above.
+ */
+
+void menu_make(event_menu_maker m,menu_selectProc sel,menu_helpProc help,void *handle);
+
+/*
+ * void menu_saveHandler(wimp_w w,menu_handler *h)
+ *
+ * Use
+ *  Saves information about the menu handle for the given window in the
+ *  block specified.  This can be used *only* to restore the handler for a
+ *  window later (although it needn't be the same one).  Note too that the
+ *  window need not have to have menu handlers registered using the menu
+ *  calls, or even have any at all.
+ *
+ * Parameters
+ *  wimp_w w == the window whose menu handlers we are to save
+ *  menu_handler *h == pointer to a chunk of memory to fill in.
+ */
+
+typedef struct menu_handler
+{
+  BOOL doneByMenu;
+  union
+  {
+    struct
+    {
+      menu m;
+      event_menu_maker make;
+      menu_selectProc sel;
+      menu_helpProc help;
+      void *handle;
+    }
+    m;
+    struct
+    {
+      menu m;
+      event_menu_maker make;
+      event_menu_proc proc;
+      void *handle;
+    }
+    e;
+  }
+  info;
+}
+menu_handler;
+
+void menu_saveHandler(wimp_w w,menu_handler *h);
+
+/*
+ * void menu_restoreHandler(wimp_w w,menu_handler *h)
+ *
+ * Use
+ *  Restores handlers from a structure filled in by menu_saveHandler.
+ *
+ * Parameters
+ *  wimp_w w == the window whose handlers we are to set up.
+ *  menu_handler *h == pointer to a chunk of memory filled in correctly.
+ */
+
+void menu_restoreHandler(wimp_w w,menu_handler *h);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/menuExt b/StraySrc/Libraries/Steel/h/menuExt
new file mode 100644 (file)
index 0000000..ad8d1f5
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * menuExt
+ *  A little menu extension for things like submenus.
+ *
+ * v. 1.00 (10 August 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __menuExt_h
+#define __menuExt_h
+
+#ifndef __menu_h
+#include "menu.h"
+#endif
+
+#define menuExt_submenu(a,b,c) menu_submenu(a,b,c)
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/msgs b/StraySrc/Libraries/Steel/h/msgs
new file mode 100644 (file)
index 0000000..ed918e2
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * msgs.h
+ *
+ * Handling message files
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __msgs_h
+#define __msgs_h
+
+/*----- Implementation limits ---------------------------------------------*
+ *
+ * These limits are not enforced.  Woe betides anyone who oversteps them.
+ */
+
+#define msgs_TAG_MAX 20
+#define msgs_MSG_MAX 1024
+#define msgs_VARIANT_MAX 10
+
+/*----- Functions ---------------------------------------------------------*/
+
+/*
+ * void msgs_init(void)
+ *
+ * Use
+ *  Loads the messages file `Messages' using msgs_readfile.
+ */
+
+void msgs_init(void);
+
+/*
+ * void msgs_readfile(char *name)
+ *
+ * Use
+ *  Merges the file named into the current messages.  Duplicates are likely
+ *  to cause problems, so try to avoid them.  The file is found using the
+ *  res_findname mechanism.
+ *
+ * Parameters
+ *  char *name == pointer to the name of the messages file
+ */
+
+void msgs_readfile(char *name);
+
+/*
+ * char *msgs_lookup(char *tag)
+ *
+ * Use
+ *  Looks up a message given its tag.  The tag may optionally be followed by
+ *  a default string, which is returned if the message is not found.  If no
+ *  default is supplied, and the message tag is not found, the tag is
+ *  returned.
+ *
+ * Parameters
+ *  char *tag == pointer to tag string to find
+ */
+
+char *msgs_lookup(char *tag);
+
+/*
+ * void msgs_delete(void)
+ *
+ * Use
+ *  Removes all messages from memory.
+ */
+
+void msgs_delete(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/nopoll b/StraySrc/Libraries/Steel/h/nopoll
new file mode 100644 (file)
index 0000000..f55f2d6
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * nopoll
+ *  Provides handling for a dbox without polling (for error boxes and so
+ *  on
+ *
+ * v. 1.00 (30 July 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __nopoll_h
+#define __nopoll_h
+
+#ifndef __dbox_h
+#include "dbox.h"
+#endif
+
+/*---------------------------------------------------------------------------
+
+  Support is provided for three action buttons, here referred to as 'OK',
+  'Cancel' and 'Other'.  Fair enough?  Good.  'OK' is the default action
+  button, which may also be selected by pressing return.  Pressing escape
+  is equivalent to clicking Cancel.  The 'Other' button (good, eh?) has no
+  keyboard equivalent.  To indicate that you don't want a particular button
+  to exist, just pass -1 as the number.
+
+---------------------------------------------------------------------------*/
+
+#define nopoll_OK 1
+#define nopoll_CANCEL 2
+#define nopoll_OTHER 3
+
+#define nopoll_NOBUTTON -1
+
+/*
+ * Flags for how you want the box to appear
+ */
+typedef enum
+{
+  nopoll_ASIS,
+  nopoll_CENTRE,
+  nopoll_ONPTR
+}
+nopoll_appearFlags;
+
+/*
+ * void nopoll_showDbox(dbox d,nopoll_appearFlags flags)
+ *
+ * Use
+ *  Displays a dbox on-screen without polling the WIMP.  Useful
+ *  for copyright windows and things.
+ *
+ * Parameters
+ *  dbox d == the dbox handle
+ *  nopoll_appearFlags flags == how you want the dbox to appear
+ */
+
+void nopoll_showDbox(dbox d,nopoll_appearFlags flags);
+
+/*
+ * int nopoll_doDbox
+ * (
+ *   dbox d,
+ *   nopoll_appearFlags flags,
+ *   dbox_field OK,
+ *   dbox_field cancel,
+ *   dbox_field other
+ * )
+ *
+ * Use
+ *  Opens a NoPoll dialogue box, continues until it gets a sensible result,
+ *  closes it, and then returns the result.
+ *
+ * Parameters
+ *  dbox d == the dialogue box you want to use for this.
+ *  nopoll_appearFlags flags == how you want the box to appear (see above)
+ *  dbox_field OK == the number of the OK button
+ *  dbox_field cancel == the number of the Cancel button
+ *  dbox_field other == the number of the Other button
+ *
+ * Returns
+ *  One of the macros defined above, depending on what the user did.
+ */
+
+int nopoll_doDbox
+(
+  dbox d,
+  nopoll_appearFlags flags,
+  dbox_field OK,
+  dbox_field cancel,
+  dbox_field other
+);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/os b/StraySrc/Libraries/Steel/h/os
new file mode 100644 (file)
index 0000000..b969cc0
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * os.h
+ *
+ * OS kernel and generic SWI interface
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __os_h
+#define __os_h
+
+#ifndef __kernel_h
+  #include "kernel.h"
+#endif
+
+/*----- Notes -------------------------------------------------------------*
+ *
+ * --- Deviency from the RISC_OSLib version ---
+ *
+ * All the generic SWI interfaces are implemented in this module, rather
+ * than being passed on via the run-time kernel.
+ *
+ * os_error is declared here to be synonymous with _kernel_oserror, to avoid
+ * messy casts between the two (otherwise identical) error structures.
+ *
+ * All the specific SWI interfaces (e.g. os_find etc.) are implemented by
+ * direct calls to the SWI in question, rather than by being passed on
+ * through os_swix and then on to _kernel_swi.  This is also true of the
+ * other SWI interfaces found in wimp, bbc etc.
+ *
+ * --- Additions ---
+ *
+ * The collection of register-counted generic SWI veneers (i.e. os_swi0,
+ * os_swi4r etc.) have been filled in with versions for 5 registers.  The
+ * non-returning ones (os_swi0-os_swi6) are implemented using only two
+ * separate routines.  The returning calls are implemented separately, but
+ * each one uses a single main SWI veneer.
+ *
+ * Also, two more SWI interfaces have been added: os_swiv and os_swivr, each
+ * of which takes a variable number of arguments (the input registers in
+ * order).  os_swivr will write the output registers into a register block.
+ */
+
+/*----- Miscellaneous types -----------------------------------------------*/
+
+#ifndef BOOL
+  #define BOOL int
+  #define TRUE 1
+  #define FALSE 0
+#endif
+
+/*----- Generic SWI veneers -----------------------------------------------*/
+
+/* --- SWI handling types --- *
+ *
+ * We map directly to the kernel types, because they're identical and it
+ * prevents messy typecasting.
+ */
+
+typedef _kernel_oserror os_error;
+typedef _kernel_swi_regs os_regset;
+
+/* --- The basic SWI veneers --- */
+
+void os_swi(int swi,os_regset *r);
+os_error *os_swix(int swi,os_regset *r);
+
+/* --- Counted, nonreturning SWI veneers --- */
+
+os_error *os_swi0(int swi);
+
+os_error *os_swi1(int swi,int r0);
+
+os_error *os_swi2(int swi,int r0,
+                          int r1);
+
+os_error *os_swi3(int swi,int r0,
+                          int r1,
+                          int r2);
+
+os_error *os_swi4(int swi,int r0,
+                          int r1,
+                          int r2,
+                          int r3);
+
+os_error *os_swi5(int swi,int r0,
+                          int r1,
+                          int r2,
+                          int r3,
+                          int r4);
+
+os_error *os_swi6(int swi,int r0,
+                          int r1,
+                          int r2,
+                          int r3,
+                          int r4,
+                          int r5);
+
+/* --- Counted, returning SWI veneers --- */
+
+os_error *os_swi1r(int swi,int r0,
+                           int *r0_out);
+
+os_error *os_swi2r(int swi,int r0,
+                           int r1,
+                           int *r0_out,
+                           int *r1_out);
+
+os_error *os_swi3r(int swi,int r0,
+                           int r1,
+                           int r2,
+                           int *r0_out,
+                           int *r1_out,
+                           int *r2_out);
+
+os_error *os_swi4r(int swi,int r0,
+                           int r1,
+                           int r2,
+                           int r3,
+                           int *r0_out,
+                           int *r1_out,
+                           int *r2_out,
+                           int *r3_out);
+
+os_error *os_swi5r(int swi,int r0,
+                           int r1,
+                           int r2,
+                           int r3,
+                           int r4,
+                           int *r0_out,
+                           int *r1_out,
+                           int *r2_out,
+                           int *r3_out,
+                           int *r4_out);
+
+os_error *os_swi6r(int swi,int r0,
+                           int r1,
+                           int r2,
+                           int r3,
+                           int r4,
+                           int r5,
+                           int *r0_out,
+                           int *r1_out,
+                           int *r2_out,
+                           int *r3_out,
+                           int *r4_out,
+                           int *r5_out);
+
+/* --- Variable argument SWI veneers --- */
+
+os_error *os_swiv(int swi,...);
+os_error *os_swivr(int swi,os_regset *r_out,...);
+
+/*----- Specific SWI veneers ----------------------------------------------*/
+
+/* --- Structure types --- *
+ *
+ * These have dummy blocks on the end for compatibility with RISC_OSLib
+ * tried to treat them as os_regsets.
+ */
+
+typedef struct
+{
+  int action;                          /* Which action to perform         */
+  char *name;                          /* Name of the file to do it to    */
+  int loadaddr;                                /* May also be a filetype          */
+  int execaddr;                                /* File execution address          */
+  int start;                           /* May also be object length       */
+  int end;                             /* May also be object attributes   */
+  int dummy[4];
+}
+os_filestr;
+
+typedef struct
+{
+  int action;                          /* Which action to perform         */
+  int file_handle;                     /* May point to directory name     */
+  void *data_addr;                     /* Point to input or output buffer */
+  int number;                          /* Bytes to get or put, or number  */
+                                       /*   of filenames to read          */
+  int seq_point;                       /* Item number to read in dir or 0 */
+  int buf_len;                         /* Buffer length for reading names */
+  char *wild_fld;                      /* Pointer to wildcard leafname    */
+  int dummy[3];
+}
+os_gbpbstr;
+
+/* --- SWI veneers --- */
+
+os_error *os_byte(int action,int *x,int *y);
+os_error *os_word(int action,int *pblock);
+os_error *os_file(os_filestr *f);
+os_error *os_gbpb(os_gbpbstr *g);
+os_error *os_args(os_regset *r);
+os_error *os_find(os_regset *r);
+os_error *os_cli(const char *command);
+
+/* --- Reading system variables --- *
+ *
+ * We recommend using the standard getenv function for this.  The veneer
+ * returns the string null-terminated, which may mess things up.
+ */
+
+os_error *os_read_var_val(char *name,char *buffer,int bufferSize);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/pane b/StraySrc/Libraries/Steel/h/pane
new file mode 100644 (file)
index 0000000..aa81853
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Pane
+ *   Handles all those many problems you get with panes
+ *
+ * v. 1.100 (25 July 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __pane_h
+#define __pane_h
+
+#ifndef __wimp_h
+#include "wimp.h"
+#endif
+
+typedef struct pane__panestr *pane;
+
+#ifndef __listbox_h
+#include "listbox.h"
+#endif
+
+/*
+ * pane pane_create(wimp_w tool)
+ *
+ * Use
+ *  Sets up a structure for a pane, and returns a handle.
+ *
+ * Parameters
+ *  wimp_w tool == the window handle of the tool window (the one that isn't
+ *  a pane)
+ *
+ * Returns
+ *  An abstract handle to the pane.
+ */
+
+pane pane_create(wimp_w tool);
+
+/*
+ * void pane_addPane(pane p,wimp_w w)
+ *
+ * Use
+ *  Registers a new pane as being associated with the tool window given in 
+ *  pane_create().
+ *
+ * Parameters
+ *  pane p == the pane handle for the tool window
+ *  wimp_w w == the window handle of the new pane
+ */
+
+void pane_addPane(pane p,wimp_w w);
+
+/*
+ * void pane_addListbox(pane p,list l)
+ *
+ * Use
+ *  Adds a listbox to the tool window.  Handles things properly, so that
+ *  scroll bars and things appear at the right time.
+ *
+ * Parameters
+ *  pane p == the pane to add to
+ *  list l == the list to add
+ */
+
+void pane_addListbox(pane p,list l);
+
+/*
+ * void pane_delete(pane p)
+ *
+ * Use
+ *  Destroys and free()s the memory occupied by a pane structure.
+ *
+ * Parameters
+ *  pane p == the pane's handle
+ */
+
+void pane_delete(pane p);
+
+/*
+ * void pane_removePane(pane p,wimp_w w)
+ *
+ * Use
+ *  Removes the specified pane from the structure.
+ *
+ * Parameters
+ *  pane p == the pane in question
+ *  wimp_w w == the window to remove
+ */
+
+void pane_removePane(pane p,wimp_w w);
+
+/*
+ * void pane_updatePanes(pane p)
+ *
+ * Use
+ *  Updates position of panes attached to the main window after it has been 
+ *  moved.
+ *
+ * Parameters
+ *  pane p == the pane handle
+ */
+
+void pane_updatePanes(pane p);
+
+/*
+ * void pane_moved(pane p)
+ *
+ * Use
+ *  Asks the pane segment to reopen a pane in response to an wimp_EOPEN
+ *  event.
+ *
+ * Parameters
+ *  pane p == the pane handle
+ */
+
+void pane_moved(pane p);
+
+/*
+ * void pane_front(pane p)
+ *
+ * Use
+ *  Moves a tool window and associated panes to the front of the screen.
+ *
+ * Parameters
+ *  pane p == the pane handle
+ */
+
+void pane_front(pane p);
+
+/*
+ * void pane_close(pane p)
+ *
+ * Use
+ *  This routine will close all the windows attached to the pane structure.
+ *
+ * Parameters
+ *  pane p == the pane handle
+ */
+
+void pane_close(pane p);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/pointer b/StraySrc/Libraries/Steel/h/pointer
new file mode 100644 (file)
index 0000000..3ad10fe
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * pointer.h
+ *
+ * Handling of pointer-shape changing
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __pointer_h
+#define __pointer_h
+
+#ifndef __os_h
+  #include "os.h"
+#endif
+
+#ifndef __sprite_h
+  #include "sprite.h"
+#endif
+
+/*
+ * os_error *pointer_set_shape(sprite_area *a,sprite_id *sid,int x,int y)
+ *
+ * Use
+ *  Sets the pointer shape to be the pointer specified.  If a pointer with
+ *  name `name<dx><dy>' is found in the sprite area, that's used instead, and
+ *  the active point is scaled assuming that the original was specified in
+ *  mode-8 type coordinates.
+ *
+ * Parameters
+ *  sprite_area *a == the sprite area containing the sprite
+ *  sprite_id *sid == pointer to the sprite identifier (dumb idea)
+ *  int x,int y == coordinates (in pixels) of the hot-spot
+ */
+
+os_error *pointer_set_shape(sprite_area *a,sprite_id *sid,int x,int y);
+
+/*
+ * void pointer_reset_shape(void)
+ *
+ * Use
+ *  Resets the pointer shape
+ */
+
+void pointer_reset_shape(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/prefs b/StraySrc/Libraries/Steel/h/prefs
new file mode 100644 (file)
index 0000000..7027d5c
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * prefs
+ *
+ * Preferences loading and saving
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __prefs_h
+#define __prefs_h
+
+#ifndef __stdio_h
+  #include <stdio.h>
+#endif
+
+/*-----------------------------------------------------------------------
+
+  Maybe a few words of description may not go amiss...
+
+  This segment manages a preferences file <Appl$Dir>.Choices as far as
+  loading and saving is concerned.  There were two possibilities for
+  the format of the file: either you could store the preferences in a
+  structure type, and just fread and fwrite it (in which case this
+  wouldn't be here, 'cos doing that is really simple) or as text, in
+  which case reading and writing can be difficult.  I have chosen the
+  latter for its versatility, and perhaps even more importantly the fact
+  that accessing individual options by name will give great scope for
+  backwards compatibility.
+
+  The file is read as lines separated by line feeds.  Each line can be
+  either blank (self-explanatory), a comment (begins with a ';') or
+  an assignment.  An assignment has the following syntax:
+
+    <assignment> ::= <tag> [=] <value>
+
+  <tag> and <value> can be any valid ASCII strings.
+
+  The method envisaged for the use of this system is as follows:
+
+   * A structure type (prefs_prefstr) is defined here in this header.
+     The application should define a bunch of static variables (the
+     lifetime is important, not the scope) to store the actual choices.
+
+   * Then the application defines a static array of prefs_prefstrs, and
+     fills it with entries as follows:
+
+       tag == pointer to a tag name to match
+       read == a procedure to interpret a line matched with the tag
+       write == a procedure to write out all lines with the tag
+       handle == a pointer type passed to both procedures
+
+  The procedures must return 0 for success, or a pointer to an error
+  message.  The standard employed by the routines in this segment is
+  that handle points to the variable to be read/written.  Thus, a
+  concept of variable types can be built up over time.  I have included
+  processors for the three main data types likely to appear: boolean,
+  integer and string.  The layout of these has been to make the Choices
+  file as human-intelligible as possible.
+
+  Tags in the structure beginning with ';' or '\n' are not sent to read/
+  write procedures, but instead are written directly to the file, and
+  ignored when reading.  Thus, you can insert comments (like copyright
+  messages) and spacing to give the file a well-designed look.
+
+                                          Straylight
+
+-----------------------------------------------------------------------*/
+
+typedef char *(*prefs_readproc)(char *tag,char *args,void *handle);
+typedef char *(*prefs_writeproc)(char *tag,FILE *fp,void *handle);
+
+typedef struct
+{
+  char *tag;
+  prefs_readproc read;
+  prefs_writeproc write;
+  void *handle;
+}
+prefs_prefstr;
+
+/*
+ * char *prefs_readBoolean(char *tag,char *args,void *handle)
+ *
+ * Use
+ *  Reads a Boolean variable (i.e. one that can be either TRUE or FALSE).
+ */
+
+char *prefs_readBoolean(char *tag,char *args,void *handle);
+
+/*
+ * char *prefs_writeBoolean(char *tag,FILE *fp,void *handle)
+ *
+ * Use
+ *  Writes a Boolean variable to the preferences file.
+ */
+
+char *prefs_writeBoolean(char *tag,FILE *fp,void *handle);
+
+/*
+ * char *prefs_readNumeric(char *tag,char *args,void *handle)
+ *
+ * Use
+ *  Reads a signed integer from the preferences file.
+ */
+
+char *prefs_readNumeric(char *tag,char *args,void *handle);
+
+/*
+ * char *prefs_writeNumeric(char *tag,FILE *fp,void *handle)
+ *
+ * Use
+ *  Writes a signed integer to the preferences file.
+ */
+
+char *prefs_writeNumeric(char *tag,FILE *fp,void *handle);
+
+/*
+ * char *prefs_readString(char *tag,char *args,void *handle)
+ *
+ * Use
+ *  Reads a string from the preferences file.  It is assumed that the buffer
+ *  pointed to by handle is big enough.
+ */
+
+char *prefs_readString(char *tag,char *args,void *handle);
+
+/*
+ * char *prefs_writeString(char *tag,FILE *fp,void *handle)
+ *
+ * Use
+ *  Writes a signed integer to the preferences file.
+ */
+
+char *prefs_writeString(char *tag,FILE *fp,void *handle);
+
+/*
+ * void prefs_preferences(prefs_prefstr *p)
+ *
+ * Use
+ *  Sets up the prefs system to use the preferences definition specified.
+ *  'p' should be a pointer to an array of prefs_prefstrs, terminated by an
+ *  entry with a null 'tag'.  The preferences file created will be called
+ *  'Choices' in the current application's directory (<App$Dir>.Choices).
+ *
+ * Parameters
+ *  prefs_prefstr *p == pointer to an array of preferences definitions
+ */
+
+void prefs_preferences(prefs_prefstr *p);
+
+/*
+ * void prefs_read(void)
+ *
+ * Use
+ *  Reads preferences from the preferences file.
+ */
+
+void prefs_read(void);
+
+/*
+ * void prefs_write(void)
+ *
+ * Use
+ *  Writes preferences out to disk.
+ */
+
+void prefs_write(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/res b/StraySrc/Libraries/Steel/h/res
new file mode 100644 (file)
index 0000000..608762b
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * res
+ *
+ * Access to resources
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __res_h
+#define __res_h
+
+#ifndef __stdio_h
+#include <stdio.h>
+#endif
+
+#ifndef BOOL
+  #define BOOL int
+  #define TRUE 1
+  #define FALSE 0
+#endif
+
+/*
+ *
+ * void res_init(char *progname)
+ *
+ * Use
+ *  Sets up res to use a certain path for resources.  Mainly for
+ *  compatibility with older applications.
+ *
+ * Parameters
+ *  char *progname == the program name (sets up path as <progname$Dir>)
+ */
+
+void res_init(char *progname);
+
+/*
+ * void res_setPrefix(char *prefix)
+ *
+ * Use
+ *  Sets up a full prefix for resources.  This means you can keep resources
+ *  in separate directories.
+ *
+ * Parameters
+ *  char *prefix == the prefix
+ */
+
+void res_setPrefix(char *prefix);
+
+/*
+ * BOOL res_fileExists(char *name)
+ *
+ * Use
+ *  Informs the caller if a given file exists
+ *
+ * Parameters
+ *  char *name == the name of the file
+ *
+ * Returns
+ *  TRUE if the file really does exist
+ */
+
+BOOL res_fileExists(char *name);
+
+/*
+ * int res_findname(const char *resname,char *buf)
+ *
+ * Use
+ *  Returns a full pathname for the resource file as given in the buffer.
+ *  This is for compatibility reasons.  If I was writing this fresh, I
+ *  would return a pointer to an internal static object, but Acorn know
+ *  best...
+ *
+ *  Some new functionality has been added.  It will look for files first in
+ *  the directory set up using res_init or res_setPrefix, and then in the
+ *  'Resources' subdirectory.  If neither is present, then the name returned
+ *  is in the main application directory.
+ *
+ *  Also, under RISC OS 3, it will search for files with mode prefixes, so
+ *  you can use multiple sprite files for different resolutions.  Isn't this
+ *  fun!
+ *
+ * Parameters
+ *  const char *resname == the leafname of the resource file.
+ *  char *buf == where to put the result.
+ *
+ * Returns
+ *  TRUE for compatibility with the Acorn version.  What good it does, I
+ *  don't know.  This is in all a very odd routine indeed.
+ */
+
+int res_findname(const char *resname,char *buf);
+
+/*
+ * char *res_name(const char *resname)
+ *
+ * Use
+ *  Translates the name given as for res_findname and returns a pointer to
+ *  the translated string
+ */
+
+char *res_name(const char *resname);
+
+/*
+ * FILE *res_openfile(const char *resname,const char *mode)
+ *
+ * Use
+ *  Opens a resource file in a given ANSI mode.  It does this without the
+ *  odd adding on of numbers to the end that the Acorn one does (I hope!)
+ *
+ * Parameters
+ *  const char *resname == leafname of file to open
+ *  const char *mode == pointer to ANSI mode string
+ *
+ * Returns
+ *  A standard ANSI-type FILE pointer.
+ */
+
+FILE *res_openfile(const char *resname,const char *mode);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/resspr b/StraySrc/Libraries/Steel/h/resspr
new file mode 100644 (file)
index 0000000..8e10cd5
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * resspr.c
+ *
+ * Loading sprites
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __resspr_h
+#define __resspr_h
+
+#ifndef __sprite_h
+  #include "sprite.h"
+#endif
+
+/*
+ * void resspr_init(void)
+ *
+ * Use
+ *  Loads the applications `Sprites' file into memory.
+ */
+
+void resspr_init(void);
+
+/*
+ * sprite_area *resspr_area(void)
+ *
+ * Use
+ *  Returns the address of the application's sprite area.
+ */
+
+sprite_area *resspr_area(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/saveas b/StraySrc/Libraries/Steel/h/saveas
new file mode 100644 (file)
index 0000000..2563b17
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * saveas
+ *  Handler for a save dbox under new dbox system
+ *
+ * v. 1.00 (9 August 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __saveas_h
+#define __saveas_h
+
+#ifndef __xfersend_h
+#include "xfersend.h"
+#endif
+
+/*
+ * void saveas
+ * (
+ *   char *title,
+ *   char *name,
+ *   int filetype,
+ *   int estsize,
+ *   xfersend_saveproc saveproc,
+ *   xfersend_sendproc sendproc,
+ *   xfersend_printproc printproc,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Creates and handles a save as dialogue box (even saving your data for
+ *  you!).
+ *
+ * Parameters
+ *  char *title == the title of the dialogue box.
+ *  char *name == the default filename for the box.
+ *  int filetype == the filetype of the data to be sent.
+ *  int estsize == the estimated file size.
+ *  xfersend_saveproc saveproc == function to save the data.
+ *  xfersend_sendproc sendproc == function to export data to another
+ *    application (RAM transfer).
+ *  xfersend_printproc printproc == function to print data.
+ *  void *handle == your handle to the data (or anything else!)
+ */
+
+void saveas
+(
+  char *title,
+  char *name,
+  int filetype,
+  int estsize,
+  xfersend_saveproc saveproc,
+  xfersend_sendproc sendproc,
+  xfersend_printproc printproc,
+  void *handle
+);
+
+/*
+ * BOOL saveas_file_is_safe(void)
+ *
+ * Use
+ *  Informs caller if the file is going to a safe home.
+ *
+ * Returns
+ *  TRUE if the file is 'safe' - i.e. on disk
+ */
+
+BOOL saveas_file_is_safe(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/scroller b/StraySrc/Libraries/Steel/h/scroller
new file mode 100644 (file)
index 0000000..39ce838
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * scroller.h
+ *
+ * Scroll some text in an icon nicely ;-)
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __scroller_h
+#define __scroller_h
+
+#ifndef __wimp_h
+  #include "wimp.h"
+#endif
+
+#ifndef __dbox_h
+  #include "dbox.h"
+#endif
+
+typedef struct scroller__str *scroller;
+
+void scroller_redraw(scroller s,wimp_redrawstr *r);
+
+scroller scroller_create(dbox d,
+                         dbox_field f,
+                         char *string,
+                         char *initial,
+                         int startDelay);
+
+void scroller_speed(scroller s,int speed);
+
+void scroller_go(scroller s);
+
+void scroller_destroy(scroller s);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/sculptrix b/StraySrc/Libraries/Steel/h/sculptrix
new file mode 100644 (file)
index 0000000..c8f4a45
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * sculptrix.h
+ *
+ * Interface to sculptrix SWIs
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __sculptrix_h
+#define __sculptrix_h
+
+#ifndef __os_h
+  #include "os.h"
+#endif
+
+#ifndef __wimp_h
+  #include "wimp.h"
+#endif
+
+typedef struct sculptrix_slabDescriptor
+{
+  wimp_w w;
+  wimp_i i;
+  int colour;
+  int time;
+}
+sculptrix_slabDescriptor;
+
+os_error *sculptrix_redrawWindow(wimp_redrawstr *r);
+os_error *sculptrix_doSlab(wimp_w w,wimp_i i,int colour,int *old);
+os_error *sculptrix_slabIcon(wimp_w w,wimp_i i,sculptrix_slabDescriptor *d);
+os_error *sculptrix_unslabIcon(sculptrix_slabDescriptor *d);
+BOOL sculptrix_boundingBox(wimp_icon *i);
+os_error *sculptrix_plotIcon(wimp_icon *i,wimp_redrawstr *r);
+os_error *sculptrix_plotGroupBox(wimp_icon *i,
+                                 wimp_redrawstr *r,
+                                 int type,
+                                 char *titleString);
+os_error *sculptrix_setSpriteArea(sprite_area *s);
+os_error *sculptrix_updateIcon(wimp_w w,wimp_i i);
+int sculptrix_slabColour(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/sprite b/StraySrc/Libraries/Steel/h/sprite
new file mode 100644 (file)
index 0000000..8397ac3
--- /dev/null
@@ -0,0 +1,536 @@
+/****************************************************************************
+ * This source file was written by Acorn Computers Limited. It is part of   *
+ * the RISCOS library for writing applications in C for RISC OS. It may be  *
+ * used freely in the creation of programs for Archimedes. It should be     *
+ * used with Acorn's C Compiler Release 3 or later.                         *
+ *                                                                          *
+ ***************************************************************************/
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Title  : sprite.h
+ * Purpose: provide access to RISC OS sprite facilities
+ *
+ */
+
+# ifndef __sprite_h
+# define __sprite_h
+
+# ifndef __os_h
+# include "os.h"
+# endif
+
+/*
+ * This file contains functions for performing operations on sprites.
+ * For brevity only a brief description is given for each call. More details
+ * can be found in the Programmer's Reference manual under the section on
+ * Sprite SWIs.
+ *
+ */
+
+
+
+/******** Simple operations, use no sprite area, no name/sprite pointer ***/
+
+typedef enum
+{
+  sprite_nopalette  = 0,
+  sprite_haspalette = 1
+} sprite_palflag;
+
+typedef struct
+{
+  int xmag,ymag,xdiv,ydiv;
+} sprite_factors;
+
+typedef char sprite_pixtrans;
+
+
+
+
+/* ----------------------------- sprite_screensave -------------------------
+ * Save the current graphics window as a sprite file, with optional palette.
+ * Equivalent to *ScreenSave.
+ *
+ */
+extern os_error * sprite_screensave(const char *filename, sprite_palflag);
+
+/* ---------------------------- sprite_screenload --------------------------
+ * Load a sprite file onto the screen. Equivalent to *ScreenLoad.
+ *
+ */
+extern os_error * sprite_screenload(const char *filename);
+
+
+
+/****** Operations on either system/user area, no name/sprite pointer *****/
+
+typedef struct /* Format of a sprite area control block */
+{
+  int size;
+  int number;
+  int sproff;
+  int freeoff;
+} sprite_area;
+
+typedef struct /* Format of a sprite header */
+{
+  int  next;      /*  Offset to next sprite                */
+  char name[12];  /*  Sprite name                          */
+  int  width;     /*  Width in words-1      (0..639)       */
+  int  height;    /*  Height in scanlines-1 (0..255/511)   */
+  int  lbit;      /*  First bit used (left end of row)     */
+  int  rbit;      /*  Last bit used (right end of row)     */
+  int  image;     /*  Offset to sprite image               */
+  int  mask;      /*  Offset to transparency mask          */
+  int  mode;      /*  Mode sprite was defined in           */
+                  /*  Palette data optionally follows here */
+                  /*  in memory                            */
+} sprite_header;
+
+#define sprite_mainarea ((sprite_area *) 0)
+
+typedef void * sprite_ptr;
+
+
+/* ------------------------ sprite_area_initialise -------------------------
+ * Initialise an area of memory as a sprite area
+ *
+ */
+void sprite_area_initialise(sprite_area *, int size);
+
+/* ----------------------- sprite_area_readinfo ----------------------------
+ * Read information from a sprite area control block
+ *
+ */
+extern os_error * sprite_area_readinfo(sprite_area *, sprite_area *resultarea);
+
+/* --------------------------- sprite_area_reinit --------------------------
+ * Reinitialise a sprite area.
+ * If system area, then equivalent to *SNew
+ *
+ */
+extern os_error * sprite_area_reinit(sprite_area *);
+
+/* --------------------------- sprite_area_load ----------------------------
+ * Load a sprite file into a sprite area.
+ * If system area, then equivalent to *SLoad
+ *
+ */
+extern os_error * sprite_area_load(sprite_area *, const char *filename);
+
+/* ---------------------------- sprite_area_merge --------------------------
+ * Merge a sprite file with a sprite area.
+ * If system area, then equivalent to *SMerge
+ *
+ */
+extern os_error * sprite_area_merge(sprite_area *, const char *filename);
+
+/* ---------------------------- sprite_area_save ---------------------------
+ * Saves a sprite area as a sprite file.
+ * If system area, then equivalent to *SSave
+ *
+ */
+extern os_error * sprite_area_save(sprite_area *, const char *filename);
+
+/* ---------------------------- sprite_getname -----------------------------
+ * Return the name and length of name of the n'th sprite in a sprite area into
+ * a buffer.
+ *
+ */
+extern os_error * sprite_getname(sprite_area *, void *buffer, int *length, int index);
+
+/* ---------------------------- sprite_get ---------------------------------
+ * Copy a rectangle of screen delimited by the last pair of graphics cursor
+ * positions as a named sprite in a sprite area, optionally storing the
+ * palette with the sprite.
+ *
+ */
+extern os_error * sprite_get(sprite_area *, char *name, sprite_palflag);
+
+/* ---------------------------- sprite_get_rp ------------------------------
+ * Copy a rectangle of screen delimited by the last pair of graphics cursor
+ * positions as a named sprite in a sprite area, optionally storing the
+ * palette with the sprite. Address of sprite returned in resultaddress.
+ *
+ */
+extern os_error * sprite_get_rp(sprite_area *, char *name, sprite_palflag,
+                         sprite_ptr *resultaddress);
+
+/* ---------------------------- sprite_get_given ---------------------------
+ * Copy a rectangle of screen delimited by the given pair of graphics
+ * coordinates as a named sprite in a sprite area, optionally storing the
+ * palette with the sprite.
+ *
+ */
+extern os_error * sprite_get_given(sprite_area *, char *name, sprite_palflag,
+                            int x0, int y0, int x1, int y1);
+
+/* --------------------------- sprite_get_given_rp -------------------------
+ * Copy a rectangle of screen delimited by the given pair of graphics
+ * coordinates as a named sprite in a sprite area, optionally storing the
+ * palette with the sprite. Address of sprite returned in resultaddress.
+ *
+ */
+extern os_error * sprite_get_given_rp(sprite_area *, char *name, sprite_palflag,
+                               int x0, int y0, int x1, int y1,
+                               sprite_ptr *resultaddress);
+
+/* ------------------------------ sprite_create ----------------------------
+ * Create a named sprite in a sprite area of specified size and screen mode,
+ * optionally reserving space for palette data with the sprite.
+ *
+ */
+extern os_error * sprite_create(sprite_area *, char *name, sprite_palflag,
+                         int width, int height, int mode);
+
+/* ------------------------------ sprite_create_rp -------------------------
+ * Create a named sprite in a sprite area of specified size and screen mode,
+ * optionally reserving space for palette data with the sprite.Address of
+ * sprite returned in resultaddress.
+ *
+ */
+extern os_error * sprite_create_rp(sprite_area *, char *name, sprite_palflag,
+                            int width, int height, int mode,
+                            sprite_ptr *resultaddress);
+
+
+/*********** Operations on system/user area, name/sprite pointer **********/
+
+typedef enum
+{
+  sprite_id_name = 0,
+  sprite_id_addr = 0x74527053 /* 'Magic' number ("SpRt") to test against */
+} sprite_type;
+
+typedef struct
+{
+  union
+  {
+    char *     name; /* Can use either name of sprite or address (faster) */
+    sprite_ptr addr;
+  } s;
+  sprite_type tag;   /* User must tag the use of this structure manually */
+} sprite_id;
+
+
+/* ----------------------------- sprite_select -----------------------------
+ * Select the specified sprite for plotting using plot(0xed,x,y).
+ *
+ */
+extern os_error * sprite_select(sprite_area *, sprite_id *);
+
+/* ----------------------------- sprite_select_rp --------------------------
+ * Select the specified sprite for plotting using plot(0xed,x,y). Address of
+ * sprite returned in resultaddress.
+ *
+ */
+extern os_error * sprite_select_rp(sprite_area *, sprite_id *,
+                            sprite_ptr *resultaddress);
+
+/* ----------------------------- sprite_delete -----------------------------
+ * Delete the specified sprite.
+ *
+ */
+extern os_error * sprite_delete(sprite_area *, sprite_id *);
+
+/* ----------------------------- sprite_rename -----------------------------
+ * Rename the specified sprite within the same sprite area.
+ *
+ */
+extern os_error * sprite_rename(sprite_area *, sprite_id *, char *newname);
+
+/* ----------------------------- sprite_copy -------------------------------
+ * Copy the specified sprite as another named sprite in the same sprite area.
+ *
+ */
+extern os_error * sprite_copy(sprite_area *, sprite_id *, char *copyname);
+
+/* ----------------------------- sprite_put --------------------------------
+ * Plot the specified sprite using the given GCOL action.
+ *
+ */
+extern os_error * sprite_put(sprite_area *, sprite_id *, int gcol);
+
+/* ----------------------------- sprite_put_given --------------------------
+ * Plot the specified sprite at (x,y) using the given GCOL action.
+ *
+ */
+extern os_error * sprite_put_given(sprite_area *, sprite_id *, int gcol,
+                            int x, int y);
+
+/* --------------------------- sprite_put_scaled ---------------------------
+ * Plot the specified sprite at (x,y) using the given GCOL action, and scaled
+ * using the given scale factors.
+ *
+ */
+extern os_error * sprite_put_scaled(sprite_area *, sprite_id *, int gcol,
+                            int x, int y,
+                            sprite_factors *factors,
+                            sprite_pixtrans pixtrans[]);
+
+/* ---------------------------- sprite_put_greyscaled ----------------------
+ * Plot the specified sprite at (x,y) using the given GCOL action, and
+ * greyscaled using the given scale factors.
+ *
+ */
+extern os_error * sprite_put_greyscaled(sprite_area *, sprite_id *,
+                            int x, int y,
+                            sprite_factors *factors,
+                            sprite_pixtrans pixtrans[]);
+
+/* ----------------------------- sprite_put_mask ---------------------------
+ * Plot the specified sprite mask in the background colour.
+ *
+ */
+extern os_error * sprite_put_mask(sprite_area *, sprite_id *);
+
+/* ----------------------------- sprite_put_mask_given ---------------------
+ * Plot the specified sprite mask at (x,y) in the background colour.
+ *
+ */
+extern os_error * sprite_put_mask_given(sprite_area *, sprite_id *, int x, int y);
+
+/* --------------------------- sprite_put_mask_scaled ----------------------
+ * Plot the sprite mask at (x,y) scaled, using the background colour/action
+ *
+ */
+extern os_error * sprite_put_mask_scaled(sprite_area *, sprite_id *,
+                            int x, int y,
+                            sprite_factors *factors);
+
+/* ----------------------------- sprite_put_char_scaled --------------------
+ * Paint char scaled at (x,y)
+ *
+ */
+extern os_error * sprite_put_char_scaled(char ch,
+                                  int x, int y,
+                                  sprite_factors *factors);
+
+/* ---------------------------- sprite_create_mask -------------------------
+ * Create a mask definition for the specified sprite.
+ *
+ */
+extern os_error * sprite_create_mask(sprite_area *, sprite_id *);
+
+/* ---------------------------- sprite_remove_mask -------------------------
+ * Remove the mask definition from the specified sprite.
+ *
+ */
+extern os_error * sprite_remove_mask(sprite_area *, sprite_id *);
+
+/* ---------------------------- sprite_insert_row --------------------------
+ * Insert a row into the specified sprite at the given row.
+ *
+ */
+extern os_error * sprite_insert_row(sprite_area *, sprite_id *, int row);
+
+/* ---------------------------- sprite_delete_row --------------------------
+ * Delete the given row from the specified sprite.
+ *
+ */
+extern os_error * sprite_delete_row(sprite_area *, sprite_id *, int row);
+
+/* ---------------------------- sprite_insert_column -----------------------
+ * Insert a column into the specified sprite at the given column.
+ *
+ */
+extern os_error * sprite_insert_column(sprite_area *, sprite_id *, int column);
+
+/* ---------------------------- sprite_delete_column -----------------------
+ * Delete the given column from the specified sprite.
+ *
+ */
+extern os_error * sprite_delete_column(sprite_area *, sprite_id *, int column);
+
+/* ----------------------------- sprite_flip_x -----------------------------
+ * Flip the specified sprite about the x axis
+ *
+ */
+extern os_error * sprite_flip_x(sprite_area *, sprite_id *);
+
+/* ----------------------------- sprite_flip_y -----------------------------
+ * Flip the specified sprite about the y axis
+ *
+ */
+extern os_error * sprite_flip_y(sprite_area *, sprite_id *);
+
+
+typedef struct
+{
+ int width;
+ int height;
+ int mask;
+ int mode;
+} sprite_info;
+
+/* -------------------------------- sprite_readsize ------------------------
+ * Read the size information for the specified sprite_id
+ *
+ */
+extern os_error * sprite_readsize(sprite_area *, sprite_id *,
+                           sprite_info *resultinfo);
+
+
+typedef struct
+{
+  int colour;
+  int tint;
+} sprite_colour;
+
+/* ----------------------------- sprite_readpixel --------------------------
+ * Read the colour of a given pixel in the specified sprite_id
+ *
+ */
+extern os_error * sprite_readpixel(sprite_area *, sprite_id *,
+                            int x, int y, sprite_colour *resultcolour);
+
+/* ----------------------------- sprite_writepixel -------------------------
+ * Write the colour of a given pixel in the specified sprite_id
+ *
+ */
+extern os_error * sprite_writepixel(sprite_area *, sprite_id *,
+                             int x, int y, sprite_colour *colour);
+
+
+typedef enum
+{
+  sprite_masktransparent = 0,
+  sprite_masksolid       = 1
+} sprite_maskstate;
+
+/* ------------------------------- sprite_readmask -------------------------
+ * Read the state of a given pixel in the specified sprite mask
+ *
+ */
+extern os_error * sprite_readmask(sprite_area *, sprite_id *,
+                           int x, int y, sprite_maskstate *resultmaskstate);
+
+/* ------------------------------- sprite_writemask ------------------------
+ * Write the state of a given pixel in the specified sprite mask
+ *
+ */
+extern os_error * sprite_writemask(sprite_area *, sprite_id *,
+                            int x, int y, sprite_maskstate *maskstate);
+
+
+typedef struct
+        { int r[4];
+        } sprite_state;
+
+/* ----------------------------- sprite_restorestate -----------------------
+ * Restores the old state after one of the sprite redirection calls
+ *
+ */
+extern os_error *sprite_restorestate(sprite_state state);
+
+
+/* ---------------------------- sprite_outputtosprite ----------------------
+ * Redirect VDU output to a sprite, saving old state
+ *
+ */
+extern os_error *sprite_outputtosprite(sprite_area *area, sprite_id *id,
+                                int *save_area, sprite_state *state);
+
+/* ----------------------- sprite_outputtomask -----------------------------
+ * Redirects output to a sprite's transparency mask, saving old state
+ *
+ */
+extern os_error *sprite_outputtomask(sprite_area *area, sprite_id *id,
+                              int *save_area, sprite_state *state);
+
+/* --------------------------- sprite_outputtoscreen -----------------------
+ * Redirect output back to screen, saving old state
+ *
+ */
+extern os_error *sprite_outputtoscreen(int *save_area, sprite_state *state);
+
+/* --------------------------- sprite_sizeof_spritecontext -----------------
+ * Get size of save area needed to save sprite context.
+ *
+ */
+extern os_error *sprite_sizeof_spritecontext(sprite_area *area, sprite_id *id,
+                                      int *size);
+
+/* ------------------------- sprite_sizeof_screencontext -------------------
+ * Get size of save area needed to save screen context.
+ *
+ */
+extern os_error *sprite_sizeof_screencontext(int *size);
+
+/* ------------------------ sprite_removewastage ---------------------------
+ * Removes left hand wastage from a sprite
+ *
+ */
+extern os_error *sprite_removewastage(sprite_area *area, sprite_id *id);
+
+
+/* new SWIs */
+
+/* ------------------------ sprite_change_size -----------------------------
+ * General insert/delete rows/columns operations
+ *
+ */
+extern os_error
+  *sprite_change_size
+  (sprite_area *area, sprite_id *id, BOOL rows, int at, int number);
+
+/* Typedefs and functions for rotating sprites. */
+
+typedef struct {int p0 [2], p1 [2], p2 [2], p3 [2];} sprite_pgm;
+typedef int sprite_transmat [6];
+typedef struct {int x0, y0, x1, y1;} sprite_box;
+
+/* ------------------------ sprite_put_mask_trans ---------------------
+ * Put a box from the mask in background colours through a transformation matrix
+ *
+ */
+extern os_error
+  *sprite_put_mask_trans
+  (sprite_area *, sprite_id *, sprite_box *, sprite_transmat *);
+
+/* ------------------------ sprite_put_mask_pgm -----------------------
+ * Put a box from the mask in background colours to a parallelogram
+ *
+ */
+extern os_error
+  *sprite_put_mask_pgm
+  (sprite_area *, sprite_id *, sprite_box *, sprite_pgm *);
+
+/* ------------------------ sprite_put_trans --------------------------
+ * Put a box from the sprite through a transformation matrix
+ *
+ */
+extern os_error
+  *sprite_put_trans
+  (sprite_area *, sprite_id *, int gcol_action, sprite_box *, sprite_transmat *, sprite_pixtrans *);
+
+/* ------------------------ sprite_put_pgm ----------------------------
+ * Put a box from the sprite to a parallelogram
+ *
+ */
+extern os_error
+  *sprite_put_pgm
+  (sprite_area *, sprite_id *, int gcol_action, sprite_box *, sprite_pgm *, sprite_pixtrans *);
+
+# endif
+
+/* end of sprite.h */
diff --git a/StraySrc/Libraries/Steel/h/stddbox b/StraySrc/Libraries/Steel/h/stddbox
new file mode 100644 (file)
index 0000000..3e69752
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * stddbox
+ *  Some standard Straylight dboxes.
+ *
+ * v. 1.00 (9 August 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __stddbox_h
+#define __stddbox_h
+
+#ifndef __xfersend_h
+  #include "xfersend.h"
+#endif
+
+#ifndef __dbox_h
+  #include "dbox.h"
+#endif
+
+typedef BOOL (*stddbox_writableHandler)(char *result,void *handle);
+
+/*
+ * BOOL warning(char *okMsg,char *warn,...)
+ *
+ * Use
+ *  Pops up a warning box, with a Cancel button and a default action button
+ *  with your own text in it.  
+ *
+ * Parameters
+ *  char *okMsg == what to put in the default action button.
+ *  char *warn == the warning message (printf()-style format string)
+ *
+ * Returns
+ *  TRUE if the user chose the OK button.
+ */
+
+BOOL warning(char *okMsg,char *warn,...);
+
+/*
+ * void note(char *notemsg,...)
+ *
+ * Use
+ *  Displays a small note on the screen, so you can tell the user that he
+ *  has done something silly, etc.  A lot nicer than old werr().
+ *
+ * Parameters
+ *  char *notemsg == the note (printf()-style format string)
+ */
+
+void note(char *notemsg,...);
+
+/*
+ * BOOL writable
+ * (
+ *   char *title,
+ *   char *deflt,
+ *   char *result,
+ *   stddbox_writableHandler proc,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Opens a dialogue box for the user to input a string.  Needs
+ *  the 'writable' template.
+ *
+ * Parameters
+ *  char *title == the title for the dialogue box.
+ *  char *default == the default string to put in the writable area.
+ *  char *result == a buffer to contain the result string.  May be 0.
+ *  stddbox_writableHandler proc == proc to call when OK is clicked.  May
+ *    be 0.  Return TRUE if successful (i.e. we may close the dbox).
+ *  void *handle == passed to proc.
+ *
+ * Returns
+ *  TRUE if the string has been updated.
+ */
+
+BOOL writable
+(
+  char *title,
+  char *deflt,
+  char *result,
+  stddbox_writableHandler proc,
+  void *handle
+);
+
+/*
+ * void saveWarn
+ * (
+ *   BOOL useName,
+ *   void (*dispose)(void *handle),
+ *   char *title,
+ *   char *name,
+ *   int filetype,
+ *   int estsize,
+ *   xfersend_saveproc saveproc,
+ *   xfersend_sendproc sendproc,
+ *   xfersend_printproc printproc,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Pops up a save warning box allowing the use the luxury of saving his
+ *  data before closing the file.  The file is only removed if the data is 
+ *  'safe'.
+ *
+ * Parameters
+ *  BOOL useName == whether to use the given name in the warning message
+ *  void (*dispose)(void *handle) == function to dispose the user's data
+ *  the others == as for saveas()
+ */
+
+void saveWarn
+(
+  BOOL useName,
+  void (*dispose)(void *handle),
+  char *title,
+  char *name,
+  int filetype,
+  int estsize,
+  xfersend_saveproc saveproc,
+  xfersend_sendproc sendproc,
+  xfersend_printproc printproc,
+  void *handle
+);
+
+/*
+ * void progInfo
+ * (
+ *   char *name,
+ *   char *purpose,
+ *   char *author,
+ *   int version,
+ *   char *date
+ * )
+ *
+ * Use
+ *  Presents a standard progInfo window giving information about an
+ *  application.
+ *
+ * Parameters
+ *  char *name == the name of the program
+ *  char *purpose == what it does
+ *  char *author == author/copyright string (usually something like
+ *    '© 1992-1998 Straylight')
+ *  int version == the version number*100 (e.g. 374 for 3.74 etc.)
+ *  char *date == the date of compilation (use _TIME_NOW)
+ */
+
+void progInfo(char *name,char *purpose,char *author,int version,char *date);
+
+/*
+ * void mbox(dbox d)
+ *
+ * Use
+ *  Handles a monologue box (like info windows) where no input is required.
+ *  You should create the dbox, fill in any fields required.  This routine
+ *  then handles the rest.  It deletes the dbox when it's finished - it's of
+ *  no use to the caller anyway - who wants a used dialogue box with no
+ *  input?  Yuk...
+ *
+ *  You can specify a help message tag to be displayed before any messages
+ *  embedded in the icons.  This is passed through msgs_lookup before
+ *  sending to help_addLine.  Specify zero for this to send no message.
+ *
+ * Parameters
+ *  dbox d == the box to handle
+ *  char *help == the help message tag to stick on the top
+ */
+
+void mbox(dbox d,char *help);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/steel b/StraySrc/Libraries/Steel/h/steel
new file mode 100644 (file)
index 0000000..bce067d
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * steel.h
+ *
+ * Central control of header files and things
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __steel_h
+#define __steel_h
+
+#define steel_VERSION 132
+#define steel_DATE "1 September 1993"
+
+/*-----------------------------------------------------------------------
+
+  OK, let's face it - we've got so many header files we don't know
+  whether we're coming or going.  This header is designed to help manage
+  all the others.  The way I've decided to handle this is for the source
+  code to define a bunch of constants concerned with not what bits of
+  code you need to access, but what sort of program you want to write,
+  and then include this header.
+
+  The following table shows the constant names, their meanings, and
+  which headers they include.  Note that the order of inclusions here is
+  such that each is included at most once.  You *won't* make anything
+  faster by doing it all yourself.  Also, note that not all Steel
+  headers are included in this selection.
+
+          Constant   Meaning           Notes             Includes
+
+          _CORE                        Always included   wimp.h
+                                                         wimpt.h
+                                                         win.h
+                                                         menu.h
+                                                         event.h
+                                                         ibicon.h
+                                                         res.h
+                                                         resspr.h
+                                                         template.h
+                                                         dbox.h
+                                                         mem.h
+                                                         visdelay.h
+
+          _STDAPP   Standard includes                    help.h
+                    for most programs                    exception.h
+                                                         msgs.h
+                                                         utils.h
+                                                         stddbox.h
+                                                         werr.h
+
+          _XFER      Program will                        xferrecv.h
+                     transfer data                       xfersend.h
+                                                         saveas.h
+
+          _LOWLVL    Program needs     Includes kernel   kernel.h
+                     low-level access  rather than os    swis.h
+                     to OS calls       because Acorn
+                                       prefer it
+
+-----------------------------------------------------------------------*/
+
+#ifndef __wimp_h
+  #include "wimp.h"
+#endif
+#ifndef __wimpt_h
+  #include "wimpt.h"
+#endif
+#ifndef __win_h
+  #include "win.h"
+#endif
+#ifndef __event_h
+  #include "event.h"
+#endif
+#ifndef __ibicon_h
+  #include "ibicon.h"
+#endif
+#ifndef __res_h
+  #include "res.h"
+#endif
+#ifndef __resspr_h
+  #include "resspr.h"
+#endif
+#ifndef __template_h
+  #include "template.h"
+#endif
+#ifndef __dbox_h
+  #include "dbox.h"
+#endif
+#ifndef __mem_h
+  #include "mem.h"
+#endif
+#ifndef __visdelay_h
+  #include "visdelay.h"
+#endif
+
+#ifdef _STDAPP
+  #ifndef __help_h
+    #include "help.h"
+  #endif
+  #ifndef __exception_h
+    #include "exception.h"
+  #endif
+  #ifndef __msgs_h
+    #include "msgs.h"
+  #endif
+  #ifndef __utils_h
+    #include "utils.h"
+  #endif
+  #ifndef __stddbox_h
+    #include "stddbox.h"
+  #endif
+  #ifndef __werr_h
+    #include "werr.h"
+  #endif
+#endif
+
+#ifdef _XFER
+  #ifndef __xferrecv_h
+    #include "xferrecv.h"
+  #endif
+  #ifndef __saveas_h
+    #include "saveas.h"
+  #endif
+#endif
+
+#ifdef _LOWLVL
+  #ifndef __kernel_h
+    #include "kernel.h"
+  #endif
+  #ifndef __swis_h
+    #include "swis.h"
+  #endif
+#endif
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/tcol b/StraySrc/Libraries/Steel/h/tcol
new file mode 100644 (file)
index 0000000..9daa834
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Tcol
+ *   A true-colour dialogue box thingy
+ *
+ * v. 1.00 24 July 1991
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __tcol_h
+#define __tcol_h
+
+#ifndef __wimp_h
+#include "wimp.h"
+#endif
+
+typedef enum
+{
+  tcol_OK,               /* User clicked OK, and dbox closed */
+  tcol_OK_REOPEN,        /* User clicked OK, and dbox stays open */
+  tcol_CANCEL            /* Dbox closed without changes (since last OK) */
+}
+tcol_reason;
+
+/*
+ * A function to be called when all is said and done.
+ */
+typedef void (*tcol_finishhandler)(tcol_reason r,
+                                   wimp_paletteword c,
+                                   void *handle);
+
+/*
+ * void tcol
+ * (
+ *   char *editing,
+ *   wimp_paletteword c,
+ *   BOOL isStatic,
+ *   tcol_finishhandler proc,
+ *   void *handle
+ *  )
+ *
+ * Use
+ *  Creates and handles a dbox, which allows the user to input a true
+ *  colour.  You must have a template called 'tcol' for this routine.
+ *
+ * Parameters
+ *  char *editing == what we're editing (put in the little box at the top)
+ *  wimp_paletteword c == the initial colour
+ *  BOOL isStatic == whether the dbox is static
+ *  tcol_finishhandler proc == procedure called when the user clicks OK
+ *  void *handle == the jolly old handle
+ */
+
+void tcol
+(
+  char *editing,
+  wimp_paletteword c,
+  BOOL isStatic,
+  tcol_finishhandler proc,
+  void *handle
+);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/tearoff b/StraySrc/Libraries/Steel/h/tearoff
new file mode 100644 (file)
index 0000000..cc35938
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * tearoff.h
+ *
+ * Tearoff menu handling
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __tearoff_h
+#define __tearoff_h
+
+/*----- Constants and exported types --------------------------------------*/
+
+/* --- Event type codes --- */
+
+typedef enum
+{
+  tearoff_SELECTION,
+  tearoff_CLOSE,
+  tearoff_SUBMENU,
+  tearoff_HELP
+}
+tearoff_message;
+
+/* --- Left-side adornments for menu items --- */
+
+typedef enum
+{
+  tearoff_NONE,
+  tearoff_TICKED,
+  tearoff_RADIOED
+} tearoff_selectType;
+
+/* --- Event handler interface --- */
+
+typedef void (*tearoff_selectProc)(tearoff_message m,int hit,void *handle);
+
+/* --- What a tearoff menu looks like --- */
+
+typedef struct tearoff__str *tearoff;
+
+/*----- Exported functions ------------------------------------------------*/
+
+/* --- tearoff_create --- *
+ *
+ * Arguments
+ *
+ * char *title == title for the menu
+ * char *items == text and properties of the menu items.  See above for
+ *                syntax.
+ * BOOL tearoff == whether to display the tearoff bar along the top
+ * tearoff_selectProc proc == an event handler for the menu
+ * int max == maximum height of the menu (OS units) or 0 for no maximum
+ * void *handle == a `this' pointer for the event handler.
+ *
+ * Return value
+ *
+ * A handle to the newly created menu, or 0 if it failed.
+ */
+
+tearoff tearoff_create(char *title,char *items,BOOL tearoff,
+                       tearoff_selectProc proc, int max, void *handle);
+
+/* --- tearoff_attachSubMenu --- *
+ *
+ * Arguments
+ *
+ * tearoff to == a handle for the tearoff to which we must attach the submenu
+ * int itm == the index (numbered from 1) of the item to attach to.  The item
+ *            must exist in tearoff to.
+ * tearoff sub == a handle to the (to be) submenu
+ */
+
+void tearoff_attachSubMenu(tearoff to,int itm,tearoff sub);
+
+/* --- tearoff_destroy --- *
+ *
+ * Arguments
+ *
+ * tearoff t == handle to a tearoff to get rid of. This call does
+ *             not recursively destroy sub menus.
+ */
+
+void tearoff_destroy(tearoff t);
+
+/* --- tearoff_displayMenu --- *
+ *
+ * Arguments
+ *
+ * tearoff t == handle to the tearoff to display on the screen. It
+ *             is opened as a sub menu if one is expected.
+ * void *handle == Handle to be returned to handler function. If
+ *                it is 0 then the old value is used.
+ */
+
+BOOL tearoff_displayMenu(tearoff t,void *handle);
+
+/* --- tearoff_init --- *
+ *
+ * Make sure you call this before any of the other tearoff functions.  The
+ * results are undefined in the traditional manner if you don't.
+ */
+
+void tearoff_init(void);
+
+/* --- tearoff_selectItem --- *
+ *
+ * Arguments
+ *
+ * tearoff t == the tearoff containing the item to select
+ * int item == the item (indexed from 1) to select (or not)
+ * tearoff_selectType type == how to select the item
+ */
+
+void tearoff_selectItem(tearoff t, int item, tearoff_selectType type);
+
+/* --- tearoff_shadeItem --- *
+ *
+ * Arguments
+ *
+ * tearoff t == the menu
+ * int item == the item to (un)shade
+ * BOOL shaded == whether to shade the item or not
+ */
+
+void tearoff_shadeItem(tearoff t, int item, BOOL shaded);
+
+/* --- tearoff_closeMenu --- *
+ *
+ * Arguments
+ *
+ * tearoff t == the tearoff to close
+ */
+
+void tearoff_closeMenu(tearoff t);
+
+/* --- tearoff_changeItemText --- *
+ *
+ * Arguments
+ *
+ * tearoff t == the tearoff menu
+ * int item == the item to change (indexed from 1)
+ * char *text == the new text message. Control key shortcuts must be
+                regiven if they are still wanted.
+ */
+
+void tearoff_changeItemText(tearoff t,int item,char *text);
+
+/* --- tearoff_extendMenu --- *
+ *
+ * Arguments
+ *
+ * tearoff t == the menu to extend
+ * char *items == the items to add in the same syntax as for tearoff_create.
+ *               The results are unpleasent if the menu is open
+ *
+ * Return Value
+ *
+ * A new pointer to the tearoff menu, or NULL if it could not be extended.
+ */
+
+tearoff tearoff_extendMenu(tearoff t,char *items);
+
+/* --- tearoff_changeTitle --- *
+ *
+ * Arguments
+ *
+ * tearoff t == the tearoff menu
+ * char *title == the new title - the menu changes size if nessesary
+ */
+
+void tearoff_changeTitle(tearoff t,char *title);
+
+/* --- tearoff_displayAt --- *
+ *
+ * Arguments
+ *
+ * tearoff t == the menu to open
+ * void *handle == Handle to be returned to handler function. If
+ *                 it is 0 then the old value is used
+ * int x == the x coordinate to open left of menu
+ * int y == the y coordinate to open top of menu
+ */
+
+void tearoff_displayAt(tearoff t,void *handle,int x,int y);
+
+/* --- tearoff_height --- *
+ *
+ * Arguments
+ *
+ * tearoff t == the tearoff menu to find height of
+ *
+ * Return value
+ *
+ * The height of the menu - not including the title bar
+ */
+
+int tearoff_height(tearoff t);
+
+/* --- tearoff_attachMenu --- *
+ *
+ * Arguments
+ *
+ * wimp_w w == the window the attach menu to
+ * tearoff t == the menu to attach
+ * void *handle == the handle to pass to the handler function,
+ *                 if it is 0 then the old value is used.
+ *
+ * Return value
+ *
+ * TRUE if successful
+ */
+
+BOOL tearoff_attachMenu(wimp_w w,tearoff t,void *handle);
+
+/* --- tearoff__isShaded --- *
+ *
+ * Arguments
+ *
+ * tearoff t == the tearoff in question
+ * int item == the item to be questioned
+ *
+ * Return value
+ *
+ * TRUE if the item is shaded
+ */
+
+BOOL tearoff_isShaded(tearoff t,int item);
+
+/* --- tearoff_howSelected --- *
+ *
+ * Arguments
+ *
+ * tearoff t == the tearoff in question
+ * int item == the item to be questioned
+ *
+ * Return value
+ *
+ * How the item has been selected
+ */
+
+tearoff_selectType tearoff_howSelected(tearoff t,int item);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/template b/StraySrc/Libraries/Steel/h/template
new file mode 100644 (file)
index 0000000..16c2843
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * template.c
+ *
+ * Loading and manipulation of window templates
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __template_h
+#define __template_h
+
+/* --- Acorn stupidly decided to make this public --- */
+
+typedef struct template__str
+{
+  struct template__str *next;
+  char *workspace;
+  int workspacesize;
+  char *font;
+  char name[12];
+  wimp_wind window;
+}
+template;
+
+/* --- The actual functions --- */
+
+/*
+ * template *template_copy(template *from)
+ *
+ * Use
+ *  Copies a template field-for-field and fixes up new indirected data for
+ *  it.
+ */
+
+template *template_copy(template *from);
+
+/*
+ * BOOL template_readfile(char *name)
+ *
+ * Use
+ *  Loads the template file named into memory, and sorts out all its
+ *  indirected data.
+ *
+ *  Template entries with strange identifiers are ignored.  Other entry
+ *  types may be supported later.
+ *
+ * Parameters
+ *  char *name == the name of the template file to load (a resource file)
+ *
+ * Returns
+ *  FALSE if the file contained no sprite icons.  No, I don't understand
+ *  the use of this either.  It's not my problem though.  I just write the
+ *  code.
+ */
+
+BOOL template_readfile(char *file);
+
+/*
+ * void template_init(void)
+ *
+ * Use
+ *  Loads the application's `Templates' file.
+ */
+
+void template_init(void);
+
+/*
+ * void template_use_fancyfonts(void)
+ *
+ * Use
+ *  Does absolutely nothing at all.  Fancy font support happens anyway.
+ */
+
+void template_use_fancyfonts(void);
+
+/*
+ * BOOL template_exists(char *name)
+ *
+ * Use
+ *  Returns TRUE if the named template is known at the moment, or FALSE
+ *  otherwise
+ */
+
+BOOL template_exists(char *name);
+
+/*
+ * template *template_find(char *name)
+ *
+ * Use
+ *  Locates a named template and returns a pointer to it
+ */
+
+template *template_find(char *name);
+
+/*
+ * wimp_wind *template_syshandle(char *name)
+ *
+ * Use
+ *  Not very much, if the truth be known.  It returns a pointer to a named
+ *  window definition.
+ */
+
+wimp_wind *template_syshandle(char *name);
+
+/*
+ * BOOL template_loaded(void)
+ *
+ * Use
+ *  Returns TRUE if we have templates on board.
+ */
+
+BOOL template_loaded(void);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/utils b/StraySrc/Libraries/Steel/h/utils
new file mode 100644 (file)
index 0000000..66ea024
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * utils
+ *
+ * Various miscellaneous (and largely non-WIMP) utility routines
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __utils_h
+#define __utils_h
+
+#ifndef __os_h
+#include "os.h"
+#endif
+
+/*
+ * int utils_caselessCmp(const char *s1,const char *s2)
+ *
+ * Use
+ *  Caseless comparison between string 1 and string 2
+ *
+ * Parameters
+ *  const char *s1 == source string
+ *  const char *s2 == target string
+ *
+ * Returns
+ *  0 if the strings are equal, >0 if s1>s2, or <0 if s1<s2.
+ */
+
+int utils_caselessCmp(const char *s1,const char *s2);
+
+/*
+ * char *utils_ctermToNterm(char *s)
+ *
+ * Use
+ *  Changes a control-terminated string into a null-terminated string.
+ *
+ * Parameters
+ *  char *s == the string to change
+ *
+ * Returns
+ *  A pointer to the string.
+ */
+
+char *utils_ctermToNterm(char *s);
+
+/*
+ * char *utils_leafname(char *filename)
+ *
+ * Use
+ *  Returns the leafname of the file whose full pathname is given in
+ *  filename.
+ *
+ * Parameters
+ *  char *filename == pointer to full filename string
+ *
+ * Returns
+ *  Pointer to character after last '.' of string.
+ */
+
+char *utils_leafname(char *filename);
+
+/*
+ * os_error *utils_complain(os error *e,char *string)
+ *
+ * Use
+ *  If e is an error (i.e. not NULL) then the routine calls werr() with
+ *  parameters (string,e->errmess).  Ths string must contain a '%s' at some
+ *  point.
+ *
+ * Parameters
+ *  os_error *e == either NULL or a pointer to a standard system
+ *    error structure.
+ *  char *string == a string containing one %s, for which the error
+ *    message from the structure passed above will be substituted.
+ *
+ * Returns
+ *  The error pointer.
+ */
+
+os_error *utils_complain(os_error *e,char *string);
+
+/*
+ * char *utils_cvtSize(int size)
+ *
+ * Use
+ *  Converts a size in bytes into a string suitable to display the size to
+ *  a user.  It uses OS_ConvertFileSize to do he translation, although this
+ *  is not guaranteed for future versions.
+ *
+ * Parameters
+ *  int size == the size in bytes
+ *
+ * Returns
+ *  A pointer to the result (read-only)
+ */
+
+char *utils_cvtSize(int size);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/viewer b/StraySrc/Libraries/Steel/h/viewer
new file mode 100644 (file)
index 0000000..afc8a87
--- /dev/null
@@ -0,0 +1,784 @@
+/*
+ * viewer
+ *  Allows creation of Filer-like windows which rearrange themselves.
+ *
+ * v. 1.00 (13 August 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __viewer_h
+#define __viewer_h
+
+#ifndef __wimp_h
+#include "wimp.h"
+#endif
+
+#ifndef __sprite_h
+#include "sprite.h"
+#endif
+
+#ifndef __menu_h
+#include "menu.h"
+#endif
+
+/*
+ * The handle types for the viewer segment
+ */
+typedef struct viewer__viewerstr *viewer;
+typedef struct viewer__iconstr *viewer_icon;
+
+/*
+ * Event handler types
+ *
+ * The whole viewer can have a caller-defined handle, and each icon in it
+ * also has one.  The standard event handler gets both.  If no ico was 
+ * clicked, the icon handle is 0.  You should have a handle to your viewer 
+ * global data in the icon structure.  The raw event handler passes only the
+ * global handle.
+ */
+
+typedef void (*viewer_eventhandler)
+(
+  viewer v,
+  viewer_icon i,
+  wimp_bbits b,
+  void *vhandle,
+  void *ihandle
+);
+
+typedef BOOL (*viewer_raweventhandler)
+(
+  viewer v,
+  wimp_eventstr *e,
+  void *handle
+);
+
+typedef void (*viewer_redrawhandler)
+(
+  viewer_icon i,
+  wimp_redrawstr *r,
+  wimp_box *box,
+  char *text,
+  char *sprite,
+  BOOL selected,
+  void *handle
+);
+
+/*
+ * Types for data export.
+ */
+
+typedef BOOL (*viewer_saveproc)(viewer_icon i,char *filename, void *handle);
+typedef BOOL (*viewer_sendproc)(viewer_icon i,void *handle, int *maxbuf);
+typedef int (*viewer_printproc)(viewer_icon i,char *filename, void *handle);
+
+/*
+ * For sorting icons
+ */
+
+typedef int (*viewer_compare)(void *a,void *b);
+
+/*
+ * A macro for telling the event handler about a close event.  I know it's 
+ * not the same, but...
+ */
+#define viewer_CLOSE ((viewer_icon)-1)
+
+/*
+ * A macro for telling the event handler about a help request
+ */
+#define viewer_HELP ((viewer_icon)-2)
+
+/*
+ * A macro representing no icon being clicked.
+ */
+#define viewer_NOICON ((viewer_icon)0)
+
+/*
+ * void viewer_drawFileIcons
+ * (
+ *   viewer_icon icn,
+ *   wimp_redrawstr *r,
+ *   wimp_box *box,
+ *   char *text,
+ *   char *sprite,
+ *   BOOL selected,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Redraw handler which takes into account filetypes of icons.  The icons
+ *  automatically get new sprites if the sprites for their filetypes change.
+ *  For applications, the text is considered to be a filename.  Register
+ *  this function using viewer_redrawHandler().
+ *
+ * Parameters
+ *  viewer_icon icn == the icon to paint
+ *  wimp_redrawstr *r == information about this redraw
+ *  wimp_box *box == the box to draw the icon in
+ *  char *text == the text to display
+ *  char *sprite == the sprite to display
+ *  BOOL selected == is the icon selected?
+ *  void *handle == a caller defined handle (ignored)
+ */
+
+void viewer_drawFileIcons
+(
+  viewer_icon icn,
+  wimp_redrawstr *r,
+  wimp_box *box,
+  char *text,
+  char *sprite,
+  BOOL selected,
+  void *handle
+);
+
+/*
+ * viewer viewer_create
+ * (
+ *   int x,
+ *   int y,
+ *   int width,
+ *   int height,
+ *   sprite_area *spr,
+ *   char *title,
+ *   char *banner
+ * )
+ *
+ * Use
+ *  Creates a viewer window.  Note that viewer windows don't need templates,
+ *  and don't contain real wimp icons, just yer normal redrawn-by-
+ *  application things (which can be handled by a caller-defined function if
+ *  necessary).  The banner along the top is optional - if a null pointer is
+ *  passed, no banner is included.  The sprite area passed applies to all
+ *  the icons in the window, although if  you want to, you can use your own
+ *  redraw routine to handle different sprite areas for them.
+ *
+ * Parameters
+ *  int x,int y == the coordinates of the top-left corner of the window
+ *    (file windows for editors need good positioning here).
+ *  int width == the width of an icon
+ *  int height == the height of an icon
+ *  sprite_area *spr == the sprite area for the window
+ *  char *title == the title of the window
+ *  char *banner == the banner heading along the top (like 'Sprite file
+ *    window' or something)
+ *
+ * Returns
+ *  A handle to the viewer window.  As usual, a NULL pointer indicates
+ *   something went wrong.
+ */
+
+viewer viewer_create
+(
+  int x,
+  int y,
+  int width,
+  int height,
+  sprite_area *spr,
+  char *title,
+  char *banner
+);
+
+/*
+ * void viewer_display(viewer v)
+ *
+ * Use
+ *  Displays a viewer on the screen.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ */
+
+void viewer_display(viewer v);
+
+/*
+ * void viewer_hide(viewer v)
+ *
+ * Use
+ *  Hides an open viewer.
+ *
+ * Parameters
+ *  viewer v == the handle
+ */
+
+void viewer_hide(viewer v);
+
+/*
+ * void viewer_delete(viewer v,void (*freeProc)(void *handle))
+ *
+ * Use
+ *  Zaps a viewer and everything in it.  The function you pass to this
+ *  routine is called with every icon handle the viewer has associated with
+ *  it, so you don't need to link all the structures together - I've already
+ *  done that here!
+ *
+ * Parameters
+ *  viewer v == the viewer to destroy
+ *  void (*freeProc)(void *handle) == a function to free one of the caller-
+ *    defined viewer icon structures.
+ */
+
+void viewer_delete(viewer v,void (*freeProc)(void *handle));
+
+/*
+ * void viewer_eventHandler(viewer v,viewer_eventhandler proc,void *handle)
+ *
+ * Use
+ *  Attaches an event handler to the viewer.  The handle passed to this
+ *  function is only used for close events, so you can take appropriate
+ *  action at the other end.  Otherwise, the handle for the icon concerned
+ *  is used.  Suggested code:
+ *
+ * void user_viewer(viewer v,viewer_icon i,wimp_bbits b,void *handle)
+ * {
+ *   user_fileStructure *file=(user_fileStructure *)handle;
+ *   user_itemStructure *item=(user_itemStructure *)handle;
+ *   switch ((int)i)
+ *   {
+ *     case (int)viewer_CLOSE:
+ *       ... use 'file' for this bit of code ...
+ *       break;
+ *     case viewer_NOICON:
+ *       ... use 'file' for this bit as well ...
+ *       break;
+ *     default:
+ *       ... use 'item' for this bit of code ...
+ *       break;
+ *   }  
+ * }
+ *
+ * Parameters
+ *  viewer v == the viewer to attach the handler to
+ *  viewer_eventhandler proc == the event handler
+ *  void *handle == the handle
+ */
+
+void viewer_eventHandler(viewer v,viewer_eventhandler proc,void *handle);
+
+/*
+ * void viewer_rawEventHandler
+ * (
+ *   viewer v,
+ *   viewer_raweventhandler proc,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Attaches a raw event handler to a viewer.  Same as always, this one.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  viewer_raweventhandler proc == the handler routine
+ *  void *handle == the handle for the user's data
+ */
+
+void viewer_rawEventHandler
+(
+  viewer v,
+  viewer_raweventhandler proc,
+  void *handle
+);
+
+/*
+ * void viewer_redrawHandler(viewer v,viewer_redrawhandler proc,void *handle)
+ *
+ * Use
+ *  Adds in a user-defined routine for redrawing icons in the window.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  viewer_redrawhandler proc == the routine for doing the redraw
+ *  void *handle == a handle to be passed to the routine (a sprite area or
+ *    something)
+ */
+
+void viewer_redrawHandler(viewer v,viewer_redrawhandler proc,void *handle);
+
+/*
+ * void viewer_setIconSize(viewer v,int width,int height)
+ *
+ * Use
+ *  Sets a new icon size for the viewer.  This would normally be
+ *  accompanied by a chnge in redraw handler.  It would be used e.g. when
+ *  using a menu option giving a choice between 'Large icons' and 'Small
+ *  icons'.
+ *
+ * Parameters
+ *  viewer v == the viewer which is to receive this change
+ *  int width == the new width
+ *  int height == the new height
+ */
+void viewer_setIconSize(viewer v,int width,int height);
+
+/*
+ * void viewer_setCompare(viewer v,viewer_compare cmp)
+ *
+ * Use
+ *  Registers a compare function for the viewer specified.  The function
+ *  is passed the caller-defined handles of two icons.  The function must
+ *  return <0 if a<b, >0 if a>b, or ==0 if a==b (like strcmp does).  The
+ *  viewer's icons are then resorted.  Pass 0 to use the default sorting
+ *  system (a caseless compare on the icon text)
+ *
+ * Parameters
+ *  viewer v == the viewer we're going to set the comparer up for
+ *  viewer_compare cmp == the function to do comparing
+ */
+
+void viewer_setCompare(viewer v,viewer_compare cmp);
+
+/*
+ * viewer_icon viewer_addIcon
+ * (
+ *   viewer v,
+ *   char *text,
+ *   char *sprite,
+ *   BOOL inOrder,
+ *   void *handle
+ * )
+ *
+ * Use
+ *  Adds a new icon to a viewer window.  
+ *
+ * Parameters
+ *  viewer v == the handle of the viewer to use.
+ *  char *text == the text to put under the icon (may be null)
+ *  char *sprite == the sprite to use (may be null)
+ *  BOOL inOrder == whether you want the icons sorted into order according
+ *   to the text fields
+ *  void *handle == the handle you want to pass to the event handler routine
+ *
+ * Returns
+ *  A handle to the icon.  If this is NULL, something went majorly wrong 
+ *  (sorry, John)
+ */
+
+viewer_icon viewer_addIcon
+(
+  viewer v,
+  char *text,
+  char *sprite,
+  BOOL inOrder,
+  void *handle
+);
+
+/*
+ * void viewer_setFiletype(viewer_icon i,int type)
+ *
+ * Use
+ *  Sets the filetype of the icon - useful for bins and things.  This
+ *  filetype overrides the setting given to viewer_exportSelected().  It can
+ *  also be used to display the correct icon in the viewer by changing the
+ *  redraw handler to viewer_drawFileIcons().
+ *
+ * Parameters
+ *  viewer_icon i == the icon to change
+ *  int type == the filetype to give it (any valid WIMP filetype will do)
+ */
+
+void viewer_setFiletype(viewer_icon i,int type);
+
+/*
+ * int viewer_readFiletype(viewer_icon i)
+ *
+ * Use
+ *  Returns the filetype attached to an icon.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *
+ * Returns
+ *  The type attached using viewer_setFiletype(), or -1 if none.
+ */
+
+int viewer_readFiletype(viewer_icon i);
+
+/*
+ * viewer_icon viewer_findIcon(viewer v,char *text)
+ *
+ * Use
+ *  Searches through a viewer to find an icon with the same text as 'text'.
+ *  The search is case-insensitive.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  char *text == text to search for
+ *
+ * Returns
+ *  The icon handle, or viewer_NOICON if unsuccessful.
+ */
+
+viewer_icon viewer_findIcon(viewer v,char *text);
+
+/*
+ * void viewer_removeIcon(viewer_icon i)
+ *
+ * Use
+ *  Removes the icon specified.  This routine is real easy!
+ *
+ * Parameters
+ *  viewer_icon i == the icon to remove (they ALL have unique handles, so
+ *    this is OK)
+ */
+
+void viewer_removeIcon(viewer_icon i);
+
+/*
+ * wimp_w viewer_syshandle(viewer v)
+ *
+ * Use
+ *  Returns the WIMP window handle used for the viewer (and much use may it
+ *  do you!)
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *
+ * Returns
+ *  The wimp_w window handle
+ */
+
+wimp_w viewer_syshandle(viewer v);
+
+/*
+ * viewer_icon viewer_iconFromCoords(viewer v,int x,int y)
+ *
+ * Use
+ *  Given a set of (absolute) coordinates, this returns the icon in the
+ *  viewer specified that the point is on.  This is mainly useful for menu 
+ *  maker routines, which will want to be able to select items and so on.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  int x == the x-coordinate of the point
+ *  int y == the y-coordinate of the point
+ *
+ * Returns
+ *  The icon handle, or viewer__NOICON if there isn't one.
+ */
+
+viewer_icon viewer_iconFromCoords(viewer v,int x,int y);
+
+/*
+ * void viewer_iconToCoords(viewer_icon i,wimp_box *box)
+ *
+ * Use
+ *  Calculates the bounding box of the icon given.  If there is an error,
+ *  nothing is written in the block.
+ *
+ * Parameters
+ *  viewer_icon i == the icon we're interested in
+ *  wimp_box *box == where to store the coordinates
+ */
+
+void viewer_iconToCoords(viewer_icon i,wimp_box *box);
+
+/*
+ * BOOL viewer_isSelected(viewer_icon i)
+ *
+ * Use
+ *  Returns whether an icon is selected or not.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *
+ * Returns
+ *  TRUE if the icon is selected, or FALSE otherwise.
+ */
+
+BOOL viewer_isSelected(viewer_icon i);
+
+/*
+ * void viewer_selectIcon(viewer_icon i,BOOL onOrOff)
+ *
+ * Use
+ *  Selects or deselects the icon specified.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *  BOOL onOrOff == TRUE to select, FALSE to deselect
+ */
+
+void viewer_selectIcon(viewer_icon i,BOOL onOrOff);
+
+/*
+ * viewer viewer_iconToViewer(viewer_icon i)
+ * 
+ * Use
+ *  Returns the viewer in which an icon is contained.
+ *
+ * Parameters
+ *  viewer_icon i == the icon handle
+ *
+ * Returns
+ *  The viewer handle.
+ */
+
+viewer viewer_iconToViewer(viewer_icon i);
+
+/*
+ * void *viewer_iconHandle(viewer_icon i)
+ *
+ * Use
+ *  Returns the handle attached to the icon when it was created
+ *
+ * Parameters
+ *  viewer_icon i == the icon in question
+ *
+ * Returns
+ *  The handle attached
+ */
+
+void *viewer_iconHandle(viewer_icon i);
+
+/*
+ * char *viewer_textOfIcon(viewer_icon i)
+ *
+ * Use
+ *  Returns the text of the icon given.
+ *
+ * Parameters
+ *  viewer_icon i == the icon
+ *
+ * Returns
+ *  Pointer to the string (read only!).
+ */
+
+char *viewer_textOfIcon(viewer_icon i);
+
+/*
+ * int viewer_selected(viewer v)
+ *
+ * Use
+ *  Informs caller how many icons are selected.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *
+ * Returns
+ *  The number of icons selected.
+ */
+
+int viewer_selected(viewer v);
+
+/*
+ * int viewer_icons(viewer v)
+ *
+ * Use
+ *  Returns the number of icons in a viewer.
+ *
+ * Parameters
+ *  viewer v == the viewer
+ *
+ * Returns
+ *  The number of icons.
+ */
+
+int viewer_icons(viewer v);
+
+/*
+ * void viewer_doForIcons
+ * (
+ *   viewer v,
+ *   BOOL onlySelected,
+ *   void (*proc)(viewer_icon i,void *handle)
+ * )
+ *
+ * Use
+ *  Does the same thing for either all the icons in a viewer, or just the
+ *  selected ones.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  BOOL onlySelected == whether you want to handle just the selected ones,
+ *    or the whole lot.
+ *  void (*proc)(viewer_icon i,void *handle) == the routine to do whatever
+ *    it is you want to do.
+ */
+
+void viewer_doForIcons
+(
+  viewer v,
+  BOOL onlySelected,
+  void (*proc)(viewer_icon i,void *handle)
+);
+
+/*
+ * void viewer_selectAll(viewer v,BOOL onOrOff)
+ *
+ * Use
+ *  Selects or deselects all the icons in a viewer.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  BOOL onOrOff == whether you want the icons to be on or off
+ */
+
+void viewer_selectAll(viewer v,BOOL onOrOff);
+
+/*
+ * void viewer_clickSelect(viewer v,viewer_icon i,wimp_bbits b)
+ *
+ * Use
+ *  Handles a click on an icon just like clicks in Filer windows.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  viewer_icon i == the icon that was clicked
+ *  wimp_bbits b == the mouse button status
+ */
+
+void viewer_clickSelect(viewer v,viewer_icon i,wimp_bbits b);
+
+/*
+ * char *viewer_menuItem(viewer v,char *header)
+ *
+ * Use
+ *  Returns a menu item of the form either "~<header> ''", 
+ *  "<header> '<icon name>'", or "Selection", for inclusion in a menu 
+ *  string.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  char *header == the header for the menu item
+ *
+ * Returns
+ *  A pointer to a read-only string.
+ */
+
+char *viewer_menuItem(viewer v,char *header);
+
+/*
+ * void viewer_setupMenu(viewer v,char *header,menu m,int i,char *buff)
+ *
+ * Use
+ *  Writes a menu item out as for the previous routine, but implants it
+ *  directly into the menu, so you don't need to fiddle about with things
+ *  like that, and also means that the menu pointer changes.  The menu item
+ *  must have been previously set up with menu_redirectItem.  This call will
+ *  also set the menu to the correct width.  However, ensure that you call
+ *  menu_minWidth(m,0) before fiddling with the width!
+ *
+ * Parameters
+ *  viewer v == the viewer handle pertaining to this request
+ *  menu m == the menu to doctor
+ *  int i == the menu item
+ *  char *buff == where the menu item wants the data
+ */
+
+void viewer_setupMenu(viewer v,char *header,menu m,int i,char *buff);
+
+/*
+ * viewer_icon viewer_firstSelected(viewer v)
+ *
+ * Use
+ *  Returns the handle of the first selected icon.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *
+ * Returns
+ *  A handle to the first one, or viewer_NOICON.
+ */
+
+viewer_icon viewer_firstSelected(viewer v);
+
+/*
+ * void viewer_settitle(viewer v,char *title)
+ *
+ * Use
+ *  Changes a viewer's title, so that the extent is updated as well.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *  char *title == the new title string
+ */
+
+void viewer_settitle(viewer v,char *title);
+
+/*
+ * void viewer_dragSelected(viewer_icon icn,wimp_bbits b)
+ *
+ * Use
+ *  Drags a set of icons around a window.
+ *
+ * Parameters
+ *  viewer_icon icn == the viewer icon handle
+ *  wimp_bbits b == the button types that started this lot off
+ */
+
+void viewer_dragSelected(viewer_icon icn,wimp_bbits b);
+
+/*
+ * void viewer_exportSelected
+ * (
+ *   viewer_icon icn,
+ *   wimp_bbits b,
+ *   int filetype,
+ *   viewer_saveproc save,
+ *   viewer_sendproc send,
+ *   viewer_printproc print
+ * )
+ *
+ * Use
+ *  Allows you to export the data connected with each selected icon to 
+ *  another application.  The filename used is the icon's text.
+ *
+ * Parameters
+ *  viewer_icon icn == the icon on which the user clicked to start the drag
+ *    operation.
+ *  wimp_bbits b == the mouse buttons which started this up.
+ *  int filetype == the filetype of the data.
+ *  viewer_saveproc save == the save routine (saving and <Wimp$Scrap> 
+ *    transfer.
+ *  viewer_sendproc send == the send routine (RAM transfer).
+ *  viewer_printproc print == the print routine (printing etc.)
+ */
+
+void viewer_exportSelected
+(
+  viewer_icon icn,
+  wimp_bbits b,
+  int filetype,
+  viewer_saveproc save,
+  viewer_sendproc send,
+  viewer_printproc print
+);
+
+/*
+ * viewer_icon viewer_helpIcon(viewer v)
+ *
+ * Use
+ *  Informs the caller which icon the Help system is interested in.
+ *
+ * Parameters
+ *  viewer v == the viewer handle
+ *
+ * Returns
+ *  The icon's handle (or maybe viewer_NOICON)
+ */
+
+viewer_icon viewer_helpIcon(viewer v);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/visdelay b/StraySrc/Libraries/Steel/h/visdelay
new file mode 100644 (file)
index 0000000..957f71d
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * videlay
+ *
+ *  Provides a bit more control than the original version
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __visdelay_h
+#define __visdelay_h
+
+/*
+ * This is a strcuture type only defined here for the use of the compiler to
+ * get the size right.  You should not rely on any part of the definition of
+ * this structure, or even that it will remain a structure.
+ */
+
+typedef struct
+{
+  int count;
+  int percent;
+}
+visdelay_state;
+
+/*
+ * visdelay_init() is one of the biggest wastes of space in RISC_OSlib.
+ * Well, here we rectify the problem.  In no versions of visdelay included
+ * with ArmenLib will a call to visdelay_init() be necessary.
+ */
+
+#define visdelay_init(x) ((void)0)
+
+/*
+ * void visdelay_begin(void)
+ *
+ * Use
+ *  Starts the hourglass.
+ */
+
+void visdelay_begin(void);
+
+/*
+ * void visdelay_end(void)
+ *
+ * Use
+ *  Turns off the hourglass.  Note that calls to visdelay_begin() and
+ *  visdelay_end() must be matched.
+ */
+
+void visdelay_end(void);
+
+/*
+ * void visdelay_percent(int percent)
+ *
+ * Use
+ *  Puts up the little percentage indicator on the hourglass.
+ *
+ * Parameters
+ *  int percent == the percentage number to indicate.
+ */
+
+void visdelay_percent(int percent);
+
+/*
+ * visdelay_state visdelay_suspend(void)
+ *
+ * Use
+ *  Turns the hourglass right off.  It also returns information about the
+ *  current state of the hourglass so that it can be resumed.
+ *
+ * Returns
+ *  State information recorded in an undefined manner.
+ */
+
+visdelay_state visdelay_suspend(void);
+
+/*
+ * void visdelay_resume(visdelay_state state)
+ *
+ * Use
+ *  Returns the hourglass to the state it was in when the last
+ *  visdelay_suspend() call was made.
+ *
+ * Parameters
+ *  visdelay_state state == the hourglass state as returned by
+ *    visdelay_suspend().
+ */
+
+void visdelay_resume(visdelay_state state);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/vsscanf b/StraySrc/Libraries/Steel/h/vsscanf
new file mode 100644 (file)
index 0000000..1503c79
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * vsscanf
+ *
+ *  the function that ANSI forgot...
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __vsscanf_h
+#define __vsscanf_h
+
+#ifndef __stdarg_h
+#include <stdarg.h>
+#endif
+
+/*
+ * int vsscanf(char *string,char *format,va_list ap)
+ *
+ * Use
+ *  vsscanf() should be an alternative entry point for sscanf().  
+ *  Unfortunately, it doesn't exist, so it has been reimplemented.  It is as
+ *  compatible with sscanf() as I can make it.  It supports all features of
+ *  the original, including scansets and things.
+ *
+ * Parameters
+ *  char *string == the string to parse
+ *  char *format == the format string
+ *  va_list ap == pointer to variable length parameters list.  If there are
+ *    too many arguments, they are ignored.  If there are too few, the
+ *    machine will problably crash.
+ *
+ * Returns
+ *  The number of arguments assigned with values.
+ */
+
+int vsscanf(char *string,char *format,va_list ap);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/werr b/StraySrc/Libraries/Steel/h/werr
new file mode 100644 (file)
index 0000000..7acaffc
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * werr
+ *  Just like the old one, only nicer.
+ *
+ * v. 1.00 (8 Aug 1991)
+ *
+ * © 1991-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __werr_h
+#define __werr_h
+
+/*
+ * void werr_bleepy(void)
+ *
+ * Use
+ *  Bleeps if and only if the appropriate WimpFlags bit is right for
+ *  bleeping.
+ */
+
+void werr_bleepy(void);
+
+/*
+ * void werr_init(void)
+ *
+ * Use
+ *  Sets up the werr system ready for action.
+ */
+
+void werr_init(void);
+
+/*
+ * void werr(int fatal,char *error,...)
+ *
+ * Use
+ *  Compatibility with the old werr segment mainly.
+ *
+ * Parameters
+ *  int fatal == 1 if the error is fatal, or 0 otherwise.
+ *  char *error == printf()-type format string.
+ */
+
+void werr(int fatal,char *error,...);
+
+/*
+ * int werr_error(int buttons,char *error,...)
+ *
+ * Use
+ *  Reports an error.  You can have two buttons, OK and Cancel if you really
+ *  want, now.
+ *
+ * Parameters
+ *  int buttons == 1 for 1 button, 2 for 2 buttons, or anything else for an
+ *    unpredictable result.
+ *  char *error == printf()-like format string.
+ *
+ * Returns
+ *  1 for OK, 0 for cancel.
+ */
+
+int werr_error(int buttons,char *error,...);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/wimp b/StraySrc/Libraries/Steel/h/wimp
new file mode 100644 (file)
index 0000000..b34f454
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * wimp.h
+ *
+ * Interface to WIMP SWIs
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __wimp_h
+#define __wimp_h
+
+#ifndef __wimpstruct_h
+  #include "wimpstruct.h"
+#endif
+
+/*----- Notes -------------------------------------------------------------*
+ *
+ * This file defines functions callable from C programs to allow access to
+ * the WIMP at the SWI level.
+ *
+ * Each function maps directly to a single WIMP SWI, and performs little
+ * or no additional processing.  For full information about each one,
+ * you should consult the RISC OS 3 Programmer's Reference Manual.
+ * Little or no documentation is provided for each function.
+ *
+ * Two SWIs are not supported currently:
+ *
+ * Wimp_ClaimFreeMemory -- since the memory is only usable in SVC mode,
+ *   it doesn't seem to be very useful to be able to claim it from C.
+ *
+ * Wimp_SetColourMapping -- this call is only useful for specialised 
+ *   applications, and a veneer defined here isn't really appropriate.
+ */
+
+/*----- Polling the WIMP --------------------------------------------------*
+ *
+ * The two functions wimp_poll and wimp_pollidle map to SWIs Wimp_Poll and
+ * Wimp_PollIdle respectively.  The other two functions control the saving
+ * or not of the floating point status -- the default is to save this
+ * status (although this is not performed if the FPEmulator is not present).
+ *
+ * Correct handling of the DLL Application Handle is also performed.
+ */
+
+os_error *wimp_poll(wimp_emask mask,wimp_eventstr *e);
+os_error *wimp_pollidle(wimp_emask mask,wimp_eventstr *e,int time);
+
+void wimp_corrupt_fp_state_on_poll(void);
+void wimp_save_fp_state_on_poll(void);
+
+/*----- Initialising the WIMP ---------------------------------------------*
+ *
+ * wimp_initialise should only be used if you don't want a multitasking
+ * application -- not very useful, really.  wimp_taskinit will perform all
+ * the initialisation a full multitasking application requires.  If you
+ * initialise with a version number of 300 or higher, the optional messages
+ * argument should be filled in with a pointer to an array of message
+ * numbers.
+ */
+
+os_error *wimp_initialise(int *version);
+os_error *wimp_taskinit(char *name,
+                        int *version,
+                        wimp_t *taskhandle,...
+                     /* int *messages */);
+
+/*----- Closing down the WIMP ---------------------------------------------*/
+
+os_error *wimp_closedown(void);
+os_error *wimp_taskclose(wimp_t taskhandle);
+
+/*----- Creating and deleting windows and icons ---------------------------*/
+
+os_error *wimp_create_wind(wimp_wind *w,wimp_w *handle);
+os_error *wimp_delete_wind(wimp_w w);
+os_error *wimp_create_icon(wimp_icreate *i,wimp_i *handle);
+os_error *wimp_delete_icon(wimp_w w,wimp_i i);
+
+/*----- Getting and changing window and icon states -----------------------*/
+
+os_error *wimp_open_wind(wimp_openstr *o);
+os_error *wimp_close_wind(wimp_w w);
+os_error *wimp_set_extent(wimp_redrawstr *r);
+os_error *wimp_get_wind_state(wimp_w w,wimp_wstate *s);
+os_error *wimp_get_wind_info(wimp_winfo *w);
+os_error *wimp_get_icon_info(wimp_w w,wimp_i i,wimp_icon *icn);
+os_error *wimp_set_icon_state(wimp_w w,wimp_i i,int eorMask,int bicMask);
+os_error *wimp_which_icon(wimp_which_block *w,wimp_i *icons);
+os_error *wimp_getwindowoutline(wimp_redrawstr *r);
+
+/*----- Redrawing windows -------------------------------------------------*/
+
+os_error *wimp_redraw_wind(wimp_redrawstr *r,BOOL *more);
+os_error *wimp_update_wind(wimp_redrawstr *r,BOOL *more);
+os_error *wimp_get_rectangle(wimp_redrawstr *r,BOOL *more);
+os_error *wimp_force_redraw(wimp_redrawstr *r);
+os_error *wimp_ploticon(wimp_icon *i);
+os_error *wimp_blockcopy(wimp_w w,wimp_box *box,int x,int y);
+
+/*----- Menu handling -----------------------------------------------------*/
+
+os_error *wimp_create_menu(wimp_menustr *m,int x,int y);
+os_error *wimp_create_submenu(wimp_menustr *m,int x,int y);
+os_error *wimp_decode_menu(wimp_menustr *m,void *hits,void *stringbuffer);
+os_error *wimp_getmenustate(int action,
+                            int *hits,...
+                         /* wimp_w w, */
+                         /* wimp_i i */);
+
+/*----- Colour handling ---------------------------------------------------*/
+
+os_error *wimp_setcolour(int colour);
+os_error *wimp_textcolour(int colour);
+os_error *wimp_setfontcolours(int background,int foreground);
+os_error *wimp_setpalette(wimp_palettestr *pal);
+os_error *wimp_readpalette(wimp_palettestr *pal);
+
+/*----- Sprite handling ---------------------------------------------------*/
+
+os_error *wimp_spriteop(int action,char *sprite);
+os_error *wimp_spriteop_full(os_regset r);
+void *wimp_baseofsprites(void);
+os_error *wimp_readpixtrans(sprite_area *sa,
+                            sprite_id *sid,
+                            sprite_factors *zoomage,
+                            sprite_pixtrans *pixtrans);
+
+/*----- Message handling --------------------------------------------------*/
+
+os_error *wimp_sendmessage(wimp_etype event,wimp_msgstr *m,wimp_t dest);
+os_error *wimp_sendwmessage(wimp_etype event,
+                            wimp_msgstr *m,
+                            wimp_w w,
+                            wimp_i i);
+os_error *wimp_addmessages(wimp_msgaction *messages);
+os_error *wimp_removemessages(wimp_msgaction *messages);
+
+/*----- Pointer handling --------------------------------------------------*/
+
+os_error *wimp_get_point_info(wimp_mousestr *m);
+os_error *wimp_set_point_shape(wimp_pshapestr *shapeinfo);
+
+/*----- Caret and key handling --------------------------------------------*
+ *
+ * Warning: Don't pass STEEL extended keyset keys on with wimp_processkey!
+ *          Only use standard WIMP key mapping codes.
+ */
+
+os_error *wimp_set_caret_pos(wimp_caretstr *c);
+os_error *wimp_get_caret_pos(wimp_caretstr *c);
+os_error *wimp_processkey(int key);
+
+/*----- Handing template files --------------------------------------------*/
+
+os_error *wimp_open_template(char *filename);
+os_error *wimp_close_template(void);
+os_error *wimp_load_template(wimp_template *loadinfo);
+
+/*----- Miscellaneous calls -----------------------------------------------*
+ *
+ * Warning: Use _dll_starttask instead of wimp_starttask if you are using
+ *          a dynamically linked STEEL.
+ */
+
+os_error *wimp_drag_box(wimp_dragstr *d);
+os_error *wimp_starttask(char *command);
+os_error *wimp_reporterror(os_error *error,wimp_errflags how,char *appname);
+os_error *wimp_setmode(int newmode);
+os_error *wimp_slotsize(int *current,int *next,int *free);
+os_error *wimp_commandwindow(wimp_commandwind *dowhat);
+os_error *wimp_transferblock(wimp_t sourceTask,
+                             char *sourceBuffer,
+                             wimp_t destinationTask,
+                             char *destinationBuffer,
+                             int size);
+os_error *wimp_readsysinfo(wimp_sysinfo info,
+                           int *r0_out,...
+                        /* int *r1_out */);
+
+/*----- The end -----------------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/wimpext b/StraySrc/Libraries/Steel/h/wimpext
new file mode 100644 (file)
index 0000000..59dc647
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * wimpExt.h
+ *
+ * C access to DoggySoft's WimpExtension module
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __wimpExt_h
+#define __wimpExt_h
+
+/*----- Required headers --------------------------------------------------*/
+
+#ifndef __os_h
+  #include "os.h"
+#endif
+
+#ifndef __wimp_h
+  #include "wimp.h"
+#endif
+
+/*----- Data structures and things ----------------------------------------*/
+
+typedef enum wimpExt_features                  /* For wimpExt_initialise   */
+{
+  wimpExt_SEMIAUTOSLAB       =1<<0,
+  wimpExt_AUTORECREATEMENU   =1<<1,
+  wimpExt_USEFONTMENUS       =1<<2,
+  wimpExt_AUTOCOMPACTHEAP    =1<<3,
+  wimpExt_CORRECTRADIO       =1<<4,
+  wimpExt_SEMIAUTOHELP       =1<<5,
+  wimpExt_ALTARGSINSETFLAGS  =1<<6,
+  wimpExt_MAYBEADDELLIPSIS   =1<<7,
+  wimpExt_AUTOMOVECARET      =1<<8,
+  wimpExt_USEESG             =1<<9,
+  wimpExt_SCROLLONCARETMOVE  =1<<10,
+  wimpExt_TABDOESNTMOVECARET =1<<11
+}
+wimpExt_features;
+
+typedef enum wimpExt_ibarSide
+{
+  wimpExt_IBLEFT=-2,
+  wimpExt_IBRIGHT=-1
+}
+wimpExt_ibarSide;
+
+typedef enum wimpExt_linkflags
+{
+  wimpExt_CLIPLEFT  =1<<0,
+  wimpExt_CLIPRIGHT =1<<1,
+  wimpExt_CLIPABOVE =1<<2,
+  wimpExt_CLIPBELOW =1<<3,
+  wimpExt_HIDELINK  =~0x7FFFFFFF /* Yipes */
+}
+wimpExt_linkflags;
+
+typedef enum wimpExt_templateFlags
+{
+  wimpExt_HCENTRE  =1<<0,
+  wimpExt_NOCREATE =1<<1,
+  wimpExt_VCENTRE  =1<<2
+}
+wimpExt_templateFlags;
+
+typedef enum wimpExt_state
+{
+  wimpExt_RESET,
+  wimpExt_SET,
+  wimpExt_TOGGLE
+}
+wimpExt_state;
+
+#define wimpExt_WIMPAREA ((sprite_area *)1)
+#define wimpExt_SYSTEMAREA ((sprite_area *)0)
+
+typedef enum wimpExt_dragFlags
+{
+  /* --- Sprite positionings --- */
+  wimpExt_HLEFT       =0<<0,
+  wimpExt_HMID        =1<<0,
+  wimpExt_HRIGHT      =2<<0,
+  wimpExt_VBOT        =0<<2,
+  wimpExt_VMID        =1<<2,
+  wimpExt_VTOP        =2<<2,
+
+  /* --- Mouse bounding box --- */
+  wimpExt_SCREEN      =0<<4,
+  wimpExt_WINDOW      =1<<4,
+  wimpExt_GIVEN       =2<<4,
+
+  /* --- Other things --- */
+  wimpExt_BOUNDSPRITE =1<<6,
+  wimpExt_SHADOW      =1<<7,
+  wimpExt_FORCESPRITE =1<<8
+}
+
+#define wimpExt_REQUESTER (-3)
+
+#define wimpExt_STANDARDHELP ((void *)1)
+#define wimpExt_NOCHANGEHEAP ((void *)-1)
+#define wimpExt_NOHEAP((void *)0)
+
+typedef struct wimpExt_heapDescription
+{
+  void *currHeap;
+  int largestBlock;
+  int totFree;
+  int heapUsed;
+  int totAnchors;
+  int anchorsUsed;
+}
+wimpExt_heapDescription;
+
+typedef void *wimpExt_heapAnchor;
+
+/*----- Routines ----------------------------------------------------------*
+ *
+ * These aren't described in great detail here.  Instead, you are referred
+ * to Jon Ribbens' excellent documentation, which you should have, or which
+ * may obtained at your friendly local bulletin board or FTP site.  I have
+ * only marked oddities, or departures from the standard interface.
+ *
+ * Hardened speed freaks: have no fear -- all of these interface routines
+ * is written in hand-crafted assembler, by an expert (me :-) ).  I am
+ * *not* Acorn, and really do know that _kernel_swi and os_swi are *not*
+ * the best way to write module veneers.
+ *
+ *---- Some notes on naming calls -----------------------------------------*
+ *
+ * I have attempted to provide a mechanical translation from the SWI names
+ * to the veneer calls which is (a) easy to remember, (b) consistent (Acorn
+ * please note :-( ) and (c) easily fits in with the normal 'style' of C.
+ * All calls begin with the prefix 'wimpExt_'.  I have then lower-cased the
+ * first letter of the individual call name.  e.g. wimpExt_plotSprite.
+ * Some calls return values which aren't always useful.  These have two
+ * variants: one which does not return the value, and one which does.  The
+ * latter has an extra parameter (where to place this return value), and a
+ * '_r' suffix.
+ *
+ * Some calls do a lot of things, depending on a reason code.  These are
+ * handled by having a lot of routines with the call name and a suffix
+ * describing what the call does.
+ *
+ * Other suffices are occasionally added to call names.  These are documented
+ * with the individual interface.
+ */
+
+os_error *wimpExt_initialise(wimpExt_features f);
+/*
+ * This call sets WimpExt_CloseDown to be called automatically via the
+ * atexit system.
+ */
+
+os_error *wimpExt_slabIcon(wimp_w w,wimp_i i,BOOL popIn);
+
+os_error *wimpExt_redraw(wimp_redrawstr *r);
+
+os_error *wimpExt_action(wimp_eventstr *e);
+/*
+ * Warning -- the event structure may be modified by this call.
+ */
+
+os_error *wimpExt_iconBarSprite(wimp_i *i,
+                                wimpExt_ibarSide s,
+                                char *sprite,
+                                wimp_ibtype btype);
+os_error *wimpExt_iconBarText(wimp_i *i,
+                              wimpExt_ibarSide s,
+                              char *sprite,
+                              char *text,
+                              wimp_ibtype btype);
+/*
+ * These last two are *not* recommended -- ibicon provides a much better 
+ * may of controlling the icon bar :-)
+ */
+
+os_error *wimpExt_linkWindows(wimp_w main,wimp_w sub,wimpExt_linkflags f);
+
+os_error *wimpExt_openLinked(wimp_openstr *o);
+
+os_error *wimpExt_closeLinked(wimp_w w);
+
+os_error *wimpExt_unLinkWindows(wimp_w main,wimp_w sub);
+
+os_error *wimpExt_currentTask(void);
+/*
+ * Like all WimpExtension calls that are interested in task handles, this
+ * one uses wimpt_task() to get it.
+ */
+
+os_error *wimpExt_loadTemplates(wimp_w handles[],
+                                void *bigBuff,
+                                char *indirectData,
+                                char *indirectEnd,
+                                char fontArray[], /* Or *0* for no fonts */
+                                char *filename,
+                                sprite_area *s);
+/*
+ * I recommend you use tyhe standard template functions instead -- they
+ * prevent you from creating all the windows on startup.
+ */
+
+os_error *wimpExt_setIconString(BOOL ellipsis, /* Only if feature code set */
+                                wimp_w w,
+                                wimp_i i,
+                                char *text);
+
+os_error *wimpExt_openWindowTop(wimp_w w);
+
+os_error *wimpExt_setIcon(wimp_w w,wimp_i i,wimpExt_state s);
+os_error *wimpExt_setIcon_r(wimp_w w,wimp_i i,wimpExt_state s,BOOL *old);
+
+os_error *wimpExt_getIcon(wimp_w w,wimp_i i,BOOL *old);
+os_error *wimpExt_getIcon_t(wimp_w w,wimp_i i,BOOL *old,char **indText);
+/*
+ * The '_t' variant returns the word at iconblock+20 (which would be the
+ * indirected text of an indirected icon).
+ */
+
+os_error *wimpExt_setNumberIcon(int base,wimp_w w,wimp_i i,int value);
+
+os_error *wimpExt_getNumberIcon(int base,wimp_w w,wimp_i i,int *value);
+
+os_error *wimpExt_incNumberIcon(int base,
+                                wimp_w w,
+                                wimp_i i,
+                                int max,
+                                int step);
+os_error *wimpExt_incNumberIcon_r(int base,
+                                  wimp_w w,
+                                  wimp_i i,
+                                  int max,
+                                  int step,
+                                  int *value);
+
+os_error *wimpExt_decNumberIcon(int base,
+                                wimp_w w,
+                                wimp_i i,
+                                int min,
+                                int step);
+os_error *wimpExt_decNumberIcon_r(int base,
+                                  wimp_w w,
+                                  wimp_i i,
+                                  int min,
+                                  int step,
+                                  int *value);
+
+os_error *wimpExt_setPointer(char *pointer,int hotx,int hoty);
+
+os_error *wimpExt_divide(int divident,
+                         int divisor,
+                         int *quotient,
+                         int *remainder);
+/*
+ * One doesn't have to see the point -- one just has to write the veneer.
+ * My suggestion -- use C's built-in divide operator.  Acorn say they've
+ * put a lot of effort into _kernel_udiv etc.  Don't let them down.  They
+ * might produce another Style Guide :-/
+ */
+
+os_error *wimpExt_coloursMenu(wimp_menustr *m,int itemToTick,BOOL backg);
+
+os_error *wimpExt_autoRedraw(wimp_redrawstr *r);
+
+os_error *wimpExt_centreWindow(wimp_wstate *s);
+
+os_error *wimpExt_dragIcon(wimpExt_dragFlags f,
+                           sprite_area *s,
+                           wimp_w w,
+                           wimp_i i,
+                           char *sprite,
+                           wimp_box *box);
+
+os_error *wimpExt_putCaretIcon(wimp_w w,wimp_i i);
+
+os_error *wimpExt_openDialogue(wimp_w,int offx,int offy);
+
+os_error *wimpExt_checkWindowOpen(wimp_w w,BOOL *open);
+
+os_error *wimpExt_copyString(char *to,char *from);
+/*
+ * If I were you, I'd use strcpy.  Still, this works on char-terminated
+ * strings, and NULL-terminates the destination.  WimpExtension veterans
+ * will notice I've swapped the arguments round.  This is to make it more
+ * like strcpy, which C users have probably encountered already.  It saves
+ * thought time.
+ */
+
+os_error *wimpExt_setWindowTitle(wimp_w w,char *string);
+
+os_error *wimpExt_setIconStringN(BOOL ellipsis, /* Only if feature code set*/
+                                 wimp_w w,
+                                 wimp_i i,
+                                 char *text);
+
+char *wimpExt_findLeaf(char *path);
+/*
+ * Purists will note that I have deviated from the convention of returning
+ * the error information.  This is because (a) it makes the calling more 
+ * natural, and (b) this SWI doesn't have any errors anyway (I checked with
+ * Zap :-) ).
+ */
+
+os_error *wimpExt_limitPointer(wimp_w w);
+
+os_error *wimpExt_releasePointer(void);
+
+os_error *wimpExt_openFullSize(wimp_w w,wimp_w behind);
+
+os_error *wimpExt_loadRAMTemplate(wimp_wind *buf,
+                                  char **indStart,
+                                  char *indEnd,
+                                  char fonts[], /* Ignored in this release */
+                                  void *temp);
+/*
+ * I can't see the use of it myself.  Still, it's there, so I've got to do
+ * the veneer for it...
+ */
+
+os_error *wimpExt_openRequester(char *title,
+                               char *text,
+                               char *buttons[],
+                               int escape);
+
+os_error *wimpExt_closeRequester(void);
+
+os_error *wimpExt_hideLink(wimp_w main,wimp_w sub);
+
+os_error *wimpExt_unHideLink(wimp_w main,wimp_w sub);
+
+os_error *wimpExt_sendHelp(char *text,wimp_msgstr *m);
+
+os_error *wimpExt_sendWimpHelp(char *ref,char *document);
+/*
+ * This call may change, depending on Diamond's final name.  There will also
+ * be Diamond Help Viewer support in Steel anyway.
+ */
+
+os_error *wimpExt_createMenu(wimp_menustr *m,int x,int y);
+
+os_error *wimpExt_reCreateMenu(void);
+
+os_error *wimpExt_shadeEntry(wimp_menustr *m,int option,wimpExt_state s);
+os_error *wimpExt_shadeEntry_r(wimp_menustr *m,
+                               int option,
+                               wimpExt_state s,
+                               BOOL *old);
+
+os_error *wimpExt_tickEntry(wimp_menustr *m,int option,wimpExt_state s);
+os_error *wimpExt_tickEntry_r(wimp_menustr *m,
+                              int option,
+                              wimpExt_state s,
+                              BOOL *old);
+
+os_error *wimpExt_setIconColour(wimp_w w,wimp_i i,int fg,int bg);
+os_error *wimpExt_setIconColour_r(wimp_w w,wimp_i i,int *fg,int *bg);
+
+os_error *wimpExt_shadeIcon(wimp_w w,wimp_i i,wimpExt_state s);
+os_error *wimpExt_shadeIcon_r(wimp_w w,wimp_i i,wimpExt_state s,BOOL *old);
+
+/*
+ * WimpExt_PlotSprite should not be used.  Use wimpExt_spriteOp_plot
+ * instead.
+ */
+
+/*
+ * WimpExt_RedrawDraw should not be used.  Use wimpExt_drawOp_redraw
+ * instead.
+ */
+
+os_error *wimpExt_prePoll(void);
+
+os_error *wimpExt_setExtent(wimp_redrawstr *r);
+
+os_error *wimpExt_moveCaret(int *key,wimp_w w,wimp_i i);
+
+os_error *wimpExt_getFontMenu(BOOL shadeSystem,char *title,wimp_menustr **m);
+os_error *wimpExt_decodeFontMenu(char *name,wimp_eventstr *e);
+/*
+ * I recommend that you use the Steel font menu routines -- they're much
+ * nicer :-).  WimpExtension doesn't do item ticking etc.
+ */
+
+/* --- WimpExt_ControlImmediate --- */
+
+os_error *wimpExt_controlImmediate_close(void);
+os_error *wimpExt_controlImmediate_checkMouse(wimp_i *icon);
+os_error *wimpExt_controlImmediate_openAndCheck(char *title,
+                                               char *text,
+                                               char *buttons[],
+                                               int escape
+                                               wimp_i *icon);
+os_error *wimpExt_controlImmediate_redrawIcon(wimp_i i);
+os_error *wimpExt_controlImmediate_slabIcon(wimp_i i,BOOL slabIn);
+os_error *wimpExt_controlImmediate_limitPtr(void);
+os_error *wimpExt_controlImmediate_redrawBorder(wimp_i i);
+os_error *wimpExt_controlImmediate_redrawIcon(wimp_icon *i,int ox,int oy);
+os_error *wimpExt_controlImmediate_fromWindow(wimp_wind *w,wimp_i *icon);
+
+/* --- WimpExt_Heap --- *
+ *
+ * Fun time...
+ */
+
+os_error *wimpExt_heap_initStd(void *base,int anchors);
+os_error *wimpExt_heap_describe(wimpExt_heapDescription *h);
+os_error *wimpExt_heap_alloc(wimpExt_heapAnchor **a,size_t size);
+os_error *wimpExt_heap_free(void *p);
+os_error *wimpExt_heap_realloc(wimpExt_heapAnchor **a,void *p,size_t size);
+os_error *wimpExt_heap_tidy(void);
+os_error *wimpExt_heap_compact(void);
+os_error *wimpExt_heap_findAnchor(wimpExt_heapAnchor **a,void *p);
+os_error *wimpExt_heap_fix(void);
+os_error *wimpExt_heap_forceUnfix(void);
+os_error *wimpExt_heap_unfix(void);
+os_error *wimpExt_heap_addAnchors(int anchors,BOOL *worked);
+os_error *wimpExt_heap_allocAddAnchors(wimpExt_heapAnchor **a,size_t size);
+os_error *wimpExt_heap_freeAll(void);
+os_error *wimpExt_heap_select(void *heap);
+os_error *wimpExt_heap_select_r(void *heap,void **oldHeap,void **newHeap);
+os_error *wimpExt_heap_relocate(void);
+os_error *wimpExt_heap_createInHeap(void **heap,int anchors);
+
+os_error *wimpExt_memCopy(void *to,void *from,size_t for);
+/*
+ * Again, I have switched the order of arguments.  I suggest you use memcpy
+ * or (better) memmove for these jobs -- it's highly optimised now, and
+ * generally really good.
+ */
+
+os_error *wimpExt_dataSave(size_t size,
+                           char *name,
+                           int ftype,
+                           void *data,
+                           BOOL dontSaveToSelf,
+                           wimp_mousestr *m);
+os_error *wimpExt_dataSave_r(size_t size,
+                             char *name,
+                             int ftype,
+                             void *data,
+                             BOOL dontSaveToSelf,
+                             wimp_mousestr *m);
+
+
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/wimpstruct b/StraySrc/Libraries/Steel/h/wimpstruct
new file mode 100644 (file)
index 0000000..fa29c84
--- /dev/null
@@ -0,0 +1,914 @@
+/*
+ * wimpstruct.h
+ *
+ * All the many structures you need for the WIMP
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __wimpstruct_h
+#define __wimpstruct_h
+
+#ifndef __os_h
+  #include "os.h"
+#endif
+
+#ifndef __sprite_h
+  #include "sprite.h"
+#endif
+
+/*----- Various handles ---------------------------------------------------*/
+
+typedef int wimp_w;                    /* Normal window handle            */
+typedef int wimp_i;                    /* Icon `handle'                   */
+typedef int wimp_t;                    /* Task handle                     */
+
+/*----- Defining windows and icons ----------------------------------------*/
+
+/* --- Window flags --- *
+ *
+ * Warning: The naming here is inconsistent.  Be careful.  The names are
+ *          the same as used in RISC_OSLib, so it's not my fault
+ */
+
+typedef enum
+{
+  /* --- Basic window properties --- */
+
+  wimp_WMOVEABLE       =(1<<1),        /* Can be moved by user            */
+  wimp_REDRAW_OK       =(1<<4),        /* Is redrawn only by WIMP         */
+  wimp_WPANE           =(1<<5),        /* Is a pane of a window           */
+  wimp_WTRESPASS       =(1<<6),        /* Can move off-screen             */
+  wimp_WSCROLL_R1      =(1<<8),        /* Scroll requests, auto-repeat    */
+  wimp_SCROLL_R2       =(1<<9),        /* Scroll requests, debounced      */
+  wimp_REAL_COLOURS    =(1<<10),       /* Use real window colours         */
+  wimp_BACK_WINDOW     =(1<<11),       /* Always stays at the back        */
+  wimp_HOT_KEYS                =(1<<12),       /* Intercepts hotkeys              */
+
+  /* --- Current window state (set by the WIMP) --- */
+
+  wimp_WOPEN           =(1<<16),       /* Is currently open               */
+  wimp_WTOP            =(1<<17),       /* Is completely visible           */
+  wimp_WFULL           =(1<<18),       /* Is as big as possible           */
+  wimp_WCLICK_TOGGLE   =(1<<19),       /* Size has just been toggled      */
+  wimp_WFOCUS          =(1<<20),       /* Owns the input focus            */
+
+  /* --- Window `gadgets' --- */
+
+  wimp_WBACK           =(1<<24),       /* Send-to-back gadget             */
+  wimp_WQUIT           =(1<<25),       /* Close window gadget             */
+  wimp_WTITLE          =(1<<26),       /* Title bar                       */
+  wimp_WTOGGLE         =(1<<27),       /* Toggle size gadget              */
+  wimp_WVSCR           =(1<<28),       /* Vertical scroll bar             */
+  wimp_WSIZE           =(1<<29),       /* Adjust size gadget              */
+  wimp_WHSCR           =(1<<30),       /* Horizontal scroll bar           */
+  wimp_WNEW            =~0x7FFFFFFF    /* Use new gadget flags            */
+}
+wimp_wflags;
+
+/* --- Icon flags --- */
+
+typedef enum
+{
+  /* --- General flags --- */
+
+  wimp_ITEXT           =(1<<0),        /* Contains text                   */
+  wimp_ISPRITE         =(1<<1),        /* Contains a sprite               */
+  wimp_IBORDER         =(1<<2),        /* Has a WIMP-drawn border         */
+  wimp_IHCENTRE                =(1<<3),        /* Is horizontally centred         */
+  wimp_IVCENTRE                =(1<<4),        /* Is vertically centred           */
+  wimp_IFILLED         =(1<<5),        /* Has a filled background         */
+  wimp_IFONT           =(1<<6),        /* Draw text anti-aliased          */
+  wimp_IREDRAW         =(1<<7),        /* Force redraw on change          */
+  wimp_INDIRECT                =(1<<8),        /* Icon data is indirected         */
+  wimp_IRJUST          =(1<<9),        /* Is right-aligned                */
+  wimp_IESG_NOC                =(1<<10),       /* Adjust clicks toggle selection  */
+  wimp_IHALVESPRITE    =(1<<11),       /* Draw sprite half sized          */
+
+  /* --- Larger fields --- */
+
+  wimp_IBTYPE          =(1<<12),       /* Button type (4 bits)            */
+  wimp_IESG            =(1<<16),       /* ESG number (5 bits)             */
+
+  /* --- Some more flags --- */
+
+  wimp_ISELECTED       =(1<<21),       /* Is selected (inverted)          */
+  wimp_INOSELECT       =(1<<22),       /* Is shaded (unavailable)         */
+  wimp_IDELETED                =(1<<23),       /* Is deleted (invisible)          */
+
+  /* --- Colours/font information --- */
+
+  wimp_IFORECOL                =(1<<24),       /* Foreground colour (4 bits)      */
+  wimp_IBACKCOL                =(1<<28),       /* Background colour (4 bits)      */
+
+  wimp_IFONTH          =(1<<24)        /* Font handle (8 bits)            */
+}
+wimp_iconflags;
+
+/* --- Icon and window button types --- */
+
+typedef enum
+{
+  wimp_BIGNORE,                                /* Ignore all mouse clicks         */
+  wimp_BNOTIFY,                                /* Always report pointer over icon */
+  wimp_BCLICKAUTO,                     /* Report mouse clicks, autorepeat */
+  wimp_BCLICKDEBOUNCE,                 /* Report mouse clicks, debounced  */
+  wimp_BSELREL,                                /* Report mouse button release     */
+  wimp_BSELDOUBLE,                     /* Report mouse double clicks      */
+  wimp_BDEBOUNCEDRAG,                  /* Report clicks and drags         */
+  wimp_BRELEASEDRAG,                   /* Report releases and drags       */
+  wimp_BDOUBLEDRAG,                    /* Report double clicks and drags  */
+  wimp_BSELNOTIFY,                     /* `Menu icon' (reports clicks)    */
+  wimp_BCLICKDRAGDOUBLE,               /* Clicks, double clicks and drags */
+  wimp_BCLICKSEL,                      /* `Radio icon' (clicks and drags) */
+  wimp_BTYPE12,                                /* Reserved for future exapansion  */
+  wimp_BTYPE13,                                /* Reserved for future exapansion  */
+  wimp_BCLICKWRITEDRAG,                        /* Writable; report clicks, drags  */
+  wimp_BWRITABLE                       /* Writable; report nothing        */
+}
+wimp_ibtype;
+
+/* --- Window colours --- */
+
+typedef enum
+{
+  wimp_WCTITLEFORE,                    /* Title bar foreground        (7) */
+  wimp_WCTITLEBACK,                    /* Title bar background        (1) */
+  wimp_WCWKAREAFORE,                   /* Workarea default foreground (7) */
+  wimp_WCWKAREABACK,                   /* Workarea default background (0) */
+  wimp_WCSCROLLOUTER,                  /* Scroll bar `shoulder' area  (3) */
+  wimp_WCSCROLLINNER,                  /* Scroll bar `thumb' area     (1) */
+  wimp_WCTITLEHI,                      /* Highlight for input focus  (12) */
+  wimp_WCRESERVED                      /* The non-existant useless colour */
+}
+wimp_wcolours;
+
+/* --- Defining rectangles --- */
+
+typedef struct
+{
+  int x0,y0;                           /* Bottom left (inclusive)         */
+  int x1,y1;                           /* Top right (exclusive)           */
+}
+wimp_box;
+
+/* --- Icon data --- */
+
+typedef union
+{
+  char text[12];                       /* Non-indirected text string      */
+
+  char sprite_name[12];                        /* Non-indirected sprite name      */
+
+  struct
+  {
+    char *name;                                /* Pointer to sprite name          */
+    void *spritearea;                  /* Pointer to real sprite area     */
+    BOOL nameisname;                   /* FALSE => name is sprite pointer */
+  }
+  indirectsprite;                      /* Indirected sprite information   */
+
+  struct
+  {
+    char *buffer;                      /* Pointer to text buffer          */
+    char *validstring;                 /* Pointer to validation string    */
+    int bufflen;                       /* Size of text buffer in bytes    */
+  }
+  indirecttext;                                /* Indirectted text information    */
+}
+wimp_icondata;
+
+/* --- Window definitions --- */
+
+typedef struct
+{
+  wimp_box box;                                /* Initial position on the screen  */
+  int scx,scy;                         /* Initial scroll bar positions    */
+  wimp_w behind;                       /* Window behind which to open     */
+
+  wimp_wflags flags;                   /* Window flags word               */
+  char colours[8];                     /* Various colours for the window  */
+
+  wimp_box ex;                         /* Initial window extent           */
+
+  wimp_iconflags titleflags;           /* Information about window title  */
+  wimp_iconflags workflags;            /* Work area button type           */
+
+  void *spritearea;                    /* Sprite area for this window     */
+  int minsize;                         /* Minimum size for the window     */
+  wimp_icondata title;                 /* Title bar icon data info        */
+  int nicons;                          /* Number of icons in the window   */
+}
+wimp_wind;
+
+/* --- Icon definitions --- */
+
+typedef struct
+{
+  wimp_box box;                                /* Position of icon within window  */
+  wimp_iconflags flags;                        /* Icon flags word                 */
+  wimp_icondata data;                  /* Icon data information           */
+}
+wimp_icon;
+
+/*----- Manipulating windows and icons ------------------------------------*/
+
+/* --- Creating an icon --- */
+
+typedef struct
+{
+  wimp_w w;                            /* Window in which to create icon  */
+  wimp_icon i;                         /* Information about icon          */
+}
+wimp_icreate;
+
+/* --- Opening windows --- */
+
+typedef struct
+{
+  wimp_w w;                            /* Window handle to open           */
+  wimp_box box;                                /* Position on screen to open at   */
+  int x,y;                             /* Scroll bar positions to set     */
+  wimp_w behind;                       /* Window behind which to open     */
+}
+wimp_openstr;
+
+/* --- Redrawing windows --- */
+
+typedef struct
+{
+  wimp_w w;                            /* The window handle to redraw     */
+  wimp_box box;                                /* Where it is on the screen       */
+  int scx,scy;                         /* Scroll bar positions            */
+  wimp_box g;                          /* Graphics clipping rectangle     */
+}
+wimp_redrawstr;    
+
+/* --- Finding information about a window --- */
+
+typedef struct
+{
+  wimp_openstr o;                      /* Where the window is on screen   */
+  wimp_wflags flags;                   /* Anything else about the window  */
+}
+wimp_wstate;
+
+/* --- Reading a whole window definition --- */
+
+typedef struct
+{
+  wimp_w w;                            /* Window handle (fill this in)    */
+  wimp_wind info;                      /* Window definition (Wimp fills)  */
+}
+wimp_winfo;
+
+/*----- Pointer and caret structures --------------------------------------*/
+
+/* --- Mouse button status --- */
+
+typedef enum
+{
+  /* --- Button-type independent actions --- */
+
+  wimp_BMID                    =0x002, /* Menu button click               */
+
+  /* --- Standard click codes --- *
+   *
+   * As returned by wimp_get_point_info, or for single clicks on button 
+   * types Always, Autorepeat, Debounced, Release, Click/Drag, Release/Drag,
+   * Menu, Select/Drag or Click/Write/Drag, or double clicks on Double,
+   * Double/Drag and Double/Click/Drag.
+   */
+
+  wimp_BRIGHT                  =0x001, /* Adjust click or double click    */
+  wimp_BLEFT                   =0x004, /* Select click or double click    */
+
+  /* --- Drag codes --- *
+   *
+   * As returned by drags on button types Click/Drag, Release/Drag,
+   * Double/Drag, Select/Drag, Double/Click/Drag and Click/Write/Drag.
+   */
+
+  wimp_BDRAGRIGHT              =0x010, /* Adjust drag                     */
+  wimp_BDRAGLEFT               =0x040, /* Select drag                     */
+
+  /* --- Odd click codes --- *
+   *
+   * As returned by single clicks on button type Double/Click/Drag.
+   */
+
+  wimp_BCLICKRIGHT             =0x100, /* Adjust single click             */
+  wimp_BCLICKLEFT              =0x400, /* Select single click             */
+
+  /* --- And nothing at all --- *
+   *
+   * As returned by wimp_get_point_info, or by just pointing at button type
+   * Always.
+   */
+
+  wimp_BNOTHING                        =0x000  /* Not doing anything at all       */
+}
+wimp_bbits;
+
+/* --- Current mouse status --- */
+
+typedef struct
+{
+  int x,y;                             /* Mouse position on the screen    */
+  wimp_bbits bbits;                    /* Current mouse button state      */
+  wimp_w w;                            /* Window under the mouse pointer  */
+  wimp_w i;                            /* Icon under the mouse pointer    */
+}
+wimp_mousestr;
+
+/* --- Special caret flags --- */
+
+typedef enum
+{
+  wimp_CHEIGHT         =(1<<0),        /* The caret height (16 bits)      */
+  wimp_CCOLOUR         =(1<<16),       /* The caret colour (8 bits)       */
+  wimp_CVDUSTYLE       =(1<<24),       /* Plot VDU-5 caret, not Font one  */
+  wimp_CINVISIBLE      =(1<<25),       /* Don't actually draw it at all   */
+  wimp_CUSECOLOUR      =(1<<26),       /* Use the colour I've specified   */
+  wimp_CNOTWIMPCOL     =(1<<27)        /* The colour is a GCOL, not a     */
+                                       /* normal Wimp colour              */
+}
+wimp_caretflags;
+
+/* --- Current caret status --- */
+
+typedef struct
+{
+  wimp_w w;                            /* The window containing the caret */
+  wimp_w i;                            /* The icon containing the caret   */
+  int x,y;                             /* Its position within the window  */
+  wimp_caretflags height;              /* Its height, and other things    */
+  int index;                           /* Its index into the icon         */
+}
+wimp_caretstr;
+
+/*----- Wimp message structures -------------------------------------------*/
+
+typedef enum
+{
+  wimp_MCLOSEDOWN      =0x00000,       /* Task is being told to quit      */
+
+  /* --- Data transfer protocol messages --- */
+
+  wimp_MDATASAVE       =0x00001,       /* Request to import some data     */
+  wimp_MDATASAVEOK     =0x00002,       /* Import data by scrap file       */
+  wimp_MDATALOAD       =0x00003,       /* Request to load data from file  */
+  wimp_MDATALOADOK     =0x00004,       /* File loaded successfully        */
+  wimp_MDATAOPEN       =0x00005,       /* File double-clicked in Filer    */
+  wimp_MRAMFETCH       =0x00006,       /* Transfer data to by buffer      */
+  wimp_MRAMTRANSMIT    =0x00007,       /* Data transferred, try again     */
+  wimp_MDATASAVED      =0x0000D,       /* File has magically become safe  */
+
+  /* --- Miscellaneous --- */
+
+  wimp_MPREQUIT                =0x00008,       /* Task will be asked to quit soon */
+  wimp_PALETTECHANGE   =0x00009,       /* Desktop palette has changed     */
+
+  /* --- RISC OS 3 only --- */
+
+  wimp_SAVEDESK                =0x0000A,       /* Save application status to file */
+  wimp_MDEVICECLAIM    =0x0000B,       /* Broadcast before device claims  */
+  wimp_MDEVICEINUSE    =0x0000C,       /* The device claimed is in use    */
+
+  /* --- Filer messages --- */
+
+  wimp_FilerOpenDir    =0x00400,       /* Open a Filer window on screen   */
+  wimp_FilerCloseDir   =0x00401,       /* Close a Filer window or two     */
+
+  /* --- Help messages --- */
+
+  wimp_MHELPREQUEST    =0x00502,       /* `What does this thing do?'      */
+  wimp_MHELPREPLY      =0x00503,       /* `Oh well, it does this, y'see'  */
+
+  /* --- NetFiler messages --- */
+
+  wimp_Notify          =0x40040,       /* Someone else notified us        */
+
+  /* --- WIMP messages --- */
+
+  wimp_MMENUWARN       =0x400C0,       /* A submenu needs opening         */
+  wimp_MMODECHANGE     =0x400C1,       /* The screen mode has changed     */
+  wimp_MINITTASK       =0x400C2,       /* A new application has started   */
+  wimp_MCLOSETASK      =0x400C3,       /* An application has vanished     */
+  wimp_MSLOTCHANGE     =0x400C4,       /* An application's slot changed   */
+  wimp_MSETSLOT                =0x400C5,       /* Task's slot bar was dragged     */
+  wimp_MTASKNAMERQ     =0x400C6,       /* Find out a task's name          */
+  wimp_MTASKNAMEIS     =0x400C7,       /* Reply to TaskNameRq             */
+  wimp_MTASKSTARTED    =0x400C8,       /* `I have initialised properly'   */
+
+  /* --- Straylight messages --- */
+
+  wimp_MINTERNAL       =0x427FF,       /* For internal broadcast messages */
+
+  /* --- Messing about with printers --- */
+
+  wimp_MPrintFile      =0x80140,       /* Printer's response to DataSave  */
+  wimp_MWillPrint      =0x80141,       /* Response: `I will print it'     */
+  wimp_MPrintSave      =0x80142,       /* Task: `I want to print a file'  */
+  wimp_MPrintInit      =0x80143,       /* Tell other drivers to hari-kiri */
+  wimp_MPrintError     =0x80144,       /* Printer is busy/something died  */
+  wimp_MPrintTypeOdd   =0x80145,       /* Printer: `How do I print this?' */
+  wimp_MPrintTypeKnown =0x80146,       /* Response: `Give it here...'     */
+  wimp_MPrinterChange  =0x80147        /* Printer driver settings changed */
+}
+wimp_msgaction;
+
+/* --- The message header format --- */
+
+typedef struct
+{
+  int size;                            /* Size of the message (20-256)    */
+  wimp_t task;                         /* Task handle of the sender       */
+  int my_ref;                          /* The sender's reference          */
+  int your_ref;                                /* Which message it's replying to  */
+  wimp_msgaction action;               /* What sort of message it is      */
+}
+wimp_msghdr;
+
+/* --- Lots of structures containing message information --- */
+
+typedef struct
+{
+  wimp_w w;                            /* Window handle to save to        */
+  wimp_i i;                            /* Icon handle to save to          */
+  int x,y;                             /* Position of mouse pointer       */
+  int estsize;                         /* Estimated size of the file      */
+  int type;                            /* Filetype of the file            */
+  char leaf[12];                       /* Leafname of the file            */
+}
+wimp_msgdatasave;
+
+typedef struct
+{
+  wimp_w w;                            /* Window handle to save to        */
+  wimp_i i;                            /* Icon handle to save to          */
+  int x,y;                             /* Position of mouse pointer       */
+  int estsize;                         /* Estimated size of the file      */
+  int type;                            /* Filetype of the file            */
+  char name[212];                      /* The name of the file to save    */
+}
+wimp_msgdatasaveok;
+
+typedef struct
+{
+  wimp_w w;                            /* Window handle to save to        */
+  wimp_i i;                            /* Icon handle to save to          */
+  int x,y;                             /* Position of mouse pointer       */
+  int size;                            /* Actual size of the file         */
+  int type;                            /* Filetype of the file            */
+  char name[212];                      /* The name of the file to save    */
+}
+wimp_msgdataload;
+
+typedef wimp_msgdataload wimp_msgdataopen;
+
+typedef struct
+{
+  char *addr;                          /* Address in my workspace to fill */
+  int nbytes;                          /* The size of my buffer           */
+}
+wimp_msgramfetch;
+
+typedef struct
+{
+  char *addr;                          /* Address in your workspace       */
+  int nbyteswritten;                   /* How much I filled it up         */
+}
+wimp_msgramtransmit;
+
+typedef struct
+{
+  int filehandle;                      /* RISC OS file handle to write to */
+}
+wimp_msgsavedesk;
+
+typedef struct
+{
+  int major,minor;                     /* Device idenitification numbers  */
+  char information[228];               /* A string of stuff about it all  */
+}
+wimp_msgdevice;
+
+typedef struct
+{
+  wimp_mousestr m;                     /* What it wants help about        */
+}
+wimp_msghelprequest;
+
+typedef struct
+{
+  char text[200];                      /* What it's all about             */
+}
+wimp_msghelpreply;
+
+typedef struct
+{
+  int filler[5];                       /* Nothing really interesting      */
+  int type;                            /* File type of the file to print  */
+  char name[212];                      /* The full name of the file       */
+}
+wimp_msgprint;
+
+typedef struct
+{
+  int errnum;                          /* The error number of the error   */
+  char errmess[232];                   /* The error's textual message     */
+}
+wimp_msgprinterror;
+
+/* --- An actual message structure --- */
+
+typedef struct
+{
+  wimp_msghdr hdr;                     /* The message's common header     */
+
+  union
+  {
+    /* --- Standard forms --- */
+
+    char chars[236];                   /* Information as a char string    */
+    int words[59];                     /* Information as array of words   */
+
+    /* --- Data transfer --- */
+
+    wimp_msgdatasave datasave;
+    wimp_msgdatasaveok datasaveok;
+    wimp_msgdataload dataload;
+    wimp_msgdataopen dataopen;
+    wimp_msgramfetch ramfetch;
+    wimp_msgramtransmit ramtransmit;
+
+    /* --- Help messages --- */
+
+    wimp_msghelprequest helprequest;
+    wimp_msghelpreply helpreply;
+
+    /* --- Printer driver messages --- */
+
+    wimp_msgprint print;               /* Printer message common format   */
+    wimp_msgprinterror printerror;
+
+    /* --- Other messages --- */
+
+    wimp_msgsavedesk savedesk;
+    wimp_msgdevice device;
+  }
+  data;                                        /* The message's individual data   */
+}
+wimp_msgstr;
+
+/*----- Defining WIMP events ----------------------------------------------*/
+
+/* --- All the different types of event --- */
+
+typedef enum
+{
+  wimp_ENULL                   =0,     /* Null_Reason_Code                */
+  wimp_EREDRAW,                                /* Redraw_Window_Request           */
+  wimp_EOPEN,                          /* Open_Window_Request             */
+  wimp_ECLOSE,                         /* Close_Window_Request            */
+  wimp_EPTRLEAVE,                      /* Pointer_Leaving_Window          */
+  wimp_EPTRENTER,                      /* Pointer_Entering_Window         */
+  wimp_EBUT,                           /* Mouse_Clicked                   */
+  wimp_EUSERDRAG,                      /* User_Drag_Box                   */
+  wimp_EKEY,                           /* Key_Pressed                     */
+  wimp_EMENU,                          /* Menu_Selection                  */
+  wimp_ESCROLL,                                /* Scroll_Request                  */
+  wimp_ELOSECARET,                     /* Lose_Caret                      */
+  wimp_EGAINCARET,                     /* Gain_Caret                      */
+  wimp_ESEND                   =17,    /* User_Message                    */
+  wimp_ESENDWANTACK            =18,    /* User_Message_Recorded           */
+  wimp_EACK                    =19     /* User_Message_Acknowledge        */
+}
+wimp_etype;
+
+/* --- Wimp event mask --- */
+
+typedef enum
+{
+  wimp_EMNULL          =(1<<wimp_ENULL),
+  wimp_EMREDRAW                =(1<<wimp_EREDRAW),
+  wimp_EMOPEN          =(1<<wimp_EOPEN),
+  wimp_EMCLOSE         =(1<<wimp_ECLOSE),
+  wimp_EMPTRLEAVE      =(1<<wimp_EPTRLEAVE),
+  wimp_EMPTRENTER      =(1<<wimp_EPTRENTER),
+  wimp_EMBUT           =(1<<wimp_EBUT),
+  wimp_EMUSERDRAG      =(1<<wimp_EUSERDRAG),
+  wimp_EMKEY           =(1<<wimp_EKEY),
+  wimp_EMMENU          =(1<<wimp_EMENU),
+  wimp_EMSCROLL                =(1<<wimp_ESCROLL),
+  wimp_EMLOSECARET     =(1<<wimp_ELOSECARET),
+  wimp_EMGAINCARET     =(1<<wimp_EGAINCARET),
+  wimp_EMSEND          =(1<<wimp_ESEND),
+  wimp_EMSENDWANTACK   =(1<<wimp_ESENDWANTACK),
+  wimp_EMACK           =(1<<wimp_EACK)
+}
+wimp_emask;
+
+/* --- Wimp event data --- */
+
+typedef union
+{
+  wimp_openstr o;                      /* For Redraw, Open, Close, Enter  */
+                                       /* and leave events                */
+  struct
+  {
+    wimp_mousestr m;                   /* The new mouse status            */
+    wimp_bbits b;                      /* The old mouse button status     */
+  }
+  but;                                 /* For Mouse_Clicked events        */
+
+  wimp_box dragbox;                    /* For User_Drag_Box events        */
+
+  struct
+  {
+    wimp_caretstr c;                   /* The current caret location      */
+    int chcode;                                /* The key pressed (Wimp keymap)   */
+  }
+  key;                                 /* For Key_Pressed events          */
+
+  int menu[10];                                /* For Menu_Selection events       */
+
+  struct
+  {
+    wimp_openstr o;                    /* Where the window is right now   */
+    int x,y;                           /* Scroll offsets to apply         */
+  }
+  scroll;                              /* For Scroll_Request events       */
+
+  wimp_caretstr c;                     /* For Lose_ and Gain_Caret events */
+                                       /* It's a shame they don't work    */
+
+  wimp_msgstr msg;                     /* For all the User_Message events */
+}
+wimp_eventdata;
+
+typedef struct
+{
+  wimp_etype e;                                /* What the event's all about      */
+  wimp_eventdata data;                 /* And all the information for it  */
+}
+wimp_eventstr;
+
+/*----- Menu definitions --------------------------------------------------*/
+
+/* --- Menu item flags --- */
+
+typedef enum
+{
+  wimp_MTICK           =(1<<0),        /* The item is shown ticked        */
+  wimp_MSEPARATE       =(1<<1),        /* Item has a rule-off after it    */
+  wimp_MWRITABLE       =(1<<2),        /* Item is writable (yuk)          */
+  wimp_MSUBLINKMSG     =(1<<3),        /* Generate submenu warnings       */
+  wimp_MOPENSUB                =(1<<4),        /* Open submenu even when shaded   */
+  wimp_MLAST           =(1<<7)         /* This is the last item here      */
+}
+wimp_menuflags;
+
+typedef struct wimp_menustr *wimp_menuptr;
+
+/* --- A menu item --- */
+
+typedef struct
+{
+  wimp_menuflags flags;                        /* Flags for this menu item        */
+  wimp_menuptr submenu;                        /* Pointer to the item's  submenu  */
+  wimp_iconflags iconflags;            /* Icon flags for the menu item    */
+  wimp_icondata data;                  /* Icon data for the menu item     */
+}
+wimp_menuitem;
+
+/* --- A menu header --- */
+
+typedef struct
+{
+  char title[12];                      /* The menu's title string         */
+  char tit_fcol;                       /* Title foreground colour     (7) */
+  char tit_bcol;                       /* Title background colour     (2) */
+  char work_fcol;                      /* Work area foreground colour (7) */
+  char work_bcol;                      /* Work area background colour (0) */
+  int width,height;                    /* Dimensions of the menu items    */
+  int gap;                             /* Gap between items (0, please!)  */
+}
+wimp_menuhdr;
+
+/* --- A whole menu --- *
+ *
+ * Curiouser and curiouser -- the whole thing is set up to allow a circular
+ * reference between wimp_menustr and wimp_menuitem, which is never actually
+ * taken advantage.  I'd love to put a wimp_menuitem items[1] on the end of
+ * wimp_menustr, but my hands are tied by Compatibility Problems.
+ */
+
+typedef struct wimp_menustr
+{
+  wimp_menuhdr hdr;                    /* The menu header                 */
+}
+wimp_menustr;
+
+/*----- A mixed bag of other structures -----------------------------------*/
+
+/* --- Types of drag operations --- */
+
+typedef enum
+{
+  /* --- System drag types --- */
+
+  wimp_MOVE_WIND               =1,     /* Drag the window's position      */
+  wimp_SIZE_WIND               =2,     /* Drag the window's size          */
+  wimp_DRAG_HBAR               =3,     /* Drag the horizontal scroll bar  */
+  wimp_DRAG_VBAR               =4,     /* Drag the vertical scroll bar    */
+  wimp_DRAG_SCROLL             =12,    /* Drag both scroll bars at once   */
+
+  /* --- User types --- */
+
+  wimp_USER_FIXED              =5,     /* Drag a fixed-size box around    */
+  wimp_USER_RUBBER             =6,     /* Drag a rubbery box around       */
+  wimp_USER_HIDDEN             =7      /* Drag an invisible point around  */
+
+  /* --- Other types omitted --- *
+   *
+   * On the grounds that the actual code has to be in the RMA, we omit the
+   * support for types 8-11.
+   */
+}
+wimp_dragtype;
+
+/* --- Dragging boxes around --- */
+
+typedef struct
+{
+  wimp_w window;                       /* Window handle for system drags  */
+  wimp_dragtype type;                  /* The type of the drag to do      */
+  wimp_box box;                                /* The actual box to drag around   */
+  wimp_box parent;                     /* The box to drag it around in    */
+}
+wimp_dragstr;
+
+/* --- Wimp_WhichIcon parameter block --- *
+ *
+ * I can't see what's wrong with just passing the arguments to
+ * wimp_which_icon, but then again I lack Acorn's great Wisdom, and am
+ * merely a humble Infidel, who comprehends not the great Subtleties and
+ * Mysteries of the great Edifice which is RISC_OSLib's wimp interface.
+ *
+ * I can't actually see why Wimp_WhichIcon is useful at all, since just
+ * skimming through the icon definitions is probably faster anyway.
+ */
+
+typedef struct
+{
+  wimp_w window;                       /* Which window do we search?      */
+  int bit_mask;                                /* BIC mask for all the icon flags */
+  int bit_set;                         /* Compare mask for the icon flags */
+}
+wimp_which_block;
+
+/* --- Setting pointer shapes --- *
+ *
+ * There is no excuse for using this call.  *Please* don't.  It's really
+ * not very nice.
+ */
+
+typedef struct
+{
+  int shape_num;
+  char *shape_data;
+  int width,height;
+  int activex,activey;
+}
+wimp_pshapestr;
+
+/* --- A font reference count array --- */
+
+typedef struct
+{
+  char f[256];
+}
+wimp_font_array;
+
+/* --- For loading templates --- */
+
+typedef struct
+{
+  int reserved;                                /* A pointless waste of space left */
+                                       /* so that the structure doesn't   */
+                                       /* change size                     */
+
+  wimp_wind *buf;                      /* Pointer to window def to fill   */
+  char *work_free;                     /* Pointer to indirected data area */
+  char *work_end;                      /* Limit of indirected data area   */
+  wimp_font_array *font;               /* Pointer to font ref count array */
+  char *name;                          /* Pointer to name to find         */
+  int index;                           /* Index to search from in file    */
+}
+wimp_template;
+
+/* --- A palette information word --- */
+
+typedef union
+{
+  struct
+  {
+    char gcol;                         /* Actual colour number used       */
+    char red,green,blue;               /* The real colour for the entry   */
+  }
+  bytes;                               /* The colour split up nicely      */
+
+  int word;                            /* The colour as an integer        */
+}
+wimp_paletteword;
+
+/* --- A whole palette --- */
+
+typedef struct
+{
+  wimp_paletteword c[16];              /* The main 16 WIMP colours used   */
+  wimp_paletteword screenborder;       /* The colour of the screen border */
+  wimp_paletteword mouse1;             /* The `outer' pointer colour      */
+  wimp_paletteword mouse2;             /* The `inner' pointer colour      */
+  wimp_paletteword mouse3;             /* The `don't use' pointer colour  */
+}
+wimp_palettestr;
+
+/* --- Flags for error boxes --- */
+
+typedef enum
+{
+  wimp_EOK             =(1<<0),        /* Put in an `OK' box              */
+  wimp_ECANCEL         =(1<<1),        /* Put in a `Cancel' box           */
+  wimp_EHICANCEL       =(1<<2),        /* Highlight `Cancel', not `OK'    */
+  wimp_ENOPROMPT       =(1<<3),        /* Don't prompt in textual message */
+  wimp_ENOPREFIX       =(1<<4),        /* Don't put `Error from' in title */
+  wimp_ERETURN         =(1<<5),        /* Return immediately if no click  */
+  wimp_ESELECT         =(1<<6),        /* Select `OK' or `Cancel'         */
+  wimp_ENOBEEP         =(1<<7)         /* Don't make a beepy noise        */
+}
+wimp_errflags;
+
+/* --- Command window actions --- *
+ *
+ * They've outdone themselves this time.  I wonder if it's intentional.
+ */
+
+typedef enum
+{
+  wimp_command_TITLE           =0,     /* Set up the window title         */
+  wimp_command_ACTIVE          =1,     /* Just mark CommandWindow as on   */
+  wimp_command_CLOSE_PROMPT    =2,     /* Close the window and prompt     */
+  wimp_command_CLOSE_NOPROMPT  =3      /* Close the window straight away  */
+}
+wimp_command_tag;
+
+/* --- Actually getting anything done in a CommandWindow --- */
+
+typedef struct
+{
+  wimp_command_tag tag;                        /* What to do                      */
+  char *title;                         /* The title to do it with         */
+}
+wimp_commandwind;
+
+/* --- ReadSysInfo numbers --- */
+
+typedef enum
+{
+  wimp_ITASKS,                         /* The number of tasks running     */
+  wimp_IWIMPMODE,                      /* The current Wimp mode           */
+  wimp_ISUFFIX,                                /* The filename mode suffix        */
+  wimp_ICMDMODE,                       /* 0 for command mode, 1 for desk  */
+  wimp_IWRITEDIR,                      /* 0 == left-to-right              */
+  wimp_IHANDLE,                                /* R0 == handle, R1 == Wimp version*/
+  wimp_IDUNNO,                         /* Not implemented, oddly enough   */
+  wimp_IWIMPVERSION,                   /* Current WIMP version            */
+  wimp_IFONTHANDLE                     /* The font handle for icons       */
+}
+wimp_sysinfo;
+
+/*----- That's it then ----------------------------------------------------*/
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/wimpt b/StraySrc/Libraries/Steel/h/wimpt
new file mode 100644 (file)
index 0000000..3871b0c
--- /dev/null
@@ -0,0 +1,395 @@
+/****************************************************************************
+ * This source file was written by Acorn Computers Limited. It is part of   *
+ * the RISCOS library for writing applications in C for RISC OS. It may be  *
+ * used freely in the creation of programs for Archimedes. It should be     *
+ * used with Acorn's C Compiler Release 3 or later.                         *
+ *                                                                          *
+ ***************************************************************************/
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Title  : wimpt.h
+ * Purpose: provides low-level wimp functionality
+ *
+ */
+
+# ifndef __wimpt_h
+# define __wimpt_h
+
+# ifndef __wimp_h
+# include "wimp.h"
+# endif
+
+# ifndef __os_h
+# include "os.h"
+# endif
+
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define wimpt_OSCULPTRIX       (1<<0)    /* Support Sculptrix 3D icons    */
+#define wimpt_OINTERFACE       (1<<1)    /* Support Interface 3D icons    */
+#define wimpt_OWIMPEXT         (1<<2)    /* Support WimpExtension a bit   */
+#define wimpt_ONOWIMPSHADE     (1<<3)    /* Use fancy shading in dboxes   */
+#define wimpt_OREMSAVEICON      (1<<4)    /* Hide save icon in sprite drag */
+#define wimpt_ONOBACKTRACE      (1<<5)    /* Don't offer backtrace buttons */
+
+/* ------------------------------ wimpt_poll -------------------------------
+ * Description:   Poll for an event from the wimp (with extras to buffer
+ *                one event).
+ *
+ * Parameters:    wimp_emask mask -- ignore events in the mask
+ *                wimp_eventstr *result -- the event returned from wimp
+ * Returns:       possible error condition.
+ * Other Info:    If you want to poll at this low level (ie avoiding
+ *                event_process()), then use this function rather than
+ *                wimp_poll. Using wimpt_poll allows you to use the routines
+ *                shown below.
+ *
+ */
+
+os_error * wimpt_poll(wimp_emask mask, wimp_eventstr *result);
+
+/*
+ * int wimpt_pollingTime(int new)
+ *
+ * Use
+ *  Adjusts the time spent between polls with idle events enabled.  The
+ *  current polling time may be read by passing new as -1.  Otherwise, the
+ *  time is set to be new, and the previous setting is returned.
+ *
+ *  The polling is performed using Wimp_PollIdle, unless the polling time
+ *  is set to 0, in which case full scale processor-hog mode is engaged.
+ *
+ * Parameters
+ *  int new == the new setting for the polling time, or -1 to read
+ *
+ * Returns
+ *  The setting of the polling time in force when the call was made.
+ */
+
+int wimpt_pollingTime(int new);
+
+/*
+ * BOOL wimpt_justChangedMode(void)
+ *
+ * Use
+ *  Returns whether we have just changed mode
+ */
+
+BOOL wimpt_justChangedMode(void);
+
+/* -------------------------- wimpt_fake_event -----------------------------
+ * Description:   Post an event to be collected by wimpt_poll.
+ *
+ * Parameters:    wimp_eventstr * -- the posted event
+ * Returns:       void
+ * Other Info:    use with care!
+ *
+ */
+
+void wimpt_fake_event(wimp_eventstr *);
+
+
+/* ----------------------------- wimpt_last_event --------------------------
+ * Description:   Informs caller of last event returned by wimpt_poll.
+ *
+ * Parameters:    void
+ * Returns:       pointer to last event returned by wimpt_poll.
+ * Other Info:    none.
+ *
+ */
+
+wimp_eventstr *wimpt_last_event(void);
+
+
+/* ---------------------- wimpt_last_event_was_a_key -----------------------
+ * Description:   Informs caller if last event returned by wimpt_poll was
+ *                a key stroke.
+ *
+ * Parameters:    void
+ * Returns:       non-zero if last event was a keystroke.
+ * Other Info:    retained for compatibility with old world.
+ *                Use wimpt_last_event by preference, and test
+ *                if e field of returned struct == wimp_EKEY.
+ *
+ */
+
+int wimpt_last_event_was_a_key(void);
+
+
+/* ------------------------------ wimpt_noerr ------------------------------
+ * Description:   Halts program and reports error in dialogue box (if e!=0).
+ *
+ * Parameters:    os_error *e -- error return from system call
+ * Returns:       void.
+ * Other Info:    Useful for "wrapping up" system calls which are not
+ *                expected to fail; if so your program probably has a
+ *                logical error. Call when an error would mean disaster!!
+ *                    eg. wimpt_noerr(some_system_call(.......));
+ *                Error message is : "<ProgName> has suffered a fatal
+ *                internal error (<errormessage>) and must exit immediately".
+ *
+ */
+
+void wimpt_noerr(os_error *e);
+
+
+/* ----------------------------- wimpt_complain ----------------------------
+ * Description:   Reports error in dialogue box (if e!=0).
+ *
+ * Parameters:    os_error *e -- error return from system call
+ * Returns:       the error returned from the system call (ie. e).
+ * Other Info:    Useful for "wrapping up" system calls which may fail. Call
+ *                when your program can still limp on regardless (taking
+ *                some appropriate action).
+ *
+ */
+
+os_error *wimpt_complain(os_error *e);
+
+
+
+/* -------- Control of graphics environment -------- */
+
+
+/* -------------------------- wimpt_checkmode ----------------------------
+ * Description:   Registers with the wimpt module the current screen
+ *                mode.
+ *
+ * Parameters:    void
+ * Returns:       TRUE if screen mode has changed.
+ * Other Info:    none.
+ *
+ */
+
+BOOL wimpt_checkmode(void);
+
+
+/* --------------------------- wimpt_mode --------------------------------
+ * Description:   Reads the screen mode
+ *
+ * Parameters:    void
+ * Returns:       screen mode.
+ * Other Info:    faster than a normal OS call. Value is only valid if
+ *                wimpt_checkmode is called at redraw events.
+ *
+ */
+
+int wimpt_mode(void);
+
+
+/* ---------------------- wimpt_dx/wimpt_dy ------------------------------
+ * Description:   Inform caller of OS x/y units per screen pixel
+ *
+ * Parameters:    void
+ * Returns:       OS x/y units per screen pixel.
+ * Other Info:    faster than a normal OS call. Value is only valid if
+ *                wimpt_checkmode is called at redraw events.
+ *
+ */
+
+int wimpt_dx(void);
+int wimpt_dy(void);
+
+
+/* -------------------------- wimpt_bpp ----------------------------------
+ * Description:   Informs caller of bits per screen pixel.
+ *
+ * Parameters:    void
+ * Returns:       bits per screen pixel (in current mode).
+ * Other Info:    faster than a normal OS call. Value is only valid if
+ *                wimpt_checkmode is called at redraw events.
+ *
+ */
+
+int wimpt_bpp(void);
+
+int wimpt_scwidth(void);
+int wimpt_scheight(void);
+
+/*
+ * void wimpt_setMessages(int msg,...)
+ *
+ * Use
+ *  Sets up the messages that the task is to respond to.  If ommitted,
+ *  suitable defaults are included.  Call before wimpt_init.  If the WIMP
+ *  version is lower than 3.00, 3.00 is specified.
+ *
+ * Parameters
+ *  A list of message numbers, terminated by 0.
+ */
+
+void wimpt_setMessages(int msg,...);
+
+/*
+ * void wimpt_wimpversion(int version)
+ *
+ * Use
+ *  Sets up Steel to use a later version of the WIMP than normal.
+ *
+ * Parameters
+ *  int version == 100 * the latest version number known about
+ */
+
+void wimpt_wimpversion(int version);
+
+/* --------------------------- wimpt_init --------------------------------
+ * Description:   Set program up as a WIMP task.
+ *
+ * Parameters:    char *programname -- name of your program
+ * Returns:       void
+ * Other Info:    Remembers screen mode, and sets up signal handlers
+ *                so that task exits cleanly, even after fatal errors.
+ *                Response to signals SIGABRT, SIGFPE, SIGILL, SIGSEGV
+ *                SIGTERM is to display error box with message:
+ *                "<progname> has suffered an internal error (type =
+ *                <signal>) and must exit immediately"
+ *                SIGINT (Escape) is ignored. Progname will appear in the
+ *                task manager display and in error messages.
+ *                Calls wimp_taskinit and stores task_id returned
+ *                Also installs exit-handler to close down task when
+ *                program calls exit() function.  If version has not been
+ *                set, it is worked out according to the current OS version.
+ *
+ */
+
+void wimpt_init(char *programname);
+
+void wimpt_setOptions(int eor,int bic);
+int wimpt_options(void);
+
+#define wimpt_init_noInterface(name) \
+  do \
+  { \
+    wimpt_setOptions(0,wimpt_OSCULPTRIX | \
+                       wimpt_OINTERFACE | \
+                       wimpt_OWIMPEXT); \
+    wimpt_init(name); \
+  } \
+  while (0)
+
+#define wimpt_useWimpExt(x) \
+  wimpt_setOptions(wimpt_OWIMPEXT,wimpt_OWIMPEXT);
+
+/*
+ * int wimpt_getVersion(void)
+ *
+ * Use
+ *  Before wimpt_init, returns the version the application will be started
+ *  with (0 for guess), and afterwards, returns the WIMP version that the
+ *  application has been initialised with
+ *
+ * Returns
+ *  Version, as above, * 100
+ */
+
+int wimpt_getVersion(void);
+
+/*
+ * BOOL wimpt_interface(void)
+ *
+ * Use
+ *  Informs caller if Interface is being used in the application.
+ *
+ * Returns
+ *  TRUE if Interface is being used.
+ */
+
+#define wimpt_interface(x) \
+  (wimpt_options() & wimpt_OINTERFACE)
+
+/* ----------------------------- wimpt_programname -----------------------
+ * Description:   Informs the caller of name passed to wimpt_init
+ *
+ * Parameters:    void
+ * Returns:       the program's name (pointer to).
+ * Other Info:    none.
+ *
+ */
+
+char *wimpt_programname(void);
+
+
+/* -------------------------- wimpt_reporterror --------------------------
+ * Description:   Reports an OS error in a dialogue box.
+ *                (including program name)
+ *
+ * Parameters:    os_error* -- OS error block
+ *                wimp_errflags -- flag whether to include OK and/or
+ *                                 CANCEL(highlighted or not) button
+ *                                 in dialogue box
+ * Returns:       void.
+ * Other Info:    similar to wimp_reporterror(), but includes prog. name
+ *                automatically (eg. the one passed to wimpt_init).
+ *
+ */
+
+void wimpt_reporterror(os_error*, wimp_errflags);
+
+
+/* ----------------------------- wimpt_task ------------------------------
+ * Description:   Informs caller of its task handle.
+ *
+ * Parameters:    void
+ * Returns:       task handle.
+ * Other Info:    none.
+ *
+ */
+
+wimp_t wimpt_task(void);
+
+
+/* ----------------------------- wimpt_forceredraw -----------------------
+ * Description:   Causes whole screen to be invalidated (ie. running
+ *                applications will be requested to redraw all windows)
+ *
+ * Parameters:    void
+ * Returns:       void.
+ * Other Info:    none.
+ *
+ */
+
+void wimpt_forceredraw(void);
+
+typedef void (*wimpt_redraw_proc)(wimp_redrawstr *r,void *handle);
+void wimpt_redraw(wimpt_redraw_proc rdr,void *handle);
+
+/*
+ * int wimpt_stringWidth(char *s)
+ *
+ * Use
+ *  Determines the width of a string in OS units, taking into account the
+ *  fact that it may be represented in a WIMP anti-aliased font.
+ *
+ * Parameters
+ *  char *s == pointer to the string to font the length of
+ *
+ * Returns
+ *  The width of the string in OS units
+ */
+
+int wimpt_stringWidth(char *s);
+
+#endif
diff --git a/StraySrc/Libraries/Steel/h/win b/StraySrc/Libraries/Steel/h/win
new file mode 100644 (file)
index 0000000..c880582
--- /dev/null
@@ -0,0 +1,470 @@
+/****************************************************************************
+ * This source file was written by Acorn Computers Limited. It is part of   *
+ * the RISCOS library for writing applications in C for RISC OS. It may be  *
+ * used freely in the creation of programs for Archimedes. It should be     *
+ * used with Acorn's C Compiler Release 3 or later.                         *
+ *                                                                          *
+ ***************************************************************************/
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* Title:   win.h
+ * Purpose: central management of RISC OS windows
+ *
+ */
+
+# ifndef __win_h
+# define __win_h
+
+# ifndef __wimp_h
+# include "wimp.h"
+# endif
+
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+
+/* This module constructs a very simple idea of "window class" within RISCOS.
+ * RISCOS window class implementations register the existence of each window
+ * with this module. 
+ */
+
+/* This structure allows event-processing loops to be constructed that
+ * have no knowledge of what other modules are present in the program.
+ * For instance, the dialogue box module can contain an event-processing loop
+ * without reference to what other window types are present in the program.
+ */
+
+typedef void (*win_event_handler)(wimp_eventstr*, void *handle);
+
+typedef void (*win_idle_claimer)(void *handle);
+
+/* ************************** Claiming Events. *************************** */
+
+
+/* ------------------------- win_register_event_handler --------------------
+ * Description:   Install an event handler function for a given window.
+ *
+ * Parameters:    wimp_w -- the window's handle
+ *                win_event_handler -- the event handler function
+ *                void *handle -- caller-defined handle 
+ * Returns:       void.
+ * Other Info:    This call has no effect on the window itself -- it just
+ *                informs the win module that the supplied function should
+ *                be called when events are delivered to the window.
+ *                To remove a handler, call with a null function pointer,
+ *                ie.  win_register_event_handler(w,(win_event_handler)0,0)
+ *                To catch key events for an icon on the icon bar register
+ *                a handler for win_ICONBAR,
+ *                   ie. win_event_handler(win_ICONBAR, handler_func, handle)
+ *                To catch load event for an icon on the icon bar register
+ *                a handler for win_ICONBARLOAD,
+ *                 ie. win_event_handler(win_ICONBARLOAD, load_func, handle).
+ *
+ */
+
+#define win_ICONBAR (-3)
+#define win_ICONBARLOAD (-99)
+void win_register_event_handler(wimp_w, win_event_handler, void *handle);
+
+/* ------------------------- win_read_event_handler ------------------------
+ * Description:   Read current event handler for a given window, and the
+ *                handle which it is passed.
+ *
+ * Parameters:    wimp_w w -- the window's handle
+ *                win_event_handler *p -- the handler function
+ *                void **handle -- the handle passed to the handler function
+ * Returns:       TRUE if given window is registered, FALSE otherwise
+ * Other Info:    This is useful for registering an alternative event handler
+ *                which can vet events, before passing them on to the original
+ *                handler.
+ *
+ */
+
+BOOL win_read_eventhandler(wimp_w w, win_event_handler *p, void **handle);
+
+/*
+ * void win_idleTime(int time)
+ *
+ * Use
+ *  Sets the approximate time requested between calls of idle claimer
+ *  routines.  The actual time may be more (e.g. if other tasks are busy) or 
+ *  less (if idle claimers with a lower time are specified).
+ *
+ * Parameters
+ *  int time == approximate time in centiseconds between idle claimer calls
+ */
+
+void win_idleTime(int time);
+
+/*
+ * void win_addIdleClaimer(win_idle_claimer proc,void *handle)
+ *
+ * Use
+ *  Allows a list of idle event claimers to be set up, as opposed to just
+ *  one.
+ *
+ * Parameters
+ *  win_idle_claimer proc == the procedure to add
+ *  int speed == requested number centiseconds between calls, or
+ *    win_DONTCARE
+ *  void *handle == the jolly old handle (again!)
+ */
+
+#define win_DONTCARE (-1)
+
+void win_addIdleClaimer(win_idle_claimer proc,int speed,void *handle);
+
+/*
+ * BOOL win_any_idles(void)
+ *
+ * Use
+ *  Returns TRUE if there are any routines using the idle claimer system
+ */
+
+BOOL win_any_idles(void);
+
+/*
+ * void win_removeIdleClaimer(win_idle_claimer proc,void *handle)
+ *
+ * Use
+ *  Removes a procedure from the list.
+ *
+ * Parameters
+ *  win_idle_claimer proc == the procedure to remove
+ *  void *handle == the procedure's handle
+ */
+
+void win_removeIdleClaimer(win_idle_claimer proc,void *handle);
+
+/* --- Macros for the old versions --- */
+
+#define win_add_idle_claimer(p,h) win_addIdleClaimer(p,win_DONTCARE,h)
+#define win_remove_idle_claimer(p,h) win_removeIdleClaimer(p,h)
+
+/* ------------------------- win_claim_idle_events -------------------------
+ * Description:   Cause "idle" events to be delivered to a given window.
+ *
+ * Parameters:    wimp_w -- the window's handle
+ * Returns:       void.
+ * Other Info:    To cancel this, call with window handle (wimp_w)-1.
+ *
+ */
+
+void win_claim_idle_events(wimp_w);
+
+
+
+typedef BOOL (*win_unknown_event_processor)(wimp_eventstr*, void *handle);
+/* You can ask to vet unknown events, before they are passed to the default
+   unknown event handler. These procs return TRUE if they have dealt with the
+   event.
+*/
+
+
+/* --------------------- win_add_unknown_event_processor -------------------
+ * Description:   Add a handler for unknown events onto the front of the
+ *                queue of such handlers.
+ *
+ * Parameters:    win_unknown_event_processor -- handler function
+ *                void *handle -- passed to handler on call
+ * Returns:       void.
+ * Other Info:    The win module maintains a list of unknown event handlers.
+ *                An unknown event results in the "head of the list" function
+ *                being called; if this function doesn't deal with the event
+ *                it is passed on to the next in the list, and so on.
+ *                Handler functios should return a Boolean result to show
+ *                if they dealt with the event, or if it should be passed on.
+ *                "Known" events are as follows:
+ *                         ENULL, EREDRAW, ECLOSE, EOPEN, EPTRLEAVE, 
+ *                         EPTRENTER, EKEY, ESCROLL, EBUT
+ *                         and ESEND/ESENDWANTACK for the following msg types
+ *                             MCLOSEDOWN, MDATASAVE, MDATALOAD, MHELPREQUEST
+ *                All other events are considered "unknown"
+ *                Note: if none of the unknown event handlers deals with the
+ *                event, then it is passed on to the unknown event claiming
+ *                window (registered by win_claim_unknown_events()). If 
+ *                there is no such claimer, then the unknown event is 
+ *                ignored. 
+ *
+ */
+
+void win_add_unknown_event_processor(win_unknown_event_processor,
+                                     void *handle) ;
+
+
+/* ------------------ win_remove_unknown_event_processor -------------------
+ * Description:   Removes the given unknown event handler with the given
+ *                handle from the stack of handlers.
+ *
+ * Parameters:    win_unknown_event_processor -- the handler to be removed
+ *                void *handle -- its handle
+ * Returns:       void.
+ * Other Info:    The handler to be removed can be anyway in the stack
+ *                (not necessarily at the top).
+ *
+ */
+
+void win_remove_unknown_event_processor(win_unknown_event_processor,
+                                        void *handle) ;
+
+
+/* ---------------------- win_idle_event_claimer ---------------------------
+ * Description:   Informs caller of which window is claiming idle events.
+ *
+ * Parameters:    void
+ * Returns:       Handle of window claiming idle events.
+ * Other Info:    Returns (wimp_w)-1, if no window is claiming idle events.
+ *
+ */
+
+wimp_w win_idle_event_claimer(void);
+
+
+/* ---------------------- win_claim_unknown_events -------------------------
+ * Description:   Cause any unknown, or non-window-specific events to be
+ *                delivered to a given window.
+ *
+ * Parameters:    wimp_w -- handle of window to which unknown events should
+ *                          be delivered
+ * Returns:       void.
+ * Other Info:    Calling with (wimp_w)-1 cancels this
+ *                See win_add_unknown_event_processor() for details of which
+ *                events are "known".
+ *
+ */
+
+void win_claim_unknown_events(wimp_w);
+
+
+/* ------------------------- win_unknown_event_claimer ---------------------
+ * Description:   Informs caller of which window is claiming unknown events.
+ *
+ * Parameters:    void
+ * Returns:       Handle of window claiming unknown events.
+ * Other Info:    Return of (wimp_w)-1 means no claimer registered.
+ *
+ */
+
+wimp_w win_unknown_event_claimer(void);
+
+
+
+/* ********************************* Menus. ****************************** */
+
+
+/* ---------------------------- win_setmenuh -------------------------------
+ * Description:   Attaches the given menu structure to the given window
+ *
+ * Parameters:    wimp_w -- handle of window
+ *                void *handle -- pointer to menu structure
+ * Returns:       void.
+ * Other Info:    Mainly used by higher level RISC_OSlib routines to attach
+ *                menus to windows (eg. event_attachmenu()).
+ *
+ */
+
+void win_setmenuh(wimp_w, void *handle);
+
+
+/* --------------------------- win_getmenuh --------------------------------
+ * Description:   Returns a pointer to the menu structure attached to given
+ *                window.
+ *
+ * Parameters:    wimp_w -- handle of window
+ * Returns:       pointer to the attached menu (0 if no menu attached).
+ * Other Info:    As for win_setmenuh(), this is used mainly by higher level
+ *                RISC_OSlib routines (eg. event_attachmenu()).
+ *
+ */
+
+void *win_getmenuh(wimp_w); 
+
+
+/* ************************** Event Processing. ************************** */
+
+/*
+ * void win_broadcast(wimp_eventstr *e)
+ *
+ * Use
+ *  Broadcasts the given event to ALL windows currently active.  Note: this
+ *  works in a similar way to module service calls - a broadcast can be
+ *  'claimed' by changing it to a null event.  This is most useful for 
+ *  informing other windows about events (such as a parent window being
+ *  closed), and thus message broadcasts should be used.
+ *
+ * Parameters
+ *  wimp_eventstr *e == the event to broadcast.
+ */
+
+void win_broadcast(wimp_eventstr *e);
+
+/* -------------------------- win_processevent -----------------------------
+ * Description:   Delivers an event to its relevant window, if such a window
+ *                has been registered with this module (via
+ *                win_register_event_handler()).
+ *
+ * Parameters:    wimp_eventstr* -- pointer to the event which has occurred
+ * Returns:       true if an event handler (registered with this module)
+ *                has dealt with the event, false otherwise.
+ * Other Info:    the main client for this routine is event_process(), which
+ *                uses it to deliver an event to its appropriate window.
+ *                Keyboard events are delivered to the current owner of the
+ *                caret.
+ *
+ */
+
+BOOL win_processevent(wimp_eventstr*);
+
+
+/* ****************************** Termination. *************************** */
+
+
+/* --------------------------- win_activeinc -------------------------------
+ * Description:   Increment by one the win module's idea of the number of
+ *                active windows owned by a program.
+ *
+ * Parameters:    void
+ * Returns:       void.
+ * Other Info:    Note: event_process() calls exit() on behalf of the program
+ *                when the number of active windows reaches zero
+ *                Programs which wish to remain running even when they have
+ *                no active windows, should ensure that win_activeinc() is
+ *                called once before creating any windows, so that the no.
+ *                of active windows is always >= 1. This is done for you
+ *                if you use baricon() to install your program's icon on the
+ *                iconbar.
+ *
+ */
+
+void win_activeinc(void);
+
+
+/* ---------------------------- win_activedec ------------------------------
+ * Description:   Decrements by one the win module's idea of the number of
+ *                active windows owned by a program.
+ *
+ * Parameters:    void
+ * Returns:       void.
+ * Other Info:    See note in win_activeinc() regarding program termination.
+ *
+ */
+
+void win_activedec(void);
+
+
+/* ---------------------------- win_activeno -------------------------------
+ * Description:   Informs the caller of the number of active windows owned
+ *                by your program.
+ *
+ * Parameters:    void
+ * Returns:       no. of active windows owned by program.
+ * Other Info:    This is given by (no. of calls to win_activeinc()) minus
+ *                (no. of calls to win_activedec())
+ *                Note that modules in RISCOSlib itself may have made calls
+ *                to win_activeinc() and win_activedec().
+ *
+ */
+
+int win_activeno(void);
+
+
+/* -------------------------- win_give_away_caret --------------------------
+ * Description:   gives the caret away to the open window at the top of the
+ *                WIMP's window stack (if that window is owned by your
+ *                program).
+ * 
+ * Parameters:    void
+ * Returns:       void.
+ * Other Info:    If the top window is interested it will take the caret
+ *                If not then nothing happens.
+ *                Note: only works if polling is done using the wimpt module,
+ *                which is the case if your main inner loop goes something
+ *                like:   while (TRUE)
+ *                            event_process();
+ *
+ */
+
+void win_give_away_caret(void);
+
+/* ------------------------------ win_settitle -----------------------------
+ * Description:   changes the title displayed in a given window
+ *
+ * Parameters:    wimp_w w      -- given window's handle
+ *                char *newtitle -- null-terminated printf-type string 
+ *                                  giving new title for window
+ *                ... -- more parameters
+ *
+ * Returns:       void.
+ * Other Info:    The title icon of the given window must be indirected text
+ *                This will change the title used by all windows created
+ *                from the given window's template if you have used the
+ *                template module (since the Window manager uses your address
+ *                space to hold indirected text icons). To avoid this the 
+ *                window can be created from a copy of the template, ie.
+ *                    template *t = template_copy(template_find("name"));
+ *                    wimp_create_wind(t->window, &w);
+ *
+ */
+
+void win_settitle(wimp_w w, char *newtitle,...);
+
+/*
+ * void win_gadgetWidths(wimp_wflags f,wimp_box *b)
+ *
+ * Use
+ *  Returns a box giving the width of the system area around a window with
+ *  window flags f.
+ */
+
+void win_gadgetWidths(wimp_wflags f,wimp_box *b);
+
+/*
+ * void win_adjustBox(wimp_openstr *o)
+ *
+ * Use
+ *  Adjusts a window so that it fits on the screen.
+ *
+ * Parameters
+ *  wimp_openstr *o == pointer to the block to fiddle
+ */
+
+void win_adjustBox(wimp_openstr *o);
+
+/*
+ * BOOL win_anyWindows(void)
+ *
+ * Use
+ *  Informs the caller if there are any windows left.
+ *
+ * Returns
+ *  TRUE if there are
+ */
+
+BOOL win_anyWindows(void);
+
+
+
+#endif
+
+/* end win.h */
diff --git a/StraySrc/Libraries/Steel/h/xferrecv b/StraySrc/Libraries/Steel/h/xferrecv
new file mode 100644 (file)
index 0000000..898ce7b
--- /dev/null
@@ -0,0 +1,211 @@
+/****************************************************************************
+ * This source file was written by Acorn Computers Limited. It is part of   *
+ * the RISCOS library for writing applications in C for RISC OS. It may be  *
+ * used freely in the creation of programs for Archimedes. It should be     *
+ * used with Acorn's C Compiler Release 3 or later.                         *
+ *                                                                          *
+ ***************************************************************************/
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* Title:   xferrecv.h
+ * Purpose: general purpose import of data by dragging icon
+ *
+ */
+
+#ifndef __xferrecv_h
+#define __xferrecv_h
+
+#ifndef __flex_h
+  #include "flex.h"
+#endif
+
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+
+/* -------------------------- xferrecv_checkinsert -------------------------
+ * Description:   Set up the acknowledge message for a MDATAOPEN or MDATALOAD
+ *                and get filename to load from.
+ *
+ * Parameters:    char **filename -- returned pointer to filename
+ * Returns:       the file's type (eg. 0x0fff for !Edit)
+ * Other Info:    This function checks to see if the last wimp event was a 
+ *                request to import a file. If so it returns file type and
+ *                a pointer to file's name is put into *filename. If not
+ *                it returns -1.   
+ *
+ */
+
+int xferrecv_checkinsert(char **filename);
+
+
+/* --------------------------- xferrecv_insertfileok -----------------------
+ * Description:   Deletes scrap file (if used for transfer), and sends
+ *                acknowledgement of MDATALOAD message.
+ *
+ * Parameters:    void
+ * Returns:       void.
+ * Other Info:    none.
+ *
+ */
+
+void xferrecv_insertfileok(void);
+
+
+/* --------------------------- xferrecv_checkprint -------------------------
+ * Description:   Set up acknowledge message to a MPrintTypeOdd message
+ *                and get file name to print.
+ *
+ * Parameters:    char **filename -- returned pointer to filename
+ * Returns:       The file's type (eg. 0x0fff for !Edit).
+ * Other Info:    Application can either print file directly or convert it to
+ *                <Printer$Temp> for printing by the printer application.
+ *
+ */
+
+int xferrecv_checkprint(char **filename);
+
+
+/* --------------------------- xferrecv_printfileok ------------------------
+ * Description:   Send an acknowledgement back to printer application. If
+ *                file sent to <Printer$Temp> then this also fills in file
+ *                type in message.
+ *
+ * Parameters:    int type -- type of file sent to <Printer$Temp> 
+ *                            (eg. 0x0fff for !edit)
+ * Returns:       void.
+ * Other Info:    none.
+ *
+ */
+
+void xferrecv_printfileok(int type);
+
+
+/* ---------------------------- xferrecv_checkimport -----------------------
+ * Description:   Set up acknowledgement message to a MDATASAVE message.
+ *
+ * Parameters:    int *estsize -- sender's estimate of file size
+ * Returns:       File type.
+ * Other Info:    none.
+ *
+ */
+
+int xferrecv_checkimport(int *estsize);
+
+/*
+ * char *xferrecv_nameToImport(void)
+ *
+ * Use
+ *  Returns the name of the file to import (full pathname if available).
+ *
+ * Returns
+ *  A pointer to a read-only string.
+ */
+
+char *xferrecv_nameToImport(void);
+
+/*
+ * void xferrecv_importByScrap(void)
+ *
+ * Use
+ *  Tells xferrecv not to bother with RAM transfer, but to use the
+ *  <Wimp$Scrap> file instead.  It checks that the system variables and
+ *  everything are set up right beforehand.
+ */
+
+void xferrecv_importByScrap(void);
+
+/* ------------------------- xferrecv_buffer_processor ---------------------
+ * Description:   This is a typedef for the caller-supplied function
+ *                to empty a full buffer during data transfer.
+ *
+ * Parameters:    char **buffer -- new buffer to be used
+ *                int *size -- updated size
+ * Returns:       return FALSE if unable to empty buffer or create new one.
+ * Other Info:    This is the function (supplied by application,) which will
+ *                be called when buffer is full. It should empty the current
+ *                buffer, or create more space and modify size accordingly
+ *                or return FALSE. *buffer and *size are the current buffer
+ *                and its size on function entry.
+ *
+ */
+typedef BOOL (*xferrecv_buffer_processor)(char **buffer, int *size);
+
+
+
+/* ---------------------------- xferrecv_doimport --------------------------
+ * Description:   Loads data into a buffer, and calls the caller-supplied
+ *                function to empty the buffer when full.
+ *
+ * Parameters:    char *buf -- the buffer
+ *                int size -- buffer's size
+ *                xferrecv_buffer_processor -- caller-supplied function to
+ *                                             be called when buffer full
+ * Returns:       Number of bytes transferred on successful completion
+ *                or -1 otherwise.
+ * Other Info:    none.
+ *
+ */
+
+int xferrecv_doimport(char *buf, int size, xferrecv_buffer_processor);
+
+/*
+ * int xferrecv_returnImportedBlock(flex_ptr p)
+ *
+ * Use
+ *  Performs the data import if possible, and returns with the block filled
+ *  with *ALL* the imported data i.e. it obviates the need of any work on
+ *  your part for the data transfer.  This is the life, huh?  If anything
+ *  went wrong, it returns -1 as for xferrecv_doimport
+ *
+ * Parameters
+ *  flex_ptr p == flex pointer to nothing in particular (certainly not a
+ *    flex block - one is allocated for you).  Remember to free it after
+ *    you've read all the data!  Also ensure that flex has been initialised.
+ *    If there is no data to import (i.e. the import failed) then p is freed
+ *    of any data that may have been stored there.
+ *
+ * Returns
+ *  -1 for failure, or the total size of the imported data for success
+ */
+
+int xferrecv_returnImportedBlock(flex_ptr p);
+
+/* ---------------------- xferrecv_file_is_safe ----------------------------
+ * Description:   Informs caller if file was recieved from a "safe" source
+ *                (see below for definition of "safe").
+ *
+ * Parameters:    void
+ * Returns:       true if file is safe.
+ * Other Info:    "Safe" in this context means that the supplied filename
+ *                will not change in the foreseeable future.
+ *
+ */
+
+BOOL xferrecv_file_is_safe(void);
+
+#endif
+
+/* end xferrecv.h */
diff --git a/StraySrc/Libraries/Steel/h/xfersend b/StraySrc/Libraries/Steel/h/xfersend
new file mode 100644 (file)
index 0000000..e8b6895
--- /dev/null
@@ -0,0 +1,234 @@
+/****************************************************************************
+ * This source file was written by Acorn Computers Limited. It is part of   *
+ * the RISCOS library for writing applications in C for RISC OS. It may be  *
+ * used freely in the creation of programs for Archimedes. It should be     *
+ * used with Acorn's C Compiler Release 3 or later.                         *
+ *                                                                          *
+ ***************************************************************************/
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* Title:   xfersend.h
+ * Purpose: general purpose export of data by dragging icon
+ *
+ */
+
+#ifndef __xfersend_h
+#define __xfersend_h
+
+#ifndef BOOL
+#define BOOL int
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#ifndef __wimp_h
+#include "wimp.h"
+#endif
+                                      
+
+/******************* CALLER-SUPPLIED FUNCTION TYPES ************************/
+
+/* ------------------------ xfersend_saveproc ------------------------------
+ * Description:   A function of this type should save to the given file and
+ *                return TRUE if successful. Handle is passed to the
+ *                function by xfersend().
+ *
+ * Parameters:    char *filename -- file to be saved
+ *                void *handle -- the handle you passed to xfersend()
+ * Returns:       The function must return TRUE if save was successful.
+ * Other Info:    none.
+ *
+ */
+
+typedef BOOL (*xfersend_saveproc)(char *filename, void *handle);
+
+
+/* ----------------------- xfersend_sendproc -------------------------------
+ * Description:   A function of this type should call xfersend_sendbuf() 
+ *                to send one "buffer-full" of data no bigger than
+ *                *maxbuf.
+ *
+ * Parameters:    void *handle -- handle which was passed to xfersend
+ *                int *maxbuf -- size of receiver's buffer
+ * Returns:       The function must return TRUE if data was successfully 
+ *                transmitted.
+ * Other Info:    Note: Your sendproc will be called by functions in the
+ *                xfersend module to do an in-core data transfer, on 
+ *                receipt of MRAMFetch messages from the receiving 
+ *                application. If xfersend_sendbuf() returns FALSE, then
+ *                return FALSE **IMMEDIATELY**.
+ *
+ */
+typedef BOOL (*xfersend_sendproc)(void *handle, int *maxbuf);
+
+
+/* --------------------------- xfersend_printproc --------------------------
+ * Description:   A function of this type should either print the file
+ *                directly, or save it into the given filename, from
+ *                where it will be printed by the printer application.
+ *
+ * Parameters:    char *filename -- file to save into, for printing
+ *                void *handle -- handle that was passed to xfersend()
+ * Returns:       The function should return either the file type of the
+ *                file it saved, or one of the reason codes #defined below.
+ *               
+ * Other Info:    This is called if the file icon has been dragged onto a
+ *                printer application.
+ *
+ */
+
+typedef int (*xfersend_printproc)(char *filename, void *handle);
+
+#define xfersend_printPrinted -1    /* file dealt with internally */
+#define xfersend_printFailed  -2    /* had an error along the way */
+
+/* The saveproc should report any errors it encounters itself. If saving
+   to a file, it should convert the data into a type that can be printed by
+   the printer application (i.e. text). */
+
+
+/*************************** LIBRARY FUNCTIONS *****************************/
+
+
+/* ----------------------------- xfersend ----------------------------------
+ * Description:   Allows the user to export application data, by icon drag.
+ *
+ * Parameters:    int filetype -- type of file to save to
+ *                char *name -- suggested file name
+ *                int estsize -- estimated size of the file
+ *                xfersend_saveproc -- caller-supplied function for saving
+ *                                     application data to a file
+ *                xfersend_sendproc -- caller-supplied function for in-core
+ *                                     data transfer (if application is able
+ *                                     to do this)
+ *                xfersend_printproc -- caller-supplied function for printing
+ *                                      application data, if "icon" is
+ *                                      dragged onto printer application
+ *                wimp_eventstr *e --  the event which started the export
+ *                                     (usually mouse drag)
+ *                void *handle -- handle to be passed to handler functions.
+ * Returns:       TRUE if data exported successfully.
+ * Other Info:    You should typically call this function in a window's
+ *                event handler, when you get a "mouse drag" event.
+ *                See the "saveas.c" code for an example of this.
+ *                xfersend deals with the complexities of message-passing
+ *                protocols to achieve the data transfer. Refer to the above
+ *                typedefs for an explanation of what the three 
+ *                caller-supplied functions should do.
+ *                If "name" is 0 then a default name of "Selection" is
+ *                supplied.
+ *                If you pass 0 as the xfersend_sendproc, then no in-core
+ *                data transfer will be attempted
+ *                If you pass 0 as the xfersend_printproc, then the file
+ *                format for printing is assumed to be the same as for saving
+ *                The estimated file size is not essential, but may improve
+ *                performance.
+ *
+ */
+  
+BOOL xfersend(int filetype, char *name, int estsize,
+              xfersend_saveproc, xfersend_sendproc, xfersend_printproc,
+              wimp_eventstr *e, void *handle);
+
+
+/* ------------------------ xfersend_sendbuf -------------------------------
+ * Description:   Sends the given buffer to a receiver.
+ *
+ * Parameters:    char *buffer -- the buffer to be sent
+ *                int size -- the number of characters placed in the buffer
+ * Returns:       TRUE if send was successful.
+ * Other Info:    This function should be called by the caller-supplied
+ *                xfersend_sendproc (if such exists) to do in-core data
+ *                transfer (see notes on xfersend_sendproc above).
+ *
+ */
+
+BOOL xfersend_sendbuf(char *buffer, int size);
+
+
+/* ------------------------ xfersend_file_is_safe --------------------------
+ * Description:   Informs caller if the file's name can be reliably assumed
+ *                not to change (during data transfer!!)
+ *
+ * Parameters:    void
+ * Returns:       TRUE if file is "safe".
+ * Other Info:    See also the xferrecv module.
+ *
+ */
+
+BOOL xfersend_file_is_safe(void) ;
+
+/* Returns TRUE if file recipient will not modify it; changing the
+   window title of the file can be done conditionally on this result. This
+   can be called within your xfersend_saveproc,sendproc, or printproc,
+   or immediately after the main xfersend. */
+
+/* ---------------------------- xfersend_set_fileissafe --------------------
+ * Description:   Allows caller to set an indication of whether a file's
+ *                name will remain unchanged during data transfer.
+ *
+ * Parameters:    BOOL value -- TRUE means file is safe.
+ * Returns:       void.
+ * Other Info:    none.
+ *
+ */
+
+void xfersend_set_fileissafe(BOOL value);
+
+/*
+ * void xfersend_close_on_xfer(BOOL closeIt,wimp_w window)
+ *
+ * Use
+ *  Tells xfersend whether you want to close a window (say a save dbox) after the
+ *  data transfer.  If you do, you have to specify the window as well.  This isn't
+ *  my architecture, this is just a header for a function that Acorn didn't header,
+ *  but this may be useful to people who want to call xfersend direct, not through
+ *  saveas.
+ *
+ * Parameters
+ *  BOOL closeIt == if you want to close a window.
+ *  wimp_w window == the window to close.
+ */
+
+void xfersend_close_on_xfer(BOOL closeIt,wimp_w window);
+
+/*
+ * BOOL xfersend_sendBlock(void *block,size_t length,int *maxbuf)
+ *
+ * Use
+ *  Sends a block to xfersend_sendbuf() a chunk at a time.
+ *
+ * Parameters
+ *  void *block == pointer to the block
+ *  size_t length == length of block
+ *  int *maxbuf == pointer to the length of the destination task's buffer
+ *
+ * Returns
+ *  TRUE if successful, FALSE if it failed.  If this returns FALSE, you must
+ *  return FALSE immediately.
+ */
+
+BOOL xfersend_sendBlock(void *block,int length,int *maxbuf);
+
+#endif
+
+/* end xfersend.h */
diff --git a/StraySrc/Libraries/Steel/h/xproginfo b/StraySrc/Libraries/Steel/h/xproginfo
new file mode 100644 (file)
index 0000000..2f7829f
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * xproginfo.h
+ *
+ * An 'Info about program' box with scrolltext :-)
+ *
+ * © 1994-1998 Straylight
+ */
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __xproginfo_h
+#define __xproginfo_h
+
+void xprogInfo(char *name,
+               char *purpose,
+               char *author,
+               int version,
+               char *date,
+               char *scrolltext,
+               char *initText,
+               int delay);
+               
+#endif
diff --git a/StraySrc/Libraries/Steel/h/xtearoff b/StraySrc/Libraries/Steel/h/xtearoff
new file mode 100644 (file)
index 0000000..0a05975
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Tearoff menu system
+ * Internal header file
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Steel library.
+ *
+ * Steel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Steel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Steel.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __xtearoff_h
+#define __xtearoff_h
+
+#include "tearoff.h"
+
+#define tearoff__HEIGHT 24             /* Height of tearoff bar */
+
+typedef struct tearoff__str
+{
+  char *menuTitle;                     /* Title of menu */
+  int numberOfItems;                   /* Number of items in menu */
+  int width;                           /* Width of menu */
+  int keyWidth;                        /* Max width of shortcut */
+  int dotted;                          /* Height of dotted lines */
+  int selected;                        /* Currently selected item */
+  int maxHeight;                       /* Maximum height before scrollbar */
+  int fromItem;                        /* I came from this item */
+  tearoff_selectProc selectProc;       /* Called with related event */
+  void *userHandle;                    /* User supplied handle */
+  wimp_w w;                            /* The `menu's window handle */
+  struct tearoff__str *sub;           /* The submenu pointer thingy */
+  struct tearoff__str *prev;          /* The previous menu */
+  struct tearoff__str *nextTornoff;    /* The next tornoff menu in list */
+  char *indirected;                    /* Pointer to indirected space */
+  int indbytes;                        /* Length of indirected area */
+  BOOL open;                           /* Is menu open? */
+  BOOL tearoff :8;                     /* Can menu be torn off? */
+  BOOL tornoff :8;                     /* Has it been? */
+  BOOL warned  :8;                     /* Hs usr bn wrnd about submenu? */
+  BOOL folded  :8;                     /* Is menu folded */
+  BOOL redraw;                         /* Does it need redrawing? */
+  BOOL scrollBar;                      /* Menu has scroll bar */
+                                       /* Now followed by lots of items */
+} tearoff__str;
+
+typedef struct tearoff__item
+{
+  char *text;                          /* Item text */
+  char *keys;                          /* Short cut text */
+  tearoff sub;                         /* Sub menu to open */
+  int y;                               /* y coord of item */
+  BOOL shaded           :1;            /* Item is shaded */
+  BOOL subShaded        :1;            /* Arrow is shaded */
+  BOOL selType          :2;            /* Item is ticked */
+  BOOL dotted           :1;            /* Dotted line next */
+  BOOL blank            :1;            /* Word Align */
+  BOOL subMenu          :1;            /* Item has submenu */
+  BOOL subMenuWarning   :1;            /* Report a submenu warning */
+} tearoff__item;
+
+typedef struct tearoff__alarm
+{
+  tearoff t;                           /* The tearoff alarm was set on */
+  int item;                           /* The item is was set for */
+}
+tearoff__alarm;
+
+void tearoff__doRedraw(tearoff t, wimp_redrawstr *r);
+void tearoff_calculateMenuWidth(tearoff t);
+void tearoff_rebuildMenu(tearoff t);
+void tearoff_highlightItem(int s, tearoff t, BOOL select);
+
+#ifdef notdef
+os_error *tearoff_opened(wimp_t task);
+os_error *tearoff_closed(void);
+os_error *tearoff_closeMenus(void);
+#endif
+
+#endif
diff --git a/StraySrc/Libraries/Steel/s/bbc b/StraySrc/Libraries/Steel/s/bbc
new file mode 100644 (file)
index 0000000..ac11bf6
--- /dev/null
@@ -0,0 +1,746 @@
+;
+; bbc.s
+;
+; Low-level graphics and mouse/keyboard handling
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               AREA    |C$$Code|,CODE,READONLY
+
+;----- VDU and character output ---------------------------------------------
+
+; --- bbc_vdu ---
+;
+; On entry:    a1 == a character to output
+
+               EXPORT  bbc_vdu
+bbc_vdu                SWI     XOS_WriteC
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_vduw ---
+;
+; On entry:    a1 == halfword to output
+
+               EXPORT  bbc_vduw
+bbc_vduw       SWI     XOS_WriteC
+               MOVVC   a1,a1,LSR #8
+               SWIVC   XOS_WriteC
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_vduq ---
+;
+; On entry:    APCS args contain bytes to output
+
+bbc__vduqTable DCB     1,2,1,1,1,1,1,1
+               DCB     1,1,1,1,1,1,1,1
+               DCB     1,2,3,6,1,1,2,10
+               DCB     9,6,1,1,5,5,1,3
+
+               EXPORT  bbc_vduq
+bbc_vduq       ROUT
+
+               STMFD   sp!,{a2-a4}             ;Stack extra args
+               ADR     a2,bbc__vduqTable       ;Point to the table
+               CMP     a1,#' '                 ;Is the char a control char?
+               MOVGE   a2,#1                   ;Yes -- only one in the queue
+               LDRLTB  a2,[a2,a1]              ;No -- load queue length
+               MOV     a3,sp                   ;Point to queue on the stack
+
+00bbc_vduq     SWI     XOS_WriteC              ;Write the character out
+               ADDVS   sp,sp,#12               ;If it failed, reclaim stack
+               MOVVSS  pc,lr                   ;And quit right this second
+               SUBS    a2,a2,#1                ;Decrement the byte counter
+               LDRGT   a1,[a3],#4              ;If more, get another byte
+               BGT     %00bbc_vduq             ;And print that one too
+
+               ADD     sp,sp,#12               ;Bump the stack back again
+               MOV     a1,#0                   ;No error returned
+               MOVS    pc,lr                   ;Return to the caller
+
+; --- bbc_stringprint ---
+;
+; On entry:    a1 == pointer to a NULL-terminated string
+
+               EXPORT  bbc_stringprint
+bbc_stringprint        SWI     XOS_Write0
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_cls ---
+;
+; On entry:    --
+
+               EXPORT  bbc_cls
+bbc_cls                SWI     XOS_WriteI+12
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_colour ---
+;
+; On entry:    a1 == text colour to set
+
+               EXPORT  bbc_colour
+bbc_colour     SWI     XOS_WriteI+17
+               SWIVC   XOS_WriteC
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_pos ---
+;
+; On entry:    --
+; On exit:     a1 == x coord of text cursor
+
+               EXPORT  bbc_pos
+bbc_pos                MOV     a1,#&86
+               SWI     XOS_Byte
+               MOV     a1,a2
+               MOVS    pc,lr
+
+; --- bbc_vpos ---
+;
+; On entry:    --
+; On exit:     a1 == y coord of text cursor
+
+               EXPORT  bbc_vpos
+bbc_vpos       MOV     a1,#&86
+               SWI     XOS_Byte
+               MOV     a1,a3
+               MOVS    pc,lr
+
+; --- bbc_tab ---
+;
+; On entry:    a1 == x coordinate to move to
+;              a2 == y coordinate to move to
+
+               EXPORT  bbc_tab
+bbc_tab                SWI     XOS_WriteI+31
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a2
+               SWIVC   XOS_WriteC
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+;----- Graphics output ------------------------------------------------------
+
+; --- bbc_plot ---
+;
+; On entry:    a1 == plot code number
+;              a2 == x coordinate to plot at
+;              a3 == y coordinate to plot at
+
+               EXPORT  bbc_plot
+bbc_plot       SWI     XOS_Plot
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_mode ---
+;
+; On entry:    a1 == new mode number to set
+
+               EXPORT  bbc_mode
+bbc_mode       SWI     XOS_WriteI+22
+               SWIVC   XOS_WriteC
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_move ---
+;
+; On entry:    a1 == x coordinate to move to
+;              a2 == y coordinate to move to
+
+               EXPORT  bbc_move
+bbc_move       MOV     a3,a2
+               MOV     a2,a1
+               MOV     a1,#4
+               SWI     XOS_Plot
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_moveby ---
+;
+; On entry:    a1 == x offset to move to
+;              a2 == y offset to move to
+
+               EXPORT  bbc_moveby
+bbc_moveby     MOV     a3,a2
+               MOV     a2,a1
+               MOV     a1,#0
+               SWI     XOS_Plot
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_draw ---
+;
+; On entry:    a1 == x coordinate to draw to
+;              a2 == y coordinate to draw to
+
+               EXPORT  bbc_draw
+bbc_draw       MOV     a3,a2
+               MOV     a2,a1
+               MOV     a1,#5
+               SWI     XOS_Plot
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_drawby ---
+;
+; On entry:    a1 == x offset to draw to
+;              a2 == y offset to draw to
+
+               EXPORT  bbc_drawby
+bbc_drawby     MOV     a3,a2
+               MOV     a2,a1
+               MOV     a1,#1
+               SWI     XOS_Plot
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_rectangle ---
+;
+; On entry:    a1 == bottom left x coordinate
+;              a2 == bottom left y coordinate
+;              a3 == rectangle width
+;              a4 == rectangle height
+
+               EXPORT  bbc_rectangle
+bbc_rectangle  MOV     ip,a3                   ;Look after rectangle width
+               MOV     a3,a2
+               MOV     a2,a1
+               MOV     a1,#4
+               SWI     XOS_Plot
+               MOVVC   a1,#9
+               MOVVC   a2,ip
+               MOVVC   a3,#0
+               SWIVC   XOS_Plot
+               MOVVC   a1,#9
+               MOVVC   a2,#0
+               MOVVC   a3,a4
+               SWIVC   XOS_Plot
+               MOVVC   a1,#9
+               RSBVC   a2,ip,#0
+               MOVVC   a3,#0
+               SWIVC   XOS_Plot
+               MOVVC   a1,#9
+               MOVVC   a2,#0
+               RSBVC   a3,a4,#0
+               SWIVC   XOS_Plot
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_rectanglefill ---
+;
+; On entry:    a1 == bottom left x coordinate
+;              a2 == bottom left y coordinate
+;              a3 == rectangle width
+;              a4 == rectangle height
+
+               EXPORT  bbc_rectanglefill
+bbc_rectanglefill
+               MOV     ip,a3
+               MOV     a3,a2
+               MOV     a2,a1
+               MOV     a1,#4
+               SWI     XOS_Plot
+               MOVVC   a1,#&61                 ;Rectangle plot relative
+               MOVVC   a2,ip
+               MOVVC   a3,a4
+               SWIVC   XOS_Plot
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_circle ---
+;
+; On entry:    a1 == x coordinate of centre
+;              a2 == y coordinate of centre
+;              a3 == radius of circle
+
+               EXPORT  bbc_circle
+bbc_circle     MOV     a4,a3
+               MOV     a3,a2
+               MOV     a2,a1
+               MOV     a1,#4
+               SWI     XOS_Plot
+               MOVVC   a1,#&91
+               MOVVC   a2,a4
+               MOVVC   a3,#0
+               SWIVC   XOS_Plot
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_circlefill ---
+;
+; On entry:    a1 == x coordinate of centre
+;              a2 == y coordinate of centre
+;              a3 == radius of circle
+
+               EXPORT  bbc_circlefill
+bbc_circlefill MOV     a4,a3
+               MOV     a3,a2
+               MOV     a2,a1
+               MOV     a1,#4
+               SWI     XOS_Plot
+               MOVVC   a1,#&99
+               MOVVC   a2,a4
+               MOVVC   a3,#0
+               SWIVC   XOS_Plot
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_origin ---
+;
+; On entry:    a1 == x coordinate to move origin to
+;              a2 == x coordinate to move origin to
+
+               EXPORT  bbc_origin
+bbc_origin     SWI     XOS_WriteI+29
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a1,LSR #8
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a2
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a1,LSR #8
+               SWIVC   XOS_WriteC
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_gwindow ---
+;
+; On entry:    a1 == bottom left x coord
+;              a2 == bottom left y coord
+;              a3 == top right x coord
+;              a4 == top right y coord
+
+               EXPORT  bbc_gwindow
+bbc_gwindow    SWI     XOS_WriteI+24
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a1,LSR #8
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a2
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a1,LSR #8
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a3
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a1,LSR #8
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a4
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a1,LSR #8
+               SWIVC   XOS_WriteC
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_clg ---
+;
+; On entry:    --
+
+               EXPORT  bbc_clg
+bbc_clg                SWI     XOS_WriteI+16
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_fill ---
+;
+; On entry:    a1 == x coordinate to fill from
+;              a2 == y coordinate to fill from
+;
+; WARNING: this call uses the OS flood-fill, which is (or at least used to
+; be) very badly broken.  Use with care, or crash horribly.  We may change
+; to use our own flood fill algorithm some day, but don't hold your breath.
+
+               EXPORT  bbc_fill
+bbc_fill       MOV     a3,a2
+               MOV     a2,a1
+               MOV     a1,#&85
+               SWI     XOS_Plot
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_gcol ---
+;
+; On entry:    a1 == gcol action
+;              a2 == gcol value
+
+               EXPORT  bbc_gcol
+bbc_gcol       SWI     XOS_WriteI+18
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a2
+               SWIVC   XOS_WriteC
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_tint ---
+;
+; On entry:    a1 == tint action (what colour to set)
+;              a2 == tint value
+
+               EXPORT  bbc_tint
+bbc_tint       SWI     XOS_WriteI+23           ;1
+               ANDVC   a1,a1,#&03
+               SWIVC   XOS_WriteC              ;2
+               MOVVC   a1,a2,LSL #6
+               ANDVC   a1,a1,#&C0
+               SWIVC   XOS_WriteC              ;3
+               SWIVC   XOS_WriteI+0            ;4
+               SWIVC   XOS_WriteI+0            ;5
+               SWIVC   XOS_WriteI+0            ;6
+               SWIVC   XOS_WriteI+0            ;7
+               SWIVC   XOS_WriteI+0            ;8
+               SWIVC   XOS_WriteI+0            ;9
+               SWIVC   XOS_WriteI+0            ;10
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_palette ---
+;
+; On entry:    a1 == logical colour to remap
+;              a2 == physical colour to assign
+;              a3 == red level to assign
+;              a4 == green level to assign
+;              [sp] == blue level to assign
+
+               EXPORT  bbc_palette
+bbc_palette    SWI     XOS_WriteI+19
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a2
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a3
+               SWIVC   XOS_WriteC
+               MOVVC   a1,a4
+               SWIVC   XOS_WriteC
+               LDRVC   a1,[sp]
+               SWIVC   XOS_WriteC
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_point ---
+;
+; On entry:    a1 == x coordinate of point to read
+;              a2 == y coordinate of point to read
+; On exit;     a1 == logical colour at the point, or &FF if not on-screen
+;
+; NOTE: The RISC_OSLib version is utterly buggered.  For no known reason,
+; the fools decided to pass parameters in wholewords rather than OS_Word's
+; own inimitable halfwords, meaning that RISC_OSLib's bbc_point invariably
+; returns 0.  We side-step the entire issue by using OS_ReadPoint instead.
+
+               EXPORT  bbc_point
+bbc_point      MOV     ip,v1
+               SWI     XOS_ReadPoint
+               MOV     v1,ip
+               MOVVS   a1,#&FF
+               ANDVC   a1,a3,#&FF
+               MOVS    pc,lr
+
+; --- bbc_vduvar ---
+;
+; On entry:    a1 == variable number to read
+; On exit:     a1 == variable value read
+
+               EXPORT  bbc_vduvar
+bbc_vduvar     MOV     a2,#-1                  ;Terminator for input array
+               STMFD   sp!,{a1-a3}             ;Store on stack, with output
+               MOV     a1,sp                   ;Point to the input array
+               ADD     a2,a1,#8                ;Point to output word
+               SWI     XOS_ReadVduVariables    ;Read the variable's value
+               ADD     sp,sp,#8                ;Point sp at the value
+               LDMIA   sp!,{a1}                ;Read the value
+               MOVS    pc,lr
+
+; --- bbc_vduvars ---
+;
+; On entry:    a1 == pointer to input array
+;              a2 == pointer to output array
+
+               EXPORT  bbc_vduvars
+bbc_vduvars    SWI     XOS_ReadVduVariables
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_modevar ---
+;
+; On entry:    a1 == mode number to read variable for
+;              a2 == variable number
+; On exit:     a1 == variable value
+
+               EXPORT  bbc_modevar
+bbc_modevar    SWI     XOS_ReadModeVariable
+               MOV     a1,a3
+               MOVS    pc,lr
+
+;----- Keyboard handling ----------------------------------------------------
+
+; --- bbc_get ---
+;
+; On entry:    --
+; On exit:     a1 == key code read, bit 8 set if escape condition
+
+               EXPORT  bbc_get
+bbc_get                SWI     XOS_ReadC
+               ORRCS   a1,a1,#&100
+               MOVS    pc,lr
+
+; --- bbc_inkey ---
+;
+; On entry:    a1 == time to wait, or -ve inkey number
+
+               EXPORT  bbc_inkey
+bbc_inkey      MOV     a3,a1,LSR #8
+               AND     a3,a3,#&FF
+               AND     a2,a1,#&FF
+               MOV     a1,#&81
+               SWI     XOS_Byte
+               CMP     a3,#&FF
+               MOVEQ   a1,#-1
+               MOVNE   a1,a2
+               MOVS    pc,lr
+
+; --- bbc_cursor ---
+;
+; On entry:    a1 == new text cursor mode
+
+               EXPORT  bbc_cursor
+bbc_cursor     SWI     XOS_WriteI+23           ;1
+               SWIVC   XOS_WriteI+1            ;2
+               SWIVC   XOS_WriteC              ;3
+               SWIVC   XOS_WriteI+0            ;4
+               SWIVC   XOS_WriteI+0            ;5
+               SWIVC   XOS_WriteI+0            ;6
+               SWIVC   XOS_WriteI+0            ;7
+               SWIVC   XOS_WriteI+0            ;8
+               SWIVC   XOS_WriteI+0            ;9
+               SWIVC   XOS_WriteI+0            ;10
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+;----- Mouse handling -------------------------------------------------------
+
+; --- bbc_mouse ---
+;
+; On entry:    a1 == where to put x coordinate
+;              a2 == where to put y coordinate
+;              a3 == where to put button status
+;              a4 == where to put time of click
+
+               EXPORT  bbc_mouse
+bbc_mouse      STMFD   sp!,{v1-v4,lr}
+               MOV     v1,a1
+               MOV     v2,a2
+               MOV     v3,a3
+               MOV     v4,a4
+               SWI     XOS_Mouse
+               LDMVSFD sp!,{v1-v4,pc}^
+               CMP     v1,#0
+               STRNE   a1,[v1]
+               CMP     v2,#0
+               STRNE   a2,[v2]
+               CMP     v3,#0
+               STRNE   a3,[v3]
+               CMP     v4,#0
+               STRNE   a4,[v4]
+               MOV     a1,#0
+               LDMFD   sp!,{v1-v4,pc}^
+
+; --- bbc_mouserect ---
+;
+; On entry:    a1 == mouse rectangle bottom left x coord
+;              a2 == mouse rectangle bottom left y coord
+;              a3 == mouse rectangle top right x coord
+;              a4 == mouse rectangle top right y coord
+
+               EXPORT  bbc_mouserect
+bbc_mouserect  SUB     sp,sp,#12
+               MOV     ip,#1
+               STRB    ip,[sp,#0]
+               MOV     ip,a1
+               STRB    ip,[sp,#1]
+               MOV     ip,a1,LSR #8
+               STRB    ip,[sp,#2]
+               MOV     ip,a2
+               STRB    ip,[sp,#3]
+               MOV     ip,a2,LSR #8
+               STRB    ip,[sp,#4]
+               MOV     ip,a3
+               STRB    ip,[sp,#5]
+               MOV     ip,a3,LSR #8
+               STRB    ip,[sp,#6]
+               MOV     ip,a4
+               STRB    ip,[sp,#7]
+               MOV     ip,a4,LSR #8
+               STRB    ip,[sp,#8]
+               MOV     a1,#21
+               MOV     a2,sp
+               SWI     XOS_Word
+               ADD     sp,sp,#12
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+;----- Strangeness ----------------------------------------------------------
+
+; --- bbc_adval ---
+;
+; NOTE: Since I don't have a clue about what the RISC_OSLib version's trying
+; to do, although at a guess it's utterly wrong.  I'll just do it properly.
+;
+; On entry:    a1 == reason code for OS_Byte 128
+; On exit:     a1 == output of OS_Byte 128
+
+               EXPORT  bbc_adval
+bbc_adval      AND     a2,a1,#&FF
+               MOV     a1,#&80
+               SWI     XOS_Byte
+               MOVVS   a1,#&80000000
+               ORRVC   a1,a2,a3,LSL #8
+               MOVS    pc,lr
+
+;----- Messing about with sound ---------------------------------------------
+
+; --- bbc_getbeat ---
+;
+; On entry:    --
+; On exit:     a1 == current beat value
+
+               EXPORT  bbc_getbeat
+bbc_getbeat    MOV     a1,#0
+               SWI     XSound_QBeat
+               MOVS    pc,lr
+
+; --- bbc_getbeats ---
+;
+; On entry:    --
+; On exit:     a1 == previous bar length
+
+               EXPORT  bbc_getbeats
+bbc_getbeats   MOV     a1,#-1
+               SWI     XSound_QBeat
+               MOVS    pc,lr
+
+; --- bbc_gettempo ---
+;
+; On entry:    --
+; On exit:     a1 == tempo for beat counter
+
+               EXPORT  bbc_gettempo
+bbc_gettempo   MOV     a1,#0
+               SWI     XSound_QTempo
+               MOVS    pc,lr
+
+; --- bbc_setbeats ---
+;
+; On entry:    a1 == new bar length
+
+               EXPORT  bbc_setbeats
+bbc_setbeats   SWI     XSound_QBeat
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_settempo ---
+;
+; On entry:    a1 == new tempo for beat counter
+
+               EXPORT  bbc_settempo
+bbc_settempo   SWI     XSound_QTempo
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_sound ---
+;
+; On entry:    a1 == channel number
+;              a2 == amplitude of noise to make
+;              a3 == pitch to make the noise
+;              a4 == duration of noise
+;              [sp] == time to make the noise, or -2 for `right now'
+
+               EXPORT  bbc_sound
+bbc_sound      ROUT
+
+               LDR     ip,[sp]                 ;Get the time to make noise
+               CMP     ip,#-2                  ;Do we make noises right now?
+               BEQ     %00bbc_sound            ;Yes -- deal with that case
+
+               ORR     a4,a3,a4,LSL #16        ;Pack the arguments up
+               ORR     a3,a1,a2,LSL #16
+               MOV     a1,ip                   ;Get the time to schedule
+               MOV     a2,#0                   ;Use Sound_ControlPacked
+               SWI     XSound_QSchedule        ;Schedule the noise nicely
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+00bbc_sound    SWI     XSound_Control          ;Just make a noise now
+               MOVVS   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_soundoff ---
+;
+; On entry:    --
+
+               EXPORT  bbc_soundoff
+bbc_soundoff   MOV     a1,#1
+               SWI     XSound_Enable
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_soundon ---
+;
+; On entry:    --
+
+               EXPORT  bbc_soundon
+bbc_soundon    MOV     a1,#2
+               SWI     XSound_Enable
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_stereo ---
+;
+; On entry:    a1 == channel to set position of
+;              a2 == new stereo position of channel
+
+               EXPORT  bbc_stereo
+bbc_stereo     SWI     XSound_Stereo
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- bbc_voices ---
+;
+; On entry:    a1 == number of voices to set
+
+               EXPORT  bbc_voices
+bbc_voices     MOV     ip,v1
+               MOV     a2,#0
+               MOV     a3,#0
+               MOV     a4,#0
+               MOV     v1,#0
+               SWI     XSound_Configure
+               MOV     v1,ip
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Steel/s/calltrace b/StraySrc/Libraries/Steel/s/calltrace
new file mode 100644 (file)
index 0000000..be09b8b
--- /dev/null
@@ -0,0 +1,103 @@
+;
+; calltrace
+;
+; Display a backtrace of the call stack
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               GET     libs:header
+               GET     libs:swis
+
+               IMPORT  |_kernel_unwind|
+               IMPORT  |_kernel_procname|
+
+               AREA    |C$$Code|,CODE,READONLY
+
+99
+               DCB     "_calltrace",0
+               ALIGN
+               DCD     &FF000000+{PC}-%b99
+
+               EXPORT  |_calltrace|
+|_calltrace|   ROUT
+
+               MOV     ip,sp
+               STMFD   sp!,{fp,ip,lr,pc}
+               SUB     fp,ip,#4
+               SUB     sp,sp,#20               ;Make a small buffer
+
+               ; --- Start displaying the command window ---
+
+               ADR     a1,wintitle
+               SWI     Wimp_CommandWindow
+               SWI     XOS_WriteI+14
+
+               ; --- Set up dunny `frame pointer' ---
+
+               MOV     ip,fp
+
+00             ; --- Print address from which it's called ---
+
+               LDR     a1,[ip,#-4]             ;Get the link regiser
+               BIC     a1,a1,#&FC000003        ;Strip off saved PSR
+               SUB     a1,a1,#4                ;Find the call address
+               MOV     a2,sp                   ;Point to the buffer
+               MOV     a3,#20                  ;Buffer size
+               SWI     XOS_ConvertHex8         ;Convert the address
+               SWI     XOS_Write0              ;Display it on screen
+               SWI     XOS_WriteI+' '
+               SWI     XOS_WriteI+'('
+
+               ; --- Print procedure name ---
+
+               LDR     ip,[ip,#-12]
+               LDR     a4,[ip,#0]              ;Where's the stacked pc?
+               BIC     a4,a4,#&FC000003        ;Mask off the PSR bits
+               SUB     a4,a4,#20               ;Point to procedure word
+               LDR     a2,[a4,#0]              ;And load it
+               AND     a3,a2,#&FF000000        ;Check the top byte is right
+               CMP     a3,#&FF000000           ;Is it the right pattern?
+               BICEQ   a3,a2,#&FF000000        ;Yes: Find the string length
+               SUBEQ   a1,a4,a3                ;     Point to the proc name
+               ADRNE   a1,anon                 ;No:  Point to `anonymous'
+               SWI     XOS_Write0              ;Display the procedure name
+               SWI     XOS_WriteI+')'
+               SWI     XOS_NewLine             ;Move on to next line
+
+               ; --- Unwind the stack another level ---
+
+               LDR     a1,[ip,#-12]            ;Get the stacked frame ptr
+               CMP     a1,#0                   ;Is there a real stack frame?
+               BNE     %00                     ;Yes -- dump that one out
+
+               ; --- Turn the command window off ---
+
+01             SWI     Wimp_CommandWindow
+
+               LDMDB   fp,{fp,sp,pc}^
+
+wintitle       DCB     "Stack backtrace",0
+anon           DCB     "Anonymous function",0
+
+               LTORG
+
+               END
diff --git a/StraySrc/Libraries/Steel/s/colourtran b/StraySrc/Libraries/Steel/s/colourtran
new file mode 100644 (file)
index 0000000..66187be
--- /dev/null
@@ -0,0 +1,421 @@
+;
+; colourtran.s
+;
+; ColourTrans interface
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |C$$Code|,CODE,READONLY
+
+; --- colourtran_select_table ---
+;
+; On entry:    a1 == source mode
+;              a2 == pointer to source palette
+;              a3 == destination mode
+;              a4 == pointer to destination palette
+;              [sp,#0] == pointer to buffer to fill with table
+;              [sp,#4] == flags word
+;
+; We don't support the transfer function, because it's not APCS.
+
+               EXPORT  colourtran_select_table
+colourtran_select_table
+               MOV     ip,sp
+               STMFD   sp!,{v1,v2,lr}
+               CMP     a1,#256
+               LDMGEIA ip,{v1,v2}
+               LDRLT   v1,[ip]
+               SWI     XColourTrans_SelectTable
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,v2,pc}^
+
+; --- colourtran_select_GCOLtable ---
+;
+; On entry:    a1 == source mode
+;              a2 == pointer to source palette
+;              a3 == destination mode
+;              a4 == pointer to destination palette
+;              [sp,#0] == pointer to buffer to fill in
+;              [sp,#4] == flags word
+
+               EXPORT  colourtran_select_GCOLtable
+colourtran_select_GCOLtable
+               MOV     ip,sp
+               STMFD   sp!,{v1,v2,lr}
+               CMP     a1,#256
+               LDMGEIA ip,{v1,v2}
+               LDRLT   v1,[ip]
+               SWI     XColourTrans_SelectGCOLTable
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,v2,pc}^
+
+; --- colourtran_returnGCOL ---
+;
+; On entry:    a1 == palette entry
+;              a2 == pointer to GCOL word to store
+
+               EXPORT  colourtran_returnGCOL
+colourtran_returnGCOL
+               SWI     XColourTrans_ReturnGCOL
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_setGCOL ---
+;
+; On entry:    a1 == palette entry
+;              a2 == flags word
+;              a3 == GCOL action to set
+;              a4 == pointer to where to store the output
+
+               EXPORT  colourtran_setGCOL
+colourtran_setGCOL
+               STMFD   sp!,{a4,v1,lr}
+               MOV     v1,a3
+               MOV     a4,a2
+               SWI     XColourTrans_SetGCOL
+               LDR     a2,[sp],#4
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,pc}^
+
+; --- colourtran_return_colournumber ---
+;
+; On entry:    a1 == palette entry
+;              a2 == pointer to where to put the colour
+
+               EXPORT  colourtran_return_colournumber
+colourtran_return_colournumber
+               SWI     XColourTrans_ReturnColourNumber
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_return_GCOLformode ---
+;
+; On entry:    a1 == palette entry
+;              a2 == destination mode number
+;              a3 == pointer to destination palette
+;              a4 == pointer to where to store the colour
+
+               EXPORT  colourtran_return_GCOLformode
+colourtran_return_GCOLformode
+               SWI     XColourTrans_ReturnGCOLForMode
+               STRVC   a1,[a4]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_return_colourformode ---
+;
+; On entry:    a1 == palette entry to set
+;              a2 == destination mode number
+;              a3 == pointer to destination palette
+;              a4 == pointer to where to store the number
+
+               EXPORT  colourtran_return_colourformode
+colourtran_return_colourformode
+               SWI     XColourTrans_ReturnColourNumberForMode
+               STRVC   a1,[a4]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_return_OppGCOL ---
+;
+; On entry:    a1 == palette entry
+;              a2 == pointer to where to store the GCOL
+
+               EXPORT  colourtran_return_OppGCOL
+colourtran_return_OppGCOL
+               SWI     XColourTrans_ReturnOppGCOL
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_setOppGCOL ---
+;
+; On entry:    a1 == palette entry
+;              a2 == flags word
+;              a3 == GCOL action to set
+;              a4 == pointer to where to store the output
+
+               EXPORT  colourtran_setOppGCOL
+colourtran_setOppGCOL
+               STMFD   sp!,{a4,v1,lr}
+               MOV     v1,a3
+               MOV     a4,a2
+               SWI     XColourTrans_SetOppGCOL
+               LDR     a2,[sp],#4
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,pc}^
+
+; --- colourtran_return_Oppcolournumber ---
+;
+; On entry:    a1 == palette entry
+;              a2 == pointer to where to store the colour
+
+               EXPORT  colourtran_return_Oppcolournumber
+colourtran_return_Oppcolournumber
+               SWI     XColourTrans_ReturnOppColourNumber
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_return_OppGCOLformode ---
+;
+; On entry:    a1 == a1 == palette entry
+;              a2 == destination mode number
+;              a3 == pointer to destination palette
+;              a4 == pointer to where to store the colour
+
+               EXPORT  colourtran_return_OppGCOLformode
+colourtran_return_OppGCOLformode
+               SWI     XColourTrans_ReturnOppGCOLForMode
+               STRVC   a1,[a4]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_return_Oppcolourformode ---
+;
+; On entry:    a1 == palette entry to set
+;              a2 == destination mode number
+;              a3 == pointer to destination palette
+;              a4 == pointer to where to store the number
+
+               EXPORT  colourtran_return_Oppcolourformode
+colourtran_return_Oppcolourformode
+               SWI     XColourTrans_ReturnOppColourNumberForMode
+               STRVC   a1,[a4]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_GCOL_tocolournumber ---
+;
+; On entry:    a1 == GCOL to convert
+;              a2 == pointer to where to put colour number
+
+               EXPORT  colourtran_GCOL_tocolournumber
+colourtran_GCOL_tocolournumber
+               SWI     XColourTrans_GCOLToColourNumber
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_colournumbertoGCOL ---
+;
+; On entry:    a1 == colour number to convert
+;              a2 == pointer to where to put GCOL
+
+               EXPORT  colourtran_colournumbertoGCOL
+colourtran_colournumbertoGCOL
+               SWI     XColourTrans_ColourNumberToGCOL
+               STRVC   a1,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_returnfontcolours ---
+;
+; On entry:    a1 == pointer to font handle
+;              a2 == pointer to background palette entry
+;              a3 == pointer to foreground palette entry
+;              a4 == pointer to amount of antialiasing to do
+;
+; Christ knows what all this is about.  Well, I hope so, 'cos I haven't got
+; a clue.  For a start, ColourTrans_ReturnFontColours preserves R0, so
+; passing the font handle through a pointer is really silly.  For seconds,
+; the output R1 and R2 values aren't palette entries at all.  My verdict:
+; someone at Acorn doesn't have a clue.  But then again, what do you expect
+; from SWI veneers written in C?
+
+               EXPORT  colourtran_returnfontcolours
+colourtran_returnfontcolours
+               STMFD   sp!,{a1-a4}
+               LDR     a1,[a1]
+               LDR     a2,[a2]
+               LDR     a3,[a3]
+               LDR     a4,[a4]
+               SWI     XColourTrans_ReturnFontColours
+               LDR     ip,[sp],#4
+               STRVC   a1,[ip]
+               LDR     ip,[sp],#4
+               STRVC   a2,[ip]
+               LDR     ip,[sp],#4
+               STRVC   a3,[ip]
+               LDR     ip,[sp],#4
+               STRVC   a4,[ip]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_setfontcolours ---
+;
+; On entry:    The same braindead pointers as the last one
+
+               EXPORT  colourtran_setfontcolours
+colourtran_setfontcolours
+               STMFD   sp!,{a1-a4}
+               LDR     a1,[a1]
+               LDR     a2,[a2]
+               LDR     a3,[a3]
+               LDR     a4,[a4]
+               SWI     XColourTrans_SetFontColours
+               LDR     ip,[sp],#4
+               STRVC   a1,[ip]
+               LDR     ip,[sp],#4
+               STRVC   a2,[ip]
+               LDR     ip,[sp],#4
+               STRVC   a3,[ip]
+               LDR     ip,[sp],#4
+               STRVC   a4,[ip]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_invalidate_cache ---
+;
+; On entry:    --
+
+               EXPORT  colourtran_invalidate_cache
+colourtran_invalidate_cache
+               SWI     ColourTrans_InvalidateCache
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- Omitted veneers ---
+;
+; Setting and reading calibration tables is not supported.  Applications
+; probably shouldn't be doing this sort of thing anyway.
+
+; --- colourtran_convert_device_colour ---
+;
+; On entry:    a1 == palette entry to convert
+;              a2 == pointer to where to store the standard colour
+
+               EXPORT  colourtran_convert_device_colour
+colourtran_convert_device_colour
+               STR     a2,[sp,#-4]!
+               MOV     a4,#0
+               MOV     a2,a1
+               SWI     XColourTrans_ConvertDeviceColour
+               LDR     a2,[sp],#4
+               STRVC   a3,[a2]
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_convertRGBToCIE ---
+;
+; On entry:    a1 == pointer to RGB block
+;              a2 == pointer to CIE block
+
+               EXPORT  colourtran_convertRGBToCIE
+colourtran_convertRGBToCIE
+               STR     a2,[sp,#-4]!
+               LDMIA   a1,{a1-a3}
+               SWI     XColourTrans_ConvertRGBToCIE
+               LDR     ip,[sp],#4
+               STMVCIA ip,{a1-a3}
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_convertCIEToRGB ---
+;
+; On entry:    a1 == pointer to CIE block
+;              a2 == pointer to RGB block
+
+               EXPORT  colourtran_convertCIEToRGB
+colourtran_convertCIEToRGB
+               STR     a2,[sp,#-4]!
+               LDMIA   a1,{a1-a3}
+               SWI     XColourTrans_ConvertCIEToRGB
+               LDR     ip,[sp],#4
+               STMVCIA ip,{a1-a3}
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_convertRGBToHSV ---
+;
+; On entry:    a1 == pointer to RGB block
+;              a2 == pointer to CIE block
+
+               EXPORT  colourtran_convertRGBToHSV
+colourtran_convertRGBToHSV
+               STR     a2,[sp,#-4]!
+               LDMIA   a1,{a1-a3}
+               SWI     XColourTrans_ConvertRGBToHSV
+               LDR     ip,[sp],#4
+               STMVCIA ip,{a1-a3}
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_convertHSVToRGB ---
+;
+; On entry:    a1 == pointer to CIE block
+;              a2 == pointer to RGB block
+
+               EXPORT  colourtran_convertHSVToRGB
+colourtran_convertHSVToRGB
+               STR     a2,[sp,#-4]!
+               LDMIA   a1,{a1-a3}
+               SWI     XColourTrans_ConvertHSVToRGB
+               LDR     ip,[sp],#4
+               STMVCIA ip,{a1-a3}
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_convertRGBToCMYK ---
+;
+; On entry:    a1 == pointer to RGB block
+;              a2 == pointer to CIE block
+
+               EXPORT  colourtran_convertRGBToCMYK
+colourtran_convertRGBToCMYK
+               STR     a2,[sp,#-4]!
+               LDMIA   a1,{a1-a3}
+               SWI     XColourTrans_ConvertRGBToCMYK
+               LDR     ip,[sp],#4
+               STMVCIA ip,{a1-a4}
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- colourtran_convertCMYKToRGB ---
+;
+; On entry:    a1 == pointer to CIE block
+;              a2 == pointer to RGB block
+
+               EXPORT  colourtran_convertCMYKToRGB
+colourtran_convertCMYKToRGB
+               STR     a2,[sp,#-4]!
+               LDMIA   a1,{a1-a4}
+               SWI     XColourTrans_ConvertCMYKToRGB
+               LDR     ip,[sp],#4
+               STMVCIA ip,{a1-a3}
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Steel/s/coords b/StraySrc/Libraries/Steel/s/coords
new file mode 100644 (file)
index 0000000..725b4e5
--- /dev/null
@@ -0,0 +1,270 @@
+;
+; coords.s
+;
+; Messing about with lines and boxes
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+
+;----- Exported routines ----------------------------------------------------
+
+               AREA    |C$$Code|,CODE,READONLY
+
+; --- coords_x_toscreen ---
+;
+; On entry:    a1 == abscissa to convert
+;              a2 == pointer to block of window coordinates
+; On exit:     a1 == a converted abscissa
+
+               EXPORT  coords_x_toscreen
+coords_x_toscreen
+               LDR     a3,[a2,#0]              ;Get x0 from coords block
+               LDR     a4,[a2,#16]             ;Get xsc from coords block
+               SUB     a3,a3,a4                ;Get translation offset
+               ADD     a1,a1,a3                ;Convert to screen coords
+               MOVS    pc,lr                   ;Return to caller
+
+; --- coords_y_toscreen ---
+;
+; On entry:    a1 == ordinate to convert
+;              a2 == pointer to block of window coordinates
+; On exit:     a1 == a converted ordinate
+
+               EXPORT  coords_y_toscreen
+coords_y_toscreen
+               ADD     a2,a2,#12               ;Find y1
+               LDMIA   a2,{a3,a4,ip}           ;Get y1 and ysc (a4 not used)
+               SUB     a3,a3,ip                ;Get translation offset
+               ADD     a1,a1,a3                ;Convert to screen coords
+               MOVS    pc,lr                   ;Return to caller
+
+; --- coords_x_toworkarea ---
+;
+; On entry:    a1 == abscissa to convert
+;              a2 == pointer to block of window coordinates
+; On exit:     a1 == a converted abscissa
+
+               EXPORT  coords_x_toworkarea
+coords_x_toworkarea
+               LDR     a3,[a2,#0]              ;Get x0 from coords block
+               LDR     a4,[a2,#16]             ;Get xsc from coords block
+               SUB     a3,a3,a4                ;Get translation offset
+               SUB     a1,a1,a3                ;Convert to window coords
+               MOVS    pc,lr                   ;Return to caller
+
+; --- coords_y_toworkarea ---
+;
+; On entry:    a1 == ordinate to convert
+;              a2 == pointer to block of window coordinates
+; On exit:     a1 == a converted ordinate
+
+               EXPORT  coords_y_toworkarea
+coords_y_toworkarea
+               ADD     a2,a2,#12               ;Find y1
+               LDMIA   a2,{a3,a4,ip}           ;Get y1 and ysc (a4 not used)
+               SUB     a3,a3,ip                ;Get translation offset
+               SUB     a1,a1,a3                ;Convert to window coords
+               MOVS    pc,lr                   ;Return to caller
+
+; --- coords_box_toscreen ---
+;
+; On entry:    a1 == pointer to box to convert
+;              a2 == pointer to coordinates block
+
+               EXPORT  coords_box_toscreen
+coords_box_toscreen
+               STMFD   sp!,{v1,lr}
+               LDR     a3,[a2,#0]              ;Get x0 from coords block
+               ADD     a2,a2,#12               ;Point to y1
+               LDMIA   a2,{a2,a4,v1}           ;Get y1 and scroll position
+               SUB     a3,a3,a4                ;Get the x translation offset
+               SUB     a2,a2,v1                ;Get the y translation offset
+               LDMIA   a1,{a4,v1,ip,lr}
+               ADD     a4,a4,a3
+               ADD     v1,v1,a2
+               ADD     ip,ip,a3
+               ADD     lr,lr,a2
+               STMIA   a1,{a4,v1,ip,lr}
+               LDMFD   sp!,{v1,pc}^
+
+; --- coords_box_toworkarea ---
+;
+; On entry:    a1 == pointer to box to convert
+;              a2 == pointer to coordinates block
+
+               EXPORT  coords_box_toworkarea
+coords_box_toworkarea
+               STMFD   sp!,{v1,lr}
+               LDR     a3,[a2,#0]              ;Get x0 from coords block
+               ADD     a2,a2,#12               ;Point to y1
+               LDMIA   a2,{a2,a4,v1}           ;Get y1 and scroll position
+               SUB     a3,a3,a4                ;Get the x translation offset
+               SUB     a2,a2,v1                ;Get the y translation offset
+               LDMIA   a1,{a4,v1,ip,lr}
+               SUB     a4,a4,a3
+               SUB     v1,v1,a2
+               SUB     ip,ip,a3
+               SUB     lr,lr,a2
+               STMIA   a1,{a4,v1,ip,lr}
+               LDMFD   sp!,{v1,pc}^
+
+; --- coords_point_toscreen ---
+;
+; On entry:    a1 == pointer to box to convert
+;              a2 == pointer to coordinates block
+
+               EXPORT  coords_point_toscreen
+coords_point_toscreen
+               LDR     a3,[a2,#0]              ;Get x0 from coords block
+               ADD     a2,a2,#12               ;Point to y1
+               LDMIA   a2,{a2,a4,ip}           ;Get y1 and scroll position
+               SUB     a3,a3,a4                ;Get the x translation offset
+               SUB     a2,a2,ip                ;Get the y translation offset
+               LDMIA   a1,{a4,ip}
+               ADD     a4,a4,a3
+               ADD     ip,ip,a2
+               STMIA   a1,{a4,ip}
+               MOVS    pc,lr
+
+; --- coords_point_toworkarea ---
+;
+; On entry:    a1 == pointer to box to convert
+;              a2 == pointer to coordinates block
+
+               EXPORT  coords_point_toworkarea
+coords_point_toworkarea
+               LDR     a3,[a2,#0]              ;Get x0 from coords block
+               ADD     a2,a2,#12               ;Point to y1
+               LDMIA   a2,{a2,a4,ip}           ;Get y1 and scroll position
+               SUB     a3,a3,a4                ;Get the x translation offset
+               SUB     a2,a2,ip                ;Get the y translation offset
+               LDMIA   a1,{a4,ip}
+               SUB     a4,a4,a3
+               SUB     ip,ip,a2
+               STMIA   a1,{a4,ip}
+               MOVS    pc,lr
+
+; --- coords_withinbox ---
+;
+; On entry:    a1 == pointer to a silly point structure
+;              a2 == pointer to a slightly more sensible box structure
+; On exit:     a1 == 1 if the point is inside the box
+
+               EXPORT  coords_withinbox
+coords_withinbox
+               STMFD   sp!,{lr}                ;Save the link -- we need it
+               LDMIA   a1,{a3,a4}              ;Get the point coordinates
+               LDMIA   a2,{a1,a2,ip,lr}        ;Get the box coordinates
+               CMP     a1,a3                   ;The magic cascaded condition
+               CMPLE   a2,a4
+               CMPLE   a3,ip
+               CMPLE   a4,lr
+               MOVLE   a1,#1                   ;If it succeeded, return TRUE
+               MOVGT   a1,#0                   ;If not return FALSE
+               LDMFD   sp!,{pc}^
+
+; --- coords_offsetbox ---
+;
+; On entry:    a1 == pointer to input box to mangle
+;              a2 == x offset to mangle by
+;              a3 == y offset to mangle by
+;              a4 == where to put the mangled bits
+
+               EXPORT  coords_offsetbox
+coords_offsetbox
+               STMFD   sp!,{v1,lr}             ;Save some registers
+               LDMIA   a1,{a1,v1,ip,lr}        ;Get the box coordinates
+               ADD     a1,a1,a2
+               ADD     v1,v1,a3
+               ADD     ip,ip,a2
+               ADD     lr,lr,a3
+               STMIA   a4,{a1,v1,ip,lr}        ;Save the adjusted coords
+               LDMFD   sp!,{v1,pc}^
+
+; --- coords_intersects ---
+;
+; On entry:    a1 == pointer to box structure containing the line
+;              a2 == pointer to box structure containing the rectangle
+;              a3 == the `width' of the line (ho-hum)
+; On exit:     a1 == 0 if it didn't, 1 if it did
+;
+; This implementation is a really yukky hack, and doesn't test whether the
+; line intersects at all, but it's good enough for jazz...
+
+               EXPORT  coords_intersects
+coords_intersects
+               STMFD   sp!,{v1,v2,lr}          ;Save some registers
+               LDMIA   a1,{a4,v1,v2,ip}        ;Get the line coordinates
+
+               ; --- Sort coordinates properly ---
+
+               CMP     a4,v2                   ;Sort the x coordinates
+               EORGT   a4,a4,v2
+               EORGT   v2,v2,a4
+               EORGT   a4,a4,v2
+               CMP     v1,ip                   ;Sort the y coordinates
+               EORGT   v1,v1,ip
+               EORGT   ip,ip,v1
+               EORGT   v1,v1,ip
+
+               ; --- `Widen' the line ---
+
+               SUB     a4,a4,a3
+               SUB     v1,v1,a3
+               ADD     v2,v2,a3
+               ADD     ip,ip,a3
+
+               ; --- Now get the rectangle and compare ---
+
+               LDMIA   a2,{a1-a3,lr}
+               CMP     a4,a3
+               CMPLE   v1,lr
+               CMPLE   a1,v2
+               CMPLE   a2,ip
+               MOVLE   a1,#1
+               MOVGT   a1,#0
+               LDMFD   sp!,{v1,v2,pc}^
+
+; --- coords_boxesoverlap ---
+;
+; On entry:    a1,a2 == pointers to boxes
+; On exit:     a1 == 1 if boxes overlap, 0 otherwise
+
+               EXPORT  coords_boxesoverlap
+coords_boxesoverlap
+               STMFD   sp!,{v1,v2,lr}          ;Save registers
+               LDMIA   a1,{a3,a4,ip,lr}        ;Get coordinates of box 1
+               LDMIA   a2,{a1,a2,v1,v2}        ;Get coordinates of box 2
+               CMP     a3,v1                   ;Shhh.... it's a secret
+               CMPLE   a4,v2
+               CMPLE   a1,ip
+               CMPLE   a2,lr
+               MOVLE   a1,#1                   ;If intersection, return TRUE
+               MOVGT   a1,#0                   ;Otherwise return FALSE
+               LDMFD   sp!,{v1,v2,pc}^         ;Return to caller
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Steel/s/crc32 b/StraySrc/Libraries/Steel/s/crc32
new file mode 100644 (file)
index 0000000..f7b5e9a
--- /dev/null
@@ -0,0 +1,166 @@
+;
+; crc32.s
+;
+; 32-bit CRC calculation
+;
+;  © 1993-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               GET     libs:header
+               GET     libs:swis
+
+               AREA    |C$$Code|,CODE,READONLY
+
+;----- crc32 ----------------------------------------------------------------
+;
+; Calculates 32-bit Cyclic Redundancy Check values for a given chunk of
+; data.  A calculation may be performed in stages.
+;
+; The method used is the PKZip/Ethernet algorithm.  For reference, the
+; parameters to the Rocksoft^tm Model CRC Algorithm are:
+;
+; Name   : Straylight Cyclic Redundancy Check algorithm
+; Width  : 32
+; Poly   : 04C11DB7
+; Init   : FFFFFFFF
+; RefIn  : True
+; RefOut : True
+; XorOut : FFFFFFFF
+; Check  : CBF43926
+;
+; The routine is very small (and hopefully pretty quick, too).  The table
+; is rather large, though.
+;
+; The code can be called from any APCS-conformant langauge.  The C prototype
+; is
+;
+;      long crc32(     long seed,      /* R0==seed value (0 to start)  */
+;                      void *data,     /* R1==pointer to data to check */
+;                      size_t size,    /* R2==length of data           */
+;                      int diff);      /* R3==diff between check bytes */
+;
+; In normal use, the seed is 0 for the first call, and the previoud returned
+; value for subsequent calculations.
+;
+; The 'diff' value gives the difference in address between bytes to check,
+; so diff==1 means check all bytes, diff==2 means check every other byte,
+; and so on.
+;
+
+               EXPORT  crc32
+crc32          ROUT
+
+               STMFD   R13!,{R1-R4,R14}
+               MVN     R0,R0                   ;R0 = R0 XOR &FFFFFFFF!
+               ADR     R4,crctable             ;Point to my magic table
+
+00             LDRB    R14,[R1],R3             ;Get byte from stream
+               EOR     R14,R14,R0              ;XOR register with byte
+               AND     R14,R14,#&FF            ;Multiply to word, and mask
+               LDR     R14,[R4,R14,LSL #2]     ;Get word from table
+               EOR     R0,R14,R0,LSR #8        ;EOR with shifted register
+               SUBS    R2,R2,R3                ;Decrement counter
+               BGT     %b00                    ;If necessary, branch back
+               MVN     R0,R0                   ;R0 = R0 XOR &FFFFFFFF again
+               LDMFD   R13!,{R1-R4,PC}^
+
+               LTORG
+
+;----- The magic table ------------------------------------------------------
+;
+; The numbers in this table were generated using the Rocksoft^tm Model CRC
+; Algorithm Table Generation Table Program V1.0, written by Ross Williams.
+; Our thanks to him for placing this program in the public domain.
+;
+
+crctable       DCD     &00000000,&77073096,&EE0E612C,&990951BA
+               DCD     &076DC419,&706AF48F,&E963A535,&9E6495A3
+               DCD     &0EDB8832,&79DCB8A4,&E0D5E91E,&97D2D988
+               DCD     &09B64C2B,&7EB17CBD,&E7B82D07,&90BF1D91
+               DCD     &1DB71064,&6AB020F2,&F3B97148,&84BE41DE
+               DCD     &1ADAD47D,&6DDDE4EB,&F4D4B551,&83D385C7
+               DCD     &136C9856,&646BA8C0,&FD62F97A,&8A65C9EC
+               DCD     &14015C4F,&63066CD9,&FA0F3D63,&8D080DF5
+
+               DCD     &3B6E20C8,&4C69105E,&D56041E4,&A2677172
+               DCD     &3C03E4D1,&4B04D447,&D20D85FD,&A50AB56B
+               DCD     &35B5A8FA,&42B2986C,&DBBBC9D6,&ACBCF940
+               DCD     &32D86CE3,&45DF5C75,&DCD60DCF,&ABD13D59
+               DCD     &26D930AC,&51DE003A,&C8D75180,&BFD06116
+               DCD     &21B4F4B5,&56B3C423,&CFBA9599,&B8BDA50F
+               DCD     &2802B89E,&5F058808,&C60CD9B2,&B10BE924
+               DCD     &2F6F7C87,&58684C11,&C1611DAB,&B6662D3D
+
+               DCD     &76DC4190,&01DB7106,&98D220BC,&EFD5102A
+               DCD     &71B18589,&06B6B51F,&9FBFE4A5,&E8B8D433
+               DCD     &7807C9A2,&0F00F934,&9609A88E,&E10E9818
+               DCD     &7F6A0DBB,&086D3D2D,&91646C97,&E6635C01
+               DCD     &6B6B51F4,&1C6C6162,&856530D8,&F262004E
+               DCD     &6C0695ED,&1B01A57B,&8208F4C1,&F50FC457
+               DCD     &65B0D9C6,&12B7E950,&8BBEB8EA,&FCB9887C
+               DCD     &62DD1DDF,&15DA2D49,&8CD37CF3,&FBD44C65
+
+               DCD     &4DB26158,&3AB551CE,&A3BC0074,&D4BB30E2
+               DCD     &4ADFA541,&3DD895D7,&A4D1C46D,&D3D6F4FB
+               DCD     &4369E96A,&346ED9FC,&AD678846,&DA60B8D0
+               DCD     &44042D73,&33031DE5,&AA0A4C5F,&DD0D7CC9
+               DCD     &5005713C,&270241AA,&BE0B1010,&C90C2086
+               DCD     &5768B525,&206F85B3,&B966D409,&CE61E49F
+               DCD     &5EDEF90E,&29D9C998,&B0D09822,&C7D7A8B4
+               DCD     &59B33D17,&2EB40D81,&B7BD5C3B,&C0BA6CAD
+
+               DCD     &EDB88320,&9ABFB3B6,&03B6E20C,&74B1D29A
+               DCD     &EAD54739,&9DD277AF,&04DB2615,&73DC1683
+               DCD     &E3630B12,&94643B84,&0D6D6A3E,&7A6A5AA8
+               DCD     &E40ECF0B,&9309FF9D,&0A00AE27,&7D079EB1
+               DCD     &F00F9344,&8708A3D2,&1E01F268,&6906C2FE
+               DCD     &F762575D,&806567CB,&196C3671,&6E6B06E7
+               DCD     &FED41B76,&89D32BE0,&10DA7A5A,&67DD4ACC
+               DCD     &F9B9DF6F,&8EBEEFF9,&17B7BE43,&60B08ED5
+
+               DCD     &D6D6A3E8,&A1D1937E,&38D8C2C4,&4FDFF252
+               DCD     &D1BB67F1,&A6BC5767,&3FB506DD,&48B2364B
+               DCD     &D80D2BDA,&AF0A1B4C,&36034AF6,&41047A60
+               DCD     &DF60EFC3,&A867DF55,&316E8EEF,&4669BE79
+               DCD     &CB61B38C,&BC66831A,&256FD2A0,&5268E236
+               DCD     &CC0C7795,&BB0B4703,&220216B9,&5505262F
+               DCD     &C5BA3BBE,&B2BD0B28,&2BB45A92,&5CB36A04
+               DCD     &C2D7FFA7,&B5D0CF31,&2CD99E8B,&5BDEAE1D
+
+               DCD     &9B64C2B0,&EC63F226,&756AA39C,&026D930A
+               DCD     &9C0906A9,&EB0E363F,&72076785,&05005713
+               DCD     &95BF4A82,&E2B87A14,&7BB12BAE,&0CB61B38
+               DCD     &92D28E9B,&E5D5BE0D,&7CDCEFB7,&0BDBDF21
+               DCD     &86D3D2D4,&F1D4E242,&68DDB3F8,&1FDA836E
+               DCD     &81BE16CD,&F6B9265B,&6FB077E1,&18B74777
+               DCD     &88085AE6,&FF0F6A70,&66063BCA,&11010B5C
+               DCD     &8F659EFF,&F862AE69,&616BFFD3,&166CCF45
+
+               DCD     &A00AE278,&D70DD2EE,&4E048354,&3903B3C2
+               DCD     &A7672661,&D06016F7,&4969474D,&3E6E77DB
+               DCD     &AED16A4A,&D9D65ADC,&40DF0B66,&37D83BF0
+               DCD     &A9BCAE53,&DEBB9EC5,&47B2CF7F,&30B5FFE9
+               DCD     &BDBDF21C,&CABAC28A,&53B39330,&24B4A3A6
+               DCD     &BAD03605,&CDD70693,&54DE5729,&23D967BF
+               DCD     &B3667A2E,&C4614AB8,&5D681B02,&2A6F2B94
+               DCD     &B40BBE37,&C30C8EA1,&5A05DF1B,&2D02EF8D
+
+               END
diff --git a/StraySrc/Libraries/Steel/s/fastMove b/StraySrc/Libraries/Steel/s/fastMove
new file mode 100644 (file)
index 0000000..6e9b1f0
--- /dev/null
@@ -0,0 +1 @@
+               LNK     libs:s.fastMove
diff --git a/StraySrc/Libraries/Steel/s/flex_dll b/StraySrc/Libraries/Steel/s/flex_dll
new file mode 100644 (file)
index 0000000..880ba02
--- /dev/null
@@ -0,0 +1,4 @@
+               GBLL    OPT_APCS
+               GBLL    OPT_DLL
+               GBLL    OPT_DYNAREA
+               LNK     libs:s.flex
diff --git a/StraySrc/Libraries/Steel/s/flex_stat b/StraySrc/Libraries/Steel/s/flex_stat
new file mode 100644 (file)
index 0000000..2e85d5e
--- /dev/null
@@ -0,0 +1,3 @@
+               GBLL    OPT_APCS
+               GBLL    OPT_DYNAREA
+               LNK     libs:s.flex
diff --git a/StraySrc/Libraries/Steel/s/heap_dll b/StraySrc/Libraries/Steel/s/heap_dll
new file mode 100644 (file)
index 0000000..862c1a6
--- /dev/null
@@ -0,0 +1,3 @@
+               GBLL    OPT_APCS
+               GBLL    OPT_DLL
+               LNK     libs:s.heap
diff --git a/StraySrc/Libraries/Steel/s/heap_stat b/StraySrc/Libraries/Steel/s/heap_stat
new file mode 100644 (file)
index 0000000..7c4474a
--- /dev/null
@@ -0,0 +1,2 @@
+               GBLL    OPT_APCS
+               LNK     libs:s.heap
diff --git a/StraySrc/Libraries/Steel/s/os b/StraySrc/Libraries/Steel/s/os
new file mode 100644 (file)
index 0000000..9ac4c49
--- /dev/null
@@ -0,0 +1,449 @@
+;
+; os.s
+;
+; RISC OS kernel interface
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Generic SWI interface ------------------------------------------------
+
+               AREA    |C$$Code|,CODE,READONLY
+               GET     libs:s.swihack
+
+; --- os_swi ---
+;
+; On entry:    a1 == SWI number
+;              a2 == pointer to register set
+
+               EXPORT  os_swi
+
+os_swi         STMFD   R13!,{R1,R4-R10,R14}    ;Save registers
+               BIC     R10,R0,#&20000          ;Strip the X bit
+               LDMIA   R1,{R0-R9}              ;Load lots of registers
+               MOV     R14,PC                  ;Set return address
+               LDR     PC,_swihack             ;And call the hacky routine
+               LDR     R10,[R13],#4            ;Reload regset pointer
+               STMIA   R10,{R0-R9}             ;Save output registers
+               LDMFD   R13!,{R4-R10,PC}^       ;And return to caller
+
+               LTORG
+
+; --- os_swix ---
+;
+; On entry:    a1 == SWI number
+;              a2 == pointer to register set
+
+               EXPORT  os_swix
+
+os_swix                STMFD   R13!,{R1,R4-R10,R14}    ;Save registers
+               ORR     R10,R0,#&20000          ;Set the X bit
+               LDMIA   R1,{R0-R9}              ;Load lots of registers
+               MOV     R14,PC                  ;Set return address
+               LDR     PC,_swihack             ;And call the hacky routine
+               LDR     R10,[R13],#4            ;Reload regset pointer
+               STMIA   R10,{R0-R9}             ;Save output registers
+               MOVVC   R0,#0                   ;Return zero on no error
+               LDMFD   R13!,{R4-R10,PC}^       ;And return to caller
+
+               LTORG
+
+;----- Fixed-parameter non-returning SWI interfaces -------------------------
+
+; --- os_swi0, os_swi1, os_swi2, os_swi3 ---
+;
+; On entry:    a1 == SWI number
+;              a2,a3,a4 == R0,R1,R2 on entry to SWI
+; On exit:     a1 == pointer to possible error
+
+               EXPORT  os_swi0
+               EXPORT  os_swi1
+               EXPORT  os_swi2
+               EXPORT  os_swi3
+os_swi0
+os_swi1
+os_swi2
+os_swi3                STMFD   R13!,{R4-R10,R14}       ;Save registers
+               ORR     R10,R0,#&20000          ;Set the X bit
+               MOV     R0,R1
+               MOV     R1,R2
+               MOV     R2,R3
+               MOV     R14,PC                  ;Set return address
+               LDR     PC,_swihack             ;And call the hacky routine
+               MOVVC   R0,#0                   ;Return zero on no error
+               LDMFD   R13!,{R4-R10,PC}^       ;And return to caller
+
+               LTORG
+
+; --- os_swi4, os_swi5, os_swi6 ---
+;
+; On entry:    a1 == SWI number
+;              a2,a3,a4 == R0,R1,R2 on entry to SWI
+;              [sp,#0],[sp,#4],[sp,#8] == R3,R4,R5 on entry to SWI
+; On exit:     a1 == pointer to possible error
+
+               EXPORT  os_swi4
+               EXPORT  os_swi5
+               EXPORT  os_swi6
+os_swi4
+os_swi5
+os_swi6                MOV     R12,R12                 ;Remember stack position
+               STMFD   R13!,{R1,R4-R10,R14}    ;Save registers
+               ORR     R10,R0,#&20000          ;Set the X bit
+               MOV     R0,R1
+               MOV     R1,R2
+               MOV     R2,R3
+               LDMIA   R12,{R3-R5}
+               MOV     R14,PC                  ;Set return address
+               LDR     PC,_swihack             ;And call the hacky routine
+               MOVVC   R0,#0                   ;Return zero on no error
+               LDMFD   R13!,{R4-R10,PC}^       ;And return to caller
+
+               LTORG
+
+;----- Fixed-parameter, returning SWI interfaces ----------------------------
+
+; --- os__doSWI ---
+;
+; CAUTION: NOTHING LIKE APCS
+;
+; On entry:    R0-R5 == SWI registers
+;              R6-R11 == where to output registers
+;              R14 == SWI number
+;              sp points to saved R4-R11 and R14 on stack
+; On exit:     R0 == pointer to possible error
+
+os__doSWI      ROUT
+
+               STMFD   sp!,{R6-R11}            ;Save the pointers away
+               ORR     R10,R14,#&20000         ;Put in the X bit anyway
+               MOV     R14,PC
+               LDR     PC,_swihack
+               ADDVS   sp,sp,#24               ;Point back at saved regs
+               LDMVSFD sp!,{R4-R11,pc}^        ;If it failed, return now
+
+               ; --- Refind the the pointers and store ---
+
+               LDMFD   sp!,{R6-R11}            ;Get the output pointers
+               CMP     R6,#0
+               STRNE   R0,[R6]
+               CMP     R7,#0
+               STRNE   R1,[R7]
+               CMP     R8,#0
+               STRNE   R2,[R8]
+               CMP     R9,#0
+               STRNE   R3,[R9]
+               CMP     R10,#0
+               STRNE   R4,[R10]
+               CMP     R11,#0
+               STRNE   R5,[R11]
+
+               ; --- Now return to the caller ---
+
+               MOV     R0,#0                   ;There was no error
+               LDMFD   sp!,{R4-R11,pc}^        ;Return to caller
+
+               LTORG
+
+; --- os_swi1r ---
+
+               EXPORT  os_swi1r
+os_swi1r       MOV     ip,sp
+               STMFD   sp!,{R4-R11,lr}         ;We corrupt lots of registers
+
+               MOV     R14,R0
+
+               MOV     R0,R1
+
+               MOV     R6,R2
+               MOV     R7,#0
+               MOV     R8,#0
+               MOV     R9,#0
+               MOV     R10,#0
+               MOV     R11,#0
+
+               B       os__doSWI
+
+; --- os_swi2r ---
+
+               EXPORT  os_swi2r
+os_swi2r       MOV     ip,sp
+               STMFD   sp!,{R4-R11,lr}         ;We corrupt lots of registers
+
+               MOV     R14,R0
+
+               MOV     R0,R1
+               MOV     R1,R2
+
+               MOV     R6,R3
+               LDMIA   ip!,{R7}
+               MOV     R8,#0
+               MOV     R9,#0
+               MOV     R10,#0
+               MOV     R11,#0
+
+               B       os__doSWI
+
+; --- os_swi3r ---
+
+               EXPORT  os_swi3r
+os_swi3r       MOV     ip,sp
+               STMFD   sp!,{R4-R11,lr}         ;We corrupt lots of registers
+
+               MOV     R14,R0
+
+               MOV     R0,R1
+               MOV     R1,R2
+               MOV     R2,R3
+
+               LDMIA   ip!,{R6-R8}
+               MOV     R9,#0
+               MOV     R10,#0
+               MOV     R11,#0
+
+               B       os__doSWI
+
+; --- os_swi4r ---
+
+               EXPORT  os_swi4r
+os_swi4r       MOV     ip,sp
+               STMFD   sp!,{R4-R11,lr}         ;We corrupt lots of registers
+
+               MOV     R14,R0
+
+               MOV     R0,R1
+               MOV     R1,R2
+               MOV     R2,R3
+               LDMIA   ip!,{R3}
+
+               LDMIA   ip!,{R6-R9}
+               MOV     R10,#0
+               MOV     R11,#0
+
+               B       os__doSWI
+
+; --- os_swi5r ---
+
+               EXPORT  os_swi5r
+os_swi5r       MOV     ip,sp
+               STMFD   sp!,{R4-R11,lr}         ;We corrupt lots of registers
+
+               MOV     R14,R0
+
+               MOV     R0,R1
+               MOV     R1,R2
+               MOV     R2,R3
+               LDMIA   ip!,{R3,R4}
+
+               LDMIA   ip!,{R6-R10}
+               MOV     R11,#0
+
+               B       os__doSWI
+
+; --- os_swi6r ---
+
+               EXPORT  os_swi6r
+os_swi6r       MOV     ip,sp
+               STMFD   sp!,{R4-R11,lr}         ;We corrupt lots of registers
+
+               MOV     R14,R0
+
+               MOV     R0,R1
+               MOV     R1,R2
+               MOV     R2,R3
+               LDMIA   ip!,{R3-R5}
+
+               LDMIA   ip!,{R6-R11}
+
+               B       os__doSWI
+
+;----- Variable number of registers -----------------------------------------
+
+; --- os_swiv ---
+;
+; On entry:    a1 == SWI number
+;              a2... == registers
+; On exit:     a1 == pointer to possible to area
+
+               EXPORT  os_swiv
+
+os_swiv                MOV     R12,R13
+               STMFD   R13!,{R4-R10,R14}       ;Save registers
+               ORR     R10,R0,#&20000          ;Set the X bit
+               MOV     R0,R1
+               MOV     R1,R2
+               MOV     R2,R3
+               LDMIA   R12,{R3-R9}
+               MOV     R14,PC                  ;Set return address
+               LDR     PC,_swihack             ;And call the hacky routine
+               MOVVC   R0,#0                   ;Return zero on no error
+               LDMFD   R13!,{R4-R10,PC}^       ;And return to caller
+
+               LTORG
+
+; --- os_swivr ---
+;
+; On entry:    a1 == SWI number
+;              a2 == pointer to os_regset
+;              a3... == registers to pass
+; On exit:     a1 == pointer to possible error
+
+               EXPORT  os_swivr
+
+os_swivr       MOV     R12,R13
+               STMFD   R13!,{R1,R4-R10,R14}    ;Save registers
+               ORR     R10,R0,#&20000          ;Set the X bit
+               MOV     R0,R2
+               MOV     R1,R3
+               LDMIA   R12,{R2-R9}
+               MOV     R14,PC                  ;Set return address
+               LDR     PC,_swihack             ;And call the hacky routine
+               LDR     R12,[R13],#4            ;Load regset pointer
+               LDMVCIA R12,{R0-R9}             ;Save all of them away
+               MOVVC   R0,#0                   ;Return zero on no error
+               LDMFD   R13!,{R4-R10,PC}^       ;And return to caller
+
+               LTORG
+
+;----- Veneers to specific routines -----------------------------------------
+
+; --- os_byte ---
+;
+; On entry:    a1 == reason code for OS_Byte
+;              a2 == pointer to x value
+;              a3 == pointer to y value
+
+               EXPORT  os_byte
+os_byte                STMFD   sp!,{v1,v2,lr}          ;Save registers away
+               MOV     v1,a2
+               MOV     v2,a3
+               LDR     a2,[v1]
+               LDR     a3,[v2]
+               SWI     XOS_Byte
+               STRVC   a2,[v1]
+               STRVC   a3,[v2]
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,v2,pc}^
+
+; --- os_word ---
+;
+; On entry:    a1 == reason code for OS_Word
+;              a2 == pointer to parameter block
+
+               EXPORT  os_word
+os_word                SWI     XOS_Word
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- os_gbpb ---
+;
+; On entry:    a1 == pointer to `reg block'
+
+               EXPORT  os_gbpb
+os_gbpb                STMFD   sp!,{a1,v1-v6,lr}
+               LDMIA   a1,{a1-a4,v1-v6}
+               SWI     XOS_GBPB
+               LDR     lr,[sp],#4
+               STMVCIA lr,{a1-a4,v1-v6}
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1-v6,pc}^
+
+               LTORG
+
+; --- os_file ---
+;
+; On entry:    a1 == pointer to `reg block'
+
+               EXPORT  os_file
+os_file                STMFD   sp!,{a1,v1-v6,lr}
+               LDMIA   a1,{a1-a4,v1-v6}
+               SWI     XOS_File
+               LDR     lr,[sp],#4
+               STMVCIA lr,{a1-a4,v1-v6}
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1-v6,pc}^
+
+               LTORG
+
+; --- os_args ---
+;
+; On entry:    a1 == pointer to a real reg block
+
+               EXPORT  os_args
+os_args                STMFD   sp!,{a1,v1-v6,lr}
+               LDMIA   a1,{a1-a4,v1-v6}
+               SWI     XOS_Args
+               LDR     lr,[sp],#4
+               STMVCIA lr,{a1-a4,v1-v6}
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1-v6,pc}^
+
+               LTORG
+
+; --- os_find ---
+;
+; On entry:    a1 == pointer to a real reg block
+
+               EXPORT  os_find
+os_find                STMFD   sp!,{a1,v1-v6,lr}
+               LDMIA   a1,{a1-a4,v1-v6}
+               SWI     XOS_Find
+               LDR     lr,[sp],#4
+               STMVCIA lr,{a1-a4,v1-v6}
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1-v6,pc}^
+
+               LTORG
+
+; --- os_cli ---
+;
+; On entry:    a1 == pointer to command string
+
+               EXPORT  os_cli
+os_cli         SWI     XOS_CLI
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- os_read_var_val ---
+;
+; On entry:    a1 == pointer to variable name
+;              a2 == pointer to buffer to store the value
+;              a3 == size of the buffer
+
+               EXPORT  os_read_var_val
+os_read_var_val        STMFD   sp!,{v1,lr}
+               MOV     a4,#0
+               MOV     v1,#3
+               SWI     XOS_ReadVarVal
+               MOV     v1,#0
+               MOVVS   a3,#0
+               STRB    v1,[a2,a3]
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,pc}^
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Steel/s/sculptrix b/StraySrc/Libraries/Steel/s/sculptrix
new file mode 100644 (file)
index 0000000..5003629
--- /dev/null
@@ -0,0 +1,112 @@
+;
+; sculptrix.s
+;
+; Interface to Sculptrix SWIs
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               GET     libs:header
+               GET     libs:swis
+
+               AREA    |C$$Code|,CODE,READONLY
+
+               IMPORT  visdelay_suspend
+               IMPORT  visdelay_resume
+
+               EXPORT  sculptrix_redrawWindow
+sculptrix_redrawWindow
+               MOV     a2,a1
+               SWI     XSculptrix_RedrawWindow
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+               EXPORT  sculptrix_doSlab
+sculptrix_doSlab
+               SWI     XSculptrix_DoSlab
+               MOVVSS  pc,lr
+               CMP     a4,#0
+               STRNE   a3,[a4]
+               MOV     a1,#0
+               MOVS    pc,lr
+
+               EXPORT  sculptrix_slabIcon
+sculptrix_slabIcon
+               SWI     XSculptrix_SlabIcon
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+               EXPORT  sculptrix_unslabIcon
+sculptrix_unslabIcon
+               MOV     ip,sp
+               STMFD   sp!,{v1,fp,ip,lr,pc}
+               SUB     fp,ip,#4
+
+               SUB     sp,sp,#8
+               MOV     v1,a1
+               MOV     a1,sp
+               BL      visdelay_suspend
+               MOV     a3,v1
+               SWI     XSculptrix_UnslabIcon
+               MOVVC   v1,#0
+               MOVVS   v1,a1
+               LDMIA   sp!,{a1,a2}
+               BL      visdelay_resume
+               MOV     a1,v1
+               LDMDB   fp,{v1,fp,sp,pc}^
+
+               EXPORT  sculptrix_boundingBox
+sculptrix_boundingBox
+               MOV     a2,a1
+               SWI     XSculptrix_BoundingBox
+               MOVS    pc,lr
+
+               EXPORT  sculptrix_plotIcon
+sculptrix_plotIcon
+               SWI     XSculptrix_PlotIcon
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+               EXPORT  sculptrix_plotGroupBox
+sculptrix_plotGroupBox
+               SWI     XSculptrix_PlotGroupBox
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+               EXPORT  sculptrix_setSpriteArea
+sculptrix_setSpriteArea
+               SWI     XSculptrix_SetSpriteArea
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+               EXPORT  sculptrix_updateIcon
+sculptrix_updateIcon
+               SWI     XSculptrix_UpdateIcon
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+               EXPORT  sculptrix_slabColour
+sculptrix_slabColour
+               SWI     XSculptrix_SlabColour
+               MOV     a1,a3
+               MOVS    pc,lr
+
+               END
diff --git a/StraySrc/Libraries/Steel/s/wimpExt b/StraySrc/Libraries/Steel/s/wimpExt
new file mode 100644 (file)
index 0000000..c1bdbbe
--- /dev/null
@@ -0,0 +1,203 @@
+;
+; WimpExt.s
+;
+;  WimpExtension I interface
+;
+; © 1993-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Notes ----------------------------------------------------------------
+;
+; Not all of the calls are done yet (understatement of the year!).  I won't
+; bother with all of them until WimpExtension II is done.  It just isn't
+; worth the bother, because most of the others are doable using standard
+; RISC_OSlib or Steel features anyway.
+;
+;                                                      Straylight
+;
+
+;----- SWI names and numbers ------------------------------------------------
+
+XWimpExt_Initialise            EQU     &65780
+XWimpExt_CloseDown             EQU     &65781
+XWimpExt_SlabIcon              EQU     &65782
+XWimpExt_Redraw                        EQU     &65783
+XWimpExt_Action                        EQU     &65784
+XWimpExt_IconBarSprite         EQU     &65785
+XWimpExt_IconBarText           EQU     &65786
+XWimpExt_LinkWindows           EQU     &65787
+XWimpExt_OpenLinked            EQU     &65788
+XWimpExt_CloseLinked           EQU     &65789
+XWimpExt_UnLinkWindows         EQU     &6578A
+XWimpExt_CurrentTask           EQU     &6578B
+XWimpExt_LoadTemplates         EQU     &6578C
+XWimpExt_SetIconString         EQU     &6578D
+XWimpExt_OpenWindowTop         EQU     &6578E
+XWimpExt_SetIcon               EQU     &6578F
+XWimpExt_GetIcon               EQU     &65790
+XWimpExt_GetNumberIcon         EQU     &65791
+XWimpExt_SetNumberIcon         EQU     &65792
+XWimpExt_IncNumberIcon         EQU     &65793
+XWimpExt_DecNumberIcon         EQU     &65794
+XWimpExt_SetPointer            EQU     &65795
+XWimpExt_Divide                        EQU     &65796
+XWimpExt_ColoursMenu           EQU     &65797
+XWimpExt_AutoRedraw            EQU     &65798
+XWimpExt_CentreWindow          EQU     &65799
+XWimpExt_DragIcon              EQU     &6579A
+XWimpExt_PutCaretIcon          EQU     &6579B
+XWimpExt_OpenDialogue          EQU     &6579C
+XWimpExt_CheckWindowOpen       EQU     &6579D
+XWimpExt_CopyString            EQU     &6579E
+XWimpExt_SetWindowTitle                EQU     &6579F
+XWimpExt_SetIconStringN                EQU     &657A0
+XWimpExt_FindLeaf              EQU     &657A1
+XWimpExt_LimitPointer          EQU     &657A2
+XWimpExt_ReleasePointer                EQU     &657A3
+XWimpExt_OpenFullSize          EQU     &657A4
+XWimpExt_LoadRAMTemplate       EQU     &657A5
+XWimpExt_OpenRequester         EQU     &657A6
+XWimpExt_CloseRequester                EQU     &657A7
+XWimpExt_HideLink              EQU     &657A8
+XWimpExt_UnHideLink            EQU     &657A9
+XWimpExt_SendHelp              EQU     &657AA
+XWimpExt_SendWimpHelp          EQU     &657AB
+XWimpExt_CreateMenu            EQU     &657AC
+XWimpExt_ReCreateMenu          EQU     &657AD
+XWimpExt_ShadeEntry            EQU     &657AE
+XWimpExt_TickEntry             EQU     &657AF
+XWimpExt_SetIconColour         EQU     &657B0
+XWimpExt_ShadeIcon             EQU     &657B1
+XWimpExt_PlotSprite            EQU     &657B2
+XWimpExt_RedrawDraw            EQU     &657B3
+XWimpExt_PrePoll               EQU     &657B4
+XWimpExt_SetExtent             EQU     &657B5
+XWimpExt_MoveCaret             EQU     &657B6
+XWimpExt_GetFontMenu           EQU     &657B7
+XWimpExt_DecodeFontMenu                EQU     &657B8
+XWimpExt_ControlImmediate      EQU     &657B9
+XWimpExt_Heap                  EQU     &657BA
+XWimpExt_MemCopy               EQU     &657BB
+XWimpExt_DataSave              EQU     &657BC
+XWimpExt_PlotBorder            EQU     &657BD
+XWimpExt_CentreWindowV         EQU     &657BE
+XWimpExt_Sort                  EQU     &66380
+XWimpExt_MemMove               EQU     &66381
+XWimpExt_MenuWidth             EQU     &66382
+XWimpExt_DataLoad              EQU     &66383
+XWimpExt_MoveCaretIcon         EQU     &66384
+XWimpExt_DrawOp                        EQU     &66385
+XWimpExt_SpriteOp              EQU     &66386
+XWimpExt_Intersect             EQU     &66387
+XWimpExt_BorderOp              EQU     &66388
+XWimpExt_ManualLink            EQU     &66389
+XWimpExt_MiscOp                        EQU     &6638A
+XWimpExt_ViewIcon              EQU     &6638B
+XWimpExt_SubstituteArgs                EQU     &6638C
+XWimpExt_CreateDraw            EQU     &6638D
+XWimpExt_RedirectSprites       EQU     &6638E
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  |x$stack_overflow|
+               IMPORT  wimpt_task
+               IMPORT  atexit
+
+;----- Constants and macros -------------------------------------------------
+
+wimpExt__ver   EQU     16                      ;WimpExt version for Steel
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |C$$Code|,CODE,READONLY
+
+               EXPORT  wimpExt_initialise
+
+wimpExt_initialise
+               MOV     ip,sp
+               STMFD   sp!,{v1,fp,ip,lr,pc}
+               SUB     fp,ip,#4
+               CMP     sp,sl
+               BLLT    |x$stack_overflow|
+               MOV     v1,a1                   ;Keep hold of flags word
+               BL      wimpt_task              ;Get the task handle
+               MOV     R2,v1                   ;Get features word back
+               MOV     R1,a1                   ;Get task handle again
+               MOV     R0,#wimpExt__ver        ;Latest version I know of
+               SWI     XWimpExt_Initialise     ;Initialise the module
+               LDMVSDB fp,{v1,fp,sp,pc}^       ;If there's an error, leave
+               ADR     a1,wimpExt_quit         ;Point to closedown routine
+               BL      atexit                  ;Shut down the module nicely
+               MOV     a1,#0                   ;The SWI worked -- no error
+               LDMDB   fp,{v1,fp,sp,pc}^       ;Return to sender...
+
+wimpExt_quit   MOV     ip,sp
+               STMFD   sp!,{fp,ip,lr,pc}
+               SUB     fp,ip,#4
+               CMP     sp,sl
+               BLLT    |x$stack_overflow|
+               BL      wimpt_task              ;Get the task handle
+               SWI     XWimpExt_CloseDown      ;Inform WimpExt we're dead
+               MOVVC   R0,#0                   ;If no error, return NULL
+               LDMDB   fp,{v1,fp,sp,pc}^       ;Return to sender...
+
+               EXPORT  wimpExt_slabIcon
+
+wimpExt_slabIcon
+               STMFD   sp!,{v1}                ;We're going to corrupt this
+               MOV     R4,a3                   ;To slab or not to slab...
+               MOV     R3,a2                   ;Icon to slab or unslab
+               MOV     R2,a1                   ;Window handle of icon
+               SWI     XWimpExt_SlabIcon       ;Do the job
+               MOVVC   a1,#0                   ;If no error, return NULL
+               LDMFD   sp!,{v1}
+               MOVS    pc,lr
+
+               EXPORT  wimpExt_redraw
+
+wimpExt_redraw
+               MOV     R1,a1                   ;Point to redraw block
+               SWI     XWimpExt_Redraw         ;Redraw the icons
+               MOVVC   a1,#0                   ;If no error, return NULL
+               MOVS    pc,lr
+
+               EXPORT  wimpExt_action
+
+wimpExt_action
+               MOV     ip,sp
+               STMFD   sp!,{v1,fp,ip,lr,pc}
+               SUB     fp,ip,#4
+               CMP     sp,sl
+               BLLT    |x$stack_overflow|
+               MOV     v1,a1                   ;Remember wimp_eventstr ptr
+               BL      wimpt_task              ;Get my task handle
+               LDR     R2,[v1]                 ;Get the reason code out
+               ADD     R1,v1,#4                ;Point to main block
+               SWI     XWimpExt_Action         ;Do the job
+               LDMVSDB fp,{v1,fp,sp,pc}^       ;Quit now if it failed
+               STR     R0,[v1]                 ;Store (altered) reason code
+               MOV     a1,#0                   ;SWI was successful
+               LDMDB   fp,{v1,fp,sp,pc}^       ;Return to caller
+
+               EXPORT  wimpExt_iconBarSprite
+
+wimpExt_iconBarSprite
+               
\ No newline at end of file
diff --git a/StraySrc/Libraries/Steel/s/wimp_dll b/StraySrc/Libraries/Steel/s/wimp_dll
new file mode 100644 (file)
index 0000000..56bf45d
--- /dev/null
@@ -0,0 +1,148 @@
+;
+; wimp_dll.s
+;
+; Special DLL parts of wimp
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:SWIs
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  |_dll_wimpPoll|
+               IMPORT  |_dll_wimpPollIdle|
+
+;----- Some flags and things -----------------------------------------------
+
+dpoll__savefp  EQU     1<<24                   ;Bit to set to save FP state
+
+;----- Private data ---------------------------------------------------------
+
+               AREA    |C$$data|,DATA
+
+wimp__savefp   DCD     1
+
+;----- Polling code ---------------------------------------------------------
+
+               AREA    |C$$Code|,CODE,READONLY
+
+; --- wimp_poll ---
+;
+; On entry:    a1 == Wimp_Poll event mask
+;              a2 == pointer to wimp_eventstr to be filled in
+; On exit:     a1 == pointer to an os_error, or nothing
+
+               EXPORT  wimp_poll
+wimp_poll      ROUT
+
+               STMFD   sp!,{lr}                ;Look after some registers
+
+               ; --- Figure out about saving the FP status ---
+
+               LDR     a4,=wimp__savefp        ;Find the magic flag
+               LDR     ip,[sl,#-536]           ;Get the relocation
+               ADD     a4,ip,a4                ;And relocate this address
+               LDR     a4,[a4]                 ;Get the value of the flag
+               CMP     a4,#0                   ;Do we have to save FP state?
+               ORRNE   a1,a1,#dpoll__savefp    ;Yes -- set the flag
+               BICNE   a1,a1,#dpoll__savefp    ;No -- clear the flag
+
+               ; --- Call the SWI and get out again ---
+
+               ADD     a2,a2,#4                ;Point to the big poll block
+               BL      |_dll_wimpPoll|         ;Get a Wimp event
+               SUB     a2,a2,#4                ;Point to the wimp_eventstr
+               STRVC   a1,[a2]                 ;Store the reason code away
+               MOVVC   a1,#0                   ;If no error, return NULL
+               LDMFD   sp!,{pc}^               ;Return to caller nicely
+
+               LTORG
+
+; --- wimp_pollidle ---
+;
+; On entry:    a1 == Wimp_Poll event mask
+;              a2 == pointer to wimp_eventstr to be filled in
+;              a3 == time before which thou shalt not return
+; On exit:     a1 == pointer to an os_error, or nothing
+
+               EXPORT  wimp_pollidle
+wimp_pollidle  ROUT
+
+               STMFD   sp!,{lr}                ;Look after some registers
+
+               ; --- Figure out about saving the FP status ---
+
+               LDR     a4,=wimp__savefp        ;Find the magic flag
+               LDR     ip,[sl,#-536]           ;Get the relocation
+               ADD     a4,ip,a4                ;And relocate this address
+               LDR     a4,[a4]                 ;Get the value of the flag
+               CMP     a4,#0                   ;Do we have to save FP state?
+               ORRNE   a1,a1,#dpoll__savefp    ;Yes -- set the flag
+               BICNE   a1,a1,#dpoll__savefp    ;No -- clear the flag
+
+               ; --- Call the SWI and get out again ---
+
+               ADD     a2,a2,#4                ;Point to the big poll block
+               BL      |_dll_wimpPollIdle|     ;Get a Wimp event
+               SUB     a2,a2,#4                ;Point to the wimp_eventstr
+               STRVC   a1,[a2]                 ;Store the reason code away
+               MOVVC   a1,#0                   ;If no error, return NULL
+               LDMFD   sp!,{pc}^               ;Return to caller nicely
+
+               LTORG
+
+; --- wimp_save_fp_state_on_poll ---
+
+               EXPORT  wimp_save_fp_state_on_poll
+wimp_save_fp_state_on_poll
+               ROUT
+
+               LDR     a1,=wimp__savefp        ;Find the magic flag
+               LDR     ip,[sl,#-536]           ;Get the relocation
+               ADD     a1,ip,a1                ;And relocate this address
+               MOV     a2,#1                   ;Store a TRUE value away
+               STR     a2,[a1]                 ;Tuck it into my workspace
+               MOVS    pc,lr                   ;Return to the caller
+
+               LTORG
+
+; --- wimp_corrupt_fp_state_on_poll ---
+
+               EXPORT  wimp_corrupt_fp_state_on_poll
+wimp_corrupt_fp_state_on_poll
+               ROUT
+
+               LDR     a1,=wimp__savefp        ;Find the magic flag
+               LDR     ip,[sl,#-536]           ;Get the relocation
+               ADD     a1,ip,a1                ;And relocate this address
+               MOV     a2,#0                   ;Store a FALSE value away
+               STR     a2,[a1]                 ;Tuck it into my workspace
+               MOVS    pc,lr                   ;Return to the caller
+
+               LTORG
+
+;----- Include the main wimp veneers ----------------------------------------
+
+               LNK     s.wimp_main
diff --git a/StraySrc/Libraries/Steel/s/wimp_main b/StraySrc/Libraries/Steel/s/wimp_main
new file mode 100644 (file)
index 0000000..19f10ce
--- /dev/null
@@ -0,0 +1,818 @@
+;
+; wimp_main.s
+;
+; APCS interface to WIMP SWIs
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Initialising the WIMP ------------------------------------------------
+
+; --- wimp_initialise ---
+;
+; On entry:    a1 == pointer to where to put the version number
+
+               EXPORT  wimp_initialise
+wimp_initialise        STMFD   sp!,{lr}                ;Save the link register
+               MOV     ip,a1                   ;Save this away for a bit
+               MOV     a1,#120                 ;Make sure it's Arthur :-)
+               MOV     a2,#0                   ;Don't start a WIMP task
+               SWI     XWimp_Initialise        ;Start up the WIMP
+               STRVC   a1,[ip]                 ;Store the version number
+               MOVVC   a1,#0                   ;If no error, return no error
+               LDMFD   sp!,{pc}^               ;Return to caller
+
+; --- wimp_taskinit ---
+;
+; On entry:    a1 == pointer to name of task
+;              a2 == pointer to version number (to be updated)
+;              a3 == pointer to task handle to set
+;              a4 == optional pointer to messages block
+
+               EXPORT  wimp_taskinit
+wimp_taskinit  STMFD   sp!,{a2,a3,lr}          ;Stash lots of registers
+               MOV     a3,a1                   ;Point to the task name
+               LDR     a1,[a2]                 ;Get the version number
+               LDR     a2,wimp__magic          ;Load the strange magic value
+               SWI     XWimp_Initialise        ;Initialise the WIMP
+               LDMIA   sp!,{a3,a4,lr}          ;Get the pointers back
+               STRVC   a1,[a3]                 ;Store the version number
+               STRVC   a2,[a4]                 ;Store the task handle too
+               MOVVC   a1,#0                   ;If no error, clear return
+               MOVS    pc,lr                   ;Return to caller
+
+wimp__magic    DCB     "TASK"                  ;The magic value for initing
+
+;----- Closing the WIMP down again ------------------------------------------
+
+; --- wimp_closedown ---
+;
+; On entry:    --
+
+               EXPORT  wimp_closedown
+wimp_closedown SWI     XWimp_CloseDown         ;Close down the WIMP
+               MOVVC   a1,#0                   ;If no error, return clear
+               MOVS    pc,lr                   ;Return to caller
+
+; --- wimp_taskclose ---
+;
+; On entry:    a1 == my task handle to use
+
+               EXPORT  wimp_taskclose
+wimp_taskclose LDR     a2,wimp__magic          ;Get the magic number again
+               SWI     XWimp_CloseDown         ;Close down my task only
+               MOVVC   a1,#0                   ;Clear error if it worked
+               MOVS    pc,lr                   ;Return to caller
+
+;----- Everything else :-) --------------------------------------------------
+
+; --- wimp_create_wind ---
+;
+; On entry:    a1 == pointer to window definition
+;              a2 == pointer to window handle to fill in
+
+               EXPORT  wimp_create_wind
+wimp_create_wind
+               MOV     a4,a2                   ;Keep pointer to handle too
+               MOV     a2,a1                   ;Point to window definition
+               SWI     XWimp_CreateWindow      ;Create the new window
+               STRVC   a1,[a4]                 ;Store the handle away
+               MOVVC   a1,#0                   ;And clear the error code
+               MOVS    pc,lr                   ;Return to caller
+
+; --- wimp_create_icon ---
+;
+; On entry:    a1 == pointer to icon creation block
+;              a2 == pointer to icon handle to fill in
+
+               EXPORT  wimp_create_icon
+wimp_create_icon
+               MOV     a4,a2                   ;Keep pointer to icon handle
+               MOV     a2,a1                   ;Point to the icon block
+               SWI     XWimp_CreateIcon        ;Create the icon now
+               STRVC   a1,[a4]                 ;Store the icon handle away
+               MOVVC   a1,#0                   ;Clear any error code
+               MOVS    pc,lr                   ;Return to caller
+
+; --- wimp_delete_wind ---
+;
+; On entry:    a1 == window handle
+
+               EXPORT  wimp_delete_wind
+wimp_delete_wind
+               STMFD   sp!,{a1}                ;Store window handle on stack
+               MOV     a2,sp                   ;Point to saved handle
+               SWI     XWimp_DeleteWindow      ;Delete the window
+               MOVVC   a1,#0                   ;Return no error if success
+               ADD     sp,sp,#4                ;Restore stack pointer
+               MOVS    pc,lr                   ;Return to caller
+
+; --- wimp_delete_icon ---
+;
+; On entry:    a1 == window handle
+;              a2 == icon handle
+
+               EXPORT  wimp_delete_icon
+wimp_delete_icon
+               STMFD   sp!,{a1,a2}             ;Stack registers for block
+               MOV     a2,sp                   ;Point to the block
+               SWI     XWimp_DeleteIcon        ;Do the SWI
+               MOVVC   a1,#0                   ;Clear the error indicator
+               ADD     sp,sp,#8                ;Restore stack pointer
+               MOVS    pc,lr                   ;Return to caller
+
+; --- wimp_open_wind ---
+;
+; On entry:    a1 == pointer to window block
+
+               EXPORT  wimp_open_wind
+wimp_open_wind MOV     a2,a1                   ;Point to window block
+               SWI     XWimp_OpenWindow        ;Do the SWI
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_close_wind ---
+;
+; On entry:    a1 == window handle
+
+               EXPORT  wimp_close_wind
+wimp_close_wind        STMFD   sp!,{a1}                ;Store window handle away
+               MOV     a2,sp                   ;Point to the `block'
+               SWI     XWimp_CloseWindow       ;Close the window
+               MOVVC   a1,#0
+               ADD     sp,sp,#4                ;Restore the stack
+               MOVS    pc,lr
+
+; --- wimp_redraw_wind ---
+;
+; On entry:    a1 == pointer to a redraw structure to fill in
+;              a2 == pointer to a `more' variable to fill in
+
+               EXPORT  wimp_redraw_wind
+wimp_redraw_wind
+               MOV     a3,a2                   ;Keep this pointer safe
+               MOV     a2,a1                   ;Point to redraw structure
+               SWI     XWimp_RedrawWindow      ;Do the redraw window call
+               STRVC   a1,[a3]                 ;Store the `more' variable
+               MOVVC   a1,#0
+               MOVS    pc,lr                   ;Return to caller
+
+; --- wimp_update_wind ---
+;
+; On entry:    a1 == pointer to a redraw structure to fill in
+;              a2 == pointer to a `more' variable to fill in
+
+               EXPORT  wimp_update_wind
+wimp_update_wind
+               MOV     a3,a2                   ;Keep this pointer safe
+               MOV     a2,a1                   ;Point to redraw structure
+               SWI     XWimp_UpdateWindow      ;Do the update window call
+               STRVC   a1,[a3]                 ;Store the `more' variable
+               MOVVC   a1,#0
+               MOVS    pc,lr                   ;Return to caller
+
+; --- wimp_get_rectangle ---
+;
+; On entry:    a1 == pointer to a redraw structure to fill in
+;              a2 == pointer to a `more' variable to fill in
+
+               EXPORT  wimp_get_rectangle
+wimp_get_rectangle
+               MOV     a3,a2                   ;Keep this pointer safe
+               MOV     a2,a1                   ;Point to redraw structure
+               SWI     XWimp_GetRectangle      ;Get the next rectangle
+               STRVC   a1,[a3]                 ;Store the `more' variable
+               MOVVC   a1,#0
+               MOVS    pc,lr                   ;Return to caller
+
+; --- wimp_get_wind_state ---
+;
+; On entry:    a1 == window handle
+;              a2 == pointer to block to fill in
+
+               EXPORT  wimp_get_wind_state
+wimp_get_wind_state
+               STR     a1,[a2,#0]              ;Fill in the window handle
+               SWI     XWimp_GetWindowState
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_get_wind_info ---
+;
+; On entry:    a1 == pointer to block to fill in
+
+               EXPORT  wimp_get_wind_info
+wimp_get_wind_info
+               MOV     a2,a1
+               SWI     XWimp_GetWindowInfo
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_set_icon_state ---
+;
+; On entry:    a1 == window handle
+;              a2 == icon handle
+;              a3 == EOR mask
+;              a4 == BIC mask
+
+               EXPORT  wimp_set_icon_state
+wimp_set_icon_state
+               STMFD   sp!,{a1-a4}
+               MOV     a2,sp
+               SWI     XWimp_SetIconState
+               ADD     sp,sp,#16
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_get_icon_info ---
+;
+; On entry:    a1 == window handle
+;              a2 == icon handle
+;              a3 == pointer to structure to fill in
+
+               EXPORT  wimp_get_icon_info
+wimp_get_icon_info
+               SUB     sp,sp,#40               ;Make space for icon block
+               STMIA   sp,{a1,a2}              ;Fill in the handles nicely
+               MOV     a2,sp                   ;Point to the block
+               SWI     XWimp_GetIconState      ;Get information about icon
+               ADDVS   sp,sp,#40               ;If it failed, restore stack
+               MOVVSS  pc,lr                   ;And return to caller
+               ADD     sp,sp,#8                ;Point to icon info
+               LDMIA   sp!,{a1,a2,a4,ip}       ;Get some of the data
+               STMIA   a3!,{a1,a2,a4,ip}       ;Store in the caller's buffer
+               LDMIA   sp!,{a1,a2,a4,ip}       ;Get the rest of the icon
+               STMIA   a3!,{a1,a2,a4,ip}       ;And store that away too
+               MOV     a1,#0                   ;Nothing went wrong
+               MOVS    pc,lr                   ;Return to caller
+
+; --- wimp_get_point_info ---
+;
+; On entry:    a1 == pointer to block to fill in
+
+               EXPORT  wimp_get_point_info
+wimp_get_point_info
+               MOV     a2,a1                   ;Point to the block
+               SWI     XWimp_GetPointerInfo    ;Get the mouse information
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_drag_box ---
+;
+; On entry:    a1 == pointer to a drag structure
+
+               EXPORT  wimp_drag_box
+wimp_drag_box  MOV     a2,a1                   ;Point to the block
+               SWI     XWimp_DragBox           ;Perform the drag
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_force_redraw ---
+;
+; On entry:    a1 == pointer to a redraw block
+
+               EXPORT  wimp_force_redraw
+wimp_force_redraw
+               STMFD   sp!,{v1,lr}             ;Store v1 away nicely
+               LDMIA   a1,{a1-a4,v1}           ;Get registers from the block
+               SWI     XWimp_ForceRedraw
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,pc}^
+
+; --- wimp_set_caret_pos ---
+;
+; On entry:    a1 == pointer to a caret structure to set
+
+               EXPORT  wimp_set_caret_pos
+wimp_set_caret_pos
+               STMFD   sp!,{v1,v2,lr}          ;Store v1 and v2 away nicely
+               LDMIA   a1,{a1-a4,v1,v2}
+               SWI     XWimp_SetCaretPosition
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,v2,pc}^
+
+; --- wimp_get_caret_pos ---
+;
+; On entry:    a1 == pointer to caret structure to fill in
+
+               EXPORT  wimp_get_caret_pos
+wimp_get_caret_pos
+               MOV     a2,a1
+               SWI     XWimp_GetCaretPosition
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_create_menu ---
+;
+; On entry:    a1 == pointer to menu
+;              a2 == x coordinate to open menu
+;              a3 == y coordinate to open menu
+
+               EXPORT  wimp_create_menu
+wimp_create_menu
+               MOV     a4,a3
+               MOV     a3,a2
+               MOV     a2,a1
+               SWI     XWimp_CreateMenu
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_decode_menu ---
+;
+; On entry:    a1 == pointer to menu
+;              a2 == pointer to menu hit array
+;              a3 == pointer to buffer for string
+
+               EXPORT  wimp_decode_menu
+wimp_decode_menu
+               MOV     a4,a3
+               MOV     a3,a2
+               MOV     a2,a1
+               SWI     XWimp_DecodeMenu
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_which_icon ---
+;
+; On entry:    a1 == pointer to strange which block thing
+;              a2 == pointer to where to store the results
+
+               EXPORT  wimp_which_icon
+wimp_which_icon        LDMIA   a1,{a1,a3,a4}           ;Get arguments from block
+               SWI     XWimp_WhichIcon
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_set_extent ---
+;
+; On entry:    a1 == pointer to strange block with window handle
+
+               EXPORT  wimp_set_extent
+wimp_set_extent        ADD     a2,a1,#4                ;Point to extent block
+               LDR     a1,[a1]                 ;Get the window handle
+               SWI     XWimp_SetExtent
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_set_point_shape ---
+;
+; On entry:    a1 == pointer to a freaky pointer shape structure
+
+               EXPORT  wimp_set_point_shape
+wimp_set_point_shape
+               STMFD   sp!,{v1,v2,lr}
+               LDMIA   a1,{a1-a4,v1,v2}
+               SWI     XWimp_SetPointerShape
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,v2,pc}^
+
+; --- wimp_open_template ---
+;
+; On entry:    a1 == pointer to name of template file
+
+               EXPORT  wimp_open_template
+wimp_open_template
+               MOV     a2,a1
+               SWI     XWimp_OpenTemplate
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_close_template ---
+;
+; On entry:    --
+
+               EXPORT  wimp_close_template
+wimp_close_template
+               SWI     XWimp_CloseTemplate
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_load_template ---
+;
+; On entry:    a1 == pointer to a template structure
+
+               EXPORT  wimp_load_template
+wimp_load_template
+               MOV     ip,a1                   ;Keep the pointer safe
+               STMFD   sp!,{v1-v3,lr}          ;Save lots of registers
+               LDMIA   ip,{a1-a4,v1-v3}        ;Get all the arguments
+               CMP     v1,#0                   ;If no font array specified
+               MOVEQ   v1,#-1                  ;Pass the *correct* value
+               SWI     XWimp_LoadTemplate      ;Load the template
+               STMVCIA ip,{a1-a4,v1-v3}        ;Store the information back
+               MOVVC   a1,#0                   ;Clear error indicator
+               LDMFD   sp!,{v1-v3,pc}^         ;Return to caller
+
+; --- wimp_processkey ---
+;
+; On entry:    a1 == key to process
+
+               EXPORT  wimp_processkey
+wimp_processkey        SWI     XWimp_ProcessKey
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_starttask ---
+;
+; On entry:    a1 == pointer to command to execute
+
+               EXPORT  wimp_starttask
+wimp_starttask SWI     XWimp_StartTask
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_reporterror ---
+;
+; On entry:    a1 == pointer to error block
+;              a2 == Wimp_ReportError flags word
+;              a3 == pointer to application name
+
+               EXPORT  wimp_reporterror
+wimp_reporterror
+               SWI     XWimp_ReportError
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_getwindowoutline ---
+;
+; On entry:    a1 == pointer to a block to fill in
+
+               EXPORT  wimp_getwindowoutline
+wimp_getwindowoutline
+               MOV     a2,a1
+               SWI     XWimp_GetWindowOutline
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_ploticon ---
+;
+; On entry:    a1 == pointer to icon to plot
+
+               EXPORT  wimp_ploticon
+wimp_ploticon  MOV     a2,a1
+               SWI     XWimp_PlotIcon
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_setmode ---
+;
+; On entry:    a1 == new mode to set
+
+               EXPORT  wimp_setmode
+wimp_setmode   SWI     XWimp_SetMode
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_setpalette ---
+;
+; On entry:    a1 == pointer to palette to set
+
+               EXPORT  wimp_setpalette
+wimp_setpalette        MOV     a2,a1
+               SWI     XWimp_SetPalette
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_readpalette ---
+;
+; On entry:    a1 == pointer to palette block to fill in
+
+               EXPORT  wimp_readpalette
+wimp_readpalette
+               MOV     a2,a1
+               SWI     XWimp_ReadPalette
+               MOVVSS  pc,lr
+
+               ; --- It seems we must mangle the colours now ---
+               ;
+               ; Since Wimp_ReadPalette leaves the bottom nibbles clear for
+               ; no sensible reason, and RISC_OSLib's wimp.c bodges the
+               ; palette to try and make it sensible, we must do the same
+               ; here, being careful to preserve the GCOL numbers at the
+               ; bottom of the palette words.
+
+               MOV     a1,#20                  ;Do this once for each entry
+               LDR     a4,=&F0F0F000           ;Mask for copying nibbles
+00             LDR     a3,[a2]                 ;Get the next palette word
+               AND     ip,a3,a4                ;Get the top nibbles
+               BIC     a3,a3,a4,LSR #4         ;Clear the bottom nibbles
+               ORR     a3,a3,ip,LSR #4         ;Shift down to copy nibbles
+               STR     a3,[a2],#4              ;Store and bump a2 along
+               SUBS    a1,a1,#1                ;Done another one
+               BNE     %b00                    ;If there's any more, loop
+
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_setcolour ---
+;
+; On entry:    a1 == colour to set
+
+               EXPORT  wimp_setcolour
+wimp_setcolour SWI     XWimp_SetColour
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_sendmessage ---
+;
+; On entry:    a1 == the event type of the message
+;              a2 == pointer to the message to send
+;              a3 == the task handle of the recipient
+
+; --- wimp_sendwmessage ---
+;
+; On entry:    a1 == the event type again
+;              a2 == pointer to the message to send
+;              a3 == the window handle of the recipient
+;              a4 == the icon handle of the recipient
+
+; --- Note ---
+;
+; Since the registers are set up perfectly in both cases, we can use the
+; same routine!
+
+               EXPORT  wimp_sendmessage
+               EXPORT  wimp_sendwmessage
+wimp_sendmessage
+wimp_sendwmessage
+               SWI     XWimp_SendMessage
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_create_submenu ---
+;
+; On entry:    a1 == pointer to menu to open
+;              a2 == x coordinate to open it at
+;              a3 == y coordinate to open it at
+
+               EXPORT  wimp_create_submenu
+wimp_create_submenu
+               MOV     a4,a3
+               MOV     a3,a2
+               MOV     a2,a1
+               SWI     XWimp_CreateSubMenu
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_spriteop ---
+;
+; On entry:    a1 == the reason code to pass
+;              a2 == the name of the sprite to do it on
+
+               EXPORT  wimp_spriteop
+wimp_spriteop  STMFD   sp!,{v1-v6,lr}
+               MOV     a3,a2
+               SWI     XWimp_SpriteOp
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1-v6,pc}^
+
+; --- wimp_spriteop_full ---
+;
+; On entry:    a1 == pointer to registers to use
+
+               EXPORT  wimp_spriteop_full
+wimp_spriteop_full
+               STMFD   sp!,{v1-v6,lr}
+               MOV     ip,a1
+               LDMIA   ip,{a1-a4,v1-v6}
+               SWI     XWimp_SpriteOp
+               STMVCIA ip,{a1-a4,v1-v6}
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1-v6,pc}^
+
+; --- wimp_baseofsprites ---
+;
+; On entry:    --
+; On exit:     a1 == pointer to WIMP sprite pool in RMA
+
+               EXPORT  wimp_baseofsprites
+wimp_baseofsprites
+               SWI     XWimp_SpriteOp
+               MOV     a1,a2
+               MOVS    pc,lr
+
+; --- wimp_blockcopy ---
+;
+; On entry:    a1 == window handle
+;              a2 == pointer to source rectangle
+;              a3 == destination x coordinate
+;              a4 == destination y coordinate
+
+               EXPORT  wimp_blockcopy
+wimp_blockcopy STMFD   sp!,{v1-v3,lr}
+               MOV     v3,a4
+               MOV     v2,a3
+               LDMIA   a2,{a2,a3,a4,v1}
+               SWI     XWimp_BlockCopy
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1-v3,pc}^
+
+; --- wimp_slotsize ---
+;
+; On entry:    a1 == pointer to current slot size
+;              a2 == pointer to next slot size
+;              a3 == pointer to free pool size
+
+               EXPORT  wimp_slotsize
+wimp_slotsize  STMFD   sp!,{v1-v3,lr}          ;Stack registers
+               MOV     a4,a1                   ;Keep pointer to current
+               MOV     v2,a2                   ;Keep pointer to next
+               MOV     v3,a3                   ;Keep pointer to free
+               LDR     a1,[a1]                 ;Get the actual current slot
+               LDR     a2,[a2]                 ;Get the actual next slot
+               SWI     XWimp_SlotSize          ;Set or read the slot size
+               STRVC   a1,[a4]                 ;Store current slot size
+               STRVC   a2,[v2]                 ;Store next slot size
+               STRVC   a3,[v3]                 ;Store free area size
+               MOVVC   a1,#0                   ;Clear error marker
+               LDMFD   sp!,{v1-v3,pc}^         ;Return to caller
+
+; --- wimp_readpixtrans ---
+;
+; On entry:    a1 == pointer to sprite area
+;              a2 == pointer to sprite id (yuk)
+;              a3 == pointer to scale factors to fill in
+;              a4 == pointer to translation table to fill in
+
+               EXPORT  wimp_readpixtrans
+wimp_readpixtrans
+               STMFD   sp!,{v3,v4,lr}
+
+               ; --- Put the registers in the right places ---
+
+               MOV     v4,a4
+               MOV     v3,a3
+               MOV     a3,a2
+               MOV     a2,a1
+
+               ; --- Set up the reason code properly ---
+
+               CMP     a2,#0                   ;Is it the WIMP or system
+               CMPNE   a2,#1                   ;sprite area?
+               MOVEQ   a1,#&000                ;Then say it's system area
+               BEQ     %f00                    ;And branch ahead
+
+               ; --- Munge the sprite ID to get the right reason code ---
+
+               LDR     lr,[a3,#4]              ;Get the sprite ID tag
+               CMP     lr,#0                   ;Is it a name
+               MOVEQ   a1,#&100                ;Yes -- user area, named
+               MOVNE   a1,#&200                ;No -- user area, pointer
+
+               ; --- Now get the pixel translation ---
+
+00             LDR     a3,[a3,#0]              ;Get sprite name or pointer
+               SWI     XWimp_ReadPixTrans      ;Do the actual operation
+
+               MOVVC   a1,#0                   ;If it succeeded, no error
+               LDMFD   sp!,{v3,v4,pc}^         ;Return to caller
+
+; --- Missing call ---
+;
+; We omit a veneer for Wimp_ClaimFreeMemory, since it's not much use unless
+; you're in SVC mode, in which case you'd better be writing in assembler
+; anyway.
+
+; --- wimp_commandwindow ---
+;
+; On entry:    a1 == pointer to a funny structure
+
+               EXPORT  wimp_commandwindow
+wimp_commandwindow
+               MOV     a2,a1                   ;Keep pointer to structure
+               LDR     a3,[a2,#0]              ;Get the operation code
+
+               ; --- Work out what the operation is meant to be ---
+               ;
+               ; If we don't recognise the `tag' then all hell breaks loose.
+
+               CMP     a3,#0                   ;Create window with title
+               LDREQ   a1,[a2,#4]              ;Then find the title
+               CMP     a3,#1                   ;Just make window `active'
+               MOVEQ   a1,#1                   ;Horrors -- that's right
+               CMP     a3,#2                   ;Close the window, prompting
+               MOVEQ   a1,#0                   ;Then set up the code
+               CMP     a3,#3                   ;Close the window, no prompt
+               MOVEQ   a1,#-1                  ;Do that right too
+
+               ; --- Now just do it ---
+
+               SWI     XWimp_CommandWindow
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_textcolour ---
+;
+; On entry:    a1 == colour to set
+
+               EXPORT  wimp_textcolour
+wimp_textcolour        SWI     XWimp_TextColour
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_transferblock ---
+;
+; On entry:    a1 == source task's handle
+;              a2 == address of buffer in source task
+;              a3 == destination task's handle
+;              a4 == address of buffer in destination task
+;              [sp] == amount of data to transfer
+
+               EXPORT  wimp_transferblock
+wimp_transferblock
+               STMFD   sp!,{v1,lr}             ;Save v1 on the stack
+               LDR     v1,[sp,#8]              ;Get the buffer length
+               SWI     XWimp_TransferBlock     ;Do the operation
+               MOVVC   a1,#0
+               LDMFD   sp!,{v1,pc}^
+
+; --- wimp_readsysinfo ---
+;
+; On entry:    a1 == information to read
+;              a2 == where to put R0 on exit
+;              a3 == where to put R1 on exit
+
+               EXPORT  wimp_readsysinfo
+wimp_readsysinfo
+               CMP     a1,#5
+               MOVNE   a3,#0
+               MOV     a4,a2
+               SWI     XWimp_ReadSysInfo
+               MOVVSS  pc,lr
+               CMP     a4,#0
+               STRNE   a1,[a4]
+               CMP     a3,#0
+               STRNE   a2,[a3]
+               MOV     a1,#0
+               MOVS    pc,lr
+
+; --- wimp_setfontcolours ---
+;
+; On entry:    a1 == background colour
+;              a2 == foreground colour
+
+               EXPORT  wimp_setfontcolours
+wimp_setfontcolours
+               SWI     XWimp_SetFontColours
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_getmenustate ---
+;
+; On entry:    a1 == what to do
+;              a2 == pointer to buffer to fill in
+;              a3 == window handle (optional)
+;              a4 == icon handle (optional too)
+
+               EXPORT  wimp_getmenustate
+wimp_getmenustate
+               SWI     XWimp_GetMenuState
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_addmessages ---
+;
+; On entry:    a1 == pointer to messages array
+
+               EXPORT  wimp_addmessages
+wimp_addmessages
+               SWI     XWimp_AddMessages
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- wimp_removemessages ---
+;
+; On entry:    a1 == pointer to messages array
+
+               EXPORT  wimp_removemessages
+wimp_removemessages
+               SWI     XWimp_RemoveMessages
+               MOVVC   a1,#0
+               MOVS    pc,lr
+
+; --- Missing call ---
+;
+; We omit a veneer for Wimp_SetColourMapping, since it's for specialised use
+; only probably, and not of use to an average application.
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Libraries/Steel/s/wimp_stat b/StraySrc/Libraries/Steel/s/wimp_stat
new file mode 100644 (file)
index 0000000..8d1c3d9
--- /dev/null
@@ -0,0 +1,246 @@
+;
+; wimp_stat.s
+;
+; Special static parts of wimp
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Steel library.
+;
+; Steel is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Steel is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Steel.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:SWIs
+
+;----- Private data ---------------------------------------------------------
+
+               AREA    |C$$data|,DATA
+
+wimp__savefp   DCD     1
+
+;----- Some flags and things -----------------------------------------------
+
+dpoll__savefp  EQU     1<<24                   ;Bit to set to save FP state
+
+;----- Polling code ---------------------------------------------------------
+
+               AREA    |C$$Code|,CODE,READONLY
+
+; --- wimp_poll ---
+;
+; On entry:    a1 == Wimp_Poll event mask
+;              a2 == pointer to wimp_eventstr to be filled in
+; On exit:     a1 == pointer to an os_error, or nothing
+
+               EXPORT  wimp_poll
+wimp_poll      ROUT
+
+               STMFD   sp!,{lr}                ;Look after some registers
+
+               ; --- Figure out about saving the FP status ---
+
+               LDR     a4,=wimp__savefp        ;Find the magic flag
+               LDR     a4,[a4]                 ;Get the value of the flag
+               CMP     a4,#0                   ;Do we have to save FP state?
+               ORRNE   a1,a1,#dpoll__savefp    ;Yes -- set the flag
+               BICNE   a1,a1,#dpoll__savefp    ;No -- clear the flag
+
+               ; --- Call the SWI and get out again ---
+
+               ADD     a2,a2,#4                ;Point to the big poll block
+               BL      wimp__doPoll            ;Get a Wimp event
+               SUB     a2,a2,#4                ;Point to the wimp_eventstr
+               STRVC   a1,[a2]                 ;Store the reason code away
+               MOVVC   a1,#0                   ;If no error, return NULL
+               LDMFD   sp!,{pc}^               ;Return to caller nicely
+
+               LTORG
+
+; --- wimp_pollidle ---
+;
+; On entry:    a1 == Wimp_Poll event mask
+;              a2 == pointer to wimp_eventstr to be filled in
+;              a3 == time before which thou shalt not return
+; On exit:     a1 == pointer to an os_error, or nothing
+
+               EXPORT  wimp_pollidle
+wimp_pollidle  ROUT
+
+               STMFD   sp!,{v1-v3,lr}          ;Look after some registers
+
+               ; --- Figure out about saving the FP status ---
+
+               LDR     a4,=wimp__savefp        ;Find the magic flag
+               LDR     a4,[a4]                 ;Get the value of the flag
+               CMP     a4,#0                   ;Do we have to save FP state?
+               ORRNE   a1,a1,#dpoll__savefp    ;Yes -- set the flag
+               BICNE   a1,a1,#dpoll__savefp    ;No -- clear the flag
+
+               ; --- Call the SWI and get out again ---
+
+               ADD     a2,a2,#4                ;Point to the big poll block
+               BL      wimp__doPollIdle        ;Get a Wimp event
+               SUB     a2,a2,#4                ;Point to the wimp_eventstr
+               STRVC   a1,[a2]                 ;Store the reason code away
+               MOVVC   a1,#0                   ;If no error, return NULL
+               LDMFD   sp!,{v1-v3,pc}^         ;Return to caller nicely
+
+               LTORG
+
+; --- wimp_save_fp_state_on_poll ---
+
+               EXPORT  wimp_save_fp_state_on_poll
+wimp_save_fp_state_on_poll
+               ROUT
+
+               LDR     a1,=wimp__savefp        ;Find the magic flag
+               MOV     a2,#1                   ;Store a TRUE value away
+               STR     a2,[a1]                 ;Tuck it into my workspace
+               MOVS    pc,lr                   ;Return to the caller
+
+               LTORG
+
+; --- wimp_corrupt_fp_state_on_poll ---
+
+               EXPORT  wimp_corrupt_fp_state_on_poll
+wimp_corrupt_fp_state_on_poll
+               ROUT
+
+               LDR     a1,=wimp__savefp        ;Find the magic flag
+               MOV     a2,#0                   ;Store a FALSE value away
+               STR     a2,[a1]                 ;Tuck it into my workspace
+               MOVS    pc,lr                   ;Return to the caller
+
+               LTORG
+
+; --- wimp__doPoll ---
+;
+; On entry:    a1 == event mask
+;              a2 == pointer to wimp poll block
+;              a4 == pointer to poll word if bit 22 of a1 is set
+; On exit:     a1 == reason code returned by Wimp_Poll
+;              Other registers preserved
+;
+; Floating point status is preserved if a1 on entry has bit 24 set and the
+; floating point emulator or hardware is present.  The floating point
+; registers preserved are f4-f7 and the FPSR.
+
+wimp__doPoll   ROUT
+
+               STMFD   sp!,{v1-v3,lr}
+
+               MOV     v2,#0                   ;Don't restore FP state
+               TST     a1,#1<<24               ;Does caller want FP saved?
+               BIC     v3,a1,#1<<24            ;We're doing it, not the WIMP
+               BEQ     %00                     ;No -- skip this bit
+               SWI     XFPEmulator_Version     ;Is the FPE/FPA there?
+               MOVVC   v2,#1                   ;Yes -- set flag to restore
+               BLVC    save_fp                 ;Save the FP state
+
+00             MOV     a1,v3                   ;Restore event mask
+               SWI     XWimp_Poll              ;Do the SWI call
+               ORRVS   v2,v2,#2                ;Set bit 1 of v2 if error
+
+               TST     v2,#1                   ;Is bit 0 set?
+               BLNE    restore_fp              ;Yes -- restore FP state
+               TST     v2,#2                   ;Was there an error?
+               LDMFD   sp!,{v1-v3,lr}          ;Restore all registers anyhow
+               BICEQS  pc,lr,#V_flag           ;No -- clear V flag
+               ORRS    pc,lr,#V_flag           ;Yes -- set V flag
+
+               LTORG
+
+; --- wimp__doPollIdle ---
+;
+; On entry:    a1 == event mask
+;              a2 == pointer to wimp poll block
+;              a3 == earliest time to return with an idle event
+;              a4 == pointer to poll word if bit 22 of a1 is set
+; On exit:     a1 == reason code returned by Wimp_Poll
+;              Other registers preserved
+;
+; Floating point status is preserved if a1 on entry has bit 24 set and the
+; floating point emulator or hardware is present.  The floating point
+; registers preserved are f4-f7 and the FPSR.
+
+wimp__doPollIdle ROUT
+
+               STMFD   sp!,{v1-v3,lr}
+
+               MOV     v2,#0                   ;Don't restore FP state
+               TST     a1,#1<<24               ;Does caller want FP saved?
+               BIC     v3,a1,#1<<24            ;We're doing it, not the WIMP
+               BEQ     %00                     ;No -- skip this bit
+               SWI     XFPEmulator_Version     ;Is the FPE/FPA there?
+               MOVVC   v2,#1                   ;Yes -- set flag to restore
+               BLVC    save_fp                 ;Save the FP state
+
+00             MOV     a1,v3                   ;Restore event mask
+               SWI     XWimp_PollIdle          ;Do the SWI call
+               ORRVS   v2,v2,#2                ;Set bit 1 of v2 if error
+
+               TST     v2,#1                   ;Is bit 0 set?
+               BLNE    restore_fp              ;Yes -- restore FP state
+               TST     v2,#2                   ;Was there an error?
+               LDMFD   sp!,{v1-v3,lr}          ;Restore all registers anyhow
+               BICEQS  pc,lr,#V_flag           ;No -- clear V flag
+               ORRS    pc,lr,#V_flag           ;Yes -- set V flag
+
+               LTORG
+
+; --- save_fp ---
+;
+; On entry:    --
+; On exit:     v1 corrupted
+
+save_fp                ROUT
+
+               RFS     v1                      ;Read the FP status word
+               STMFD   sp!,{v1}                ;Stack it
+               MOV     v1,#0                   ;We will zero the FPSR
+               WFS     v1                      ;Zero it
+               SUB     sp,sp,#4*12             ;Leave space for 4 FP regs
+               STFE    f4,[sp,#0*12]           ;Stack F4
+               STFE    f5,[sp,#1*12]           ;Stack F5
+               STFE    f6,[sp,#2*12]           ;Stack F6
+               STFE    f7,[sp,#3*12]           ;Stack F7
+               MOVS    pc,lr                   ;Return to caller
+
+; --- restore_fp ---
+;
+; On entry:    --
+; On exit:     v1 corrupted
+
+restore_fp     ROUT
+
+               MOV     v1,#0                   ;We will zero the FPSR
+               WFS     v1                      ;Zero it
+               LDFE    f4,[sp,#0*12]           ;Unstack F4
+               LDFE    f5,[sp,#1*12]           ;Unstack F5
+               LDFE    f6,[sp,#2*12]           ;Unstack F6
+               LDFE    f7,[sp,#3*12]           ;Unstack F7
+               ADD     sp,sp,#4*12             ;Move stack ptr up past FP
+               LDMFD   sp!,{v1}                ;Restore FPSR
+               WFS     v1                      ;Write it to the FPSR
+               MOVS    pc,lr                   ;Return to caller
+
+;----- Include the main wimp veneers ----------------------------------------
+
+               LNK     s.wimp_main
diff --git a/StraySrc/Makefile,fe1 b/StraySrc/Makefile,fe1
new file mode 100644 (file)
index 0000000..e362d22
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all:
+       submake *.Makefile
+
+install:
+       submake *.Makefile -- install
+
+clean:
+       submake *.Makefile -- clean
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/MiscToys/CheckSD/Makefile,fe1 b/StraySrc/MiscToys/CheckSD/Makefile,fe1
new file mode 100644 (file)
index 0000000..3fe06c0
--- /dev/null
@@ -0,0 +1,115 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: checksd
+
+checksd: o.checksd o.templates libs:embtemp.o.embtemp
+       $(SETDATE) o.version \
+               version="1.00 ($(DATE))" \
+               cright="$(CRIGHT)"
+       $(LD_APP) o.checksd o.templates o.version libs:embtemp.o.embtemp
+       $(SQUEEZE)
+       $(SET_APP)
+
+o.templates: rsc.templates
+       templaof rsc.templates o.templates
+
+install: checksd
+       $(INSTALL) checksd <SSR$BinDir>
+
+clean:
+       -$(RM) o.* checksd
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.checksd: s.checksd
+o.checksd: libs:header
+o.checksd: libs:swis
+o.checksd: libs:stream
+o.checksd: libs:embTemp.sh.embTemp
diff --git a/StraySrc/MiscToys/CheckSD/README b/StraySrc/MiscToys/CheckSD/README
new file mode 100644 (file)
index 0000000..d9d07d9
--- /dev/null
@@ -0,0 +1,15 @@
+CHECKSD
+~~~~~~~
+
+This is a silly little program which provides a warning banner when you
+close your machine down.  I find this useful to have around, because I
+seem to do this by accident quite often, particularly when there's no
+unsaved data in any applications, and it annoys me greatly.
+
+The program's an absolute application which requires one page of memory. 
+I couldn't be bothered to make it a module, although it should be
+amenable should someone else want to make the effort.  It requires
+Sculptrix to be available.  It's quite capable of setting its own Wimp
+slot, and the warning window is embedded in the program binary.
+
+[mdw]
diff --git a/StraySrc/MiscToys/CheckSD/rsc/Templates,fec b/StraySrc/MiscToys/CheckSD/rsc/Templates,fec
new file mode 100644 (file)
index 0000000..06057ab
Binary files /dev/null and b/StraySrc/MiscToys/CheckSD/rsc/Templates,fec differ
diff --git a/StraySrc/MiscToys/CheckSD/s/CheckSD b/StraySrc/MiscToys/CheckSD/s/CheckSD
new file mode 100644 (file)
index 0000000..cc3a7a3
--- /dev/null
@@ -0,0 +1,403 @@
+;
+; checksd.s
+;
+; Ask for confirmation on shutdowns
+;
+; © 1995 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; CheckSD is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; CheckSD is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with CheckSD.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     libs:embTemp.sh.embTemp
+
+               IMPORT  tpl_warning
+
+               IMPORT  |Image$$RW$$Limit|
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Asm$$Code|,CODE,READONLY
+               ENTRY
+
+; --- main ---
+;
+; On entry:    --
+;
+; On exit:     Via OS_Exit
+;
+; Use:         Initialise the application.
+
+main           ROUT
+
+               BL      cs_init                 ;Initialise low-level things
+               BL      cs_initWimp             ;Initialise WIMPy things
+               BL      cs_poll                 ;Enter the poll loop
+               SWI     OS_Exit                 ;And return when done
+
+               LTORG
+
+; --- cs_init ---
+;
+; On entry:    --
+;
+; On exit:     R12 == pointer to workspace
+;              R13 == stack pointer
+;              Other registers corrupted
+;
+; Use:         Initialises workspace etc.
+
+cs_init                ROUT
+
+               MOV     R0,#4096                ;Only need a 4K wimpslot
+               MOV     R1,#-1                  ;Don't change next slot
+               SWI     Wimp_SlotSize           ;Change my slot, please
+
+               SWI     OS_GetEnv               ;Find the memory limit
+               MOV     R13,R1                  ;Put stack at the top
+               LDR     R12,=|Image$$RW$$Limit| ;Put workspace at end
+               ADD     R0,R12,#cs_wSize        ;Add on the workspace size
+               CMP     R0,R13                  ;Do we have enough space?
+               MOVCCS  PC,R14                  ;Yes -- then return to caller
+
+               ADR     R0,cs_noMem             ;Point to error message
+               SWI     OS_GenerateError        ;Raise the error
+
+cs_noMem       DCD     1
+               DCB     "Not enough memory for CheckSD to start up",0
+
+; --- cs_initWimp ---
+;
+; On entry:    --
+;
+; On exit:     R0-R11 corrupted
+;
+; Use:         Initialises various WIMPy things.
+
+cs_initWimp    ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+
+               MOV     R0,#200                 ;RISC OS 2 will do for me
+               LDR     R1,=&4B534154           ;Get magic WIMP number
+               ADR     R2,cs_appName           ;Point to application name
+               SWI     Wimp_Initialise         ;Initialise the WIMP then
+
+               ADRL    R0,tpl_warning          ;Find the template
+               ADR     R1,cs_pollBlock         ;Write window to poll block
+               ADR     R2,cs_indBase           ;Point to indirect buffer
+               ADR     R3,cs_indLimit          ;Point to limit of this
+               MOV     R4,#1                   ;Use the Wimp sprite area
+               MOV     R5,#1                   ;For everything, please
+               BL      embTemp_extract         ;Extract the file
+               SWI     Wimp_CreateWindow       ;Create the window
+               STR     R0,cs_warning           ;Save the window handle
+
+               LDMFD   R13!,{PC}^              ;Now return to caller
+
+cs_appName     DCB     "CheckShutdowns",0
+
+               LTORG
+
+; --- cs_poll ---
+;
+; On entry:    --
+;
+; On exit:     R0-R11 corrupted
+;
+; Use:         Does the main polling job.
+
+cs_poll                ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+00             MOV     R0,#1                   ;Don't give me null events
+               ADR     R1,cs_pollBlock         ;Point to my poll block
+               SWI     Wimp_Poll               ;Get an event, please
+               ADR     R14,%b00                ;Set up a return address
+               CMP     R0,#1                   ;Is it a redraw event?
+               BEQ     cs_redraw               ;Yes (weird)
+               CMP     R0,#17                  ;Is this a message?
+               CMPNE   R0,#18                  ;Check both types
+               BEQ     cs_message              ;Yes -- handle that then
+               MOVS    PC,R14                  ;And loop back round again
+
+               LTORG
+
+; --- cs_redraw ---
+;
+; On entry:    R1 == pointer to window handle
+;
+; On exit:     --
+;
+; Use:         Redraws a window the only way we can.
+
+cs_redraw      ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               SWI     Wimp_RedrawWindow       ;Start a redraw job
+               CMP     R0,#0                   ;Have we finished yet?
+00             SWINE   XSculptrix_RedrawWindow ;No -- do 3D bits then
+               SWINE   Wimp_GetRectangle       ;And get another rectangle
+               CMPNE   R0,#0                   ;Finished now?
+               BNE     %b00                    ;No -- keep looping
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               LTORG
+
+; --- cs_message ---
+;
+; On entry:    R1 == pointer to message block
+;
+; On exit:     R0-R11 corrupted
+;
+; Use:         Handles messages
+
+cs_message     ROUT
+
+               LDR     R0,[R1,#16]             ;Load the message type
+               CMP     R0,#0                   ;Is this a quit?
+               LDMEQFD R13!,{PC}^              ;Yes -- then stop right now
+               CMP     R0,#8                   ;Is this a pre-quit?
+               MOVNES  PC,R14                  ;No -- ignore it then
+               LDR     R0,[R1,#0]              ;Load the message size
+               CMP     R0,#20                  ;Is this the old size?
+               LDRNE   R0,[R1,#20]             ;No -- load the flags word
+               TSTNE   R0,#1                   ;Test the flag bit
+               MOVNES  PC,R14                  ;And return if not shutdown
+
+               STMFD   R13!,{R14}              ;Save a register
+               SUB     R13,R13,#48             ;Drop stack pointer further
+               LDR     R0,cs_warning           ;Load the window handle
+               STR     R0,[R13,#0]             ;Store it away
+               MOV     R1,R13                  ;Point to it there
+               SWI     Wimp_GetWindowState     ;Find the window size
+               LDMIB   R1,{R2-R5}              ;Load them out
+               SUB     R13,R13,#16             ;Make space on the stack
+               ADR     R0,cs_vduvars           ;Point to VDU variables
+               MOV     R1,R13                  ;Output on the stack
+               SWI     OS_ReadVduVariables     ;Read them then
+               LDMIA   R13!,{R6-R9}            ;Load them
+               ADD     R8,R8,#1                ;Find the screen width
+               ADD     R9,R9,#1                ;And its height
+               MOV     R8,R8,LSL R6            ;Work out widht in OS units
+               MOV     R9,R9,LSL R7            ;And the height too
+               SUB     R4,R4,R2                ;Find the window width
+               SUB     R5,R5,R3                ;And its height
+               SUB     R2,R8,R4                ;Find centre position
+               SUB     R3,R9,R5                ;Vertically too
+               MOV     R2,R2,LSR #1            ;And work out the positions
+               MOV     R3,R3,LSR #1            ;To centre on the screen
+               ADD     R4,R2,R4                ;Get the limit coords too now
+               ADD     R5,R3,R5                ;So we can store them back
+               MOV     R1,R13                  ;Point to the poll block
+               STMIB   R1,{R2-R5}              ;Save all of them away
+               SWI     Wimp_OpenWindow         ;Display it on the screen
+
+               ; --- Constrain the mouse pointer ---
+
+               MOV     R14,#1                  ;A word to shift about
+               SUB     R2,R2,R14,LSL R6        ;Knock pixel of left side
+               SUB     R3,R3,R14,LSL R7        ;And off the top
+               BL      cs_constrain            ;Constrain mouse here
+
+               BL      cs_beep                 ;Maybe make a noise
+               BL      cs_redraw               ;Force it to redraw
+
+               ; --- Work out position of buttons ---
+
+               ADD     R14,R1,#20              ;Point to scroll offsets
+               LDMIA   R14,{R10,R11}           ;Load them
+               SUB     R10,R2,R10              ;Find the x origin position
+               SUB     R11,R5,R11              ;And the y origin position
+
+               MOV     R14,#3                  ;Find default button
+               STR     R14,[R1,#4]             ;Store that in the block
+               SWI     Wimp_GetIconState       ;Read the icon block
+               ADD     R14,R1,#8               ;Point to the sizes
+               LDMIA   R14,{R4-R7}             ;Load them out
+               ADD     R4,R4,R10               ;Transform these
+               ADD     R5,R5,R11
+               ADD     R6,R6,R10
+               ADD     R7,R7,R11
+
+               MOV     R14,#4                  ;Find cancel button
+               STR     R14,[R1,#4]             ;Store that in the block
+               SWI     Wimp_GetIconState       ;Read the icon block
+               ADD     R14,R1,#8               ;Point to the sizes
+               LDMIA   R14,{R0-R3}             ;Load them out
+               ADD     R8,R0,R10               ;Transform these
+               ADD     R9,R1,R11
+               ADD     R10,R2,R10
+               ADD     R11,R3,R11
+
+               ; --- Now enter a loop thing ---
+
+               SWI     OS_Mouse                ;Read the mouse state
+               MOV     R14,R2                  ;Look after current state
+
+05             SWI     OS_Mouse                ;Read the mouse state
+               BIC     R3,R2,R14               ;Clear bits already set
+               ANDS    R3,R3,#5                ;Only look at sel and adj
+               BEQ     %f00                    ;If no buttons, skip
+
+               CMP     R0,R4                   ;Check for default button
+               CMPCS   R1,R5
+               CMPCS   R6,R0
+               CMPHI   R7,R1
+               MOVHI   R0,#3                   ;If so, get default
+               BHI     %10cs_message           ;And handle that
+
+               CMP     R0,R8                   ;Check for cancel button
+               CMPCS   R1,R9
+               CMPCS   R10,R0
+               CMPHI   R11,R1
+               MOVHI   R0,#4                   ;If so, get cancel
+               BHI     %10cs_message           ;And handle that
+
+               ; --- Check for key presses ---
+
+00             MOV     R14,R2                  ;Remember new current state
+               MOV     R0,#129                 ;Read a keypress
+               MOV     R1,#0                   ;Don't wait for it
+               MOV     R2,#0                   ;Really don't
+               SWI     OS_Byte                 ;Read that
+               MOV     R0,#0                   ;Clear a word
+               CMP     R1,#&0D                 ;Return pressed?
+               EOREQ   R0,R0,#3 :EOR: 4        ;Yes -- choose default
+               CMPNE   R1,#&1B                 ;Or escape?
+               EOREQ   R0,R0,#4                ;Yes -- choose cancel
+               BNE     %b05                    ;Otherwise loop
+
+               ; --- Choose a button ---
+
+10cs_message   MOV     R11,R0                  ;Look after the icon
+               SUB     R13,R13,#16             ;Make a slab block
+               MOV     R1,R0                   ;Get the icon handle
+               LDR     R0,cs_warning           ;Get the warning box
+               MOV     R2,R13                  ;Point to slab block
+               SWI     XSculptrix_SlabIcon     ;Slab the icon
+               ADR     R1,cs_warning           ;Point to window handle
+               SWI     Wimp_CloseWindow        ;Take the window down
+               SWI     XSculptrix_UnslabIcon   ;And unslab the icon
+               ADD     R13,R13,#16             ;Reclaim the block
+
+               ; --- Unconstrain the mouse ---
+
+               SUB     R13,R13,#16             ;Make space on the stack
+               ADR     R0,cs_vduvars           ;Point to VDU variables
+               MOV     R1,R13                  ;Output on the stack
+               SWI     OS_ReadVduVariables     ;Read them then
+               LDMIA   R13!,{R2-R5}            ;Load them
+               MOV     R4,R4,LSL R2            ;Work out widht in OS units
+               MOV     R5,R5,LSL R3            ;And the height too
+               MOV     R2,#0                   ;Start at bottom left
+               MOV     R3,#0                   ;Set both up
+               BL      cs_constrain            ;Set the rectangle
+
+               ; --- Now sort out what to do now ---
+
+               CMP     R11,#4                  ;Cancel shutdown?
+               BNE     %f00                    ;No -- skip onwards
+               ADR     R1,cs_pollBlock         ;Point to the poll block
+               LDR     R14,[R1,#8]             ;Load his ref
+               STR     R14,[R1,#12]            ;This is my ref
+               LDR     R2,[R1,#4]              ;Load his task handle
+               MOV     R0,#19                  ;Ack the message
+               SWI     Wimp_SendMessage        ;Abort the shutdown
+
+               ; --- Now tidy up and return ---
+
+00             ADD     R13,R13,#48             ;Restore the stack
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+cs_vduvars     DCD     4,5,11,12,-1
+
+               LTORG
+
+; --- cs_constrain ---
+;
+; On entry:    R2-R5 == coordinates to constrain to
+;
+; On exit:     --
+;
+; Use:         Constrain the mouse to a rectangle.
+
+cs_constrain   ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R0,#1                   ;Subreason code
+               ORR     R0,R0,R2,LSL #8
+               ORR     R0,R0,R3,LSL #24
+               MOV     R1,R3,LSR #8
+               ORR     R1,R1,R4,LSL #8
+               ORR     R1,R1,R5,LSL #24
+               MOV     R2,R5,LSR #8
+               STMFD   R13!,{R0-R2}            ;Save them on the stack
+               MOV     R0,#21                  ;Do mouse things
+               MOV     R1,R13                  ;Point to the block
+               SWI     OS_Word                 ;Do the job
+               ADD     R13,R13,#12             ;Restore stack pointer
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+
+; --- cs_beep ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sounds the bell (VDU 7) if the CMOS settings dictate that
+;              error boxes should cause a beep.
+
+cs_beep                ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R0,#161                 ;Read CMOS locations nicely
+               MOV     R1,#197                 ;Read WimpFlags location
+               SWI     OS_Byte                 ;Do the read operation
+               TST     R2,#1<<4                ;Do we make noises then?
+               SWIEQ   OS_WriteI+7             ;Yes -- bleep
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+cs_wStart      #       0
+
+cs_warning     #       4
+cs_pollBlock   #       256
+cs_indBase     #       256
+cs_indLimit    #       0
+cs_stack       #       256
+
+cs_wSize       EQU     {VAR}-cs_wStart
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/MiscToys/CurrDir/Makefile,fe1 b/StraySrc/MiscToys/CurrDir/Makefile,fe1
new file mode 100644 (file)
index 0000000..5dd313f
--- /dev/null
@@ -0,0 +1,108 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: currDir
+
+currDir: o.currDir
+       $(SETDATE) o.version version="CurrDir 1.01 [$(DATE)] $(CRIGHT)"
+       $(LD_APP) o.currDir o.version
+       $(SQUEEZE)
+       $(SET_APP)
+
+install: currDir
+       $(INSTALL) currDir <SSR$BinDir>
+
+clean:
+       -$(RM) o.* currDir
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.currDir: s.currDir
+o.currDir: libs:header
+o.currDir: libs:swis
diff --git a/StraySrc/MiscToys/CurrDir/README b/StraySrc/MiscToys/CurrDir/README
new file mode 100644 (file)
index 0000000..a9b7e61
--- /dev/null
@@ -0,0 +1,100 @@
+             ___                _____
+            /          __   __   |   \ ___  __
+            |    |  | |__) |__)  |   |  |  |__)
+            \___ \__/ |  \ |  \ _|___/ _|_ |  \
+
+             ©   1 9 9 4   S t r a y l i g h t
+___________________________________________________________
+
+                       About CurrDir
+
+For some reason, people appear to like to have the current
+directory in their command prompts.  Indeed, I wrote a code
+variable to do this last November.  Following a discussion
+on c.s.a recently, I decided to upgrade my program for
+doing this, and then, out of the kindness of my heart, give
+it away.  Nutty, isn't it?
+
+So what makes Straylight currDir better than the other
+current-directory-in-a-code-variable utilities around? 
+Well, for a start, it was written by Straylight.  For
+seconds:
+
+* It does it the `right way' by using OS_FSControl 37
+  (CanonicalisePath) on the string `@' which avoids
+  problems with the mangling-system-variables approach,
+  which can go badly wrong.
+
+* It allows you to specify the variable name, so you can
+  have lots of different variables with different options,
+  if you want.
+
+* It allows you to specify a `maximum length', beyond which
+  the path name is truncated, so that the path string
+  doesn't fill up the whole width of the screen.
+
+The truncation is fairly sensible.  It will attempt to show
+you the filing system and disk name, if there is one, and
+will chop off the beginning, rather than the end, of the
+actual pathname, so
+
+  scsi::Wintermute.$.Straylight.Software.Freeware.Dynamite
+
+might be shortened to
+
+  scsi::Wintermute.$...tware.Free.Dynamite
+
+As you have no doubt noticed, an ellipsis (`...') is
+inserted to show that characters have been removed.
+___________________________________________________________
+
+                       Using currDir
+
+At simplest, just double-click on the `currDir'
+application.  This will create a system variable called
+`CSD' which contains your full current directory path.  You
+could then put in your prompt with a command like
+
+  SetMacro CLI$Prompt [<CSD>]
+
+If you want to create a different variable, use the `-var'
+option, e.g.:
+
+  currDir -var My$Variable
+
+If you want to specify a maximum length, use the `-maxLen'
+option, e.g.
+
+  currDir -maxLen 40
+
+will ensure that the name never exceeds 40 characters.
+
+You can't remove these variables in the normal way --
+*Unset will silently ignore your attempts.  Therefore
+currDir has a `-remove' option which you can use, in
+conjunction with `-var' if necessary, to kill a variable if
+you don't want it any more.
+
+If you're stuck, typing
+
+  currDir -help
+
+will provide you with some addmittedly fairly terse
+assitance.
+___________________________________________________________
+
+                     Technical details
+
+currDir is written as an application since it can
+safely quit once it has set up the actual code variable. 
+Making it a Utility was a possibility, but that can have
+the nasty side-effect of fragmenting the module area.  It's
+unlikely you'll want to use it from anything other than the
+command line, so it shouldn't be that much of a problem. 
+The program needs a little over 2K to run, so as long as
+you have a page of memory free you won't have any problems
+there.
+
+currDir was written in an evening, using the Acorn ARM
+Assembler, which is jolly good, and I recommend it.
+___________________________________________________________
diff --git a/StraySrc/MiscToys/CurrDir/s/currDir b/StraySrc/MiscToys/CurrDir/s/currDir
new file mode 100644 (file)
index 0000000..2640056
--- /dev/null
@@ -0,0 +1,267 @@
+;
+; currDir.s
+;
+; Puts the current directory in a code variable
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; CurrDir is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; CurrDir is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with CurrDir.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  version
+               IMPORT  |Image$$RW$$Limit|
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Asm$$Code|,CODE,READONLY
+               ENTRY
+
+; --- main ---
+;
+; On entry:    --
+;
+; On exit:     Via OS_Exit
+;
+; Use:         Installs the CurrDir variable.
+
+main           ROUT
+
+               ; --- Check for RISC OS 3 ---
+
+               MOV     R0,#129                 ;Read OS version number
+               MOV     R1,#0
+               MOV     R2,#255
+               SWI     OS_Byte
+               CMP     R1,#&A3                 ;Check for RISC OS 3
+               BLO     cd__badOSVer            ;Wrong -- make an error
+
+               ; --- Parse the command line arguments ---
+
+               ADRL    R12,|Image$$RW$$Limit|  ;Find the program end
+               SWI     OS_GetEnv               ;Read the command line
+cd__skipLoop   LDRB    R14,[R0],#1             ;Get next byte from this
+               CMP     R14,#32                 ;Is it the end of the name?
+               BHI     cd__skipLoop            ;No -- go round again
+cd__spaceLoop  CMP     R14,#32                 ;Is this a space?
+               LDREQB  R14,[R0],#1             ;Yes -- get another byte
+               BEQ     cd__spaceLoop           ;And go round again
+               SUB     R1,R0,#1                ;Point at nonspace char
+               ADR     R0,cd__cliDef           ;Point to the command defn
+               MOV     R2,R12                  ;Point to my output buffer
+               MOV     R3,#256                 ;And get its size
+               SWI     OS_ReadArgs             ;Read the arguments nicely
+
+               ; --- Check for help ---
+
+               LDR     R14,[R12,#8]            ;Load the help flag
+               CMP     R14,#0                  ;Is it set?
+               BNE     cd__help                ;Yes -- then give help
+
+               ; --- Now find the variable name ---
+
+               LDR     R4,[R12,#0]             ;Load the name value
+               CMP     R4,#0                   ;Is it set?
+               ADREQ   R4,cd__defaultName      ;No -- point to a default
+
+               ; --- Do the right thing ---
+
+               LDR     R14,[R12,#12]           ;Load the `remove' flag
+               CMP     R14,#0                  ;Is it set?
+               BNE     cd__remove              ;Yes -- remove the variable
+
+               ; --- Load the maximum length of the string ---
+
+               LDR     R1,[R12,#4]             ;Load the length value
+               CMP     R1,#0                   ;Is it zero?
+               MOVEQ   R2,#-1                  ;Yes -- have a very big max
+               BEQ     cd__gotLength           ;And skip onwards
+               MOV     R0,#10+(1<<31)          ;Default is base 10
+               SWI     OS_ReadUnsigned         ;Read the value nicely
+               CMP     R2,#20                  ;Is the length OK?
+               BLO     cd__badLength           ;No -- that's an error
+cd__gotLength  STR     R2,cd__maxLen           ;Store the length in code
+
+               ; --- Set the variable value ---
+
+               MOV     R0,R4                   ;Point to the variable name
+               ADR     R14,cd__varBase         ;Point to the variable base
+               LDMIA   R14,{R1,R2}             ;Load the base and length
+               MOV     R3,#0                   ;No context value
+               MOV     R4,#16                  ;This is a code variable
+               SWI     OS_SetVarVal            ;Install the variable nicely
+               SWI     OS_Exit
+
+               ; --- Remove an installed variable ---
+
+cd__remove     MOV     R0,R4                   ;Point to the variable name
+               MOV     R2,#-1                  ;Remove the variable
+               MOV     R3,#0                   ;No context value
+               MOV     R4,#16                  ;Remove code variable
+               SWI     OS_SetVarVal            ;Remove the variable
+               SWI     OS_Exit
+
+cd__cliDef     DCB     "var,maxlen=length,help/S,remove/S",0
+cd__defaultName        DCB     "CSD",0
+
+cd__badOSVer   ADR     R0,cd__ro3Only          ;Point to the error message
+               SWI     OS_GenerateError        ;Report the error
+
+cd__ro3Only    DCD     1
+               DCB     "currDir only works on RISC OS 3.00 or later",0
+
+cd__badLength  ADR     R0,cd__minSize          ;Point to the error message
+               SWI     OS_GenerateError        ;Report the error
+
+cd__minSize    DCD     1
+               DCB     "Maximum length must be at least 20",0
+
+cd__varBase    DCD     cd__variable
+               DCD     cd__varEnd-cd__variable+512
+
+               ; --- Return help on the program ---
+
+cd__help       ADR     R0,cd__helpText         ;Point to the help text
+               MOV     R1,#0                   ;Use the default dictionary
+               ADR     R2,version              ;Point to the version string
+               SWI     OS_PrettyPrint          ;Print the string
+               SWI     OS_Exit
+
+cd__helpText   DCB     27,0,13
+               DCB     13
+               DCB     "Syntax: currDir [-var <variableName>] "
+               DCB     "[-maxlen <length>] [-remove]",13
+               DCB     13
+               DCB     "Sets a variable (by default the variable 'CSD', "
+               DCB     "although you can change this) to contain the name "
+               DCB     "of the currently selected directory.",13
+               DCB     13
+               DCB     "Optionally, you can set a maximum length.  If you "
+               DCB     "do, the directory name will be shortened to only "
+               DCB     "display the name of the filing system, disk name "
+               DCB     "(if present), and the tail end of the path.",13
+               DCB     0
+
+;----- The code variable ----------------------------------------------------
+
+cd__variable   ROUT
+
+               B        cd__cantWrite          ;Handle attempt to write
+
+               ; --- Perform the read operation ---
+
+               STMFD   R13!,{R3-R5,R12,R14}    ;Save some registers
+               ADR     R12,cd__buffer          ;Set up the buffer pointer
+               MOV     R0,#37                  ;Canonicalise path
+               ADR     R1,cd__atSign           ;Point to the `@' magic char
+               MOV     R2,R12                  ;Point at the buffer
+               MOV     R3,#0                   ;No path variable
+               MOV     R4,#0                   ;No path variable still
+               MOV     R5,#512                 ;The size of my buffer
+               SWI     XOS_FSControl           ;Read the canonical path
+               ADRVS   R2,cd__unset            ;If not point at default
+
+               ; --- Count the length ---
+
+               MOV     R0,R12                  ;Point at the buffer
+               MOV     R1,R12                  ;Start truncate at beginning
+               MOV     R2,#0                   ;Current length
+               MOV     R3,#0                   ;Current state
+
+00cd__variable LDRB    R14,[R0],#1             ;Load the next byte
+               CMP     R14,#32                 ;Is this the string end?
+               BLO     %10cd__variable         ;Yes -- skip to the end
+               ADD     R2,R2,#1                ;Bump the length counter
+               CMP     R14,#':'                ;Is it a colon?
+               BEQ     %02cd__variable         ;Yes -- handle it then
+               CMP     R14,#'%'                ;Is it a library?
+               CMPNE   R14,#'$'                ;Or a root spec?
+               CMPNE   R14,#'&'                ;Or a URD spec?
+               MOVEQ   R1,R0                   ;Yes -- truncate here
+               CMP     R14,#'.'                ;Is it a dot?
+               BNE     %00cd__variable         ;No -- go round again
+
+               ; --- We found a dot ---
+
+               CMP     R3,#2                   ;Did we find two colons?
+               SUBEQ   R1,R0,#1                ;Yes -- truncate here
+               MOVEQ   R3,#3                   ;And don't do it again
+               B       %00cd__variable         ;Go round again
+
+               ; --- Found a colon -- check it out ---
+
+02cd__variable CMP     R3,#0                   ;How many colons matched?
+               MOVEQ   R1,R0                   ;None yet -- truncate here
+               CMPNE   R3,#1                   ;Or maybe we've had one
+               ADDEQ   R3,R3,#1                ;Bump the counter
+               B       %00cd__variable         ;Go round again
+
+               ; --- Check the length now ---
+
+10cd__variable LDR     R5,cd__maxLen           ;Load the maximum length
+               SUBS    R4,R2,R5                ;Are we OK here?
+               BLS     %30cd__variable         ;Yes -- skip onwards then
+
+               ; --- Truncate the string ---
+               ;
+               ; R4 is how many bytes we have to lose.
+
+               ADD     R0,R1,R4                ;Point to where we copy from
+               MOV     R2,#3                   ;Countdown for ellipsis
+20cd__variable LDRB    R14,[R0],#1             ;Load the byte out
+               CMP     R14,#32                 ;Is this the end of it all?
+               BLO     %25cd__variable         ;Yes -- skip to end then
+               SUBS    R2,R2,#1                ;No -- decrement countdown
+               MOVGE   R14,#'.'                ;Substitute a dot if needed
+               STRB    R14,[R1],#1             ;Store the byte in buffer
+               B       %20cd__variable         ;No -- go round again then
+
+25cd__variable STRB    R14,[R1],#1             ;Store the byte in buffer
+               MOV     R2,R5                   ;Length is in R2 on exit
+
+               ; --- Return the variable ---
+
+30cd__variable MOV     R0,R12                  ;Point to the string
+               LDMFD   R13!,{R3-R5,R12,PC}^    ;Return to caller
+
+cd__maxLen     DCD     0
+cd__atSign     DCB     "@",0
+cd__unset      DCB     "<Unset>",0
+
+               ; --- Make an error about writing to the variable ---
+
+cd__cantWrite  ADR     R0,cd__writeMsg         ;Point to error
+               ORRS    PC,R14,#V_flag          ;And return it
+
+cd__writeMsg   DCD     1
+               DCB     "Can't write current directory variables",0
+
+               ALIGN
+
+cd__buffer
+
+cd__varEnd
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/MiscToys/Makefile,fe1 b/StraySrc/MiscToys/Makefile,fe1
new file mode 100644 (file)
index 0000000..e362d22
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all:
+       submake *.Makefile
+
+install:
+       submake *.Makefile -- install
+
+clean:
+       submake *.Makefile -- clean
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/MiscToys/PlainError/Makefile,fe1 b/StraySrc/MiscToys/PlainError/Makefile,fe1
new file mode 100644 (file)
index 0000000..e178829
--- /dev/null
@@ -0,0 +1,102 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: PlainError
+
+PlainError: b.plainError
+       basic -quit b.plainError
+
+install: PlainError
+       $(INSTALL) PlainError <SSR$ModDir>
+
+clean:
+       -$(RM) PlainError
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/MiscToys/PlainError/ReadMe b/StraySrc/MiscToys/PlainError/ReadMe
new file mode 100644 (file)
index 0000000..0b1bfdd
--- /dev/null
@@ -0,0 +1,15 @@
+PlainError
+~~~~~~~~~~
+
+        PlainError stops the WindowManager display the annoying `Application
+        may have gone wrong' error box -- it just gets on with the job and
+        displays the error.  You run it and it works.  If only everything
+        could be this easy.
+
+        PlainError will run perfectly on any version of RISC OS.  It's not
+        useful on anything earlier than RISC OS 3.5, unless you've got
+        a softloaded WindowManager.
+
+       If anyone finds a bug in the code, please let me know.  (I know it's
+       unlikely, but it's worth pointing this out anyway.  There was one in
+       the pre-release version.)
diff --git a/StraySrc/MiscToys/PlainError/b/plainError,ffb b/StraySrc/MiscToys/PlainError/b/plainError,ffb
new file mode 100644 (file)
index 0000000..37beedd
Binary files /dev/null and b/StraySrc/MiscToys/PlainError/b/plainError,ffb differ
diff --git a/StraySrc/MiscToys/PlainError/testit,ffb b/StraySrc/MiscToys/PlainError/testit,ffb
new file mode 100644 (file)
index 0000000..5e986ff
Binary files /dev/null and b/StraySrc/MiscToys/PlainError/testit,ffb differ
diff --git a/StraySrc/README b/StraySrc/README
new file mode 100644 (file)
index 0000000..655be56
--- /dev/null
@@ -0,0 +1,101 @@
+STRAYLIGHT SOURCE RELEASE
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This directory contains the Straylight Source Release.  The various Zip
+files contain sources to distinct pieces of software.  Unfortunately, 
+the code was never written to be distributed, so there's a complex
+pattern of interdependency between some of the packages.
+
+`Phase 1' of the Release consists of the following parts:
+
+Core           Contains standard libraries and build tools required for
+               building everything else.
+
+Dynamite       Straylight's dynamic area management module.  Requires
+               Core.
+
+MiscToys       Some fairly silly utilities.  Requires Core.
+
+Sapphire       A large library for writing applications in ARM
+               assembler.  There's a `README' file providing a brief
+               overview, documented header files and a few examples.
+               Requires Core, SDLS, and Sculptrix
+
+Sculptrix      A module for drawing 3D buttons.  Requires Sapphire for
+               the configuration program.
+
+SDLS           Straylight's dynamic linking system.  Requires Sculptrix.
+
+Phase 2 will contain some more toys, the Steel C library, and the Glass
+template editor.  I'm not making any promises with regard to release
+times for phase 2.
+
+Building the SSR should be fairly straightforward.  First, unpack the
+sections you want.  They all share the same build root directory
+`StraySrc'.
+
+Now, make sure that the environment is set up properly.  I tested the
+Release using a minimal toolset consisting of:
+
+  * The following programs available in Run$Path:
+  
+    amu                Acorn's Make Utility version 5.02
+    cc         The Acorn C compiler version 5.06
+    ccrunch    A BASIC compactor written by Ragnar Hafstað
+    libfile    Acorn's library management tool version 5.00
+    link       Acorn's linker version 5.06
+    o-cc       An old Acorn C compiler version 4.00
+    o-libfile  An old Acorn library management tool version 4.00
+    o-link     An old Acorn linker version 4.00
+    o-objasm   An old Acorn assembler version 2.00
+    objasm     Acorn's ARM assembler version 3.06
+    sed                GNU sed version 2.03
+    squeeze    Acorn's AIF squeezer version 5.00
+    unzip      InfoZIP unarchiver version 5.13c BETA
+    zip                InfoZIP archiver version 2.0j
+
+  * The following libraries available in C$Path:
+
+    clib       Acorn's C library headers
+    risc_oslib Acorn's RISC OS library headers and object files
+
+You may be able to get away with different versions of tools.  In
+particular, the old versions of Acorn's tools are used to ensure
+that AOF2 is generated for compatibility with other people's old tools.
+
+SSR requires its own tools and libraries in addition to those listed
+above.  It will create `Libs$Path' pointing at its own libraries, and
+add its own tools to `Run$Path' when you run `ssr-init'.
+
+To build everything, run
+
+  amu
+  amu install
+
+in the `StraySrc' directory.  This will recursively build and install
+everything you've unpacked.  (The Makefiles work out which bits you've
+got and build them.)  If this doesn't work, make sure you've got all
+the tools you need, and all the paths are set up right.
+
+All the source code may be modified and redistributed under the terms of
+the GNU General Public License, which is included in the distribution
+archives as `StraySrc.COPYING'.  Special exceptions for distribution of
+binaries may be given; please ask me for permission.
+
+Public discussion of the Straylight Source Release, including reporting
+of bugs, and requesting new features, will take place on a mailing list. 
+To subscribe, send mail to `ssr-subscribe@excessus.demon.co.uk'.  You
+will be asked to send a confirmation message to prove that you can
+receive mail from the list.  To send a message to the list, mail
+`ssr@excessus.demon.co.uk'.
+
+I want to gather a small team of developers to continue maintenance of
+SSR.  If you think you could help to maintain and develop parts of SSR,
+or write documentation for it, then send me email.
+
+
+My personal email address is mdw@excessus.demon.co.uk.  Please try to
+report problems or requests to the list.  (On the other hand, problems
+/about/ the list probably ought to be sent to me!)
+
+I think that about wraps it up for me.
diff --git a/StraySrc/SDLS/!DLLMerge/!Help b/StraySrc/SDLS/!DLLMerge/!Help
new file mode 100644 (file)
index 0000000..58b0ac0
--- /dev/null
@@ -0,0 +1,74 @@
+      ___                _    _
+     !   \  !     !     ! \  / !  ___  ___   ___   ___
+     !    \ !     !     !  \/  ! !__  !___) /  __ !__
+     !____/ !____ !____ !      ! !___ !   \ \___/ !___
+
+             ©   1 9 9 4   S t r a y l i g h t
+___________________________________________________________
+
+  The DLLMerge application is Copyright © 1994 Straylight.
+  You may give copies of this application to other people
+      or distribute it with software packages, whether
+  commercial or not, provided that you make no profit from
+     doing so, and that all files contained within the    
+            application are included unchanged.
+___________________________________________________________
+
+                       About DLLMerge                      
+
+The '!DLLs' resource folder contains libraries which can be
+shared by applications, thus saving memory.  When new or
+updated libraries become available, you will need to add
+these to your DLLs resource.  The DLLMerge application
+helps you do this quickly and easily.
+
+When new libraries are made available, they will be
+supplied in a DLLs resource.  If you don't have one yet,
+just copy the one supplied.  Otherwise, you'll need to
+merge the new one with your current 'master' DLLs resource.
+
+When you set up your master DLLs resource, you should put
+it with your System resource, either on your hard disk or
+the same floppy disk as the System resource.
+
+To update your DLLs resource, double click on the DLLMerge
+application.  A dialogue box (see figure 1) will appear
+on the screen.
+        ____________________________________________
+       !                __________________________  !
+       ! Master !DLLs: !__________________________! !
+       !                __________________________  !
+       !    New !DLLs: !__________________________! !
+       ! ------------------------------------------ !
+       !  Drag your original DLLs folder into this  !
+       !                 window                     !
+       !____________________________________________!
+
+              Figure 1: The DLLMerge dialogue
+
+The top area shows you the filenames of the DLLs resources,
+as confirmation.  The bottom half of the dialogue box shows
+a prompt guiding you through the merge procedure.
+
+To actually perform the merge, proceed as follows:
+
+* Drag your Master DLLs resource, from your hard disk or
+  System floppy, to the dialogue box.  The full pathname of
+  the resource appears in the display area labelled 'Master
+  !DLLs' as confirmation.
+
+* Drag the new DLLs resource, containing new and updated
+  libraries you want to add to your Master resource, to the
+  dialogue box.  The pathname of the resource appears in
+  the display area labelled 'New !DLLs' as confirmation.
+
+DLLMerge will then perform the merge.  If all went well, a
+message 'DLLs folder updated successfully' is displayed,
+and the new libraries are immediately available for use --
+you do NOT have to reset your computer.
+
+If an error occurred (e.g. 'Disc full' or 'Protected
+disc'), it is reported in a dialogue box.  You should try
+to rectify the problem and then restart the merge
+procedure.
+___________________________________________________________
\ No newline at end of file
diff --git a/StraySrc/SDLS/!DLLMerge/!Run,feb b/StraySrc/SDLS/!DLLMerge/!Run,feb
new file mode 100644 (file)
index 0000000..968f049
--- /dev/null
@@ -0,0 +1,20 @@
+|
+| DLLMerge 1.xx !Run file
+|
+| © 1994 Straylight
+|
+| This file version 1.00 (20 March 1994)
+|
+
+Set DLLMerge$Dir <Obey$Dir>
+IconSprites <DLLMerge$Dir>.!Sprites
+
+WimpSlot -min 8K -max 8K
+
+Set Alias$_RMEnsure RMEnsure %%0 0.00 RMLoad %%2 |m RMEnsure %%0 %%1
+_RMEnsure Sculptrix 2.01 <DLLMerge$Dir>.Sculptrix
+Unset Alias$_RMEnsure
+
+WimpSlot -min 8K -max 8K
+
+Run <DLLMerge$Dir>.!RunImage
\ No newline at end of file
diff --git a/StraySrc/SDLS/!DLLMerge/!Sprites,ff9 b/StraySrc/SDLS/!DLLMerge/!Sprites,ff9
new file mode 100644 (file)
index 0000000..ee718bc
Binary files /dev/null and b/StraySrc/SDLS/!DLLMerge/!Sprites,ff9 differ
diff --git a/StraySrc/SDLS/!DLLMerge/Makefile,fe1 b/StraySrc/SDLS/!DLLMerge/Makefile,fe1
new file mode 100644 (file)
index 0000000..020bffd
--- /dev/null
@@ -0,0 +1,126 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+#----- Compiling things -----------------------------------------------------
+
+all: !RunImage Sculptrix
+
+DLLM_OBJ = o.dllmerge o.messages o.templates
+DLLM_VER = 1.11
+!RunImage: $(DLLM_OBJ)
+       $(SETDATE) \
+               o.version \
+               version="$(DLLM_VER) ($(DATE))" \
+               cright="$(CRIGHT)"
+       $(LD_APP) $(DLLM_OBJ) o.version libs:embtemp.o.embtemp
+       $(SQUEEZE)
+
+o.messages: rsc.messages
+       msgaof rsc.messages o.messages sh.messages
+
+o.templates: rsc.templates
+       templaof rsc.templates o.templates sh.templates
+
+Sculptrix: <SSR$ModDir>.Sculptrix
+       $(INSTALL) <SSR$ModDir>.Sculptrix @
+
+install:
+
+clean:
+       -$(RM) o.* !RunImage Sculptrix
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.dllmerge: s.dllmerge
+o.dllmerge: libs:header
+o.dllmerge: libs:swis
+o.dllmerge: libs:stream
+o.dllmerge: libs:embTemp.sh.embTemp
+o.dllmerge: sh.templates
+o.dllmerge: sh.messages
diff --git a/StraySrc/SDLS/!DLLMerge/rsc/messages b/StraySrc/SDLS/!DLLMerge/rsc/messages
new file mode 100644 (file)
index 0000000..8a45783
--- /dev/null
@@ -0,0 +1,49 @@
+;
+; rsc.dmMessages
+;
+; DLLMerge messages
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+; --- Menu ---
+
+menuInfo:Info...
+menuQuit:Quit
+
+; --- Info box ---
+
+infoPurpose:Update DLLs resource folders
+
+; --- State messages for dialogue box ---
+
+stateSource:Now drag the new DLLs folder to this window.
+stateGoing:Merging DLLs folders.  Please wait...
+stateDone:DLLs folder updated successfully.
+stateErr:Couldn't update DLLs folder.  Correct the problem and drag the original DLLs folder to this window.
+
+; --- Error messages ---
+
+errNoMem:[1]Not enough memory for DLLMerge to initialise
+errInternal:[2]Internal error: '%0'.  Click OK to continue or Cancel to quit DLLMerge.
+errConfirm:[2]Are you sure you want to quit DLLMerge?
+errNotDLL:[1]'%0' is not a DLLs folder
+errCopy:[1]Error updating DLLs folder: %0
diff --git a/StraySrc/SDLS/!DLLMerge/rsc/templates,fec b/StraySrc/SDLS/!DLLMerge/rsc/templates,fec
new file mode 100644 (file)
index 0000000..ca5aa2d
Binary files /dev/null and b/StraySrc/SDLS/!DLLMerge/rsc/templates,fec differ
diff --git a/StraySrc/SDLS/!DLLMerge/s/dllmerge b/StraySrc/SDLS/!DLLMerge/s/dllmerge
new file mode 100644 (file)
index 0000000..7e01641
--- /dev/null
@@ -0,0 +1,1103 @@
+;
+; dllmerge.s
+;
+; Merge two DLL resources together (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Change history -------------------------------------------------------
+;
+; Version      By      Change
+;
+; 1.00         MDW     Initial version written.
+;
+; 1.01         MDW     Added error handler to stop bombing out on errors.
+;
+; 1.02         MDW     Done copyright and version messages with setdate.
+;
+; 1.03         MDW     Made most SWIs generate errors, and added confirm
+;                      on error handler.
+;
+; 1.04         MDW     Updated dm_setField in line with Sapphire version.
+;
+; 1.05         MDW     Moved menu definition into code area, and copied it
+;                      out at run-time, for the sake of tidiness.  Workspace
+;                      now *exactly* &0900 bytes!
+;
+; 1.06         MDW     Used embedded templates instead of separate file.
+;
+; 1.07         MDW     Fixed problem identifying !DLLs folder link dragged
+;                      from Kysmet -- it was returning &FC0 as the filetype,
+;                      instead of &1000/&2000 as expected.  I now check
+;                      the type with OS_File instead of relying on the
+;                      type in the message.
+;
+; 1.08         MDW     Reduced size of prompt in `merge' template and
+;                      indirected data buffer.  Image now less than 4K.
+;                      Made some other space-saving modifications, although
+;                      I can't reduce the memory requirements to less than
+;                      8K, which is a shame.
+;
+; 1.09         MDW     Changed LDRs to ADRs when finding version and
+;                      copyright strings, now that the linker can handle it.
+;
+; 1.10         MDW     Moved all messages into a separate file so it can
+;                      be easily changed for different countries should the
+;                      need arise.  This is converted to an AOF file and
+;                      linked in during the build.
+;
+; 1.11         MDW     Changed dm_error to base filler strings on `%0' not
+;                      `%1', and updated messages in line with this.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               ; --- Embedded template handling ---
+
+               GET     libs:embTemp.sh.embTemp
+
+               ; --- Linker symbols ---
+
+               IMPORT  |Image$$RW$$Limit|
+
+               ; --- Linked resources ---
+
+               GET     sh.templates
+               GET     sh.messages
+
+               ; --- Generated strings ---
+
+               IMPORT  version
+               IMPORT  cright
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         TWELVE  $string
+               ASSERT  :LEN:"$string"<=12
+               ALIGN
+$label         DCB     "$string"
+               %       12-:LEN:"$string"
+               MEND
+
+;----- Icon numbers ---------------------------------------------------------
+
+dm_INFO_NAME   EQU     7
+dm_INFO_PURPOSE        EQU     5
+dm_INFO_AUTHOR EQU     3
+dm_INFO_VERSION        EQU     1
+
+dm_MERGE_DEST  EQU     2
+dm_MERGE_SOURCE        EQU     3
+dm_MERGE_MSG   EQU     5
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLLMerge$$Code|,CODE,READONLY
+               ENTRY
+
+; --- main ---
+;
+; On entry:    --
+; On exit:     Doesn't
+
+main           ROUT
+
+               BL      dm_init
+               BL      dm_initWimp
+               BL      dm_setHandlers
+returnPoint    BL      dm_poll
+exitPoint      BL      dm_die
+               SWI     OS_Exit
+
+               LTORG
+
+; --- dm_init ---
+;
+; On entry:    --
+; On exit:     R12 and R13 set up, other registers corrupted
+
+dm_init                ROUT
+
+               ; --- Set up application workspace ---
+
+               ADRL    R12,|Image$$RW$$Limit|  ;Find limit of this program
+               SWI     OS_GetEnv               ;Find info about application
+               MOV     R13,R1                  ;Start stack at top of slot
+               SUB     R0,R13,R12              ;Find how mich space I have
+               LDR     R1,=dm_wsize            ;How much do I need?
+               CMP     R0,R1                   ;Do I have enough?
+               ADRLTL  R0,msg_errNoMem         ;No -- point to the error...
+               SWILT   OS_GenerateError        ;... and die
+
+               ; --- Initialise workspace contents ---
+
+               MOV     R0,#0                   ;No flags set yet
+               STR     R0,dm_flags             ;Store that away
+
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- dm_initWimp ---
+;
+; On entry:    --
+; On exit:     Registers corrupted
+
+dm_initWimp    ROUT
+
+               STMFD   R13!,{R14}              ;Keep link register
+
+               ; --- Initialise WindowManager ---
+
+               MOV     R0,#200                 ;WindowManager version
+               LDR     R1,=&4B534154           ;Magic TASK number
+               ADR     R2,dm__name             ;Point to my name
+               SWI     Wimp_Initialise         ;Start up the WIMP
+
+               ; --- Copy the menu over ---
+
+               ADR     R0,dm_menuBk            ;Point to output block
+               ADR     R1,dm_menuDef           ;Point to the definition
+               MOV     R2,#dm_menuSize         ;Get the size too
+00             SUBS    R2,R2,#16               ;I'll do 16 at a time
+               LDMCSIA R1!,{R3-R6}             ;Load some bytes
+               STMCSIA R0!,{R3-R6}             ;Save them out
+               BCS     %b00                    ;If more to do, loop
+               ADD     R2,R2,#16               ;We must have overshot
+00             SUBS    R2,R2,#4                ;Now do one word at a time
+               LDRCS   R14,[R1],#4             ;Load the word
+               STRCS   R14,[R0],#4             ;And store it out
+               BCS     %b00                    ;And loop back again
+
+               ; --- Load required windows ---
+
+               MOV     R1,#0                   ;Not loaded any templates
+
+               ADRL    R0,tpl_progInfo         ;Find the template
+               BL      dm_loadTemplate         ;Load a window
+               STR     R0,dm_infohand          ;Store that away nicely
+               STR     R0,dm_menuBk+28+0*24+4  ;And store as Info... submenu
+
+               ADRL    R0,tpl_merge            ;Point to template name
+               BL      dm_loadTemplate         ;Load a window
+               STR     R0,dm_windhand          ;Store that away nicely
+
+               ; --- Fill in the Info window fields ---
+
+               LDR     R0,dm_infohand
+               MOV     R1,#dm_INFO_NAME
+               ADR     R2,dm__name
+               BL      dm_setField
+               MOV     R1,#dm_INFO_PURPOSE
+               ADRL    R2,msg_infoPurpose
+               BL      dm_setField
+               MOV     R1,#dm_INFO_AUTHOR
+               ADRL    R2,cright
+               BL      dm_setField
+               MOV     R1,#dm_INFO_VERSION
+               ADRL    R2,version
+               BL      dm_setField
+
+               ; --- Open the merge window ---
+
+               ADR     R1,dm_pollbk            ;Point to a work block
+               LDR     R0,dm_windhand          ;Get the window's handle
+               STR     R0,[R1,#0]              ;Store in the block
+               SWI     Wimp_GetWindowState     ;Find the position of window
+               MOV     R2,#-1                  ;Move the window to front
+               STR     R2,[R1,#28]             ;Store in `behind' field
+               SWI     Wimp_OpenWindow         ;Open the window
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+dm__name       DCB     "DLLMerge",0
+
+dm_menuDef     TWELVE  "DLLMerge"
+               DCB     7,2,7,0
+               DCD     16*7+16
+               DCD     44
+               DCD     0
+
+               DCD     &00000000
+               DCD     0
+               DCD     &07000131
+               DCD     msg_menuInfo,-1,1
+
+               DCD     &00000080
+               DCD     -1
+               DCD     &07000131
+               DCD     msg_menuQuit,-1,1
+
+dm_menuSize    EQU     {PC}-dm_menuDef
+
+               LTORG
+
+; --- dm_setHandlers ---
+;
+; On entry:    --
+; On exit:     Registers corrupted
+
+dm_setHandlers ROUT
+
+               ; --- Find somewhere to go on an exception ---
+
+               STR     R13,dm_exceptStack      ;Save this stack pointer away
+
+               ; --- Set up the error handler ---
+
+               STMFD   R13!,{R14}
+               ADR     R11,dm_handlers         ;Point to handler buffer
+
+               MOV     R0,#6                   ;Set up error handler
+               ADR     R1,dm_errors            ;Point to the error handler
+               MOV     R2,R12                  ;Set up the workspace ptr
+               ADR     R3,dm_stacklim          ;Use stack base as error buff
+               SWI     OS_ChangeEnvironment    ;Set up the handler
+               STMIA   R11!,{R1-R3}            ;Save the old information
+
+               ; --- Set up other handlers to quit the program ---
+
+               MOV     R0,#11                  ;Set up exit handler
+               ADR     R1,dm_exits             ;Point to the handler
+               MOV     R2,R12                  ;Point to my workspace
+               MOV     R3,#0                   ;No buffer pointer
+               SWI     OS_ChangeEnvironment    ;Set up the handler
+               STMIA   R11!,{R1-R3}            ;Save the old information
+
+               MOV     R0,#16                  ;Set up UpCall handler
+               ADR     R1,dm_upcalls           ;Point to the handler
+               MOV     R2,R12                  ;Point to my workspace
+               MOV     R3,#0                   ;No buffer pointer
+               SWI     OS_ChangeEnvironment    ;Set up the handler
+               STMIA   R11!,{R1-R3}            ;Save the old information
+
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- dm_killHandlers ---
+;
+; On entry:    --
+; On exit:     Registers preserved
+
+dm_killHandlers        ROUT
+
+               STMFD   R13!,{R0-R3,R11,R14}    ;Save registers
+
+               ADR     R11,dm_handlers         ;Point to handlers buffer
+
+               MOV     R0,#6
+               LDMIA   R11!,{R1-R3}
+               SWI     XOS_ChangeEnvironment
+
+               MOV     R0,#11
+               LDMIA   R11!,{R1-R3}
+               SWI     XOS_ChangeEnvironment
+
+               MOV     R0,#16
+               LDMIA   R11!,{R1-R3}
+               SWI     XOS_ChangeEnvironment
+
+               LDMFD   R13!,{R0-R3,R11,PC}^    ;Return to caller
+
+               LTORG
+
+; --- dm_errors ---
+;
+; On entry:    R0 == pointer to my workspace
+; On exit:     Doesn't -- goes back to main loop at appropriate point
+
+dm_errors      ROUT
+
+               ; --- Reset stack and workspace pointers ---
+
+               MOV     R12,R0                  ;Point to my workspace
+               LDR     R13,dm_exceptStack      ;Restore my stack pointer
+
+               ; --- Is this a double exception? ---
+
+               LDR     R0,dm_flags             ;Get my flags
+               TST     R0,#dm_ERROR            ;Is this a repeated error?
+               BNE     %00dm_errors            ;Yes -- handle this specially
+
+               ; --- Mark that we're in the error handler ---
+
+               ORR     R0,R0,#dm_ERROR         ;Say we're in the handler
+               STR     R0,dm_flags             ;Store this in the flags
+
+               ; --- Report the error and give a chance to quit ---
+
+               ADRL    R1,dm_stacklim+8        ;Point to main error message
+               ADRL    R0,msg_errInternal      ;Point to error skeleton
+               BL      dm_error                ;Construct a message
+               MOV     R1,#&00000003           ;Provide OK and Cancel boxes
+               ADR     R2,dm__name             ;Point to my name
+               SWI     Wimp_ReportError        ;Report the error
+               CMP     R1,#1                   ;Was OK clicked?
+               BEQ     %01dm_errors            ;Yes -- return to main loop
+
+               ADRL    R0,msg_errConfirm       ;Point to the confirm message
+               MOV     R1,#3                   ;OK and Cancel buttons again
+               ADR     R2,dm__name             ;Point to my name
+               SWI     Wimp_ReportError        ;Display the question
+               CMP     R1,#1                   ;Was OK clicked?
+               BEQ     %01dm_errors            ;Yes -- return to main loop
+
+               B       exitPoint               ;Commit hari-kiri then
+
+               ; --- We can continue ---
+
+01dm_errors    LDR     R0,dm_flags             ;Get my flags
+               BIC     R0,R0,#dm_ERROR         ;There's no error any more
+               STR     R0,dm_flags             ;Store the flags away
+               B       returnPoint             ;Go back into the top level
+
+00dm_errors    BL      dm_killHandlers         ;Restore all the handlers
+               ADRL    R0,dm_stacklim+4        ;Point to the error buffer
+               SWI     OS_GenerateError        ;Let the OS handle it all
+
+               LTORG
+
+; --- dm_exits ---
+;
+; On entry:    --
+; On exit:     Doesn't -- branches to main loop
+
+dm_exits       LDR     R13,dm_exceptStack      ;Get my stack pointer
+               B       exitPoint               ;Close down the application
+
+; --- dm_upcalls ---
+;
+; On entry:    R0 == UpCall type
+; On exit:     Varies
+
+dm_upcalls     CMP     R0,#256                 ;Is a new app starting?
+               MOVNES  PC,R14                  ;No -- return to caller
+
+                ; --- Hopefully this will never happen :-) ---
+
+               MOVS    PC,R14                  ;Return to caller and hope
+
+; --- dm_die ---
+;
+; On entry:    --
+; On exit:     Registers corrupted
+
+dm_die         ROUT
+
+               STMFD   R13!,{R14}
+               BL      dm_killHandlers         ;Get rid of any handlers
+               SWI     Wimp_CloseDown          ;Stop being a Wimp task
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- dm_poll ---
+;
+; On entry:    --
+; On exit:     Registers corrupted
+
+dm_poll                ROUT
+
+               STMFD   R13!,{R14}              ;Keep return address
+
+               ; --- Find out if we need continue ---
+
+00dm_poll      LDR     R0,dm_flags             ;Get the flags word
+               TST     R0,#dm_QUIT             ;Check the quit bit
+               LDMNEFD R13!,{PC}^              ;Return if it failed
+
+               ; --- Get an event and dispatch it ---
+
+               AND     R0,R0,#dm_SOURCE :OR: dm_DONE ;What's my status?
+               CMP     R0,#dm_SOURCE           ;If not complete...
+               MOVEQ   R0,#0                   ;... wait for an idle event
+               MOVNE   R0,#1                   ;Otherwise, ignore idles
+               ADR     R1,dm_pollbk            ;Point to the big block
+               SWI     Wimp_Poll               ;Get an event
+
+               CMP     R0,#19                  ;Check the event is sensible
+               MOV     R14,PC                  ;Set up return address
+               ADDLS   PC,PC,R0,LSL #2         ;If so, go to branch table
+               B       %00dm_poll              ;Silly event -- ignore it
+
+               ; --- Event dispatching table ---
+
+               B       dm_null                 ;Null_Reason_Code
+               B       dm_redraw               ;Redraw_Window_Request
+               B       dm_open                 ;Open_Window_Request
+               B       dm_close                ;Close_Window_Request
+               MOVS    PC,R14                  ;Pointer_Leaving_Window
+               MOVS    PC,R14                  ;Pointer_Entering_Window
+               B       dm_click                ;Mouse_Clicked
+               MOVS    PC,R14                  ;User_Drag_Box
+               MOVS    PC,R14                  ;Key_Pressed
+               B       dm_menu                 ;Menu_Selection
+               MOVS    PC,R14                  ;10
+               MOVS    PC,R14                  ;11
+               MOVS    PC,R14                  ;12
+               MOVS    PC,R14                  ;13
+               MOVS    PC,R14                  ;14
+               MOVS    PC,R14                  ;15
+               MOVS    PC,R14                  ;16
+               B       dm_message              ;User_Message
+               B       dm_message              ;User_Message_Recorded
+               MOVS    PC,R14                  ;User_Message_Acknowledge
+
+               LTORG
+
+;----- Event handlers -------------------------------------------------------
+
+; --- Null_Reason_Code ---
+;
+; We copy the source to the destination
+
+dm_null                ROUT
+
+               STMFD   R13!,{R14}              ;Stack the link register
+               MOV     R0,#26                  ;We want to do a copy
+               ADR     R1,dm_source            ;Point to source app
+               ADR     R2,dm_dest              ;Point to destination app
+               LDR     R3,=&00005003           ;Copy options
+               SWI     XOS_FSControl           ;Do the copy operation
+               BVS     %00dm_null              ;If it failed, display msg
+
+               ; --- Update the DLL$Path variable ---
+
+               MOV     R0,R2                   ;Point to destination name
+               SWI     Wimp_StartTask          ;Run its !Run file
+
+               ; --- Put the text into the message field ---
+
+               LDR     R0,dm_windhand          ;Get the window handle
+               MOV     R1,#dm_MERGE_MSG        ;Get the icon handle
+               ADRL    R2,msg_stateDone        ;Point to message
+               BL      dm_setField             ;Write the text in
+
+               ; --- Update the flags and quit ---
+
+               LDR     R0,dm_flags             ;Get the flags word
+               ORR     R0,R0,#dm_DONE          ;We've finished
+               STR     R0,dm_flags             ;Write the flags back
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               ; --- It failed.  Report an error and start again ---
+
+00dm_null      ADD     R1,R0,#4                ;Point to the message
+               ADRL    R0,msg_errCopy          ;Point to the error skeleton
+               BL      dm_error                ;Fill it in
+               MOV     R1,#1                   ;Only have an OK box
+               ADR     R2,dm__name             ;Point to my name
+               SWI     Wimp_ReportError        ;Make an error
+
+               LDR     R0,dm_windhand          ;Get the window handle
+               MOV     R1,#dm_MERGE_DEST       ;Get the icon handle
+               ADR     R2,dm__empty            ;Point to message
+               BL      dm_setField             ;Write the text in
+               MOV     R1,#dm_MERGE_SOURCE     ;Get the icon handle
+               BL      dm_setField             ;Write the text in
+               MOV     R1,#dm_MERGE_MSG        ;Get the icon handle
+               ADRL    R2,msg_stateErr         ;Point to message
+               BL      dm_setField             ;Write the text in
+
+               MOV     R0,#0                   ;Clear all the flags
+               STR     R0,dm_flags             ;Store them away
+
+               LDMFD   R13!,{PC}^
+
+dm__empty      DCB     0
+
+               LTORG
+
+; --- Redraw_Window_Request ---
+;
+; We just bundle the redraw event off to Sculptrix and forget about it
+
+dm_redraw      ROUT
+
+               SWI     Wimp_RedrawWindow
+00dm_redraw    CMP     R0,#0
+               MOVEQS  PC,R14
+               SWI     XSculptrix_RedrawWindow
+               SWI     Wimp_GetRectangle
+               B       %00dm_redraw
+
+               LTORG
+
+; --- Open_Window_Request ---
+;
+; Just open the window.  Nothing could be easier ---
+
+dm_open                ROUT
+
+               SWI     Wimp_OpenWindow
+               MOVS    PC,R14
+
+               LTORG
+
+; --- Close_Window_Request ---
+;
+; We close down the application.
+
+dm_close       ROUT
+
+               LDR     R0,dm_flags
+               ORR     R0,R0,#dm_QUIT
+               STR     R0,dm_flags
+               MOVS    PC,R14
+
+               LTORG
+
+; --- Mouse_Clicked ---
+;
+; If it's the Info window, we start moving it about.  If it's the Merge
+; window, we open a menu
+
+dm_click       ROUT
+
+               LDR     R0,[R1,#12]             ;Get the window handle
+               LDR     R2,dm_windhand          ;Is it the Merge window?
+               CMP     R0,R2                   ;Find out
+               BEQ     %10dm_click             ;If so, handle it there
+               LDR     R2,dm_infohand          ;It may be the Info window
+               CMP     R0,R2                   ;So check
+               BEQ     %20dm_click             ;If so, handle it
+               MOVS    PC,R14                  ;Not recognised -- ignore it
+
+               ; --- Handle a click on the Merge window ---
+
+10dm_click     LDR     R0,[R1,#8]              ;Get the button status
+               TST     R0,#2                   ;Check the menu button bit
+               MOVEQS  PC,R14                  ;If not, return
+
+               LDMIA   R1,{R2,R3}              ;Get coordinates from block
+               SUB     R2,R2,#64               ;Displace the menu
+               ADR     R1,dm_menuBk            ;Point to the menu defn
+               SWI     Wimp_CreateMenu         ;Display the menu
+               MOVS    PC,R14                  ;Return to caller
+
+               ; --- Handle a click on the Info window ---
+
+20dm_click     LDR     R0,[R1,#8]              ;Get the button status
+               TST     R0,#5                   ;Check for Select or Adjust
+               MOVEQS  PC,R14                  ;If not, return
+
+               SUB     R13,R13,#56             ;Make a drag info block
+               LDR     R0,dm_infohand          ;Get the Info window handle
+               STR     R0,[R13,#0]             ;Store the window handle
+               MOV     R0,#1                   ;Move the window
+               STR     R0,[R13,#4]             ;Store the drag type
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_DragBox            ;Start the window moving
+               ADD     R13,R13,#56             ;Reclaim the stack space
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- Menu_Selection ---
+;
+; If it's Info, open the Info box.  If it's Quit, then quit.
+
+dm_menu                ROUT
+
+               LDR     R0,[R1,#0]              ;Get toplevel selection
+               CMP     R0,#0                   ;Is it `Info...'?
+               BEQ     %10dm_menu              ;Yes -- process it
+               CMP     R0,#1                   ;Is it `Quit'?
+               BEQ     dm_close                ;Yes -- quit the program
+               MOVS    PC,R14                  ;Return to caller
+
+               ; --- Open the Info... window ---
+
+10dm_menu      SUB     R13,R13,#36             ;Get some workspace
+               MOV     R1,R13                  ;Point to this new block
+               SWI     Wimp_GetPointerInfo     ;Where is the mouse now?
+               LDMIA   R1,{R2,R3}              ;Get the mouse coordinates
+               LDR     R0,dm_infohand          ;Get the window handle
+               STR     R0,[R1,#0]              ;Store the window handle
+               SWI     Wimp_GetWindowState     ;Get the window's information
+               LDMIA   R1,{R1,R4-R7}           ;Get the window positions
+               SUB     R4,R6,R4                ;Get the window width
+               SUB     R5,R7,R5                ;And the window height
+               SUB     R2,R2,R4,LSR #1         ;Centre window over X
+               ADD     R3,R3,R5,LSR #1         ;Centre window over Y
+               ADD     R13,R13,#36             ;Reclaim the stack space
+               SWI     Wimp_CreateMenu         ;Display the Info window
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- User_Message and User_Message_Recorded ---
+;
+; Handle Quit messages, and files dropped on the window
+
+dm_message     ROUT
+
+               LDR     R0,[R1,#16]             ;Get message type
+               CMP     R0,#0                   ;Is it a Message_Quit?
+               BEQ     dm_close                ;This has the code for quit
+               CMP     R0,#3                   ;Is it a load message?
+               BEQ     %10dm_message           ;Yes -- deal with it
+               MOVS    PC,R14                  ;If not interested, return
+
+               ; --- Someone dropped a file on my window ---
+
+10dm_message   LDR     R0,[R1,#20]             ;Where was the file dropped?
+               LDR     R11,dm_windhand         ;Get my window handle
+               CMP     R0,R11                  ;Do they match?
+               MOVNES  PC,R14                  ;No -- ignore it
+
+               ; --- Check what to do with it ---
+
+               LDR     R10,dm_flags            ;Get my flags word
+               TST     R10,#dm_SOURCE          ;Have I finished?
+               MOVNES  PC,R14                  ;Yes -- not interested then
+
+               ; --- Got to do something now ---
+
+               STMFD   R13!,{R14}              ;Stack link register now
+               BL      dm_checkFile            ;Make sure it's a !DLLs
+               CMP     R0,#0                   ;Did it fail?
+               LDMEQFD R13!,{PC}^              ;Yes -- return to poll loop
+
+               ; --- Which filename do I fill in? ---
+
+               TST     R10,#dm_DEST            ;Have I got one filename?
+               BNE     %20dm_message           ;Yes -- fill in the other
+
+               ; --- Fill in the first filename ---
+
+               ADD     R1,R1,#44               ;Point to filename
+               ADR     R0,dm_dest              ;That's the destination file
+               BL      dm_strcpy               ;Copy it across
+               MOV     R2,R1                   ;Point to name again
+               MOV     R1,#dm_MERGE_DEST+(1<<31)
+               MOV     R0,R11                  ;And set up the window handle
+               BL      dm_setField             ;Fill that icon in
+
+               ; --- Now display a new message ---
+
+               ADRL    R2,msg_stateSource      ;Point to the new message
+               MOV     R1,#dm_MERGE_MSG        ;Put it in the message icon
+               BL      dm_setField             ;Fill that icon in
+
+               ORR     R10,R10,#dm_DEST        ;Remember we've got a name
+               STR     R10,dm_flags            ;Store the new flags away
+               B       %30dm_message           ;Reply to the message now
+
+               ; --- Fill in the second filename ---
+
+20dm_message   ADD     R1,R1,#44               ;Point to filename
+               ADR     R0,dm_source            ;That's the source file
+               BL      dm_strcpy               ;Copy it across
+               MOV     R2,R1                   ;Point to name again
+               MOV     R1,#dm_MERGE_SOURCE+(1<<31)
+               MOV     R0,R11                  ;And set up the window handle
+               BL      dm_setField             ;Fill that icon in
+
+               ; --- Now display a new message ---
+
+               ADRL    R2,msg_stateGoing       ;Point to the new message
+               MOV     R1,#dm_MERGE_MSG        ;Put it in the message icon
+               BL      dm_setField             ;Fill that icon in
+               ORR     R10,R10,#dm_SOURCE      ;Remember we've got a name
+               STR     R10,dm_flags            ;Store the new flags away
+
+               ; --- Reply to the message in the block ---
+
+30dm_message   ADR     R1,dm_pollbk            ;Point to the message
+               LDR     R0,[R1,#8]              ;Get his reference
+               STR     R0,[R1,#12]             ;Store as his reference
+               MOV     R0,#4                   ;This is an acknowledgement
+               STR     R0,[R1,#16]             ;Store as the message type
+               MOV     R0,#17                  ;Don't bother recording it
+               LDR     R2,[R1,#4]              ;Get his task handle
+               SWI     Wimp_SendMessage        ;Reply to his message now
+               LDMFD   R13!,{PC}^              ;Return to the caller
+
+               LTORG
+
+;----- Support routines -----------------------------------------------------
+
+; --- dm_setField ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;              R2 == string to write
+; On exit:     Everything preserved unless there was an error
+
+dm_setField    ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Stash registers away
+
+               ; --- Find out about the icon ---
+
+               AND     R4,R1,#&FF000000        ;Get the flag bits out
+               BIC     R1,R1,#&FF000000        ;Leave just the icon number
+               SUB     R13,R13,#40             ;Make space for icon block
+               STMIA   R13,{R0,R1}             ;Store the info in it
+               MOV     R1,R13                  ;Point to the icon block
+               SWI     Wimp_GetIconState       ;Get the icon's information
+
+               ; --- Make sure we can change the text ---
+
+               LDR     R1,[R13,#24]            ;Get the icon's flags
+
+               ; --- Now find how much we actually have to copy ---
+
+               LDR     R5,[R13,#36]            ;Get the buffer length
+               SUB     R5,R5,#1                ;Take terminator into account
+               MOV     R0,R2                   ;Point to the string to copy
+               BL      dm_strlen               ;Find out how long it is
+               SUBS    R0,R0,R5                ;Find out the difference
+               BICLE   R4,R4,#(1<<31)          ;If it fits, don't add dots
+               BLE     %00dm_setField          ;And skip ahead
+               TST     R1,#1<<9                ;Is it right aligned?
+               ADDNE   R2,R2,R0                ;Yes, chop off front
+               ORRNE   R4,R4,#1                ;And set a flag to remember
+
+               ; --- Copy the text into the buffer ---
+
+00dm_setField  LDR     R0,[R13,#28]            ;Find the buffer address
+               MOV     R3,#0                   ;Count the length too
+
+10dm_setField  CMP     R5,R3                   ;How much space left in buff?
+               MOVLE   R1,#0                   ;None -- pretend null char
+               LDRGTB  R1,[R2],#1              ;Get a byte from the string
+               CMP     R1,#' '                 ;Is it a control char?
+               MOVLO   R1,#0                   ;Yes -- say it's a zero
+               BLO     %15dm_setField          ;And don't bother with dots
+
+               ; --- Handle ellipsis generation ---
+
+               TST     R4,#(1<<31)             ;Do we put the ellipsis in?
+               BEQ     %15dm_setField          ;No -- skip ahead then
+               TST     R4,#1                   ;Are we right-justified?
+               ADDNE   R14,R3,#1               ;Yes -- just get the length
+               SUBEQ   R14,R5,R3               ;Otherwise find what's left
+               CMP     R14,#4                  ;Are we within three?
+               MOVLO   R1,#'.'                 ;Yes -- put in a dot then
+
+               ; --- Return to normality ---
+
+15dm_setField  LDRB    R14,[R0],#1             ;Get one from the buffer
+               CMP     R14,#' '                ;Same for the buffer char
+               MOVLO   R14,#0
+
+               CMP     R1,R14                  ;Are they different
+               ORRNE   R4,R4,#2                ;Yes -- remember this
+               STRNEB  R1,[R0,#-1]             ;And store the different char
+
+               CMP     R1,#0                   ;Is that end of the string?
+               ADDNE   R3,R3,#1                ;No -- bump the length on
+               BNE     %10dm_setField          ;And go round for another
+
+               ; --- We've copied the string -- now update the icon ---
+
+               TST     R4,#2                   ;Is the string different?
+               BEQ     %20dm_setField          ;No -- skip ahead
+
+               MOV     R1,#0
+               STR     R1,[R13,#8]             ;The EOR mask for setstate
+               STR     R1,[R13,#12]            ;The BIC mask for setstate
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_SetIconState       ;Flicker the icon nastily
+
+               ; --- Now check for the caret ---
+
+               SWI     Wimp_GetCaretPosition   ;Find out where the caret is
+               LDMIA   R13,{R2,R4}             ;Get the window and icon
+               ADD     R0,R13,#40              ;Point past this block
+               LDMIA   R0,{R0,R1}              ;Get the old window and icon
+               CMP     R0,R2                   ;Do the window handles match?
+               CMPEQ   R1,R4                   ;And the icon handles?
+               BNE     %20dm_setField          ;No -- skip ahead
+
+               ; --- Push the caret back a little ---
+
+               LDR     R5,[R13,#20]            ;Get the caret index
+               CMP     R5,R3                   ;Is this bigger than new len?
+               MOVGT   R5,R3                   ;Yes -- trim the index
+
+               ; --- Now put the caret in the right place ---
+
+               MOV     R2,#-1                  ;Don't set the x coord
+               MOV     R3,#-1                  ;Don't set the y coord
+               MOV     R4,#-1                  ;Don't set the height
+               SWI     Wimp_SetCaretPosition   ;Put the caret in its place
+
+               ; --- Return nicely ---
+
+20dm_setField  ADD     R13,R13,#40             ;Reclaim that temporary space
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+               LTORG
+
+; --- dm_checkFile ---
+;
+; On entry:    R1 == pointer to message block
+; On exit:     R0 == 0 if it *wasn't* a DLL folder
+
+dm_checkFile   ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Stack registers
+
+               ; --- Ensure it's a directory ---
+               ;
+               ; Kysmet seems to ignore the fact that it might be an image
+               ; and returns &FC0 for links, instead of &1000/&2000 which
+               ; the Filer gives you.  So we examine the file using OS_File
+               ; and check bit 1 of the object type from that.
+
+               ADD     R1,R1,#44               ;Find the name
+               MOV     R0,#17                  ;Try to read information
+               SWI     XOS_File                ;Read the file information
+               MOVVS   R0,#0                   ;Say not there if it failed
+               TST     R0,#2                   ;Is it a directory?
+               BEQ     %10dm_checkFile         ;No -- then complain
+
+               ; --- Now find the leafname ---
+
+               MOV     R0,R1                   ;Keep pointer to name
+01dm_checkFile LDRB    R14,[R1],#1             ;Get a character
+               CMP     R14,#'.'                ;Is it a dot?
+               MOVEQ   R0,R1                   ;Yes -- this it the leafname
+               CMP     R14,#' '                ;Is it the end?
+               BGE     %01dm_checkFile         ;No -- go round again
+
+               ; --- Compare this to what it should be ---
+
+               ADR     R1,dm__dlls             ;Point to the ideal one
+               MOV     R2,#0                   ;Not case-sensitive
+               BL      dm_strcmp               ;Is it a match?
+               BNE     %10dm_checkFile         ;No -- be unhappy
+
+               MOV     R0,#1                   ;It was a real !DLLs resource
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to caller
+
+10dm_checkFile ADRL    R0,msg_errNotDLL        ;Point to error message
+               LDR     R1,[R13,#0]             ;Get the message pointer
+               ADD     R1,R1,#44               ;Find the name string
+               BL      dm_error                ;Fill in the error
+               MOV     R1,#1                   ;Just an OK box please
+               ADRL    R2,dm__name             ;Point to my name
+               SWI     Wimp_ReportError        ;Report the error
+               MOV     R0,#0                   ;It wasn't a real one
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to caller
+
+dm__dlls       DCB     "!DLLs",0
+
+               LTORG
+
+; --- dm_loadTemplate ---
+;
+; On entry:    R0 == pointer to template
+;              R1 == 0 on first call, or R1 from previous
+; On exit:     R0 == window handle
+;              R1 == a new magic number
+
+dm_loadTemplate        ROUT
+
+               STMFD   R13!,{R2-R5,R14}        ;Stack registers
+
+               ; --- Set up indirected data pointer ---
+
+               CMP     R1,#0                   ;Is this the first call?
+               ADREQL  R2,dm_indspace          ;Yes -- point to buff start
+               MOVNE   R2,R1                   ;Set up indirected data ptr
+
+               ; --- Load template into buffer ---
+
+               ADRL    R3,dm_eindspace         ;Point to buff end
+               ADR     R1,dm_pollbk            ;Point to poll block
+               MOV     R4,#1                   ;Use the Wimp sprite area
+               MOV     R5,#1                   ;I really mean that
+               BL      embTemp_extract         ;Extract the template
+
+               ; --- Create the window and return ---
+
+               SWI     Wimp_CreateWindow       ;Create the window
+               MOV     R1,R2                   ;Get magic number to return
+               LDMFD   R13!,{R2-R5,PC}^        ;Return to caller
+
+               LTORG
+
+; --- dm_strlen ---
+;
+; On entry:    R0 == pointer to string
+; On exit:     R0 == length of string
+
+dm_strlen      ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               MOV     R1,#0                   ;Start the counter nicely
+00dm_strlen    LDRB    R14,[R0],#1             ;Load a byte from the string
+               ADD     R1,R1,#1                ;Bump on the counter
+               CMP     R14,#32                 ;Is it the end?
+               BHS     %00dm_strlen            ;No -- go round again then
+               SUB     R0,R1,#1                ;Return count of actual chars
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- dm_strcpy ---
+;
+; On entry:    R0 == destination string
+;              R1 == source string
+; On exit:     R0 == pointer to terminator of destination
+
+dm_strcpy      ROUT
+
+               STMFD   R13!,{R1,R14}           ;Keep return address safe
+00dm_strcpy    LDRB    R14,[R1],#1             ;Get a byte from source
+               CMP     R14,#' '                ;Is it a control character
+               MOVLT   R14,#0                  ;Yes -- translate to a 0
+               STRB    R14,[R0],#1             ;Store in destination
+               BGE     %00dm_strcpy            ;No -- copy another byte
+               SUB     R0,R0,#1                ;Point back at terminator
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- dm_strcmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;              R2 == 0 => case insensitive, 1 => case sensitive
+;
+; On exit:     Flags as appropriate
+
+dm_strcmp      ROUT
+
+               STMFD   R13!,{R0,R1,R3,R4,R14}
+00dm_strcmp    LDRB    R3,[R0],#1              ;Get a character from A
+               LDRB    R4,[R1],#1              ;And one from B
+
+               CMP     R2,#0                   ;Do we want to do case xlate?
+               BNE     %10dm_strcmp            ;No -- miss it out then
+
+               SUB     R14,R3,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R3,R3,#&20              ;Yes -- convert to upper
+               SUB     R14,R4,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R4,R4,#&20              ;Yes -- convert to upper
+
+10dm_strcmp    CMP     R3,#&20                 ;Is that the end of A?
+               MOVLO   R3,#0                   ;Yes -- pretend it's null
+               CMP     R4,#&20                 ;Is that the end of B?
+               MOVLO   R4,#0                   ;Yes -- pretend it's null
+
+               CMP     R3,R4                   ;How do they match up?
+               LDMNEFD R13!,{R0,R1,R3,R4,PC}   ;If NE, return condition
+               CMP     R3,#0                   ;Is this the end?
+               BNE     %00dm_strcmp            ;No -- loop again
+               LDMFD   R13!,{R0,R1,R3,R4,PC}   ;Return to caller
+
+               LTORG
+
+; --- dm_error ---
+;
+; On entry:    R0 == Pointer to error message skeleton
+;              R1 == Filler 1
+;              R2 == Filler 2
+;              R3 == Filler 3
+;              R4 == Filler 4
+; On exit:     R0 == Pointer to constructed error in dm_errorbuf
+
+               EXPORT  dm_error
+dm_error       ROUT
+
+               STMFD   R13!,{R1-R6,R14}
+               ADR     R5,dm_pollbk            ;Point to error buffer
+               LDR     R14,[R0],#4             ;Read the error's number
+               STR     R14,[R5],#4             ;And store in the new buffer
+
+00dm_error     LDRB    R14,[R0],#1             ;Get an input character
+               CMP     R14,#'%'                ;Is it a '%' sign?
+               BEQ     %01dm_error             ;Yes -- deal with it
+02dm_error     STRB    R14,[R5],#1             ;Not special, so store it
+               CMP     R14,#0                  ;Is it the end of input?
+               BNE     %00dm_error             ;No -- get another one
+               ADR     R0,dm_pollbk            ;Point to error start
+               LDMFD   R13!,{R1-R6,PC}^        ;And return to caller
+
+01dm_error     LDRB    R14,[R0],#1             ;Get the next character
+               SUB     R14,R14,#'0'            ;Convert to binary (0..3)
+               CMP     R14,#4                  ;Is it in range?
+               BCS     %02dm_error             ;No -- just ignore the '%'
+               LDR     R6,[R13,R14,LSL #2]     ;Load appropriate register
+
+03dm_error     LDRB    R14,[R6],#1             ;Get an input byte
+               CMP     R14,#&20                ;Is it the end of the string?
+               BLT     %00dm_error             ;Yes -- read main string
+               STRB    R14,[R5],#1             ;No -- store it in output
+               B       %03dm_error             ;... and get another one
+
+               LTORG
+
+;----- Workspace layout -----------------------------------------------------
+
+               ^       0,R12
+
+dm_wstart      #       0
+
+dm_exceptStack #       4
+
+dm_windhand    #       4
+dm_infohand    #       4
+
+dm_flags       #       4
+
+dm_handlers    #       36
+
+dm_menuBk      #       dm_menuSize
+
+dm_QUIT                EQU     1<<0
+dm_DEST                EQU     1<<1
+dm_SOURCE      EQU     1<<2
+dm_DONE                EQU     1<<3
+dm_ERROR       EQU     1<<4
+
+dm_pollbk      #       256
+dm_dest                #       256
+dm_source      #       256
+
+dm_indspace    #       384
+dm_eindspace   #       0
+
+dm_stacklim    #       288
+
+dm_wend                #       0
+
+dm_wsize       EQU     dm_wend-dm_wstart
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/SDLS/!DLLMerge/sh/messages b/StraySrc/SDLS/!DLLMerge/sh/messages
new file mode 100644 (file)
index 0000000..6e1c2c5
--- /dev/null
@@ -0,0 +1,23 @@
+;
+; Message symbols [generated by msgAOF]
+;
+
+               [       :LNOT::DEF:msg__dfn
+               GBLL    msg__dfn
+
+               IMPORT  msg_menuInfo
+               IMPORT  msg_menuQuit
+               IMPORT  msg_infoPurpose
+               IMPORT  msg_stateSource
+               IMPORT  msg_stateGoing
+               IMPORT  msg_stateDone
+               IMPORT  msg_stateErr
+               IMPORT  msg_errNoMem
+               IMPORT  msg_errInternal
+               IMPORT  msg_errConfirm
+               IMPORT  msg_errNotDLL
+               IMPORT  msg_errCopy
+
+               ]
+
+               END
diff --git a/StraySrc/SDLS/!DLLMerge/sh/templates b/StraySrc/SDLS/!DLLMerge/sh/templates
new file mode 100644 (file)
index 0000000..7f4c1e7
--- /dev/null
@@ -0,0 +1,13 @@
+;
+; Template symbols [generated by templAOF]
+;
+
+               [       :LNOT::DEF:tpl__dfn
+               GBLL    tpl__dfn
+
+               IMPORT  tpl_merge
+               IMPORT  tpl_progInfo
+
+               ]
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/Makefile,fe1 b/StraySrc/SDLS/DLLManager/Makefile,fe1
new file mode 100644 (file)
index 0000000..b61c1a9
--- /dev/null
@@ -0,0 +1,171 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+OBJS = \
+       o.dheader \
+       o.app o.dll o.misc o.suballoc \
+       o.messages
+
+VERSION = 1.14
+
+#----- Compiling things -----------------------------------------------------
+
+all: DLLManager dllmdump
+
+DLLManager: $(OBJS)
+       $(SETDATE) \
+               o.version \
+               hdr_help="DLLManager\t$(VERSION) ($(MODDATE)) $(CRIGHT)"
+       $(LD_MOD) $(OBJS) o.version
+       $(SET_MOD)
+
+o.messages: rsc.messages
+       msgaof rsc.messages o.messages sh.messages
+
+dllmdump: o.dllmdump
+       $(LD_UTIL) o.dllmdump
+       $(SET_UTIL)
+
+install: DLLManager
+       $(INSTALL) DLLManager <SSR$DLLDir>
+       $(INSTALL) dllmdump <SSR$BinDir>
+
+clean:
+       -$(RM) o.* DLLManager
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.dheader: s.dheader
+o.dheader: libs:header
+o.dheader: libs:swis
+o.dheader: sh.wSpace
+o.dheader: sh.misc
+o.dheader: sh.dll
+o.dheader: sh.app
+o.dheader: sh.suballoc
+o.dheader: sh.messages
+o.app: s.app
+o.app: libs:header
+o.app: libs:swis
+o.app: libs:stream
+o.app: sh.wSpace
+o.app: sh.appblock
+o.app: sh.linkblock
+o.app: sh.dllblock
+o.app: sh.misc
+o.app: sh.suballoc
+o.app: sh.dll
+o.app: sh.messages
+o.dll: s.dll
+o.dll: libs:header
+o.dll: libs:swis
+o.dll: libs:stream
+o.dll: sh.wSpace
+o.dll: sh.dllblock
+o.dll: sh.linkblock
+o.dll: sh.misc
+o.dll: sh.app
+o.dll: sh.messages
+o.misc: s.misc
+o.misc: libs:header
+o.misc: libs:swis
+o.misc: sh.wSpace
+o.misc: sh.messages
+o.suballoc: s.suballoc
+o.suballoc: libs:swis
+o.suballoc: libs:header
+o.suballoc: sh.wSpace
+o.suballoc: sh.linkblock
+o.dllmdump: s.dllmdump
+o.dllmdump: libs:header
+o.dllmdump: libs:swis
+o.dllmdump: sh.dllblock
+o.dllmdump: sh.appblock
+o.dllmdump: sh.linkblock
+o.dllmdump: sh.wspace
diff --git a/StraySrc/SDLS/DLLManager/rsc/messages b/StraySrc/SDLS/DLLManager/rsc/messages
new file mode 100644 (file)
index 0000000..17ecd23
--- /dev/null
@@ -0,0 +1,141 @@
+;
+; rsc.messages
+;
+; DLLManager messages
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Error messages -------------------------------------------------------
+
+; --- Various strange errors ---
+
+errDivide:[1]Internal error in DLLManager: divide by zero
+errNoEntry:[1]DLL '%0' has no entry points
+errNoNames:[1]DLL '%0' has an omitted name table
+errBadVersion:[1]Malformed version number passed to DLLEnsure
+errInUse:[1]DLLManager is in use and cannot die
+
+; --- Odd errors with other people's error numbers ---
+
+errFileNotFound:[&D6]Dynamic Link Library '%0' not found
+
+errBadSWI:[&1E6]Unknown DLLManager operation
+
+errNoCLib:[&800E90]DLLManager requires the SharedCLibrary module
+errOldCLib:[&800E91]SharedCLibrary too old for DLLManager
+
+; --- Our own error messages ---
+
+errAppNotFound:[&80D303]Application '%0' not found
+errAppNoEntry:[&80D304]Application does not contain external entry points
+errDLLNotInMem:[&80D305]DLL '%0' not found
+errDLLNoMem:[&80D306]No memory for Dynamic Link Library
+errStackOvf:[&80D307]DLL stack overflow
+errUnknownApp:[&80D308]Application not registered with DLLManager
+errLinkNotFound:[&80D309]Couldn't find app/dll link
+errDLLNotFound:[&80D30A]DLL '%0' version %1 not found
+errNotADLL:[&80D30B]File '%0' is not a Dynamic Link Library
+errTooNew:[&80D30C]DLL '%0' has an unrecognised version number
+errDLLTooOld:[&80D30D]DLL '%0' is too old (version %1 required)
+errAppEntry:[&80D30E]Application does not support entry point %0
+errDLLEntry:[&80D30F]DLL '%0' does not support entry point %1
+errNotShared:[&80D311]DLL '%0' is not shared
+
+;----- Other messages -------------------------------------------------------
+
+appName:|<Untitled>
+
+;----- Messages for *command output -----------------------------------------
+
+; --- *DLLs ---
+
+noDLLsForApp:No DLLs registered for application<&0D><&0A>
+dllHeader:Name            Version  Author<&0D><&0A>
+noDLLs:No DLLs loaded<&0D><&0A>
+
+; --- *DLLApps ---
+
+appHeader:App name   DLL version<&0D><&0A>
+noAppsForDLL:No applications found using DLL '%0'<&0D><&0A>
+noApps:No applications registered<&0D><&0A>
+
+; --- *DLLInfo ---
+
+dinfoName:Name:<&20>
+dinfoAuthor:Author:<&20>
+dinfoVersion:Version:<&20>
+dinfoReferences:References:<&20>
+dinfoEntries:Entry points:<&0D><&0A>
+dinfoNone:<&20><&20>[None]<&0D><&0A>
+dinfoHidden:<&20><&20>[Omitted]<&0D><&0A>
+
+;----- Help and syntax messages ---------------------------------------------
+
+DLLs:{
+  *DLLs lists the Dynamic Link Libraries currently loaded.  If you specify \
+  an application name, it lists the DLLs currently associated with that \
+  application.  Otherwise, all DLLs currently in use are displayed.
+  |
+  Syntax: *DLLs [|<application name>]\
+}
+
+DLLApps:{
+  *DLLApps lists the applications currently making use of the Dynamic Link \
+  system.  If you specify a DLL name, it lists the applications currently \
+  using that DLL.  Otherwise, it lists all applications known to the \
+  DLLManager.
+  |
+  Syntax: *DLLApps [|<dll name>]\
+}
+
+DLLInfo:{
+  *DLLInfo gives you information about a named DLL including how many \
+  applications are using it and the names of its entry points.
+  |
+  Syntax: *DLLInfo [-full] |<dll name>\
+}
+
+DLLKillApp:{
+  *DLLKillApp allows you to remove a named application from the list of \
+  those which the DLLManager knows about.  This may be useful during \
+  testing of DLL clients, which may not tidy up properly after having \
+  crashed.
+  |
+  Syntax: *DLLKillApp |<app name>\
+}
+
+DLLReset:{
+  *DLLReset clears out all of the DLLManager's workspace.  This is intended \
+  to be used while developing libraries.
+  Warning: If you use this command, existing client applications are likely \
+  to crash.
+  |
+  Syntax: *DLLReset\
+}
+
+DLLEnsure:{
+  *DLLEnsure checks to see if a given version of a Dynamic Link Library is \
+  available.  If not, an error is generated.  This may be useful in !Run \
+  files for DLL client applications.
+  |
+  Syntax: *DLLEnsure |<dll name> |<version>\
+}
diff --git a/StraySrc/SDLS/DLLManager/s/app b/StraySrc/SDLS/DLLManager/s/app
new file mode 100644 (file)
index 0000000..e2bda8d
--- /dev/null
@@ -0,0 +1,1515 @@
+;
+; app.s
+;
+; Handling of application blocks
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.wSpace
+               GET     sh.appblock
+               GET     sh.linkblock
+               GET     sh.dllblock
+
+               GET     sh.misc
+               GET     sh.suballoc
+               GET     sh.dll
+
+               GET     sh.messages
+
+;----- External routines ----------------------------------------------------
+
+               AREA    |DLLM$$Code|,CODE,READONLY
+
+               GBLL    debug
+debug          SETL    {FALSE}
+
+; --- app_init ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  app_init
+app_init       ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+
+               ; --- Save workspace address ---
+               ;
+               ; This is so that app__epilogue can find our workspace.
+
+               STR     R12,app__pw             ;Store data relocation
+
+               ; --- Now locate the OS's pid word ---
+               ;
+               ; We do this using a table indexed by the OS version on the
+               ; grounds that it's easier to update if the address changes.
+               ; This is unlikely however, since DDEUtils uses this address
+               ; too, and it's right before the VDU driver workspace at
+               ; &1000, which seems to indicate it's there forever.
+
+               MOV     R0,#&81                 ;Read the OS version number
+               MOV     R1,#0                   ;Set up the odd arguments
+               MOV     R2,#255                 ;This is really very strange
+               SWI     XOS_Byte                ;Do the read operation
+
+               ADR     R14,app__verTable       ;Point to the table
+00             LDMIA   R14!,{R0,R2}            ;Load version and address
+               CMP     R0,R1                   ;How do the versions compare?
+               BCC     %b00                    ;No match -- keep going
+
+               STR     R2,app__pidAddr         ;If matched, store address
+               LDMFD   R13!,{R1,R2,PC}^        ;Restore caller's registers
+               BICS    PC,R14,#V_flag          ;And return to caller
+
+app__verTable  DCD     -1,&FF8                 ;All versions have PID here
+
+               LTORG
+
+app__pw                DCD     0                       ;Where to store private word
+
+; --- app_checkQuit ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  app_checkQuit
+app_checkQuit  ROUT
+
+               LDR     R0,app__list            ;Get list head pointer
+               CMP     R0,#0                   ;Are there any applications?
+               MOVEQS  PC,R14                  ;No -- that's OK then
+               ADRL    R0,msg_errInUse         ;Point to error
+               ORRS    PC,R14,#V_flag          ;Return an error
+
+               LTORG
+
+; --- app_findDLL ---
+;
+; On entry:    R0 == pointer to name of DLL to find
+;              R1 == version number to load
+; On exit:     R0 == DLL handle loaded
+
+               EXPORT  app_findDLL
+app_findDLL    ROUT
+
+               STMFD   R13!,{R11,R14}          ;Stack registers nicely
+               BL      app__sFindDLL           ;Find the DLL etc.
+               BVC     app__ok                 ;If it worked, make permanent
+               B       app__dead               ;Otherwise, tidy up
+
+               LTORG
+
+; --- app_loseDLL ---
+;
+; On entry:    R0 == pointer to DLL to lose
+; On exit:     --
+
+               EXPORT  app_loseDLL
+app_loseDLL    ROUT
+
+               STMFD   R13!,{R1-R3,R11,R14}    ;Look after some registers
+               MOV     R11,R0                  ;Keep hold of pointer
+
+               ; --- Find the application's handle ---
+
+               BL      app_getHandle           ;Find application's time
+               BLVC    app__find               ;Find the application block
+               LDMVSFD R13!,{R1-R3,R11,PC}     ;Return an error if any
+
+               ; --- Find the link block ---
+
+               MOV     R3,R0                   ;Keep hold of app pointer
+               MOV     R1,R11                  ;Point to application
+               BL      app__findLink           ;Find the link block
+               LDMVSFD R13!,{R1-R3,R11,PC}     ;Return an error if any
+
+               ; --- Remove the link block ---
+
+               MOV     R1,R0                   ;Point to the link block
+               MOV     R0,R3                   ;Point to the application
+               BL      app__freeLink           ;Free the link block up
+
+               ; --- Decrement the DLL count ---
+               ;
+               ; This will release the DLL if it no longer has any clients
+
+               MOV     R0,R11                  ;Point to DLL
+               BL      dll_dec                 ;Decrement its counter
+
+               ; --- Uncache the current link if we've removed it ---
+
+               LDR     R0,[R3,#app_cachedll]   ;Find which DLL we cached
+               CMP     R0,R11                  ;Have we just unlinked it?
+               MOVEQ   R0,#0                   ;Yes -- clear out the handle
+               STREQ   R0,[R3,#app_cachedll]   ;Won't match any more
+               STREQ   R0,[R3,#app_cacheptr]
+
+               ; --- Return, deleting application if necessary ---
+
+               MOV     R0,R3                   ;Point to application
+               LDMFD   R13!,{R1-R3,R11,R14}    ;Unstack registers
+               B       app__freeUnused         ;Kill app block if no DLLs
+
+               LTORG
+
+; --- app_setname ---
+;
+; On entry:    R0 == pointer to application's name
+; On exit:     --
+
+               EXPORT  app_setname
+app_setname    ROUT
+
+               STMFD   R13!,{R1,R14}           ;Store registers and things
+               MOV     R1,R0                   ;Keep pointer to the name
+               BL      app__add                ;Make sure the app exists
+
+               ADDVC   R0,R0,#app_name         ;Point to the name
+               BLVC    misc_strcpy             ;Copy the string across
+               LDMFD   R13!,{R1,PC}            ;Return to caller
+
+               LTORG
+
+; --- app_fromtable ---
+;
+; On entry:    R0 == pointer to start of external DLL block
+;              R1 == pointer to limit of same
+; On exit:     --
+
+               EXPORT  app_fromtable
+app_fromtable  ROUT
+
+               STMFD   R13!,{R11,R14}          ;Look after registers
+               BL      app_sfromtbl            ;Do primitive operation
+               BVC     app__ok                 ;If it worked, to gadget
+               B       app__dead               ;If it failed,tidy up
+
+               LTORG
+
+; --- app_sfromtbl ---
+;
+; On entry:    R0 == pointer to start of external DLL block
+;              R1 == pointer to limit of same
+; On exit:     --
+
+               EXPORT  app_sfromtbl
+app_sfromtbl   ROUT
+
+               STMFD   R13!,{R1-R5,R10,R11,R14} ;Stack some registers
+
+               MOV     R10,R0                  ;Keep pointer to base
+               MOV     R11,R1                  ;Keep pointer to limit
+
+00app_sfromtbl CMP     R10,R11                 ;Is there anything to do?
+               LDMEQFD R13!,{R1-R5,R10,R11,PC}^ ;No -- return to caller
+
+               ; --- Load an entry from the table ---
+
+               LDMIA   R10!,{R0-R3}            ;Load values from table
+               BL      app__sFindDLL           ;Try to find the DLL
+               LDMVSFD R13!,{R1-R5,R10,R11,PC} ;Return the error if any
+
+               ; --- Fill in the veneer table ---
+
+               MOV     R1,R2                   ;Point to first name to load
+               MOV     R2,R0                   ;Keep pointer to DLL base
+               LDR     R5,[R2,#dl_entries]     ;Load the entry count
+               BIC     R4,R5,#&FF000000        ;Clear entry type bits
+
+01app_sfromtbl LDR     R0,[R3,#0]              ;Load value from table
+               CMP     R0,R4                   ;Is it a valid ordinal?
+               BHS     %05app_sfromtbl         ;No -- look up the name then
+
+               LDR     R14,[R2,#dl_eveneer]    ;Yes -- load entry point base
+               TST     R5,#dl_shortEntries     ;Are the entries short?
+               ADDEQ   R0,R14,R0,LSL #4        ;No -- find base of veneer
+               LDRNE   R0,[R14,R0,LSL #2]      ;Yes -- load address
+               B       %10app_sfromtbl         ;And skip past name lookup
+
+05app_sfromtbl LDRB    R0,[R1]                 ;Load first byte from string
+               CMP     R0,#0                   ;Is it a zero (end of list)?
+               BEQ     %00app_sfromtbl         ;Yes -- do next table entry
+
+               ; --- Find entry point address ---
+
+               MOV     R0,R2                   ;Point to DLL base
+               BL      dll_findEntry           ;Find the entry point
+               LDMVSFD R13!,{R1-R5,R10,R11,PC} ;Return the error if any
+               MOV     R4,#0                   ;Remember to bump name
+
+               ; --- Convert it into a branch ---
+
+10app_sfromtbl SUB     R0,R0,R3                ;Convert to offset from R3
+               SUB     R0,R0,#8                ;Subtract 8 (pipeline)
+               MOV     R0,R0,LSR #2            ;Shift right to word align
+               BIC     R0,R0,#&FF000000        ;Clear top (opcode and cond)
+               ORR     R0,R0,#&EA000000        ;Put in BAL (Branch always)
+               STR     R0,[R3],#4              ;Store in veneer table
+               CMP     R4,#0                   ;Did we look up a name?
+               BNE     %01app_sfromtbl         ;No -- examine next entry pt
+
+               ; --- Find next entry point address ---
+
+02app_sfromtbl LDRB    R0,[R1],#1              ;Load a byte from the name
+               CMP     R0,#0                   ;Is it the string end?
+               BNE     %02app_sfromtbl         ;No -- get another
+               B       %01app_sfromtbl         ;Fill in another entry point
+
+               LTORG
+
+; --- app_findNamed ---
+;
+; On entry:    R0 == name of an application
+; On exit:     R0 == pointer to application block base
+
+               EXPORT  app_findNamed
+app_findNamed  ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Preserve registers
+               MOV     R1,R0                   ;Keep pointer to string
+               LDR     R3,app__list            ;And load the pointer to list
+
+00app_findNamed        CMP     R3,#0                   ;Is this the end of the line?
+               BEQ     %40app_findNamed        ;Yes -- give an error
+               ADD     R0,R3,#app_name         ;Find the name string
+               MOV     R2,#0                   ;Caseless compare
+               BL      misc_strcmp             ;Compare the strings
+               LDRNE   R3,[R3,#app_next]       ;If no match, move on...
+               BNE     %00app_findNamed        ;... and try again
+               MOV     R0,R3                   ;Point to DLL (give handle)
+               LDMFD   R13!,{R1-R3,PC}^        ;And return to caller
+
+40app_findNamed        ADRL    R0,msg_errAppNotFound   ;Couldn't find DLL name
+               BL      misc_error              ;... create an error message
+               LDMFD   R13!,{R1-R3,R14}        ;... restore registers
+               ORRS    PC,R14,#V_flag          ;... and return an error
+
+               LTORG
+
+; --- app_setBtable ---
+;
+; On entry:    R0 == pointer to entry point table
+;              R1 == pointer to name table
+; On exit:     --
+
+               EXPORT  app_setBtable
+app_setBtable  ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stick 'em on the stack
+               MOV     R2,R0                   ;Keep this safe
+               BL      app__add                ;Create an entry for the app
+               STRVC   R2,[R0,#app_btable]     ;Store the entry table ptr
+               STRVC   R1,[R0,#app_nametable]  ;Store the name table ptr
+               LDMFD   R13!,{R1,R2,PC}         ;Return to caller
+
+               LTORG
+
+; --- app_appEntry ---
+;
+; On entry:    R0 == pointer to name to find
+; On exit:     R0 == pointer to entry point
+
+               EXPORT  app_appEntry
+app_appEntry   ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stack registers away
+
+               ; --- Find the application ---
+
+               MOV     R2,R0                   ;Point to name start
+               BL      app_getHandle
+               BLVC    app__find               ;Try to find the app block
+               LDMVSFD R13!,{R1,R2,PC}         ;If not there, error
+
+               ; --- Get the entry table info out ---
+
+               LDR     R1,[R0,#app_nametable]  ;Find name table address
+               LDR     R0,[R0,#app_btable]     ;Find entry table address
+               CMP     R0,#0                   ;Is there no entry table?
+               BEQ     %50app_appEntry         ;No -- complain about it
+
+               ; --- Find the entry point ---
+
+               BL      dll_appEntry            ;Do the actual find
+               LDMFD   R13!,{R1,R2,PC}         ;Return to caller
+
+               ; --- Application has no entry points ---
+
+50app_appEntry ADRL    R0,msg_errAppNoEntry    ;Point to error message
+               LDMFD   R13!,{R1,R2,R14}        ;Unstack registers
+               ORRS    PC,R14,#V_flag          ;Return the error to caller
+
+               LTORG
+
+               ALIGN
+
+; --- app_fixExtension ---
+;
+; On entry:    R0 == pointer to name table
+;              R1 == pointer to branch table to fill in
+; On exit:     --
+
+               EXPORT  app_fixExtension
+app_fixExtension
+
+               STMFD   R13!,{R14}              ;Save return address
+               BL      app_fix                 ;Do the real job
+               LDMVSFD R13!,{PC}               ;If it failed, return now
+               MOV     R0,#0                   ;Otherwise do global resync
+               SWI     XOS_SynchroniseCodeAreas ;Do that then
+               LDMFD   R13!,{R14}              ;Restore return address
+               BICS    PC,R14,#V_flag          ;And return with V clear
+
+               LTORG
+
+; --- app_fix ---
+;
+; On entry:    R0 == pointer to name table
+;              R1 == pointer to branch table to fill in
+; On exit:     --
+
+               EXPORT  app_fix
+app_fix                ROUT
+
+               STMFD   R13!,{R1-R6,R14}        ;Stack registers away
+
+               ; --- Find the application ---
+
+               MOV     R2,R0                   ;Point to name start
+               MOV     R3,R1                   ;Keep entry table safe
+               BL      app_getHandle
+               BLVC    app__find               ;Try to find the app block
+               LDMVSFD R13!,{R1-R6,PC}         ;If not there, error
+
+               ; --- Get the entry table info out ---
+
+               LDR     R4,[R0,#app_btable]     ;Find entry table address
+               LDR     R5,[R0,#app_nametable]  ;Find name table address
+               MOV     R6,#&1000               ;Guess number of entries
+               CMP     R4,#0                   ;Is there no entry table?
+               BEQ     %50app_fix              ;No -- complain about it
+
+               ; --- Set up for a nice loop ---
+
+00app_fix      LDR     R0,[R3,#0]              ;Load the word from btable
+               CMP     R0,R6                   ;Is it moderately sensible?
+               ADDLO   R0,R4,R0,LSL #2         ;Yes -- find the entry
+               MOVLO   R14,#1                  ;Remember we done this
+               BLO     %10app_fix              ;And fill in the branch
+               LDRB    R0,[R2]                 ;Get the first entry byte
+               CMP     R0,#0                   ;Is it the end of the table?
+               LDMEQFD R13!,{R1-R6,PC}^        ;Yes -- we did it OK
+
+               ; --- Find another entry point address ---
+
+               MOV     R0,R4                   ;Point to entry table
+               MOV     R1,R5                   ;Point to name table
+               BL      dll_appEntry            ;Find the actual entry name
+               LDMVSFD R13!,{R1-R6,PC}         ;If not there, return error
+               MOV     R6,#0                   ;Move on to next string
+
+               ; --- Convert it to a branch instruction ---
+
+10app_fix      SUB     R0,R0,R3                ;Convert to offset from R3
+               SUB     R0,R0,#8                ;Subtract 8 (pipeline)
+               MOV     R0,R0,LSR #2            ;Shift right to word align
+               BIC     R0,R0,#&FF000000        ;Clear top (opcode and cond)
+               ORR     R0,R0,#&EA000000        ;Put in BAL (Branch always)
+               STR     R0,[R3],#4              ;Store in veneer table
+
+               ; --- Find next entry point address ---
+
+               CMP     R6,#0                   ;Do we need to move on?
+               BNE     %00app_fix              ;No -- just loop then
+01app_fix      LDRB    R0,[R2],#1              ;Load a byte from the name
+               CMP     R0,#0                   ;Is it the string end?
+               BNE     %01app_fix              ;No -- get another
+               B       %00app_fix              ;Fill in another entry point
+
+               ; --- Application has no entry points to offer ---
+
+50app_fix      ADRL    R0,msg_errAppNoEntry    ;Point to error message
+               LDMFD   R13!,{R1-R6,R14}        ;Unstack registers
+               ORRS    PC,R14,#V_flag          ;Return the error to caller
+
+               LTORG
+
+; --- app_listDLLs ---
+;
+; On entry:    R0 == pointer to name of an application
+; On exit:     --
+
+               EXPORT  app_listDLLs
+app_listDLLs   ROUT
+
+               STMFD   R13!,{R1,R14}           ;Stack registers nicely
+               BL      app_findNamed           ;Find the application block
+               LDMVSFD R13!,{R1,PC}            ;Return if not found
+               LDR     R1,[R0,#app_dlls]       ;Load head of DLL list
+               CMP     R1,#0                   ;This shouldn't be 0
+               BEQ     %01app_listDLLs         ;If it is, print a message
+
+               BL      dll_writeTitle          ;Display the line along top
+
+               ; --- Main loop thing ---
+
+00app_listDLLs LDR     R0,[R1,#lk_dll]         ;Point to the DLL
+               BL      dll_writeInfo           ;Display information about it
+               LDR     R1,[R1,#lk_next]        ;Move onto the next one
+               CMP     R1,#0                   ;Is that all?
+               BNE     %00app_listDLLs         ;No -- continue round
+
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               ; --- No DLLs to list.  Hmm... ---
+
+01app_listDLLs ADRL    R0,msg_noDLLsForApp     ;Point to the message
+               SWI     OS_Write0               ;And display it
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- app_listUsing ---
+;
+; On entry:    R0 == pointer to a DLL name
+; On exit:     --
+
+               EXPORT  app_listUsing
+app_listUsing  ROUT
+
+               STMFD   R13!,{R1,R2,R8-R11,R14} ;Stack registers
+
+               ; --- Check that the DLL exists ---
+
+               MOV     R8,R0                   ;Keep the name pointer safe
+               MOV     R1,#0                   ;Don't care which version
+               BL      dll_find                ;Try to find it
+               BVS     %11app_listUsing        ;If it's not there, error
+
+               ; --- Start a loop through the apps ---
+
+               LDR     R11,app__list           ;Find the list head pointer
+               MOV     R10,#0                  ;No matching DLLs found yet
+               CMP     R11,#0                  ;Are there any apps?
+               BEQ     %10app_listUsing        ;No -- print a message then
+
+               ; --- Start a loop through the DLLs with this app
+
+00app_listUsing        LDR     R9,[R11,#app_dlls]      ;Find the DLL list
+               CMP     R9,#0                   ;Are there any DLLs?
+               BEQ     %03app_listUsing        ;No -- move on to the next
+
+               ; --- Loop through DLLs on this app ---
+
+01app_listUsing        LDR     R0,[R9,#lk_dll]         ;Point to the DLL base
+               MOV     R1,R8                   ;Point to DLL name
+               MOV     R2,#0                   ;Don't care what version
+               BL      dll_compare             ;Compare with stuff given
+               CMP     R0,#1                   ;Is there a match?
+               BNE     %02app_listUsing        ;Move onto the next one
+
+               ; --- Print out info about this app ---
+
+               CMP     R10,#1                  ;Have we printed the title?
+               ADRNEL  R0,msg_appHeader        ;No -- point to header
+               SWINE   XOS_Write0              ;And print it
+               MOV     R10,#1                  ;We've printed it now
+               ADD     R0,R11,#app_name        ;Point to application name
+               MOV     R1,#12                  ;Field width
+               BL      dll_field               ;Print it out
+               LDR     R0,[R9,#lk_dll]         ;Find DLL pointer again
+               LDR     R0,[R0,#dl_version]     ;Load version number
+               BL      dll_convertVersion      ;Convert it into a string
+               SWI     XOS_Write0              ;Write it out as a string
+               SWI     XOS_NewLine             ;And move onto the next line
+
+               ; --- Finish off loop through app's DLLs ---
+
+02app_listUsing        LDR     R9,[R9,#lk_next]        ;Move on to next link block
+               CMP     R9,#0                   ;Anything to do here?
+               BNE     %01app_listUsing        ;Yes -- check that one too
+
+               ; --- Finish off loop through all apps ---
+
+03app_listUsing        LDR     R11,[R11,#app_next]     ;Move on to next application
+               CMP     R11,#0                  ;Is there any more to do?
+               BNE     %00app_listUsing        ;Yes -- do its DLLs
+
+               CMP     R10,#0                  ;Were any messages printed?
+               BEQ     %10app_listUsing        ;No -- print one
+               LDMFD   R13!,{R1,R2,R8-R11,PC}^ ;Return to caller
+
+               ; --- No matching DLLs were found ---
+
+10app_listUsing        ADRL    R0,msg_noAppsForDLL     ;Point to message skeleton
+               MOV     R1,R8                   ;Point to the DLL name
+               BL      misc_subst              ;Do the substitution
+               SWI     XOS_Write0              ;Display the string
+               LDMFD   R13!,{R1,R2,R8-R11,PC}^
+
+               ; --- Print an error message about this ---
+
+11app_listUsing        MOV     R1,R8                   ;Point to DLL name
+               ADRL    R0,msg_errDLLNotInMem   ;Point to error block
+               BL      misc_error              ;Create error message fully
+               LDMFD   R13!,{R1,R2,R8-R11,R14} ;Unstack all registers
+               ORRS    PC,R14,#V_flag          ;Return to caller with error
+
+               LTORG
+
+; --- app_list ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  app_list
+app_list       ROUT
+
+               STMFD   R13!,{R1,R14}           ;Stack registers
+
+               ; --- Prepare for a loop ---
+
+               LDR     R1,app__list            ;Point to first entry
+               CMP     R1,#0                   ;Are there any entries?
+               BEQ     %10app_list             ;No -- give a message
+
+               ; --- Display entries in order ---
+
+00app_list     ADD     R0,R1,#app_name         ;Point to name in structure
+               SWI     XOS_Write0              ;Display the app's name
+               SWI     XOS_NewLine             ;Display a new line char
+               LDR     R1,[R1,#app_next]       ;Get next entry in the list
+               CMP     R1,#0                   ;Is it the end yet?
+               BNE     %00app_list             ;No -- do the next one
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               ; --- Display message about no apps ---
+
+10app_list     ADRL    R0,msg_noApps           ;Point to the message
+               SWI     XOS_Write0              ;Display it on the screen
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- app_dying ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  app_dying
+app_dying      ROUT
+
+               STMFD   R13!,{R14}              ;Stack return address
+               BL      app_getHandle           ;Find application's time
+               BLVC    app__find               ;Find the application block
+               LDMFD   R13!,{R14}              ;Retrieve the return address
+               BVC     app_kill                ;If there's no error, kill it
+               ORRS    PC,R14,#V_flag          ;Return to caller with error
+
+               LTORG
+
+; --- app_kill --
+;
+; On entry:    R0 == pointer to application base
+; On exit:     --
+
+               EXPORT  app_kill
+app_kill       ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stack registers nicely
+               MOV     R2,R0                   ;Keep hold of this pointer
+
+               ; --- Free each DLL link ---
+
+               LDR     R1,[R0,#app_dlls]       ;Find head of link list
+               CMP     R1,#0                   ;Are there any DLLs?
+               BEQ     %01app_kill             ;No -- don't free them then
+
+00app_kill     LDR     R0,[R1,#lk_dll]         ;Find the DLL pointer
+               BL      dll_dec                 ;Decrement its counter
+               MOV     R0,R1                   ;Point to old block
+               LDR     R1,[R0,#lk_next]        ;Point to next block
+               BL      sub_free                ;Free the old block
+               CMP     R1,#0                   ;Are there any more to do?
+               BNE     %00app_kill             ;Yes -- do the next one
+
+               ; --- Free the application block ---
+
+01app_kill     MOV     R0,R2                   ;Point to application block
+               LDMFD   R13!,{R1,R2,R14}        ;Restore registers
+               B       app__free               ;Free the application block
+
+               LTORG
+
+; --- app_killAll ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  app_killAll
+app_killAll    ROUT
+
+               STMFD   R13!,{R1,R2,R14}
+
+               ; --- Start up the main loop ---
+
+               LDR     R2,app__list            ;Point to application list
+               CMP     R2,#0                   ;Is there anything to do?
+               BEQ     %01app_killAll          ;No -- skip the loop
+               MOV     R0,#7                   ;Free memory reason code
+
+00app_killAll  LDR     R1,[R2,#app_next]       ;Find next block in the list
+               SWI     XOS_Module              ;Free the block
+               MOVS    R2,R1                   ;Point to the next one
+               BNE     %00app_killAll          ;Loop round for the next one
+
+01app_killAll  STR     R2,app__list            ;Clear out list head pointer
+               STR     R2,app__cachePtr        ;Clear out cached pointer
+               STR     R2,app__cacheHnd        ;Clear out cached handle
+               LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- app_instvars ---
+;
+; On entry:    R0 == anything for first call, or pointer to data block
+;              R4 == 0 for first call, or pointer to link block
+; On exit:     R0 == size of block required
+;              R4 == pointer to next link block, or 0 to end
+
+               EXPORT  app_instvars
+app_instvars   ROUT
+
+               STMFD   R13!,{R1,R14}           ;Keep hold of link register
+               CMP     R4,#0                   ;Is this the first call?
+               BNE     %00app_instvars         ;No -- skip ahead quickly
+
+               ; --- Find start of application list ---
+
+               BL      app_getHandle           ;Get app's start time
+               BLVC    app__find               ;Locate the application
+               LDMVSFD R13!,{R1,PC}^           ;Return to caller on error
+               LDR     R4,[R0,#app_dlls]       ;Load list head pointer
+               B       %01app_instvars         ;Don't try registering vars
+
+               ; --- Register instance variables ---
+
+00app_instvars CMP     R0,#0                   ;Check the allocator worked
+               BEQ     %40app_instvars         ;If not, give an error
+               MOV     R1,R0                   ;Point to the new block
+               LDR     R0,[R4,#lk_dll]         ;Point to the DLL block
+               BL      dll_instvars            ;Register the instance vars
+               LDR     R0,[R4,#lk_dll]         ;Point to the DLL block again
+               BL      dll_convreloc           ;Convert to a relocation
+               STR     R0,[R4,#lk_work]        ;Store relocation
+
+               ; --- Is this the end of the line? ---
+
+02app_instvars LDR     R4,[R4,#lk_next]        ;Move to next block in list
+01app_instvars CMP     R4,#0                   ;Is this the end?
+               LDMEQFD R13!,{R1,PC}^           ;Yes -- return to caller
+               LDR     R0,[R4,#lk_work]        ;Find workspace pointer
+               CMP     R0,#0                   ;Is there one yet?
+               BNE     %02app_instvars         ;Yes -- skip this one
+               LDR     R0,[R4,#lk_dll]         ;Point to DLL
+               BL      dll_datasize            ;Find how much space we need
+               CMP     R0,#0                   ;Is there any required?
+               BEQ     %02app_instvars         ;No -- skip to next block
+               LDMFD   R13!,{R1,PC}^           ;Return -- that's done
+
+40app_instvars ADRL    R0,msg_errDLLNoMem      ;Point to error message
+               LDMFD   R13!,{R1,R14}           ;Restore registers
+               ORRS    PC,R14,#V_flag          ;Return the error
+
+               LTORG
+
+; --- app_giveclib ---
+;
+; On entry:    R0 == pointer to CLib data (__iob)
+; On exit:     --
+
+               EXPORT  app_giveclib
+app_giveclib   ROUT
+
+               STMFD   R13!,{R1,R14}           ;Stack registers
+               MOV     R1,R0                   ;Keep pointer to data
+               BL      app__add                ;Make sure there's an app
+               STRVC   R1,[R0,#app_clibdata]   ;Store the pointer nicely
+               LDMFD   R13!,{R1,PC}            ;Return to caller nicely
+
+               LTORG
+
+; --- app_appdata ---
+;
+; On entry:    R0 == application's stack limit
+; On exit:     --
+
+               EXPORT  app_appdata
+app_appdata    ROUT
+
+               STMFD   R13!,{R1,R14}           ;Stack registers
+               LDR     R1,[R0,#-536]           ;Find application's reloc
+               BL      app__add                ;Ensure the app is present
+               STRVC   R1,[R0,#app_owndata]    ;Store the relocation nicely
+               LDMFD   R13!,{R1,PC}            ;Return to caller nicely
+
+               LTORG
+
+; --- app_findclib ---
+;
+; On entry:    --
+; On exit:     R0 == pointer to CLib data
+
+               EXPORT  app_findclib
+app_findclib   ROUT
+
+               STMFD   R13!,{R14}              ;Keep return address safe
+               BL      app_getHandle           ;Find app's start time
+               BLVC    app__find               ;Look up application's block
+               LDRVC   R0,[R0,#app_clibdata]   ;Find C Library data pointer
+               LDMFD   R13!,{PC}               ;Return to caller
+
+               LTORG
+
+; --- app_readstackptr ---
+;
+; On entry:    --
+; On exit:     R0 == `magic cookie' for the stack pointer
+
+               EXPORT  app_readstkptr
+app_readstkptr ROUT
+
+               STMFD   R13!,{R14}              ;Keep return address safe
+               BL      app_getHandle           ;Find app's start time
+               BLVC    app__find               ;Locate the app's data block
+               LDRVC   R0,[R0,#app_stackPtr]   ;Find the stack pointer
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- app_setstkptr ---
+;
+; On entry:    R0 == `magic cookie' from app_readstkptr
+;              R1 == app's current stack limit
+
+               EXPORT  app_setstkptr
+app_setstkptr  ROUT
+
+               STMFD   R13!,{R11,R14}          ;Keep return address safe
+
+               ; --- Find the application block ---
+
+               MOV     R11,R0                  ;Keep hold of new pointer
+               BL      app_getHandle           ;Find the app's start time
+               BLVC    app__find               ;Find the app's data block
+               LDMVSFD R13!,{R11,PC}           ;If failed, return error
+
+               ; --- Find out what there is to do ---
+
+               LDR     R14,[R0,#app_stackPtr]  ;Load the old pointer
+               CMP     R11,R14                 ;How does it shape up?
+               LDMEQFD R13!,{R11,PC}^          ;Nothing doing here
+
+               ; --- Put back the new stack pointer and set relocation ---
+
+               STR     R11,[R0,#app_stackPtr]  ;Store new pointer
+               CMP     R11,#0                  ;Was the stack at top level?
+               ADDNE   R0,R0,#app_stack        ;Point to base of stack
+               SUBNE   R11,R11,#8              ;Point to base of stack entry
+               LDRNE   R0,[R0,R11]             ;Find data relocation
+               LDREQ   R0,[R0,#app_owndata]    ;If toplevel, get client data
+               STR     R0,[R1,#-536]           ;Store in stack limit struct
+               LDMFD   R13!,{R11,PC}^          ;Return to caller
+
+               LTORG
+
+; --- app_prologue ---
+;
+; On entry:    R0 == return address for routine
+;              R1 == pointer to stack limit structure
+;              R2 == pointer to base of DLL code
+; On exit:     R0 == new return address
+;
+; Note -- I'm directly accessing the DLL data here, which may be considered
+; naughty by some.  I don't care.
+
+               EXPORT  app_prologue
+app_prologue   ROUT
+
+               STMFD   R13!,{R9-R11,R14}       ;Stack some registers
+
+               ; --- Find application block ---
+
+               MOV     R11,R0                  ;Keep hold of this
+               BL      app__add                ;Make sure the app exists
+               LDMVSFD R13!,{R9-R11,PC}        ;Return the error on fail
+
+               ; --- Stack current relocation and return address ---
+
+               LDR     R14,[R0,#app_stackPtr]  ;Find the stack pointer
+               CMP     R14,#4096               ;Where is it currently?
+               BGE     %00app_prologue         ;Give error on overflow
+               ADD     R10,R0,#app_stack       ;Point to stack base
+               ADD     R10,R10,R14             ;Add on stack pointer
+               LDR     R9,[R1,#-536]           ;Find the current reloc
+               STMIA   R10,{R9,R11}            ;Store registers on the stack
+               MOV     R10,R1                  ;Keep pointer to stack limit
+               ADD     R14,R14,#8              ;Bump along stack pointer
+               STR     R14,[R0,#app_stackPtr]  ;Store stack pointer
+
+               ; --- Find workspace pointer ---
+
+               CMP     R2,#0                   ;What's the DLL pointer?
+               LDREQ   R1,[R0,#app_owndata]    ;0 -- find app workspace
+               BEQ     %10app_prologue         ;... and finish search
+               LDR     R14,[R2,#dl_next-dl_extra] ;Find DLL's next ptr
+               CMP     R14,#-1                 ;Is it shared?
+               LDREQ   R1,[R2,#dl_wspace-dl_extra] ;No -- find DLL workspace
+               BEQ     %10app_prologue         ;... and finish search
+
+               ; --- Get shared DLL workspace pointer ---
+
+               SUB     R1,R2,#dl_extra         ;Point to DLL handle
+               BL      app__findLink           ;Find the link block
+               LDMVSFD R13!,{R9-R11,PC}        ;Return error if it failed
+               LDR     R1,[R0,#lk_work]        ;Find relocation offset
+
+               ; --- Round everything off ---
+
+10app_prologue ADR     R0,app__epilogue        ;Point to tidy-up routine
+               STR     R1,[R10,#-536]          ;Store new data relocation
+               LDMFD   R13!,{R9-R11,PC}^       ;Return to caller happy
+
+               ; --- Stack overflow error ---
+
+00app_prologue ADRL    R0,msg_errStackOvf      ;Point to error
+               LDMFD   R13!,{R9-R11,R14}       ;Unstack registers
+               ORRS    PC,R14,#V_flag          ;Return the error
+
+               LTORG
+
+; --- app_restoreHandle ---
+;
+; On entry:    R0 == an application handle to assume
+; On exit:     --
+
+               EXPORT  app_restoreHandle
+app_restoreHandle ROUT
+
+               [       :LNOT::DEF:ddeutils_pid
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               SWI     XOS_GetEnv              ;Read current command string
+               MOV     R1,R13                  ;Point to new start time
+               SWI     XOS_WriteEnv            ;Set the start time back
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               |
+
+               MOVS    PC,R14                  ;No need to do this
+
+               ]
+
+               LTORG
+
+; --- app_getHandle ---
+;
+; On entry:    --
+; On exit:     R0 == application's start time
+;
+; Since the application's start time is held in *five* bytes we use only the
+; least significant 4 (the four that change most).
+
+               EXPORT  app_getHandle
+app_getHandle  ROUT
+
+               [       :LNOT::DEF:ddeutils_pid
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               SWI     XOS_GetEnv              ;Get the session info
+               LDR     R0,[R2,#0]              ;Load the start time nicely
+               LDMFD   R13!,{R1,R2,PC}^        ;And return to caller
+
+               |
+
+               LDR     R0,app__pidAddr         ;Load the PID address
+               LDR     R0,[R0]                 ;And load the current PID
+               MOVS    PC,R14                  ;Return to caller when done
+
+               ]
+
+               LTORG
+
+;----- Private routines -----------------------------------------------------
+
+; --- app__epilogue ---
+;
+; On entry:    --
+; On exit:     a1,a2 preserved. otherwise as APCS-R
+;
+; I've used APCS register names throughout here.
+
+app__epilogue  ROUT
+
+               STMFD   sp!,{a1,a2}             ;Keep two return values
+               LDR     ip,app__pw              ;Point to private word ptr
+               BL      app_getHandle           ;Find app's start time
+               BL      app__find               ;Find app block
+               LDR     a2,[a1,#app_stackPtr]   ;Find the stack pointer
+               ADD     a3,a1,#app_stack        ;Point to the stack base
+               ADD     a3,a3,a2                ;Point to current stack pos
+               LDMDB   a3!,{a4,lr}             ;Find relocation and ret addr
+               SUB     a2,a2,#8                ;Bump down the stack ptr
+               STR     a2,[a1,#app_stackPtr]   ;Store back in app block
+               STR     a4,[sl,#-536]           ;Store relocation offset
+               LDMFD   sp!,{a1,a2}             ;Restore return values
+               MOVS    pc,lr                   ;Return to caller
+
+               LTORG
+
+; --- app__find ---
+;
+; On entry:    R0 == application handle (i.e. start time)
+; On exit:     R0 == pointer to application block, or error
+
+app__find      ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Preserve nice registers
+
+               ; --- Try looking at the cached value ---
+
+               LDR     R1,app__cacheHnd        ;Load the cached handle
+               CMP     R1,R0                   ;Is it a match?
+               LDREQ   R0,app__cachePtr        ;Yes -- load the pointer
+               LDMEQFD R13!,{R1,R2,PC}^        ;And return!
+
+               ; --- Otherwise, scan the list ---
+
+               LDR     R2,app__list            ;Get list head pointer
+               CMP     R2,#0                   ;Is there an entry here?
+               BEQ     %10app__find            ;No -- return an error
+00app__find    LDR     R1,[R2,#app_handle]     ;Get the app's handle
+               CMP     R1,R0                   ;Is it a match?
+               BEQ     %01app__find            ;Yes -- deal with it
+               LDR     R2,[R2,#app_next]       ;No -- get the next pointer
+               CMP     R2,#0                   ;Is this the end?
+               BNE     %00app__find            ;No -- continue round
+
+               ; --- Couldn't find the application ---
+
+10app__find    ADRL    R0,msg_errUnknownApp    ;Point to error message
+               LDMFD   R13!,{R1,R2,R14}        ;Pull back registers
+               ORRS    PC,R14,#V_flag          ;And return with an error
+
+               ; --- Found an application -- update the cache ---
+
+01app__find    STR     R0,app__cacheHnd        ;Store the new handle
+               STR     R2,app__cachePtr        ;And the new pointer
+               MOV     R0,R2                   ;Return the pointer to caller
+               LDMFD   R13!,{R1,R2,PC}^        ;And live happily ever after
+
+               LTORG
+
+; --- app__add ---
+;
+; On entry:    --
+; On exit:     Application handle
+
+app__add       ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Stack registers
+
+               ; --- Find out whether the app is registered yet ---
+
+               BL      app_getHandle           ;Find app's start time
+               MOV     R1,R0                   ;Look after a copy
+               BL      app__find               ;Call the find routine
+               LDMVCFD R13!,{R1-R3,PC}^        ;If already there, return
+
+               ; --- Allocate a block from the RMA ---
+
+               MOV     R0,#6                   ;Code to allocate some store
+               LDR     R3,=app_strSize         ;The size of an app block
+               SWI     XOS_Module              ;Allocate the memory
+               LDMVSFD R13!,{R1-R3,PC}         ;If it failed, return error
+
+               ; --- Link the block into the list ---
+
+               LDR     R0,app__list            ;Find the list header
+               STR     R0,[R2,#app_next]       ;Store in next pointer
+               CMP     R0,#0                   ;Is there a next block?
+               STRNE   R2,[R0,#app_prev]       ;Yes -- link in new block
+               MOV     R0,#0                   ;Zero out the previous link
+               STR     R0,[R2,#app_prev]       ;Store in previous entry
+               STR     R2,app__list            ;Store this as new block
+
+               ; --- Set this block up in the cache ---
+
+               STR     R1,app__cacheHnd        ;Cache the app's start time
+               STR     R2,app__cachePtr        ;Cache the app's pointer
+
+               ; --- Set up the block's data ---
+
+               MOV     R0,#0                   ;Zero some entries in block
+               STR     R0,[R2,#app_cachedll]   ;No cached DLL yet
+               STR     R0,[R2,#app_cacheptr]   ;No cached DLL yet
+               STR     R0,[R2,#app_dlls]       ;No DLLs registered yet
+               STR     R0,[R2,#app_stackPtr]   ;No entries on the stack
+               STR     R0,[R2,#app_btable]     ;App has no entry table
+               STR     R1,[R2,#app_handle]     ;Store the app's time info
+               ADD     R0,R2,#app_name         ;Point to app's name field
+               ADRL    R1,msg_appName          ;Point to default name
+               BL      misc_strcpy             ;Copy the string across
+
+               ; --- Return the app's handle ---
+
+               MOV     R0,R2                   ;Return the app's pointer
+               LDMFD   R13!,{R1-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- app__free ---
+;
+; On entry:    R0 == pointer to app to free
+; On exit:     --
+
+app__free      ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Keep registers safe
+
+               ; --- Remove the block from the list ---
+
+               LDR     R1,[R0,#app_next]       ;Get next block in the list
+               LDR     R2,[R0,#app_prev]       ;Get previous block too
+               CMP     R1,#0                   ;Is there a next block?
+               STRNE   R2,[R1,#app_prev]       ;Yes -- fix up its prev
+               CMP     R2,#0                   ;Is there a previous block?
+               ADREQ   R2,app__list            ;No -- point to list head
+               STR     R1,[R2,#app_next]       ;Fix up next pointer
+
+               ; --- Remove this app from the cache ---
+
+               LDR     R2,app__cachePtr        ;Find which app was cached
+               CMP     R2,R0                   ;Is it this one?
+               MOVEQ   R2,#0                   ;Yes -- overwrite handle
+               STREQ   R2,app__cacheHnd        ;Won't match this app now
+               STREQ   R2,app__cachePtr
+
+               ; --- Free the block ---
+
+               MOV     R2,R0                   ;Point to the block to free
+               MOV     R0,#7                   ;Magic reason code
+               SWI     XOS_Module              ;Free the block
+               LDMFD   R13!,{R1,R2,PC}         ;Return to caller if failed
+
+               LTORG
+
+; --- app__freeUnused ---
+;
+; On entry:    R0 == pointer to application
+; On exit:     --
+
+app__freeUnused        ROUT
+
+               STMFD   R13!,{R14}              ;Keep link register
+               LDR     R14,[R0,#app_dlls]      ;Find DLL link list
+               CMP     R14,#0                  ;Are there any in the list?
+               LDMFD   R13!,{R14}              ;Restore link register
+               MOVNES  PC,R14                  ;Return is still attached
+               B       app__free               ;Otherwise kill the app
+
+               LTORG
+
+; --- app__sFindDLL ---
+;
+; On entry:    R0 == pointer to name of DLL to find
+;              R1 == version number to load
+; On exit:     R0 == DLL handle loaded
+
+app__sFindDLL  ROUT
+
+               STMFD   R13!,{R1,R2,R9-R11,R14} ;Stack loads of registers
+
+               MOV     R11,R0                  ;Keep pointer safe
+
+               ; --- Ensure that the application structure is there ---
+
+               BL      app__add                ;Add the application if reqd.
+               LDMVSFD R13!,{R1,R2,R9-R11,PC}  ;If it failed, return now
+               MOV     R10,R0                  ;Keep pointer to app block
+
+               ; --- Find out if there's anything to do ---
+
+               MOV     R2,R1                   ;Put version number nicely
+               MOV     R1,R11                  ;Point to required name
+               BL      app__findNamedLink      ;Is there anything to do?
+               LDMVCFD R13!,{R1,R2,R9-R11,PC}^ ;If found, return to caller
+               MOV     R1,R2                   ;Put version number back
+
+               ; --- Load the DLL if necessary ---
+
+               MOV     R0,R11                  ;Move DLL pointer back
+               BL      dll_ensure              ;Load the DLL into memory
+               MOVVS   R9,R0                   ;If it failed, keep the error
+               BVS     %50app__sFindDLL        ;And tidy up properly
+               MOV     R11,R0                  ;Keep pointer to DLL
+               BL      dll_tentative           ;Mark the DLL as tentative
+
+               ; --- Add the link between the two ---
+
+               MOV     R0,R10                  ;Point to application
+               MOV     R1,R11                  ;Point to DLL block
+               BL      app__addLink            ;Link them together
+               MOVVS   R9,R0                   ;Keep error if any
+               BVS     %51app__sFindDLL        ;And tidy things up
+
+               ; --- Now we're done ---
+
+               MOV     R0,R11                  ;Point to DLL structure
+               LDMFD   R13!,{R1,R2,R9-R11,PC}^ ;Restore registers
+
+               ; --- Tidy up if link allocation failed ---
+
+51app__sFindDLL
+50app__sFindDLL        MOV     R0,R10                  ;Point to application block
+               BL      app__freeUnused         ;If not being used, kill it
+
+               ; --- Return the error to the caller ---
+
+               MOV     R0,R9                   ;Point to the error message
+               LDMFD   R13!,{R1,R2,R9-R11,R14} ;Restore registers
+               ORRS    PC,R14,#V_flag          ;Return to caller
+
+               LTORG
+
+; --- app__ok ---
+;
+; On entry:    --
+; On exit:     All registers preserved
+;
+; Expects a stacked R11 and R14
+
+app__ok                ROUT
+
+               MOV     R11,R0                  ;Look after error pointer
+               BL      dll_confirm             ;Cancel tentative DLL blocks
+               BL      app_getHandle           ;Find app time info
+               BLVC    app__find               ;Find the application block
+               BLVC    app__confLink           ;Cancel tentative links
+
+               ; --- Resync code areas ---
+               ;
+               ; This seems as good a place as any to do this.  I'm going
+               ; to do a global resync, because I suspect that lots of
+               ; local ones are going to be rather slower, actually.
+               ; Besides, loading libraries isn't something which gets done
+               ; /that/ often.
+
+               MOV     R0,#0                   ;Resync everything
+               SWI     XOS_SynchroniseCodeAreas ;Do that then, please
+
+               MOV     R0,R11                  ;Point to error again
+               LDMFD   R13!,{R11,R14}          ;Restore registers
+               BICS    PC,R14,#V_flag          ;Return to caller with V clr
+
+               LTORG
+
+; --- app__dead ---
+;
+; On entry:    --
+; On exit:     All registers preserved
+;
+; Expects a stacked R11 and R14
+
+app__dead      ROUT
+
+               MOV     R11,R0                  ;Look after error pointer
+               CMP     R0,R0                   ;Clear the V flag
+               BL      dll_retrace             ;Destroy tentative DLL blocks
+               BL      app_getHandle           ;Find app time info
+               BLVC    app__find               ;Find the application block
+               BLVC    app__cancel             ;Destroy tentative links
+               MOV     R0,R11                  ;Point to error again
+               LDMFD   R13!,{R11,R14}          ;Restore registers
+               ORRS    PC,R14,#V_flag          ;Return to caller with V set
+
+               LTORG
+
+; --- app__findNamedLk ---
+;
+; On entry:    R0 == pointer to application
+;              R1 == pointer to DLL's name
+;              R2 == DLL's version number
+; On exit:     R0 == V set if couldn't be found, clear otherwise
+
+app__findNamedLink ROUT
+
+               STMFD   R13!,{R3,R4,R14}        ;Stack registers safely
+               LDR     R3,[R0,#app_dlls]       ;Point to first DLL block
+               CMP     R3,#0                   ;Is there anything to do?
+               BEQ     %20app__findNamedLink   ;No -- that's an error
+
+               ; --- Now construct the proper DLL name ---
+
+               MOV     R0,R1                   ;Point to the DLL name
+00             LDRB    R14,[R0],#1             ;Load the next byte
+               CMP     R14,#'['                ;Is this a new-style DAN?
+               BEQ     %f05                    ;Yes -- sort this out then
+               CMP     R14,#'.'                ;Or is it a dot?
+               MOVEQ   R1,R0                   ;Yes -- remember this place
+               CMP     R14,#&20                ;End of the string yet?
+               BCS     %b00                    ;No -- keep going
+
+               ADR     R0,misc__sharedBuf      ;Find the shared buffer
+00             LDRB    R14,[R1],#1             ;Load a byte from the name
+               CMP     R14,#&20                ;Finished yet?
+               MOVCC   R14,#0                  ;Yes -- zero-terminate
+               STRB    R14,[R0],#1             ;And store it out
+               BCS     %b00                    ;No -- keep going
+               B       %10app__findNamedLink   ;And skip to main matcher
+
+               ; --- Handle a new-style DAN ---
+
+05             ADR     R1,misc__sharedBuf      ;Find the shared buffer
+00             LDRB    R14,[R0],#1             ;Load a byte from the name
+               CMP     R14,#']'                ;End of the name yet?
+               MOVEQ   R14,#0                  ;Yes -- terminate here then
+               CMP     R14,#&20                ;Finished yet?
+               MOVCC   R14,#0                  ;Yes -- zero-terminate
+               STRB    R14,[R1],#1             ;And store it out
+               BCS     %b00                    ;No -- keep going
+
+10app__findNamedLink
+               ADR     R1,misc__sharedBuf      ;Point to the DLL name
+
+00             LDR     R0,[R3,#lk_dll]         ;Find DLL pointer for block
+               BL      dll_compare             ;Compare with passed values
+               CMP     R0,#1                   ;Did it return TRUE?
+               BEQ     %30app__findNamedLink   ;Yes -- be happy
+               LDR     R3,[R3,#lk_next]        ;Find next pointer
+               CMP     R3,#0                   ;Is there any more to do?
+               BNE     %b00                    ;Yes -- loop round and do it
+
+20app__findNamedLink
+               LDMFD   R13!,{R3,R4,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;Return with V set
+
+30app__findNamedLink
+               LDR     R0,[R3,#lk_dll]         ;Load DLL pointer again
+               LDMFD   R13!,{R3,R4,R14}        ;Restore registers
+               BICS    PC,R14,#V_flag          ;Return with V clear
+
+               LTORG
+
+; --- app__findLink ---
+;
+; On entry:    R0 == pointer to application
+;              R1 == pointer to DLL
+; On exit:     R0 == pointer to link structure
+
+app__findLink  ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Preserve nice registers
+
+               ; --- Try looking at the cached value ---
+
+               LDR     R2,[R0,#app_cachedll]   ;Load the cached handle
+               CMP     R2,R1                   ;Is it a match?
+               LDREQ   R0,[R0,#app_cacheptr]   ;Yes -- load the pointer
+               LDMEQFD R13!,{R1,R2,PC}^        ;And return!
+
+               ; --- Otherwise, scan the list ---
+
+               LDR     R2,[R0,#app_dlls]       ;Get list head pointer
+               CMP     R2,#0                   ;Is there an entry here?
+               BEQ     %10app__findLink        ;No -- return an error
+00app__findLink        LDR     R14,[R2,#lk_dll]        ;Get the DLL's pointer
+               CMP     R1,R14                  ;Is it a match?
+               BEQ     %01app__findLink        ;Yes -- deal with it
+               LDR     R2,[R2,#lk_next]        ;No -- get the next pointer
+               CMP     R2,#0                   ;Is this the end?
+               BNE     %00app__findLink        ;No -- continue round
+
+               ; --- Couldn't find the application ---
+
+10app__findLink        ADRL    R0,msg_errLinkNotFound  ;Point to error message
+               LDMFD   R13!,{R1,R2,R14}        ;Pull back registers
+               ORRS    PC,R14,#V_flag          ;And return with an error
+
+               ; --- Found an application -- update the cache ---
+
+01app__findLink        STR     R1,[R0,#app_cachedll]   ;Store the new handle
+               STR     R2,[R0,#app_cacheptr]   ;And the new pointer
+               MOV     R0,R2                   ;Return the pointer to caller
+               LDMFD   R13!,{R1,R2,PC}^        ;And live happily ever after
+
+               LTORG
+
+; --- app__addLink ---
+;
+; On entry:    R0 == pointer to application
+;              R1 == pointer to DLL
+; On exit:     --
+
+app__addLink   ROUT
+
+               STMFD   R13!,{R1,R11,R14}       ;Stack registers
+               MOV     R11,R0                  ;Keep pointer to application
+
+               ; --- Find out whether the link is registered yet ---
+
+               BL      app__findLink           ;Call the find routine
+               LDMVCFD R13!,{R1,R11,PC}^       ;If already there, return
+
+               ; --- Allocate a block from the RMA ---
+
+               CMP     R0,R0                   ;Clear V flag
+               BL      sub_alloc               ;Allocate a link block
+               LDMVSFD R13!,{R1,R11,PC}        ;If it failed, return error
+
+               ; --- Link the block into the list ---
+
+               LDR     R14,[R11,#app_dlls]     ;Find the list header
+               STR     R14,[R0,#lk_next]       ;Store in next pointer
+               CMP     R14,#0                  ;Is there a next block?
+               STRNE   R0,[R14,#lk_prev]       ;Yes -- link in new block
+               MOV     R14,#0                  ;Zero out the previous link
+               STR     R14,[R0,#lk_prev]       ;Store in previous entry
+               STR     R0,[R11,#app_dlls]      ;Store this as new block
+
+               ; --- Set this block up in the cache ---
+
+               STR     R1,[R11,#app_cachedll]  ;Cache the DLL's pointer
+               STR     R0,[R11,#app_cacheptr]  ;Cache the app's pointer
+
+               ; --- Set up the block's data ---
+
+               STR     R1,[R0,#lk_dll]         ;Store pointer to DLL
+               MOV     R1,#0                   ;No workspace yet
+               STR     R1,[R0,#lk_work]        ;So store in the block
+
+               ; --- Mark as currently tentative ---
+
+               MOV     R1,#lk_tentative        ;Tentative flag
+               STR     R1,[R0,#lk_flags]       ;Store in block's flags area
+
+               ; --- Return the app's handle ---
+
+               LDMFD   R13!,{R1,R11,PC}^       ;Return to caller
+
+               LTORG
+
+; --- app__freeLink ---
+;
+; On entry:    R0 == pointer to application
+;               R1 == pointer to link structure
+; On exit:     --
+
+app__freeLink  ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stack registers
+
+               ; --- Fix up list ---
+
+               LDR     R2,[R1,#lk_next]        ;Get next pointer
+               LDR     R14,[R1,#lk_prev]       ;Get previous pointer
+               CMP     R2,#0                   ;Is there a real next block?
+               STRNE   R14,[R2,#lk_prev]       ;Yes -- fix backwards link
+               CMP     R14,#0                  ;Is there a real prev block?
+               ADDEQ   R14,R0,#app_dlls        ;No -- point to list head
+               STR     R2,[R14,#lk_next]       ;Fix forwards link
+
+               ; --- Free the link ---
+
+               MOV     R0,R1                   ;Point to the link
+               LDMFD   R13!,{R1,R2,R14}        ;Retreive registers
+               B       sub_free                ;Free the link block
+
+               LTORG
+
+; --- app__confLk ---
+;
+; On entry:    R0 == application to confirm
+; On exit:     --
+
+app__confLink  ROUT
+
+               STMFD   R13!,{R1,R14}           ;Stack registers
+               LDR     R0,[R0,#app_dlls]       ;Find head of the link list
+               CMP     R0,#0                   ;Is it empty?
+               LDMEQFD R13!,{R1,PC}^           ;Yes -- return to caller
+00app__confLink        LDR     R1,[R0,#lk_next]        ;Find the next entry
+               LDR     R14,[R0,#lk_flags]      ;Load flags word
+               BIC     R14,R14,#lk_tentative   ;Clear the magic flag
+               STR     R14,[R0,#lk_flags]      ;Store the flags word back
+               MOVS    R0,R1                   ;Move to next entry
+               BNE     %00app__confLink        ;If more to do, do next one
+               LDMFD   R13!,{R1,PC}^           ;Return to caller, confirmed
+
+               LTORG
+
+; --- app__cancel ---
+;
+; On entry:    R0 == app to cancel
+; On exit:     --
+
+app__cancel    ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stack registers
+               MOV     R2,R0                   ;Keep pointer to app block
+               LDR     R0,[R0,#app_dlls]       ;Find head of the link list
+               CMP     R0,#0                   ;Is it empty?
+               LDMEQFD R13!,{R1,R2,PC}^        ;Yes -- return to caller
+00app__cancel  LDR     R1,[R0,#lk_next]        ;Find the next entry
+               LDR     R14,[R0,#lk_flags]      ;Load flags word
+               TST     R14,#lk_tentative       ;Is the flag set?
+               BEQ     %01app__cancel          ;No -- move on to next one
+
+               LDR     R14,[R0,#lk_prev]       ;Find pointer to previous
+               CMP     R1,#0                   ;Is there a next block?
+               STRNE   R14,[R1,#lk_prev]       ;Fix up previous pointer
+               CMP     R14,#0                  ;Is there a previous block?
+               ADDEQ   R14,R2,#app_dlls        ;No -- point to list base
+               STR     R1,[R14,#lk_next]       ;Fix up next pointer
+               BL      sub_free                ;Free the block
+
+01app__cancel  MOVS    R0,R1                   ;Move to next entry
+               BNE     %00app__cancel          ;If more to do, do next one
+
+               MOV     R0,R2                   ;Point to application block
+               BL      app__freeUnused         ;If nothing left, kill app
+               LDMFD   R13!,{R1,R2,PC}^        ;Return to caller, cancelled
+
+               LTORG
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/s/dheader b/StraySrc/SDLS/DLLManager/s/dheader
new file mode 100644 (file)
index 0000000..51002b1
--- /dev/null
@@ -0,0 +1,302 @@
+;
+; dheader.s
+;
+; Module header for DLL manager
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.wSpace
+
+               GET     sh.misc
+               GET     sh.dll
+               GET     sh.app
+               GET     sh.suballoc
+               GET     sh.messages
+
+               IMPORT  hdr_help
+
+;----- Magic numbers --------------------------------------------------------
+
+hdr_swiChunk   EQU     &4A300                  ;SWI chunk number
+
+;----- Yer actual module header ---------------------------------------------
+
+               AREA    |!!!Module$$Header|,CODE,READONLY
+
+               DCD     hdr_enter               ;Module application code
+               DCD     hdr_init                ;Module initialisation code
+               DCD     hdr_final               ;Module finalisation code
+               DCD     hdr_service             ;Module service call code
+               DCD     hdr_title               ;Module title
+               DCD     hdr_help                ;Module version string
+               DCD     hdr_commands            ;Module *command table
+               DCD     hdr_swiChunk            ;Module SWI chunk number
+               DCD     hdr_swiHandler          ;Module SWI handler code
+               DCD     hdr_swiTable            ;Module SWI name table
+               DCD     hdr_swiCode             ;Module SWI name code
+
+;----- Some text strings ----------------------------------------------------
+
+hdr_title      DCB     "DLLManager",0
+
+;----- Initialisation and finalisation --------------------------------------
+
+hdr_init       ROUT
+
+               STMFD   R13!,{R14}              ;Stack anything relevant
+
+               ; --- Now we allocate some memory ---
+
+               MOV     R0,#6                   ;Better allocate some memory
+               LDR     R3,=dm__wSize           ;Get the length of the data
+               SWI     XOS_Module              ;Try to allocate the memory
+               LDMVSFD R13!,{PC}               ;If no memory, quit now
+
+               ; --- Store workspace address in private word ---
+
+               STR     R2,[R12]                ;Store in private word
+               MOV     R12,R2                  ;Keep relocation in R12 now
+
+               ; --- Initialise the workspace ---
+               ;
+               ; Just zero-init the whole lot.
+
+               MOV     R0,R2                   ;Point to base of area
+               ADD     R1,R2,R3                ;Find add length to get limit
+               BL      misc_zinit              ;Zero-init the whole lot
+
+               ; --- Set up application section ---
+
+               BL      app_init                ;Allow app to store PW
+
+               ; --- Tha's it ---
+
+               LDMFD   R13!,{PC}               ;We are initialised
+
+               LTORG
+
+hdr_final      ROUT
+
+               STMFD   R13!,{R12,R14}          ;Keep hold of the link
+               LDR     R12,[R12]               ;Get relocation offset
+               BL      app_checkQuit           ;Make sure we can quit
+               LDMVSFD R13!,{R12,PC}           ;If not, return the error
+               BL      dll_freeAll             ;Remove DLLs in memory
+               BL      app_killAll             ;Remove application blocks
+               BL      sub_die                 ;Remove link blocks
+               MOV     R2,R12                  ;Point to workspace
+               MOV     R0,#7                   ;Free the workspace
+               SWI     XOS_Module              ;Do it!
+               LDMFD   R13!,{R12}              ;Get back private word ptr
+               MOV     R0,#0                   ;Now zero out private word
+               STR     R0,[R12]                ;Right, now that's done
+               LDMFD   R13!,{PC}               ;Return to OS
+
+               LTORG
+
+;----- Application entry ----------------------------------------------------
+
+hdr_enter      EQU     0                       ;No module application code
+
+;----- *commands and things -------------------------------------------------
+
+; --- The commands table ---
+
+hdr_commands
+
+               DCB     "DLLs",0
+               ALIGN
+               DCD     hdr_dlls_c
+               DCB     0,0,1,0
+               DCD     synt_DLLs
+               DCD     help_DLLs
+
+               DCB     "DLLApps",0
+               ALIGN
+               DCD     hdr_dll_apps_c
+               DCB     0,0,1,0
+               DCD     synt_DLLApps
+               DCD     help_DLLApps
+
+               DCB     "DLLInfo",0
+               ALIGN
+               DCD     hdr_dll_info_c
+               DCB     1,0,2,0
+               DCD     synt_DLLInfo
+               DCD     help_DLLInfo
+
+               DCB     "DLLKillApp",0
+               ALIGN
+               DCD     hdr_dll_killapp_c
+               DCB     1,0,1,0
+               DCD     synt_DLLKillApp
+               DCD     help_DLLKillApp
+
+               DCB     "DLLReset",0
+               ALIGN
+               DCD     hdr_dll_reset_c
+               DCB     0,0,0,0
+               DCD     synt_DLLReset
+               DCD     help_DLLReset
+
+               DCB     "DLLEnsure",0
+               ALIGN
+               DCD     hdr_dll_ensure_c
+               DCB     2,0,2,0
+               DCD     synt_DLLEnsure
+               DCD     help_DLLEnsure
+
+               DCD     0
+
+; --- *DLLs ---
+
+hdr_dlls_c     LDR     R12,[R12]               ;Find relocation offset
+               CMP     R1,#0                   ;Did he give arguments?
+               BEQ     dll_list                ;Display a list of DLLs
+               B       app_listDLLs
+
+; --- *DLLApps ---
+
+hdr_dll_apps_c LDR     R12,[R12]               ;Load data relocation
+               CMP     R1,#0                   ;Did he give arguments?
+               BEQ     app_list                ;Display the list
+               B       app_listUsing
+
+; --- *DLLInfo ---
+
+hdr_dll_info_c LDR     R12,[R12]               ;Find relocation to data
+               B       dll_showInfo            ;Go to a routine that can
+
+; --- *DLLKillApp ---
+
+hdr_dll_killapp_c
+               LDR     R12,[R12]               ;Find relocation to data
+               STMFD   R13!,{R14}              ;Keep return address safe
+               BL      app_findNamed           ;Find the application named
+               LDMFD   R13!,{R14}              ;Get return address back
+               BVC     app_kill                ;If no error, kill the app
+               ORRS    PC,R14,#V_flag          ;Return to caller with error
+
+; --- *DLLReset ---
+
+hdr_dll_reset_c LDR    R12,[R12]
+               STMFD   R13!,{R14}
+               BL      sub_die
+               BL      dll_freeAll
+               LDMFD   R13!,{R14}
+               B       app_killAll
+
+; --- *DLLEnsure ---
+
+hdr_dll_ensure_c
+               LDR     R12,[R12]
+               B       dll_check
+
+;----- SWI stuff ------------------------------------------------------------
+
+; --- SWI name-number translation table ---
+
+hdr_swiTable   DCB     "DLL",0                 ;SWI name prefix
+
+               DCB     "Find",0
+               DCB     "FindFromTable",0
+               DCB     "Load",0
+               DCB     "Lose",0
+               DCB     "AppDying",0
+               DCB     "GiveCLibData",0
+               DCB     "FindCLibData",0
+               DCB     "InstanceVars",0
+               DCB     "SetInstanceVars",0
+               DCB     "AppData",0
+               DCB     "Prologue",0
+               DCB     "ReadStackPtr",0
+               DCB     "SetStackPtr",0
+               DCB     "NameApp",0
+               DCB     "Info",0
+               DCB     "FindEntry",0
+               DCB     "SaveHandle",0
+               DCB     "RestoreHandle",0
+               DCB     "FindInstanceVars",0
+               DCB     "RegisterAppEntryTable",0
+               DCB     "FindAppEntry",0
+               DCB     "SetExtensionTable",0
+
+               DCB     0                       ;End of list
+               ALIGN
+
+; --- Main SWI entry point ---
+
+hdr_swiHandler ROUT
+
+               LDR     R12,[R12]               ;Get workspace relocation
+               CMP     R11,#(%01hdr_swiHandler-%00hdr_swiHandler)/4
+               ADDCC   PC,PC,R11,LSL #2        ;Branch to correct handler
+               B       %01hdr_swiHandler       ;If SWI out of range, error
+
+00hdr_swiHandler
+               B       app_findDLL             ;DLL_Find
+               B       app_fromtable           ;DLL_FindFromTable
+               B       dll_load                ;DLL_Load
+               B       app_loseDLL             ;DLL_Lose
+               B       app_dying               ;DLL_AppDying
+               B       app_giveclib            ;DLL_GiveCLibData
+               B       app_findclib            ;DLL_FindCLibData
+               B       app_instvars            ;DLL_InstanceVars
+               B       dll_instvars            ;DLL_SetInstanceVars
+               B       app_appdata             ;DLL_AppData
+               B       app_prologue            ;DLL_Prologue
+               B       app_readstkptr          ;DLL_ReadStackPtr
+               B       app_setstkptr           ;DLL_SetStackPtr
+               B       app_setname             ;DLL_NameApp
+               B       dll_info                ;DLL_Info
+               B       dll_findEntry           ;DLL_FindEntry
+               B       app_getHandle           ;DLL_SaveHandle
+               B       app_restoreHandle       ;DLL_RestoreHandle
+               B       dll_findWorkspace       ;DLL_FindInstanceVars
+               B       app_setBtable           ;DLL_RegisterAppEntryTable
+               B       app_appEntry            ;DLL_FindAppEntry
+               B       app_fixExtension        ;DLL_SetExtensionTable
+
+01hdr_swiHandler
+               ADRL    R0,msg_errBadSWI        ;Point to an error message
+               ORRS    PC,R14,#V_flag          ;Return an error to OS
+
+               LTORG
+
+; --- Name-number translation code ---
+
+hdr_swiCode    EQU     0                       ;No name-number code
+
+;----- Service call handling ------------------------------------------------
+
+hdr_service    EQU     0                       ;Not interested in these
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/s/dll b/StraySrc/SDLS/DLLManager/s/dll
new file mode 100644 (file)
index 0000000..61915d4
--- /dev/null
@@ -0,0 +1,1350 @@
+;
+; dll.s
+;
+; Handling of DLL data structures
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.wSpace
+               GET     sh.dllblock
+               GET     sh.linkblock
+
+               GET     sh.misc
+               GET     sh.app
+
+               GET     sh.messages
+
+;----- External routines ----------------------------------------------------
+
+               AREA    |DLLM$$Code|,CODE,READONLY
+
+               GBLL    debug
+debug          SETL    {FALSE}
+
+; --- dll_find ---
+;
+; On entry:    R0 == name of DLL to find
+;              R1 == minimum version number of DLL
+; On exit:     R0 == pointer to DLL block, or error
+
+               EXPORT  dll_find
+dll_find       ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Preserve registers
+
+               MOV     R4,R1                   ;Keep hold of version number
+               MOV     R1,R0                   ;Keep pointer to string
+               LDR     R3,dll__list            ;Find the list
+
+00dll_find     CMP     R3,#0                   ;Is this the end of the line?
+               BEQ     %40dll_find             ;Yes -- give an error
+               LDR     R0,[R3,#dl_name]        ;Find the name string
+               MOV     R2,#0                   ;Caseless compare
+               BL      misc_strcmp             ;Compare the strings
+               LDRNE   R3,[R3,#dl_next]        ;If no match, move on...
+               BNE     %00dll_find             ;... and try again
+
+               ; --- We found a name match ---
+
+               LDR     R0,[R3,#dl_version]     ;Get version of DLL
+               CMP     R0,R4                   ;Check against version here
+               LDRLT   R3,[R3,#dl_next]        ;If too low, move on...
+               BLT     %00dll_find             ;... and try again
+
+               ; --- The name checked out -- return ---
+
+               MOV     R0,R3                   ;Point to DLL (give handle)
+               LDMFD   R13!,{R1-R4,PC}^        ;And return to caller
+
+               ; --- It wasn't there.  Return an error ---
+
+40dll_find     MOV     R0,R4                   ;Get version number
+               BL      dll_convertVersion      ;Convert it to a string
+               MOV     R2,R0                   ;Keep pointer to the string
+               ADRL    R0,msg_errDLLNotFound   ;Couldn't find DLL name
+               BL      misc_error              ;... create an error message
+               LDMFD   R13!,{R1-R4,R14}        ;... restore registers
+               ORRS    PC,R14,#V_flag          ;... and return an error
+
+               LTORG
+
+; --- dll_ensure ---
+;
+; On entry:    R0 == pointer to name to load
+;              R1 == version number of DLL
+; On exit:     R0 == DLL handle
+
+               EXPORT  dll_ensure
+dll_ensure     ROUT
+
+               STMFD   R13!,{R1-R5,R9-R11,R14} ;Stash registers somewhere
+
+               ; --- Find the name, and see if it's in memory ---
+
+               MOV     R10,R1                  ;Save the version number
+               BL      dll__createName         ;Set up the name
+               CMP     R0,#0                   ;Was it in memory?
+               LDMNEFD R13!,{R1-R5,R9-R11,PC}  ;If so, we should be happy
+               MOV     R9,R2                   ;Keep pointer to leafname
+
+               ; --- Find the size of the DLL and allocate memory ---
+
+01dll_ensure   MOV     R0,#17                  ;Read catalogue information
+               SWI     XOS_File                ;Read the information
+               LDMVSFD R13!,{R1-R5,R9-R11,PC}  ;If it failed, return now
+               CMP     R0,#1                   ;Check that the file was OK
+               BNE     %08dll_ensure           ;If not, complain properly
+               ADD     R3,R4,#dl_extra         ;Size of memory to get
+               MOV     R0,#6                   ;Allocate memory from RMA
+               SWI     XOS_Module              ;Allocate it
+               LDMVSFD R13!,{R1-R5,R9-R11,PC}  ;If no memory, return error
+
+               ; --- Load the DLL into the block ---
+
+               MOV     R0,R2                   ;Pointer to the block to use
+               MOV     R11,R0                  ;Keep hold of DLL handle
+               BL      dll__load               ;Load the DLL into the block
+               BVS     %10dll_ensure           ;If it failed, return error
+
+               ; --- Check the DLL's version number ---
+
+               LDR     R1,[R11,#dl_version]    ;Load the DLL's version
+               CMP     R1,R10                  ;Compare against version
+               BLT     %09dll_ensure           ;If too old, give an error
+
+               ; --- Link the new DLL into the list ---
+               ;
+               ; This also marks the DLL as being shared, since the shared
+               ; marker is dl_next not being -1.
+
+               LDR     R2,dll__list            ;Point to list head
+               STR     R11,dll__list           ;Store the next one
+               MOV     R0,#0                   ;Ready to zero bits
+               STR     R0,[R11,#dl_prev]       ;No previous DLL yet
+               STR     R2,[R11,#dl_next]       ;Fix up next link
+               CMP     R2,#0                   ;Is there another block?
+               STRNE   R11,[R2,#dl_prev]       ;If so, fix up prev link
+
+               ; --- Fix up other bits of data ---
+
+               MOV     R0,#dl_tentative        ;Set DLL's `tentative' bit
+               STR     R0,[R11,#dl_clients]    ;No clients registered yet
+
+               ; --- Start up any required DLLs ---
+
+               LDR     R1,[R11,#dl_dllLimit]   ;Find limit of DLL block
+               LDR     R0,[R11,#dl_dllBase]    ;Find base of same
+               BL      app_sfromtbl            ;Load any other required DLLs
+
+               ; --- Now return the DLL handle ---
+
+               MOVVC   R0,R11                  ;Get the DLL handle
+               LDMFD   R13!,{R1-R5,R9-R11,PC}  ;Return
+
+               ; --- Say that the file wasn't found ---
+
+08dll_ensure   ADRL    R0,msg_errFileNotFound  ;Point to error skeleton
+               BL      misc_error              ;Create the message
+               B       %10dll_ensure           ;Return to an error
+
+               ; --- Create an error about old version ---
+
+09dll_ensure   MOV     R0,R10                  ;Get the required version
+               BL      dll_convertVersion      ;Convert to a string
+               MOV     R2,R0                   ;Make that fillin 2
+               MOV     R1,R9                   ;Point to DLL name string
+               ADRL    R0,msg_errDLLTooOld     ;Point to error skeleton
+               BL      misc_error              ;Set up the error block
+
+               ; --- Free up memory and return an error ---
+
+10dll_ensure   MOV     R1,R0                   ;Keep hold of the error
+               MOV     R0,#7                   ;Free the block I allocated
+               MOV     R2,R11                  ;Point to the DLL block
+               SWI     XOS_Module              ;Do the free operation
+               MOV     R0,R1                   ;Put the error pointer back
+               LDMFD   R13!,{R1-R5,R9-R11,R14} ;Retreive registers
+               ORRS    PC,R14,#V_flag          ;Return with an error
+
+               LTORG
+
+; --- dll_check ---
+;
+; On entry:    R0 == pointer to name to load <SPACE> version number
+; On exit:     --
+
+               ; --- The format string for the command line ---
+
+dll__checkfmt  DCB     "/a/g,"
+               DCB     "/a/g",0
+               ALIGN
+
+               EXPORT  dll_check
+dll_check      ROUT
+
+               STMFD   R13!,{R1-R5,R9-R11,R14} ;Stack cunning registers
+
+               ; --- Allocate a nice buffer ---
+
+               MOV     R10,R0                  ;Keep pointer to cmd string
+               MOV     R0,#6                   ;Allocate some memory
+               MOV     R3,#256                 ;The size of said memory
+               SWI     XOS_Module              ;Get it
+               LDMVSFD R13!,{R1-R5,R9-R11,PC}  ;Return if we can't have it
+               MOV     R11,R2                  ;Save the pointer
+
+               ; --- Parse up the command string ---
+
+               ADR     R0,dll__checkfmt        ;Point to format string
+               MOV     R1,R10                  ;Point to command string
+               MOV     R2,R11                  ;Point to my nice buffer
+               MOV     R3,#256                 ;And do the business
+               SWI     XOS_ReadArgs            ;Get the OS to parse it up
+               BVS     %90dll_check            ;If it failed, return
+
+               ; --- Read the version number ---
+
+               LDR     R5,[R11,#4]             ;Get info about version strng
+               LDRB    R4,[R5,#0]              ;Get LSB of its length
+               LDRB    R3,[R5,#1]              ;Get MSB of its length
+               ORR     R4,R4,R3,LSL #8         ;Turn this into a length
+
+               MOV     R3,#10                  ;We're multiplying a lot
+               MOV     R10,#0                  ;The version as we know it
+               MOV     R2,#0                   ;Decimal part of version
+               ADD     R5,R5,#2                ;Point to the real string
+
+               CMP     R4,#0                   ;Is there a string there?
+               BEQ     %70dll_check            ;No -- that's an error
+00dll_check    LDRB    R0,[R5],#1              ;Get a character
+               CMP     R0,#'.'                 ;Is it a decimal point?
+               BEQ     %01dll_check            ;Yes -- next bit please
+               BL      %80dll_check            ;Convert it to a number
+               MLA     R10,R3,R10,R0           ;Add the digit on
+               SUBS    R4,R4,#1                ;Decrement length count
+               BNE     %00dll_check            ;Get another digit if I can
+               B       %03dll_check            ;Now check for the DLL...
+
+01dll_check    CMP     R4,#1                   ;Is the string empty now?
+               BEQ     %03dll_check            ;Yes -- get on with it
+               LDRB    R0,[R5]                 ;Get the next digit
+               BL      %80dll_check            ;Convert it to a number
+               MUL     R2,R3,R0                ;And put it nicely away
+               CMP     R4,#2                   ;Is there only one char?
+               BEQ     %03dll_check            ;Yes -- we've done it now
+               LDRB    R0,[R5,#1]              ;Get the remaining digit
+               BL      %80dll_check            ;Convert it to a number
+               ADD     R2,R2,R0                ;And put it in
+               CMP     R4,#3                   ;Make sure that's all
+               BNE     %70dll_check            ;If not, complain
+
+03dll_check    MOV     R3,#100                 ;Now join the two together
+               MLA     R10,R3,R10,R2           ;Now we have a version!
+
+               ; --- Now mangle the name to something usable ---
+
+               LDR     R0,[R11,#0]             ;Point to name info
+               LDRB    R4,[R0,#0]              ;Get LSB of name length
+               LDRB    R3,[R0,#1]              ;Get MSB of name length
+               ORR     R4,R4,R3,LSL #8         ;Convert to a real length
+               ADD     R0,R0,#2                ;Point to the actual name
+               MOV     R1,#0                   ;Zero-terminate it
+               STRB    R1,[R0,R4]              ;Store that in right place
+
+               ; --- Find out a good name to use ---
+
+               MOV     R1,R10                  ;Get the version number
+               BL      dll__createName         ;Turn this into a filename
+               CMP     R0,#0                   ;Was it in memory?
+               BEQ     %10dll_check            ;No -- continue onwards
+               MOV     R0,#7                   ;Free that buffer
+               MOV     R2,R11                  ;Point to it
+               SWI     XOS_Module              ;Free it for real now
+               LDMFD   R13!,{R1-R5,R9-R11,PC}^ ;Return to caller
+
+               ; --- Free the OS_ReadArgs buffer now ---
+
+10dll_check    MOV     R9,R2                   ;Keep pointer to leafname
+               MOV     R0,#7                   ;Free that buffer
+               MOV     R2,R11                  ;Point to it
+               SWI     XOS_Module              ;Free it for real now
+               ADD     R11,R1,#200             ;Keep a pointer to misc_buf
+
+               ; --- Open a file for the DLL ---
+
+               MOV     R0,#&4F                 ;Open, with errors, no path
+               SWI     XOS_Find                ;Find the file
+               BVS     %90dll_check            ;If it failed, give error
+               MOV     R5,R0                   ;Look after the handle
+
+               ; --- Now load a bit of the file ---
+
+               MOV     R2,R11                  ;Point to the misc_buf
+               MOV     R1,R5                   ;Get the file handle
+               MOV     R3,#20                  ;Get the first twenty bytes
+               MOV     R4,#0                   ;Read from the beginning
+               MOV     R0,#3                   ;Read bytes from file
+               SWI     XOS_GBPB                ;Quick, now, do it
+
+               ; --- Close the file ---
+
+               MOV     R0,#0                   ;Close the file
+               MOV     R1,R5                   ;Get the file handle
+               SWI     XOS_Find                ;Close the file
+
+               ; --- Now check the fields in the block ---
+
+               LDR     R0,[R11,#dl_magic-dl_extra] ;Get the magic DLL word
+               LDR     R1,=dl_MAGIC            ;Get the real version
+               CMP     R0,R1                   ;Check it's kosher
+               BNE     %91dll_check            ;If not, make an error
+
+               LDR     R0,[R11,#dl_bversion-dl_extra] ;Get format version
+               LDR     R1,=dl_VERSION          ;Get the one we're on now
+               CMP     R0,R1                   ;Compare the versions
+               BGT     %92dll_check            ;If too late, complain
+
+               LDR     R0,[R11,#dl_version-dl_extra] ;Get DLL version
+               CMP     R0,R10                  ;Cmp with caller's version
+               BLT     %93dll_check            ;If too late, complain
+
+               LDMFD   R13!,{R1-R5,R9-R11,PC}^ ;Return, job well done
+
+               ; --- Get a digit, and convert ---
+
+80dll_check    CMP     R0,#'0'                 ;Is it less than 0?
+               BLT     %70dll_check            ;Yes -- that's an error
+               CMP     R0,#'9'                 ;Is it greater than 9?
+               BGT     %70dll_check            ;Yes -- that's an error
+               SUB     R0,R0,#'0'              ;Convert to a digit
+               MOVS    PC,R14                  ;Return to caller
+
+               ; --- Make an error about a mangled version ---
+
+70dll_check    ADRL    R0,msg_errBadVersion    ;Point to error message
+               B       %90dll_check            ;Free memory and return error
+
+               ; --- Tidy up after an error and return ---
+
+90dll_check    MOV     R9,R0                   ;Look after error pointer
+               MOV     R0,#7                   ;Free that buffer
+               MOV     R2,R11                  ;Point to it
+               SWI     XOS_Module              ;Free it for real now
+               MOV     R0,R9                   ;Point to the error
+               LDMFD   R13!,{R1-R5,R9-R11,R14} ;Unstack all the registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               ; --- A file wasn't a real DLL ---
+
+91dll_check    ADRL    R0,msg_errNotADLL       ;Point to error
+               MOV     R1,R9                   ;Point to leafname
+               BL      misc_error
+               LDMFD   R13!,{R1-R5,R9-R11,R14} ;Unstack all the registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               ; --- A file had a silly version number ---
+
+92dll_check    ADRL    R0,msg_errTooNew        ;Point to error
+               MOV     R1,R9                   ;Point to leafname
+               BL      misc_error
+               LDMFD   R13!,{R1-R5,R9-R11,R14} ;Unstack all the registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               ; --- A file was too old for the caller ---
+
+93dll_check    MOV     R0,R10                  ;Get version number wanted
+               BL      dll_convertVersion      ;Convert to printable form
+               MOV     R2,R0                   ;That's fillin number 2
+               ADRL    R0,msg_errDLLTooOld     ;Point to error
+               MOV     R1,R9                   ;Point to leafname
+               BL      misc_error
+               LDMFD   R13!,{R1-R5,R9-R11,R14} ;Unstack all the registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- dll_load ---
+;
+; On entry:    R0 == DLL handle (block to load into)
+;              R1 == filename of DLL
+; On exit:     --
+
+               EXPORT  dll_load
+dll_load       ROUT
+
+               STMFD   R13!,{R1,R10,R11,R14}   ;Keep link register safe
+
+               ; --- Load the DLL into the block
+
+               MOV     R11,R0                  ;Keep DLL pointer safe
+               BL      dll__load               ;Load the DLL
+               LDMVSFD R13!,{R1,R10,R11,PC}    ;Return if there's an error
+
+               ; --- If it's late enough, fit it up to the application ---
+
+               LDR     R10,[R11,#dl_bversion]  ;Get the format version
+               CMP     R10,#100                ;Is it the old version?
+
+               LDRGT   R1,[R11,#dl_appStubs]   ;Find the app stubs table
+               CMPGT   R1,R11                  ;Is this pointer sensible?
+               BLE     %90dll_load             ;Yes -- skip this bit
+               LDR     R0,[R11,#dl_appStubNames] ;Find the names table
+               CMP     R0,R0                   ;Clear V flag
+               BL      app_fix                 ;Yes -- fix up the table
+               LDMVSFD R13!,{R1,R10,R11,PC}    ;Return if there's an error
+
+               ; --- Load any required shared DLLs ---
+
+90dll_load     LDR     R1,[R11,#dl_dllLimit]   ;Find limit of DLL block
+               LDR     R0,[R11,#dl_dllBase]    ;Find base of same
+               BL      app_fromtable           ;Load any other required DLLs
+               LDMFD   R13!,{R1,R10,R11,PC}    ;Return to caller
+
+               LTORG
+
+; --- dll_appEntry ---
+;
+; On entry:    R0 == pointer to application's entry table
+;              R1 == pointer to application's name table
+;              R2 == pointer to entry point name
+; On exit:     R0 == pointer to entry point (if present)
+
+               EXPORT  dll_appEntry
+dll_appEntry   ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Stack registers
+
+               MOV     R3,R2                   ;Keep pointer to entry point
+
+               ; --- Main matching loop ---
+
+00dll_appEntry LDRB    R4,[R1],#1              ;Get first byte of next name
+               CMP     R4,#0                   ;Is it a null byte?
+               BEQ     %41dll_appEntry         ;Yes -- couldn't find entry
+               CMP     R4,#1                   ;Is it a dummy entry?
+               BEQ     %10dll_appEntry         ;Yes -- don't check it then
+01dll_appEntry LDRB    R5,[R3],#1              ;Get byte from name too
+               CMP     R4,R5                   ;Do they match?
+               BNE     %02dll_appEntry         ;No -- find the next name
+               CMP     R4,#0                   ;Is this the end?
+               LDRNEB  R4,[R1],#1              ;No -- get another name byte
+               BNE     %01dll_appEntry         ;And go round again
+
+               ; --- We found it ---
+
+               LDR     R0,[R0,#0]              ;Get the actual entry address
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to caller happy
+
+               ; --- Move on to next name in the table ---
+
+02dll_appEntry CMP     R4,#0                   ;Is this the end of the name?
+               LDRNEB  R4,[R1],#1              ;No -- get another byte
+               BNE     %02dll_appEntry         ;And go round again
+
+10dll_appEntry ADD     R0,R0,#4                ;Move on to next entry ptr
+               MOV     R3,R2                   ;Point to start of entry name
+               B       %00dll_appEntry         ;And try that one out
+
+               ; --- Entry point could not be found ---
+
+41dll_appEntry MOV     R1,R2                   ;Point to entry point name
+               ADRL    R0,msg_errAppEntry      ;Point to error message
+               BL      misc_error              ;Create the error message
+               LDMFD   R13!,{R1-R5,R14}        ;Find saved registers
+               ORRS    PC,R14,#V_flag          ;Return the error to caller
+
+               ALIGN
+
+; --- dll_findEntry ---
+;
+; On entry:    R0 == pointer to DLL
+;              R1 == pointer to entry point name
+; On exit:     R0 == pointer to entry point
+
+               EXPORT  dll_findEntry
+dll_findEntry  ROUT
+
+               STMFD   R13!,{R1-R7,R14}        ;Stack registers
+
+               ; --- Set up for main loop ---
+
+               LDR     R7,[R0,#dl_entries]     ;Find number of entry points
+               LDR     R3,[R0,#dl_enames]      ;Point to start of name table
+               LDR     R4,[R0,#dl_eveneer]     ;No entry points found yet
+               TST     R7,#dl_noNames          ;No names?
+               BNE     %42dll_findEntry        ;Then deal with this
+               BICS    R2,R7,#&FF000000        ;Clear entry type flags
+               BEQ     %40dll_findEntry        ;No entry points -- weird
+
+               ; --- Find whether this name matches ---
+
+00dll_findEntry        MOV     R5,R1                   ;Point to string to match
+               LDRB    R14,[R3,#0]             ;Load first byte from name
+               CMP     R14,#1                  ;Is this a dummy entry?
+               ADDEQ   R3,R3,#1                ;Yes -- skip past the byte
+               BEQ     %10dll_findEntry        ;Yes -- don't check the name
+
+01dll_findEntry        LDRB    R6,[R5],#1              ;Read byte from pattern
+               LDRB    R14,[R3],#1             ;Read byte from target
+               CMP     R6,R14                  ;Do they match?
+               BNE     %02dll_findEntry        ;No -- try another string
+               CMP     R6,#0                   ;Is this the string end?
+               BNE     %01dll_findEntry        ;No -- try another char
+
+               ; --- We found the entry point ---
+
+               TST     R7,#dl_shortEntries     ;Are these APCS veneers?
+               MOVEQ   R0,R4                   ;Yes -- point to veneer base
+               LDRNE   R0,[R4,#0]              ;No -- return base address
+               LDMFD   R13!,{R1-R7,PC}^        ;Return to caller
+
+               ; --- No luck -- try another entry point ---
+
+02dll_findEntry        CMP     R14,#0                  ;Is this the end of the name?
+               LDRNEB  R14,[R3],#1             ;No -- get another character
+               BNE     %02dll_findEntry        ;And try again
+
+10dll_findEntry        SUBS    R2,R2,#1                ;Decrement entry point count
+               BEQ     %41dll_findEntry        ;If we ran out, that's it
+
+               TST     R7,#dl_shortEntries     ;Are these APCS veneers?
+               ADDEQ   R4,R4,#16               ;Yes -- move to next veneer
+               ADDNE   R4,R4,#4                ;No -- move to next word
+               B       %00dll_findEntry        ;And try again
+
+               ; --- DLL has no entry points ---
+
+40dll_findEntry        LDR     R1,[R0,#dl_name]        ;Point to DLL name
+               ADRL    R0,msg_errNoEntry       ;Point to error message
+               BL      misc_error              ;Create the error message
+               LDMFD   R13!,{R1-R7,R14}        ;Find saved registers
+               ORRS    PC,R14,#V_flag          ;Return the error to caller
+
+               ; --- Entry point could not be found ---
+
+41dll_findEntry        MOV     R2,R1                   ;Point to entry point name
+               LDR     R1,[R0,#dl_name]        ;Point to DLL name
+               ADRL    R0,msg_errDLLEntry      ;Point to error message
+               BL      misc_error              ;Create the error message
+               LDMFD   R13!,{R1-R7,R14}        ;Find saved registers
+               ORRS    PC,R14,#V_flag          ;Return the error to caller
+
+               ; --- DLL has no named entry points ---
+
+42dll_findEntry        LDR     R1,[R0,#dl_name]        ;Point to DLL name
+               ADRL    R0,msg_errNoNames       ;Point to error message
+               BL      misc_error              ;Create the error message
+               LDMFD   R13!,{R1-R7,R14}        ;Find saved registers
+               ORRS    PC,R14,#V_flag          ;Return the error to caller
+
+               LTORG
+
+; --- dll_showInfo ---
+;
+; On entry:    R0 == pointer to argument string
+; On exit:     --
+
+               EXPORT  dll_showInfo
+dll_showInfo   ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack some registers
+
+               ; --- Parse some arguments ---
+
+               MOV     R1,R0                   ;Point to the command tail
+               ADR     R0,dll_sinfoDef         ;Point to definition string
+               ADR     R2,misc__sharedBuf      ;Point to scratch buffer
+               MOV     R3,#256                 ;Size of my buffer
+               SWI     XOS_ReadArgs            ;Read the command line
+               LDMVSFD R13!,{R1-R4,PC}         ;Return if it didn't work
+
+               MOV     R4,#0                   ;Clear some flags
+               LDR     R14,[R2,#0]             ;Load the `full' flag
+               CMP     R14,#0                  ;Is it clear?
+               ORRNE   R4,R4,#1                ;No -- set the flag then
+
+               LDR     R0,[R2,#4]              ;Load the string pointer
+               CMP     R0,#0                   ;Is it there?
+               ADREQL  R0,synt_DLLInfo - 4     ;No -- point to syntax string
+               LDMEQFD R13!,{R1-R4,R14}        ;Restore registers
+               ORREQS  PC,R14,#V_flag          ;And return to caller
+
+               ; --- Find the DLL ---
+
+               MOV     R2,R0                   ;Keep hold of the pointer
+               MOV     R1,#0                   ;Don't care about version
+               BL      dll_find                ;Find the DLL pointer
+               BVS     %10dll_showInfo         ;Give an error if not found
+
+               ; --- Show the info :-) ---
+
+               MOV     R3,R0                   ;Keep pointer to DLL block
+               ADRL    R0,msg_dinfoName
+               SWI     XOS_Write0
+               LDR     R0,[R3,#dl_name]        ;Point to the DLL's name
+               SWI     XOS_Write0
+               SWI     XOS_NewLine
+
+               ADRL    R0,msg_dinfoAuthor
+               SWI     XOS_Write0
+               LDR     R0,[R3,#dl_copyright]   ;Point to the DLL's author
+               SWI     XOS_Write0
+               SWI     XOS_NewLine
+
+               ADRL    R0,msg_dinfoVersion
+               SWI     XOS_Write0
+               LDR     R0,[R3,#dl_version]     ;Point to the DLL's version
+               BL      dll_convertVersion      ;Convert the version number
+               SWI     XOS_Write0
+               SWI     XOS_NewLine
+
+               ADRL    R0,msg_dinfoReferences
+               SWI     XOS_Write0
+               LDR     R0,[R3,#dl_clients]     ;Get client count
+               BIC     R0,R0,#dl_tentative     ;Clear tentative bit if any
+               SUB     R13,R13,#12             ;Give some space for string
+               MOV     R1,R13                  ;Point to this space
+               MOV     R2,#12                  ;Size of the buffer
+               SWI     XOS_ConvertInteger4     ;Convert it to a string
+               SWI     XOS_Write0
+               ADD     R13,R13,#12             ;Reclaim workspace
+               SWI     XOS_NewLine
+
+               TST     R4,#1                   ;Do we want to print this?
+               BEQ     %02dll_showInfo         ;No -- don't then
+
+               ADRL    R0,msg_dinfoEntries
+               SWI     XOS_Write0
+
+               ; --- Write out entry point names ---
+
+               LDR     R2,[R3,#dl_entries]     ;Get number of entry points
+               TST     R2,#dl_noNames          ;No name table?
+               BNE     %08dll_showInfo         ;No -- tell user
+               BICS    R2,R2,#&FF000000        ;Clear type bits
+               BEQ     %09dll_showInfo         ;No entries -- spooky
+
+               LDR     R1,[R3,#dl_enames]      ;Point to first entry name
+00dll_showInfo SWI     XOS_WriteI+' '          ;Indent the list a bit
+               SWI     XOS_WriteI+' '
+
+01dll_showInfo LDRB    R0,[R1],#1              ;Get a name byte
+               CMP     R0,#1                   ;Is it a dummy entry?
+               SWIHI   XOS_WriteC              ;No -- write it out
+               BHS     %01dll_showInfo         ;And go round for the next
+
+               SWI     XOS_NewLine             ;Start a new line
+               SUBS    R2,R2,#1                ;Done another one
+               BGT     %00dll_showInfo         ;If more to do, continue
+
+               ; --- Return to caller ---
+
+02dll_showInfo LDMFD   R13!,{R1-R4,PC}^        ;Return with registers nice
+
+               ; --- Entry point table suppressed ---
+
+08dll_showInfo ADRL    R0,msg_dinfoHidden      ;Point to the string
+               SWI     XOS_Write0              ;Display that on the screen
+               B       %02dll_showInfo         ;And return to caller
+
+               ; --- No entry points -- freaky ---
+
+09dll_showInfo ADRL    R0,msg_dinfoNone        ;Point to the string
+               SWI     XOS_Write0              ;Display that on the screen
+               B       %02dll_showInfo         ;Resume information
+
+               ; --- Couldn't find the DLL ---
+
+10dll_showInfo MOV     R1,R2                   ;Point to DLL name
+               ADRL    R0,msg_errDLLNotInMem   ;Point to the error
+               BL      misc_error              ;Create error message fully
+               LDMFD   R13!,{R1-R4,R14}        ;Unstack all registers
+               ORRS    PC,R14,#V_flag          ;Return to caller with error
+
+dll_sinfoDef   DCB     "full/s,",0
+
+               LTORG
+
+; --- dll_writeTitle ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  dll_writeTitle
+dll_writeTitle ROUT
+
+               STMFD   R13!,{R14}              ;Stack link register for this
+               ADRL    R0,msg_dllHeader        ;Point to the header line
+               SWI     XOS_Write0              ;Display it nicely
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- dll_writeInfo ---
+;
+; On entry:    R0 == pointer to a DLL block
+; On exit:     --
+
+               EXPORT  dll_writeInfo
+dll_writeInfo  ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Stack some registers
+               MOV     R2,R0                   ;Keep hold of pointer
+               MOV     R1,#17                  ;Length of DLL name
+               LDR     R0,[R2,#dl_name]        ;Point to the name
+
+               MOV     R3,#0                   ;Length so far
+00             LDRB    R14,[R0,R3]             ;Load a byte
+               CMP     R14,#0                  ;At the end?
+               ADDNE   R3,R3,#1                ;No -- inc length
+               BNE     %b00                    ;And keep on looping
+
+               CMP     R3,#16                  ;Is this to long?
+               BL      dll_field               ;Display the name
+               SWIGT   OS_NewLine              ;Too long -- print a newline
+               MOVGT   R1,#17                  ;Print 21 spaces
+               ADRGT   R0,dll__nullStr         ;Point to the string
+               BLGT    dll_field               ;And do that thing
+               LDR     R0,[R2,#dl_version]     ;Load the version
+               BL      dll_convertVersion      ;Convert it to a string
+               MOV     R1,#10                  ;Length of version field
+               BL      dll_field               ;Display it on the screen
+               LDR     R0,[R2,#dl_copyright]   ;Point to copyright string
+               SWI     XOS_Write0              ;Display on the screen
+               SWI     XOS_NewLine             ;Follow with a newline
+               LDR     R2,[R2,#dl_next]        ;Point to next one along
+               LDMFD   R13!,{R1-R3,PC}^        ;Return to caller
+
+dll__nullStr   DCB     0
+
+               LTORG
+
+; --- dll_list ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  dll_list
+dll_list       ROUT
+
+               STMFD   R13!,{R1,R2,R14}
+
+               ; --- Set up for a loop through the list ---
+
+               LDR     R2,dll__list            ;Point to list
+               CMP     R2,#0                   ;Check that it's non-null
+               BEQ     %01dll_list             ;If so, give special message
+
+               ; --- Do a bit of screen set-up ---
+
+               BL      dll_writeTitle          ;Display the title line
+
+               ; --- Main loop ---
+
+00dll_list     MOV     R0,R2                   ;Point to DLL block
+               BL      dll_writeInfo           ;Display info about it
+               LDR     R2,[R2,#dl_next]        ;Point to next one along
+               CMP     R2,#0                   ;Is there another one?
+               BNE     %00dll_list             ;Yes -- display its stuff
+               LDMFD   R13!,{R1,R2,PC}^
+
+01dll_list     ADRL    R0,msg_noDLLs           ;Point to the message
+               SWI     XOS_Write0              ;Display that on the screen
+               LDMFD   R13!,{R1,R2,PC}^
+
+               LTORG
+
+; --- dll_convertVersion ---
+;
+; On entry:    R0 == version number
+; On exit:     R0 == pointer to version string
+
+               EXPORT  dll_convertVersion
+dll_convertVersion ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Preserve registers
+               MOV     R1,#100                 ;Divisor
+               BL      dll__divide             ;Find major and minor version
+               LDMVSFD R13!,{R1-R3,PC}         ;Return if there's an error
+               MOV     R3,R1                   ;Keep minor version
+               ADR     R1,misc__sharedBuf      ;Point to buffer
+               MOV     R2,#16                  ;Give it a sensible size
+               SWI     XOS_ConvertCardinal3    ;This is excessive, but...
+               LDMVSFD R13!,{R1-R3,PC}         ;Return if there's an error
+               MOV     R0,#'.'                 ;To be written to buffer
+               STRB    R0,[R1],#1              ;Write the decimal separator
+               SUB     R2,R2,#1                ;Another byte used in buffer
+               MOV     R0,R3                   ;Get minor version number
+               SWI     XOS_ConvertCardinal1    ;Can't be more than 100
+               LDMVSFD R13!,{R1-R3,PC}         ;Return if there's an error
+               LDRB    R2,[R0,#1]              ;Get second character
+               CMP     R2,#0                   ;Is there one?
+               BNE     %00dll_convertVersion   ;Yes -- skip ahead a bit
+               STRB    R2,[R0,#2]              ;Leave exactly 2 digits
+               LDRB    R2,[R0,#0]              ;Get first character
+               STRB    R2,[R0,#1]              ;Store in second position
+               MOV     R2,#'0'                 ;And write a leading 0
+               STRB    R2,[R0,#0]              ;In first position
+00dll_convertVersion
+               ADR     R0,misc__sharedBuf      ;Point to buffer
+               LDMFD   R13!,{R1-R3,PC}^        ;Return to caller nicely
+
+               LTORG
+
+; --- dll_field ---
+;
+; On entry:    R0 == pointer to string
+;              R1 == length of field
+
+               EXPORT  dll_field
+dll_field      ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Stash registers
+               MOV     R2,R0                   ;Keep hold of string ptr
+00dll_field    LDRB    R0,[R2],#1              ;Get a string byte
+               CMP     R0,#0                   ;Check the byte
+               BEQ     %01dll_field            ;If end, write pad chars
+               SWI     XOS_WriteC              ;Write the character
+               SUB     R1,R1,#1                ;Decrement counter thing
+               B       %00dll_field            ;If allowed, get the next one
+
+01dll_field    SUBS    R1,R1,#1                ;Decrement counter thing
+               LDMLEFD R13!,{R1,R2,PC}^        ;Return if done
+02dll_field    SWI     XOS_WriteI+' '          ;Write a space
+               SUBS    R1,R1,#1                ;Decrement counter thing
+               BGT     %02dll_field            ;If allowed, write another
+               LDMFD   R13!,{R1,R2,PC}^        ;Return happy :-)
+
+               LTORG
+
+; --- dll_compare ---
+;
+; On entry:    R0 == pointer to DLL
+;              R1 == pointer to name string
+;              R2 == required version number
+; On exit:     R0 == 1 for a match, or 0 for no match
+
+               EXPORT  dll_compare
+dll_compare    ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Keep registers safe
+               LDR     R14,[R0,#dl_version]    ;Find the version number
+               CMP     R2,R14                  ;How does it shape up?
+               BGT     %00dll_compare          ;If too low, return 0
+               MOV     R2,#0                   ;Case insensitive bitty
+               LDR     R0,[R0,#dl_name]        ;Point to DLL's name string
+               BL      misc_strcmp             ;Compare the strings
+               MOVEQ   R0,#1                   ;If there's a match, return 1
+               LDMEQFD R13!,{R1,R2,PC}^        ;Return to caller
+00dll_compare  MOV     R0,#0                   ;No match here
+               LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- dll_tentative ---
+;
+; On entry:    R0 == pointer to DLL
+; On exit:     --
+
+               EXPORT  dll_tentative
+dll_tentative  ROUT
+
+               STMFD   R13!,{R14}              ;Store return address
+               LDR     R14,[R0,#dl_clients]    ;Find the magic counter
+               ORR     R14,R14,#dl_tentative   ;Set the `tentative' bit
+               STR     R14,[R0,#dl_clients]    ;And store back again
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- dll_confirm ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  dll_confirm
+dll_confirm    ROUT
+
+               STMFD   R13!,{R14}              ;Store return address
+               LDR     R0,dll__list            ;Find list base address
+               CMP     R0,#0                   ;Are there any entries
+               LDMEQFD R13!,{PC}^              ;Return to caller if not
+00dll_confirm  LDR     R14,[R0,#dl_clients]    ;Find the magic counter
+               TST     R14,#dl_tentative       ;Is it a tentative one?
+               BICNE   R14,R14,#dl_tentative   ;Yes -- clear `tentative' bit
+               ADDNE   R14,R14,#1              ;Increment the counter
+               STRNE   R14,[R0,#dl_clients]    ;And store back again
+               LDR     R0,[R0,#dl_next]        ;Find next DLL in the chain
+               CMP     R0,#0                   ;Is this the end yet?
+               BNE     %00dll_confirm          ;Go round again if not
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- dll_retrace ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  dll_retrace
+dll_retrace    ROUT
+
+               STMFD   R13!,{R1,R14}           ;Keep registers safe
+               LDR     R0,dll__list            ;Find list base address
+               CMP     R0,#0                   ;Are there any more entries
+               LDMEQFD R13!,{R1,PC}^           ;Return to caller if not
+00dll_retrace  LDR     R1,[R0,#dl_next]        ;Find the next block along
+               LDR     R14,[R0,#dl_clients]    ;Load the magic counter
+               BICS    R14,R14,#dl_tentative   ;Clear the `tentative' bit
+               STR     R14,[R0,#dl_clients]    ;Store back in structure
+               BLEQ    dll__free               ;Free the block if no count
+               MOVS    R0,R1                   ;Point to next block along
+               BNE     %00dll_retrace          ;If any more to do, do more
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- dll_freeAll ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  dll_freeAll
+dll_freeAll    ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Preserve registers nicely
+               MOV     R0,#7                   ;Freeing memory now
+               LDR     R2,dll__list            ;Point to first entry
+               CMP     R2,#0                   ;Is there anything to do?
+               LDMEQFD R13!,{R1,R2,PC}^        ;No -- just leave now
+
+00dll_freeAll  LDR     R1,[R2,#dl_next]        ;Get next pointer in list
+               SWI     XOS_Module              ;Free the block
+               MOVS    R2,R1                   ;Point to the next entry
+               BNE     %00dll_freeAll          ;If any more to do, do them
+
+               STR     R2,dll__list            ;Store 0 back into list head
+01dll_freeAll  LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- dll_dec ---
+;
+; On entry:    R0 == pointer to DLL to decrement
+; On exit:     --
+
+               EXPORT  dll_dec
+dll_dec                ROUT
+
+               STMFD   R13!,{R14}              ;Preserve link register
+               LDR     R14,[R0,#dl_next]       ;Find whether it's shared
+               CMP     R14,#-1                 ;Just check to make sure
+               BEQ     %00dll_dec              ;If not, give an error
+               LDR     R14,[R0,#dl_clients]    ;Load the DLL count
+               SUBS    R14,R14,#1              ;Chop one off the counter
+               STRNE   R14,[R0,#dl_clients]    ;Store the count back
+               LDMNEFD R13!,{PC}^              ;Return to caller
+               LDMFD   R13!,{R14}              ;Pull back return address
+               B       dll__free               ;Free the DLL -- no clients
+
+00dll_dec      LDR     R1,[R0,#dl_name]        ;Point to the DLL's name
+               ADRL    R0,msg_errNotShared     ;Point to error message
+               BL      misc_error              ;Turn into a real error
+               LDMFD   R13!,{R1,R14}           ;Pull back return address
+               ORRS    PC,R14,#V_flag          ;Return the error
+
+               LTORG
+
+; --- dll_instvars ---
+;
+; On entry:    R0 == pointer to DLL
+;              R1 == pointer to data
+; On exit:     --
+
+               EXPORT  dll_instvars
+dll_instvars   ROUT
+
+               STMFD   R13!,{R1-R6,R14}        ;Stack registers
+
+               ; --- Store pointer if needs be ---
+
+               MOV     R3,R0                   ;Look after this pointer
+               LDR     R2,[R3,#dl_instBase]    ;Find start of data block
+               SUB     R4,R1,R2                ;Calculate relocation
+               LDR     R14,[R3,#dl_next]       ;Is there a next pointer?
+               CMP     R14,#-1                 ;Is the DLL shared?
+               BNE     %00dll_instvars         ;Yes -- don't store reloc
+               STR     R4,[R3,#dl_wspace]      ;Store in special offset
+
+               ; --- Copy the data across ---
+
+00dll_instvars LDR     R0,[R3,#dl_bversion]    ;Get the format version
+               CMP     R0,#100                 ;Is it too old for this?
+               BLE     %90dll_instvars         ;Yes -- skip ahead then
+
+               LDR     R5,[R3,#dl_zinitBase]   ;Get zero-init base address
+               LDR     R6,[R3,#dl_zinitLimit]  ;Get zero-init limit address
+
+               MOV     R0,R1                   ;Move destination pointer
+               MOV     R1,R2                   ;Find start of data block
+               CMP     R5,R6                   ;Is there a zinit area?
+               MOVLT   R2,R5                   ;Yes -- use zinit base addr
+               LDRGE   R2,[R3,#dl_instLimit]   ;No -- use data end address
+               SUB     R2,R2,R1                ;Convert pointer to length
+               BL      misc_memcpy             ;Copy the data across
+
+               ; --- If the format supports it, do zero-initing ---
+
+               CMP     R5,R6                   ;Are these sensible?
+               ADDLT   R0,R5,R4                ;Yes -- add relocation
+               ADDLT   R1,R6,R4
+               BLLT    misc_zinit              ;And zero-init the area
+
+               B       %99dll_instvars
+
+               ; --- Copy the whole lot across ---
+
+90dll_instvars MOV     R0,R1                   ;Move destination pointer
+               MOV     R1,R2                   ;Find start of data block
+               LDR     R2,[R3,#dl_instLimit]   ;Find end of data block
+               SUB     R2,R2,R1                ;Convert pointer to length
+               BL      misc_memcpy             ;Copy the data across
+
+99dll_instvars LDMFD   R13!,{R1-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- dll_findWorkspace ---
+;
+; On entry:    R0 == DLL handle
+; On exit:     R0 == pointer to workspace for the DLL
+;
+; So that the caller can free it when they kill the DLL
+
+               EXPORT  dll_findWorkspace
+dll_findWorkspace ROUT
+
+               STMFD   R13!,{R14}              ;Stack link register
+               LDR     R14,[R0,#dl_instBase]   ;Find workspace base address
+               LDR     R0,[R0,#dl_wspace]      ;Find the relocation
+               ADD     R0,R0,R14               ;Relocate the address
+               LDMFD   R13!,{PC}^              ;Return to the caller
+
+               LTORG
+
+; --- dll_convreloc ---
+;
+; On entry:    R0 == pointer to DLL
+;              R1 == pointer to data block
+; On exit:     R0 == relocation offset to use
+
+               EXPORT  dll_convreloc
+dll_convreloc  ROUT
+
+               STMFD   R13!,{R14}              ;Keep link register
+               LDR     R14,[R0,#dl_instBase]   ;Find base of static data
+               SUB     R0,R1,R14               ;Convert to a relocation
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- dll_info ---
+;
+; On entry:    R0 == pointer to DLL
+; On exit:     R0 preserved
+;              R1 == pointer to DLL name
+;              R2 == version number
+;              R3 == pointer to copyright string
+;              R4 == size of instance variables
+
+               EXPORT  dll_info
+dll_info       ROUT
+
+               LDR     R3,[R0,#dl_instBase]    ;Find base of variables
+               LDR     R4,[R0,#dl_instLimit]   ;Find limit of variables
+               SUB     R4,R4,R3                ;Turn this into length
+               LDR     R1,[R0,#dl_name]        ;Point to DLL's name
+               LDR     R2,[R0,#dl_version]     ;Load version number
+               LDR     R3,[R0,#dl_copyright]   ;Point to copyright string
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+; --- dll_datasize ---
+;
+; On entry:    R0 == pointer to DLL
+; On exit:     R0 == number of bytes to allocate
+
+               EXPORT  dll_datasize
+dll_datasize   ROUT
+
+               STMFD   R13!,{R14}              ;Keep link register
+               LDR     R14,[R0,#dl_instBase]   ;Find base of area
+               LDR     R0,[R0,#dl_instLimit]   ;Find end of area
+               SUB     R0,R0,R14               ;Convert to length
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+;----- Private routines -----------------------------------------------------
+
+; --- dll__createName ---
+;
+; On entry:    R0 == pointer to name to load
+;              R1 == version number to check for
+; On exit:     R0 == DLL handle if found in memory, or 0
+;              R1 == pointer to filename of DLL to use
+;               R2 == pointer to leafname of DLL if not in memory
+
+dll__createName        ROUT
+
+               STMFD   R13!,{R9-R11,R14}       ;Stash registers somewhere
+
+               ; --- Start off by putting `DLL:' in the buffer ---
+               ;
+               ; We may not need it, but at least it's there if we do.
+
+               MOV     R11,R0                  ;Remember this name pointer
+               MOV     R10,R1                  ;And remember the version
+               LDR     R14,dll__pathPrefix     ;Load the path prefix
+               ADR     R0,misc__sharedBuf+8    ;Point to shared buffer
+               STR     R14,[R0],#4             ;And store that away
+
+               ; --- Now set up for our search ---
+
+               ADR     R9,misc__sharedBuf+8    ;Filename assumed to be leaf
+               MOV     R2,R0                   ;Assume DLL name is leaf
+
+               ; --- The first character is special ---
+
+               LDRB    R14,[R11],#1            ;Load the next byte out
+               CMP     R14,#'['                ;Is this a new-style leaf?
+               BEQ     %20dll__createName      ;Yes -- skip to copy rest
+
+               ; --- Now enter the main loop ---
+
+00             CMP     R14,#'['                ;Found new-style name delim?
+               ADREQ   R9,misc__sharedBuf+8+4  ;Yes -- ignore `DLL:' bit
+               MOVEQ   R2,R0                   ;DLL name starts here
+               BEQ     %20dll__createName      ;Yes -- skip to copy rest
+
+               STRB    R14,[R0],#1             ;Store character in output
+               CMP     R14,#'.'                ;Found a path separator?
+               ADREQ   R9,misc__sharedBuf+8+4  ;Yes -- ignore `DLL:' bit
+               MOVEQ   R2,R0                   ;DLL name is here or later
+               CMP     R14,#&21                ;Is this the end of it all?
+               LDRCSB  R14,[R11],#1            ;No -- get the next byte
+               BCS     %b00                    ;And keep on looping
+
+               MOV     R14,#0                  ;Terminate the string
+               STRB    R14,[R0,#-1]            ;Stuff that over old term
+               B       %50dll__createName      ;Now go and find the DLL
+
+               ; --- Mess about with new-style names ---
+
+20             LDRB    R14,[R11],#1            ;Load another byte out
+               CMP     R14,#&21                ;Dropped off the end?
+               MOVCC   R14,#']'                ;Yes -- pretend it was right
+               CMP     R14,#']'                ;Finished yet?
+               MOVEQ   R14,#0                  ;Yes -- zero terminate
+               STRB    R14,[R0],#1             ;Store in the buffer
+               BNE     %20dll__createName      ;And keep looping
+
+               ; --- We've found all the names now ---
+
+50             MOV     R0,R2                   ;Point to the DLL leaf
+               MOV     R1,R10                  ;Find the version number
+               BL      dll_find                ;Try to find the dll
+               LDMVCFD R13!,{R9-R11,PC}        ;It was OK -- return then
+
+               MOV     R0,#0                   ;Couldn't find the DLL
+               MOV     R1,R9                   ;Point to the filename
+               LDMFD   R13!,{R9-R11,PC}^       ;Restore registers
+
+dll__pathPrefix        DCB     "dll:",0                ;Path variable to search
+               ALIGN
+
+               LTORG
+
+; --- dll__free ---
+;
+; On entry:    R0 == DLL handle to release
+; On exit:     --
+
+dll__free      ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Keep registers safe
+
+               ; --- Mangle the list nicely ---
+
+               LDR     R1,[R0,#dl_next]        ;Get pointer to next DLL
+               LDR     R2,[R0,#dl_prev]        ;And pointer to previous one
+               CMP     R1,#0                   ;Is there a next one?
+               STRNE   R2,[R1,#dl_prev]        ;Yes -- fix up previous ptr
+               CMP     R2,#0                   ;Is there a previous one?
+               ADREQ   R2,dll__list            ;No -- point to list head
+               STR     R1,[R2,#dl_next]        ;Fix up the pointer
+
+               ; --- Free the block ---
+
+               MOV     R2,R0                   ;Point to the block
+               MOV     R0,#7                   ;Magic number to free it
+               SWI     XOS_Module              ;Free it now
+               LDMFD   R13!,{R1,R2,PC}         ;Return to caller
+
+               LTORG
+
+; --- dll__load ---
+;
+; On entry:    R0 == pointer to block to load
+;              R1 == pointer to filename
+; On exit:     --
+
+dll__load      ROUT
+
+               STMFD   R13!,{R1-R5,R9-R11,R14}
+               MOV     R10,R0                  ;Keep pointer to block safe
+               MOV     R9,R1                   ;And look after the filename
+
+               ; --- Load the DLL into the buffer ---
+
+               MOV     R0,#16                  ;Load a file into memory
+               MOV     R3,#(1<<31)             ;Resync code areas when done
+               ADD     R2,R10,#dl_extra        ;Leave space for extra info
+               SWI     XOS_File                ;Try to load the file
+               LDMVSFD R13!,{R1-R5,R9-R11,PC}  ;Return the error if any
+
+               ; --- Check that it really is a DLL ---
+
+               LDR     R0,=dl_MAGIC            ;Find the magic DLL number
+               LDR     R1,[R10,#dl_magic]      ;Get the version from DLL
+               CMP     R0,R1                   ;Check they're the same
+               BNE     %40dll__load            ;If not, give an error
+
+               LDR     R0,=dl_VERSION          ;Get known version number
+               LDR     R1,[R10,#dl_bversion]   ;Get DLL's version number
+               CMP     R0,R1                   ;How do they match up?
+               BLT     %41dll__load            ;If too new, complain
+
+               ; --- Relocate the image ---
+
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,R10,#dl_relocate     ;Perform the relocation
+
+               ; --- Fill in the C library stubs ---
+
+               LDR     R0,[R10,#dl_stubs]      ;Get pointer to stubs table
+               CMP     R0,R10                  ;If it isn't invalid
+               BLS     %10dll__load            ;... don't skip ahead
+               BL      misc_copyStubs          ;Copy the clib branch table
+               LDMVSFD R13!,{R1-R5,R9-R11,PC}  ;Return the error if any
+
+               ; --- Mark the DLL as being non-shared ---
+               ;
+               ; Here we also clear the data relocation for non-shared DLLs
+               ; since they don't need to be multiply instantiated.  We *do*
+               ; allow extension DLLs to be multiply instantiated, though.
+               ; Clearing the relocation also has the side effect of
+               ; clearing a *shared* DLL's client counter.
+
+10dll__load    MOV     R0,#-1                  ;Non-shared is indicated...
+               STR     R0,[R10,#dl_next]       ;... by dl_next being -1
+               MOV     R0,#0                   ;Also, clear relocation
+               STR     R0,[R10,#dl_wspace]     ;(also clears client count)
+
+               ; --- That's it, then ---
+
+               LDMFD   R13!,{R1-R5,R9-R11,PC}^ ;Return to caller
+
+               ; --- Give an error about a bad DLL image ---
+
+40dll__load    ADRL    R0,msg_errNotADLL       ;Point to error message
+               B       %49dll__load            ;Go to error generation bit
+
+               ; --- Give an error about an unrecognised format version ---
+
+41dll__load    ADRL    R0,msg_errTooNew        ;Point to error message
+               B       %49dll__load            ;Go to error generation bit
+
+               ; --- Create an error and leave ---
+
+49dll__load    MOV     R1,R9                   ;Point to the filename
+               BL      misc_error              ;Fill in the error message
+               LDMFD   R13!,{R1-R5,R9-R11,R14} ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return an error
+
+               LTORG
+
+; --- dll__divide ---
+;
+; On entry:    R0 == dividend
+;              R1 == divisor
+; On exit:     R0 == quotient
+;              R1 == remainder
+;
+; This routine is mostly uncommented, 'cos I copied from Acorn's Assembler
+; documentation, and it should be accurate.  It's not exactly optimised,
+; but it should hold up to the sort of treatment I'm going to be giving it
+; (very delicate and occasional use).
+
+dll__divide    ROUT
+
+               STMFD   R13!,{R2,R3,R14}
+               CMP     R1,#0                   ;Check for stupidity
+               BEQ     %10dll__divide          ;If stupid, give an error
+
+               MOV     R3,R1
+               CMP     R3,R0,LSR #1
+00dll__divide  MOVLS   R3,R3,LSL #1
+               CMP     R3,R0,LSR #1
+               BLS     %00dll__divide
+
+               MOV     R2,#0
+01dll__divide  CMP     R0,R3
+               SUBCS   R0,R0,R3
+               ADC     R2,R2,R2
+               MOV     R3,R3,LSR #1
+               CMP     R3,R1
+               BCS     %01dll__divide
+
+               MOV     R1,R0                   ;Move results into right...
+               MOV     R0,R2                   ;... registers
+               LDMFD   R13!,{R2,R3,PC}^
+
+10dll__divide  ADRL    R0,msg_errDivide        ;Point to error message
+               LDMFD   R13!,{R2,R3,R14}        ;Retreive registers
+               ORRS    PC,R14,#V_flag          ;And returnt the error
+
+               LTORG
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/s/dllmdump b/StraySrc/SDLS/DLLManager/s/dllmdump
new file mode 100644 (file)
index 0000000..27c93ab
--- /dev/null
@@ -0,0 +1,211 @@
+;
+; dump.s
+;
+; DLLManager dump utility
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               GET     libs:header
+               GET     libs:swis
+               GET     sh.dllblock
+               GET     sh.appblock
+               GET     sh.linkblock
+               GET     sh.wspace
+
+               AREA    |!!!Foonly|,CODE,READONLY
+
+start          STMFD   R13!,{R14}
+               MOV     R0,#18
+               ADR     R1,modname
+               SWI     XOS_Module
+               LDMVSFD R13!,{PC}
+               MOV     R11,R12
+               MOV     R12,R4
+               SWI     OS_WriteS
+               DCB     "*** Dump of DLLManager workspace at &",0
+               MOV     R0,R12
+               BL      writeHex
+               SWI     OS_WriteS
+               DCB     13,10,10
+               DCB     "[DLL list]",13,10
+               DCB     13,10,0
+
+               ; --- Dump out DLL list ---
+
+               LDR     R7,dll__list
+
+dll_loop       CMP     R7,#0
+               BEQ     dump_apps
+               LDR     R0,[R7,#dl_name]
+               SWI     XOS_Write0
+               SWI     XOS_WriteI+' '
+               LDR     R0,[R7,#dl_version]
+               BL      writeDec
+               SWI     XOS_WriteS
+               DCB     13,10,"  Handle: ",0
+               MOV     R0,R7
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10,"  Links: ",0
+               LDR     R0,[R7,#dl_next]
+               BL      writeHex
+               SWI     XOS_WriteI+','
+               LDR     R0,[R7,#dl_prev]
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10,"  Ref count: ",0
+               LDR     R0,[R7,#dl_clients]
+               AND     R1,R0,#&80000000
+               BIC     R0,R0,#&80000000
+               BL      writeDec
+               CMP     R1,#0
+               BEQ     notent
+               SWI     XOS_WriteI+' '
+               SWI     XOS_WriteI+'['
+               SWI     XOS_WriteI+'T'
+               SWI     XOS_WriteI+']'
+notent         SWI     XOS_NewLine
+               SWI     XOS_NewLine
+               LDR     R7,[R7,#dl_next]
+               B       dll_loop
+
+modname                DCB     "DLLManager",0
+
+               ; --- Dump out application data ---
+
+dump_apps      SWI     XOS_WriteS
+               DCB     "[App data]",13,10
+               DCB     13,10
+               DCB     "Cached handle: ",0
+               LDR     R0,app__cacheHnd
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10
+               DCB     "Cached pointer: ",0
+               LDR     R0,app__cachePtr
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10
+               DCB     13,10
+               DCB     "[App list]",13,10
+               DCB     13,10,0
+
+               ; --- Dump out application list ---
+
+               LDR     R7,app__list
+
+app_loop       CMP     R7,#0
+               BEQ     dump_sub
+               ADD     R0,R7,#app_name
+               SWI     XOS_Write0
+               SWI     XOS_WriteS
+               DCB     13,10
+               DCB     "  External handle: ",0
+               LDR     R0,[R7,#app_handle]
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10
+               DCB     "  Internal handle: ",0
+               MOV     R0,R7
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10
+               DCB     "  Links: ",0
+               LDR     R0,[R7,#app_next]
+               BL      writeHex
+               SWI     XOS_WriteI+','
+               LDR     R0,[R7,#app_prev]
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10
+               DCB     "  Stack entries: ",0
+               LDR     R0,[R7,#app_stackPtr]
+               MOV     R0,R0,LSR #3            ;Divide it by 8
+               BL      writeDec
+               SWI     XOS_WriteS
+               DCB     13,10
+               DCB     "  Cached DLL handle: ",0
+               LDR     R0,[R7,#app_cachedll]
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10
+               DCB     "  Cached DLL link: ",0
+               LDR     R0,[R7,#app_cacheptr]
+               BL      writeHex
+               SWI     XOS_WriteS
+               DCB     13,10
+               DCB     "  DLL list",13,10,0
+
+               ; --- Dump out DLL list quickly ---
+
+               LDR     R8,[R7,#app_dlls]
+used_list      CMP     R8,#0
+               BEQ     app_end
+               LDR     R9,[R8,#lk_dll]
+               SWI     XOS_WriteI+' '
+               SWI     XOS_WriteI+' '
+               SWI     XOS_WriteI+' '
+               SWI     XOS_WriteI+' '
+               LDR     R0,[R9,#dl_name]
+               SWI     XOS_Write0
+               SWI     XOS_WriteI+' '
+               LDR     R0,[R9,#dl_version]
+               BL      writeDec
+               SWI     XOS_WriteI+' '
+               SWI     XOS_WriteI+'['
+               LDR     R0,[R8,#lk_work]
+               BL      writeHex
+               SWI     XOS_WriteI+']'
+               LDR     R0,[R8,#lk_flags]
+               CMP     R0,#0
+               BEQ     floop
+               SWI     XOS_WriteI+' '
+               SWI     XOS_WriteI+'['
+               SWI     XOS_WriteI+'T'
+               SWI     XOS_WriteI+']'
+floop          SWI     XOS_NewLine
+               LDR     R8,[R8,#lk_next]
+               B       used_list
+
+app_end                SWI     XOS_NewLine
+               LDR     R7,[R7,#app_next]
+               B       app_loop
+
+               ; --- Dump sub_alloc information ---
+
+dump_sub       LDMFD   R13!,{PC}
+
+writeHex       STMFD   R13!,{R1,R2,R14}
+               MOV     R1,R11
+               MOV     R2,#256
+               SWI     XOS_ConvertHex8
+               SWI     XOS_Write0
+               LDMFD   R13!,{R1,R2,PC}^
+
+writeDec       STMFD   R13!,{R1,R2,R14}
+               MOV     R1,R11
+               MOV     R2,#256
+               SWI     XOS_ConvertInteger4
+               SWI     XOS_Write0
+               LDMFD   R13!,{R1,R2,PC}^
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/s/misc b/StraySrc/SDLS/DLLManager/s/misc
new file mode 100644 (file)
index 0000000..bef7c6e
--- /dev/null
@@ -0,0 +1,393 @@
+;
+; misc.s
+;
+; Miscellaneous things for DLL Manager
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.wSpace
+
+               GET     sh.messages
+
+;----- Some magic numbers ---------------------------------------------------
+
+misc_entkrnl   EQU     4*48                    ;48 kernel entries
+misc_entclib   EQU     4*183                   ;183 CLib entries
+misc_wspkrnl   EQU     &31C                    ;&31C bytes of kernel vars
+misc_wspclib   EQU     &B48                    ;&B48 bytes of clib vars
+misc_clibVer   EQU     5                       ;Current CLib version
+
+;----- External routines ----------------------------------------------------
+
+               AREA    |DLLM$$Code|,CODE,READONLY
+
+; --- misc_getCLib ---
+;
+; On entry:    --
+; On exit:     --
+
+               EXPORT  misc_getCLib
+misc_getCLib   ROUT
+
+               BIC     R14,R14,#V_flag         ;Clear error indicator
+               STMFD   R13!,{R1-R6,R14}        ;Store registers nicely
+
+               ; --- Allocate workspace for SharedCLibrary to corrupt ---
+               ;
+               ; The SharedCLibrary wants some workspace that it can
+               ; initialise.  We're not actually using it, so we don't need
+               ; any workspace, although it still wants some.  So we
+               ; allocate some for a bit, and get rid of it again.
+
+               MOV     R0,#6                   ;Allocate space for CLib
+               LDR     R4,=misc_wspkrnl        ;Amount of space for kernel
+               LDR     R5,=misc_wspclib        ;Amount of space for C lib
+               ADD     R3,R3,#1024             ;Add an extra 1K for luck
+               ADD     R3,R4,R5                ;Amount of space reqd
+               SWI     XOS_Module              ;Try to allocate memory
+               LDMVSFD R13!,{R1-R6,PC}         ;Return if it failed
+
+               ; --- Set up stub table temporarily on the stack ---
+
+               SUB     R13,R13,#44             ;Reserve space for stub table
+               MOV     R0,R13                  ;Point to base of table
+               STR     R2,[R0,#12]             ;Store workspace pointer
+               ADD     R2,R2,R4                ;Limit of kernel space
+               STR     R2,[R0,#16]             ;Store workspace pointer
+               STR     R2,[R0,#32]             ;Store as Clib pointer
+               ADD     R2,R2,R5                ;Limit of C lib space
+               STR     R2,[R0,#36]             ;Store as C lib limit
+
+               ; --- Set up pointers to branch table in the stub block ---
+
+               ADR     R2,misc__stubs          ;Point to entry point table
+               LDR     R4,=misc_entkrnl        ;Get size of kernel entries
+               LDR     R5,=misc_entclib        ;Get size of C lib entries
+               STR     R2,[R0,#4]              ;Store kernel entry start
+               ADD     R2,R2,R4                ;Limit of kernel entries
+               STR     R2,[R0,#8]              ;Store kernel entry limit
+               STR     R2,[R0,#24]             ;Store C lib entry start
+               ADD     R2,R2,R5                ;Limit of C lib entries
+               STR     R2,[R0,#28]             ;Store C lib entry limit
+
+               ; --- Finish off the stub table ---
+
+               MOV     R2,#1                   ;Kernel chunk ID
+               STR     R2,[R0,#0]              ;Store in correct place
+               MOV     R2,#2                   ;C lib chunk ID
+               STR     R2,[R0,#20]             ;Store in correct place
+               MOV     R2,#-1                  ;Chunk table end marker
+               STR     R2,[R0,#40]             ;Store at end of table
+
+               ; --- Get the branch table from the C Library ---
+
+               LDR     R1,[R0,#36]             ;Get limit of that space
+               ADD     R2,R1,#1024             ;Point to end of block
+               MOV     R3,#-1                  ;No zero-inited space
+               MOV     R4,#0                   ;No static data to move
+               MOV     R5,#-1                  ;No static data to move
+               MOV     R6,#&1000               ;4096 byte stack please :-)
+               SWI     XSharedCLibrary_LibInitModule ;Do the stuff
+               ADRVSL  R5,msg_errNoCLib        ;If it failed, point to err
+               MOVVC   R5,#0                   ;Otherwise, clear error mark
+
+               ; --- Tidy up the stack and the temporary space ---
+
+               MOV     R0,#7                   ;Free that memory I nabbed
+               LDR     R2,[R13,#12]            ;Get pointer to the space
+               ADD     R13,R13,#44             ;Move stack pointer back
+               SWI     XOS_Module              ;Free it now
+               LDMVSFD R13!,{R1-R6,PC}         ;If that failed, return error
+               MOVS    R0,R5                   ;Copy error pointer
+               LDMNEFD R13!,{R1-R6,R14}        ;If there was an error, unstk
+               ORRNES  PC,R14,#V_flag          ;And quit with V set
+
+               ; --- Make sure the library was new enough ---
+
+               CMP     R6,#misc_clibVer        ;Ensure returned version
+               ADRLTL  R0,msg_errOldCLib       ;If too low, point to error
+               LDMFD   R13!,{R1-R6,R14}        ;Get registers anyway
+               ORRLTS  PC,R14,#V_flag          ;If too old, quit with V set
+               BICS    PC,R14,#V_flag          ;Otherwise, clear V flag
+
+               LTORG
+
+; --- misc_copyStubs ---
+;
+; On entry:    R0 == pointer to stubs table
+; On exit:     --
+
+               EXPORT  misc_copyStubs
+misc_copyStubs ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Preserve registers
+               ADR     R1,misc__stubs          ;Get pointer to stub table
+
+               LDR     R14,[R1,#0]             ;Load the first entry
+               CMP     R14,#0                  ;Has it been filled in?
+               BLEQ    misc_getCLib            ;No -- find C library stuff
+               BVS     %80misc_copyStubs       ;If it failed, return error
+
+               LDR     R0,[R13],#4             ;Load branch table pointer
+               LDR     R2,=misc_entkrnl+misc_entclib ;Get size of table
+               SUB     R3,R1,R0                ;Find ptr_diff 'tween tables
+               MOV     R3,R3,LSR #2            ;Shift off bottom two 0 bits
+
+               SUBS    R2,R2,#4                ;Decrement counter for table
+00misc_copyStubs
+               LDR     R14,[R1,R2]             ;Get the word from the table
+               ADD     R14,R14,R3              ;Relocate to destination
+               BIC     R14,R14,#&FF000000      ;Clear some bits, for safety
+               ORR     R14,R14,#&EA000000      ;Add on the opcode nicely
+               STR     R14,[R0,R2]             ;Store in destination table
+               SUBS    R2,R2,#4                ;Decrement counter for table
+               BGE     %00misc_copyStubs       ;Continue if anything left
+
+               LDMFD   R13!,{R1-R3,R14}        ;Return if complete
+               BICS    PC,R14,#V_flag          ;Return with no errors
+
+80misc_copyStubs
+               ADD     R13,R13,#4              ;Don't restore R0
+               LDMFD   R13!,{R1-R3,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+; --- misc_strcmp ---
+;
+; On entry:    R0 == pointer to string A
+;              R1 == pointer to string B
+;              R2 == 0 => case insensitive, 1 => case sensitive
+;
+; On exit:     Flags as appropriate
+;
+; Recently bodged to allow space-separated strings, which CLIGuard approves
+; of more.
+
+               EXPORT  misc_strcmp
+misc_strcmp    ROUT
+
+               STMFD   R13!,{R0,R1,R3,R4,R14}
+00misc_strcmp  LDRB    R3,[R0],#1              ;Get a character from A
+               LDRB    R4,[R1],#1              ;And one from B
+
+               CMP     R2,#0                   ;Do we want to do case xlate?
+               BNE     %10misc_strcmp          ;No -- miss it out then
+
+               SUB     R14,R3,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R3,R3,#&20              ;Yes -- convert to upper
+               SUB     R14,R4,#'a'             ;Subtract the bottom limit
+               CMP     R14,#26                 ;Is it a lower case letter?
+               BICLO   R4,R4,#&20              ;Yes -- convert to upper
+
+10misc_strcmp  CMP     R3,#&21                 ;Is that the end of A?
+               MOVCC   R3,#0                   ;Yes -- pretend it's null
+               CMP     R4,#&21                 ;Is that the end of B?
+               MOVCC   R4,#0                   ;Yes -- pretend it's null
+
+               CMP     R3,R4                   ;How do they match up?
+               LDMNEFD R13!,{R0,R1,R3,R4,PC}   ;If NE, return condition
+               CMP     R3,#0                   ;Is this the end?
+               BNE     %00misc_strcmp          ;No -- loop again
+               LDMFD   R13!,{R0,R1,R3,R4,PC}   ;Return to caller
+
+               LTORG
+
+; --- misc_memcpy ---
+;
+; On entry:    R0 == pointer to destination
+;              R1 == pointer to source
+;              R2 == length to copy
+; On exit:     --
+
+               EXPORT  misc_memcpy
+misc_memcpy    ROUT
+
+               STMFD   R13!,{R1-R9,R14}        ;Stack registers
+
+               ; --- Do the fast copy of most of the data ---
+
+00misc_memcpy  SUBS    R2,R2,#32               ;Check there's 32 bytes left
+               LDMGEIA R1!,{R3-R9,R14}         ;Load 8 words (32 bytes)
+               STMGEIA R0!,{R3-R9,R14}         ;And store in workspace
+               BGE     %00misc_memcpy          ;Try for another one
+
+               ; --- Now do a word-by-word copy ---
+
+               ADD     R2,R2,#32               ;Reinstate the byte count
+01misc_memcpy  SUBS    R2,R2,#4                ;Check there's 4 bytes left
+               LDRGE   R14,[R1],#4             ;Load 1 word (4 bytes)
+               STRGE   R14,[R0],#4             ;And store in workspace
+               BGE     %01misc_memcpy          ;Try for another one
+
+               LDMFD   R13!,{R1-R9,PC}^        ;Return to caller
+
+               LTORG
+
+; --- misc_zinit ---
+;
+; On entry:    R0 == pointer to base of area
+;              R1 == pointer to limit
+; On exit:     --
+
+               EXPORT  misc_zinit
+misc_zinit     ROUT
+
+               STMFD   R13!,{R1-R8,R14}        ;Stack registers
+
+               ; --- Set up *lots* of zeroes ---
+
+               MOV     R2,#0
+               MOV     R3,#0
+               MOV     R4,#0
+               MOV     R5,#0
+               MOV     R6,#0
+               MOV     R7,#0
+               MOV     R8,#0
+               MOV     R14,#0
+
+               ; --- Do the fast copy of most of the data ---
+
+               SUB     R1,R1,R0                ;Convert limit to length
+
+00misc_zinit   SUBS    R1,R1,#32               ;Check there's 32 bytes left
+               STMGEIA R0!,{R2-R8,R14}         ;And store in workspace
+               BGE     %00misc_zinit           ;Try for another one
+
+               ; --- Now do a word-by-word copy ---
+
+               ADD     R1,R1,#32               ;Reinstate the byte count
+01misc_zinit   SUBS    R1,R1,#4                ;Check there's 4 bytes left
+               STRGE   R14,[R0],#4             ;And store in workspace
+               BGE     %01misc_zinit           ;Try for another one
+
+               LDMFD   R13!,{R1-R8,PC}^        ;Return to caller
+
+               LTORG
+
+; --- misc_strcpy ---
+;
+; On entry:    R0 == destination string
+;              R1 == source string
+; On exit:     R0 == pointer to terminator of destination
+
+               EXPORT  misc_strcpy
+misc_strcpy    ROUT
+
+               STMFD   R13!,{R1,R14}           ;Keep return address safe
+00misc_strcpy  LDRB    R14,[R1],#1             ;Get a byte from source
+               CMP     R14,#' '                ;Is it a control character
+               MOVLT   R14,#0                  ;Yes -- translate to a 0
+               STRB    R14,[R0],#1             ;Store in destination
+               BGE     %00misc_strcpy          ;No -- copy another byte
+               SUB     R0,R0,#1                ;Point back at terminator
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+; --- misc__subst ---
+;
+; On entry:    R0 == Pointer to error message skeleton
+;              R1 == Filler 1
+;              R2 == Filler 2
+;              R3 == Filler 3
+;              R4 == Filler 4
+;              R5 == Pointer to buffer
+; On exit:     --
+
+misc__subst    ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+
+00misc__subst  LDRB    R14,[R0],#1             ;Get an input character
+               CMP     R14,#'%'                ;Is it a '%' sign?
+               BEQ     %01misc__subst          ;Yes -- deal with it
+02misc__subst  STRB    R14,[R5],#1             ;Not special, so store it
+               CMP     R14,#0                  ;Is it the end of input?
+               BNE     %00misc__subst          ;No -- get another one
+               LDMFD   R13!,{R1-R5,PC}^        ;And return to caller
+
+01misc__subst  LDRB    R14,[R0],#1             ;Get the next character
+               SUB     R1,R14,#'0'             ;Get the index
+               CMP     R1,#4                   ;Is it in range?
+               BCS     %02misc__subst          ;No -- just ignore the '%'
+               LDR     R1,[R13,R1,LSL #2]      ;Load appropriate register
+
+03misc__subst  LDRB    R14,[R1],#1             ;Get an input byte
+               CMP     R14,#&20                ;Is it the end of the string?
+               STRCSB  R14,[R5],#1             ;No -- store it in output
+               BCS     %03misc__subst          ;... and get another one
+               B       %00misc__subst          ;Yes -- read main string
+
+               LTORG
+
+; --- misc_error ---
+;
+; On entry:    R0 == Pointer to error message skeleton
+;              R1 == Filler 1
+;              R2 == Filler 2
+;              R3 == Filler 3
+;              R4 == Filler 4
+; On exit:     R0 == Pointer to constructed error in misc__errorBuf
+
+               EXPORT  misc_error
+misc_error     ROUT
+
+               STMFD   R13!,{R5,R14}
+               ADR     R5,misc__errorBuf       ;Point to error buffer
+               LDR     R14,[R0],#4             ;Read the error's number
+               STR     R14,[R5],#4             ;And store in the new buffer
+               BL      misc__subst             ;Do the substitution
+               SUB     R0,R5,#4                ;Point at the buffer
+               LDMFD   R13!,{R5,PC}^           ;And return to caller
+
+               LTORG
+
+; --- misc_subst ---
+;
+; On entry:    R0 == Pointer to error message skeleton
+;              R1 == Filler 1
+;              R2 == Filler 2
+;              R3 == Filler 3
+;              R4 == Filler 4
+; On exit:     R0 == Pointer to constructed string in misc__errorBuf
+
+               EXPORT  misc_subst
+misc_subst     ROUT
+
+               STMFD   R13!,{R5,R14}
+               ADR     R5,misc__errorBuf       ;Point to error buffer
+               BL      misc__subst             ;Do the substitution
+               MOV     R0,R5                   ;Point at the buffer
+               LDMFD   R13!,{R5,PC}^           ;And return to caller
+
+               LTORG
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/s/suballoc b/StraySrc/SDLS/DLLManager/s/suballoc
new file mode 100644 (file)
index 0000000..69ca6ac
--- /dev/null
@@ -0,0 +1,150 @@
+;
+; suballoc.s
+;
+; Handling of requests for small link blocks
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.wSpace
+               GET     sh.linkblock
+
+;----- Word to the wise -----------------------------------------------------
+;
+; The DLink manager requires lots of small blocks for linked lists and
+; things.  To avoid mangling the RMA, we allocate very big blocks and then
+; split them up into littler ones.  The format of the very big blocks is as
+; follows:
+;
+;    +0  link to next one
+;    +4  [data]
+;
+; The data blocks are allocated such that they are just big enough for the
+; data -- the caller must specify the actual size of the block when freeing.
+; Freed blocks are *not* returned to the OS.  There isn't much point -- it
+; would take ages, and they're only going to be allocated again anyway.  All
+; big blocks are returned to the OS when the module quits.
+
+;----- Magic numbers --------------------------------------------------------
+
+bigBlockSize   EQU     1024*lk_strSize+4       ;Allocate 1024 small blocks
+                                               ;at a time
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |DLLM$$Code|,CODE,READONLY
+
+               GBLL    debug
+debug          SETL    {FALSE}
+
+; --- sub_alloc ---
+;
+; On entry:    --
+; On exit:     R0 == pointer to block allocated, or 0 if no memory
+;
+
+               EXPORT  sub_alloc
+sub_alloc      ROUT
+
+               STMFD   R13!,{R1-R4,R14}
+               LDR     R0,sub__free            ;Get the free list offset
+               CMP     R0,#0                   ;Are there any free blocks?
+               BEQ     %01sub_alloc            ;No -- better allocate some
+
+00sub_alloc    LDR     R2,[R0]                 ;Get next pointer from block
+               STR     R2,sub__free            ;This is now first free block
+               LDMFD   R13!,{R1-R4,PC}^        ;Restore registers and return
+
+01sub_alloc    MOV     R0,#6                   ;Allocate some more from RMA
+               LDR     R3,=bigBlockSize        ;Allocate correct size
+               SWI     XOS_Module              ;Allocate the block
+               LDMVSFD R13!,{R1-R4,PC}         ;Return on an error
+
+               LDR     R4,sub__blocks          ;Load the pointer
+               STR     R4,[R2]                 ;Store in next ptr of new blk
+               STR     R2,sub__blocks          ;And link new block into list
+
+               MOV     R0,#0                   ;Next free pointer start at 0
+               SUB     R3,R3,#lk_strSize       ;Offset to next field of sub
+02sub_alloc    STR     R0,[R2,R3]              ;Store in next field
+               ADD     R0,R2,R3                ;Point to that block
+               SUBS    R3,R3,#lk_strSize       ;Point to previous block
+               BGT     %02sub_alloc            ;If more to do, continue...
+               B       %00sub_alloc            ;Then allocate as normal
+
+               LTORG
+
+; --- sub_free ---
+;
+; On entry:    R0 == pointer to block
+; On exit:     R0 corrupted
+
+               EXPORT  sub_free
+sub_free       ROUT
+
+               STMFD   R13!,{R14}              ;Preserve registers
+               LDR     R14,sub__free           ;Get current first block
+               STR     R14,[R0]                ;Store in newly freed block
+               STR     R0,sub__free            ;And insert new block in list
+               LDMFD   R13!,{PC}^              ;Oh, and return to caller
+
+               LTORG
+
+; --- sub_die ---
+;
+; On entry:    --
+; On exit:     R0 corrupted
+
+               EXPORT  sub_die
+sub_die                ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Preserve used registers
+               MOV     R3,#0                   ;No errors yet
+               LDR     R2,sub__blocks          ;Point to list of blocks
+               MOV     R0,#0                   ;Blank out bigblock pointer
+               STR     R0,sub__blocks          ;In case it fails a bit
+               STR     R0,sub__free
+00sub_die      CMP     R2,#0                   ;Are we at the end?
+               BEQ     %01sub_die              ;Yes -- leave the loop
+               LDR     R1,[R2]                 ;Get next pointer right now
+               MOV     R0,#7                   ;Free memory
+               SWI     XOS_Module              ;Free the block up
+               MOVVS   R3,R0                   ;Remember the error, if any
+               MOV     R2,R1                   ;Move on to next block
+               B       %00sub_die              ;And try again
+
+01sub_die      MOVS    R0,R3                   ;Copy the error pointer back
+               LDMFD   R13!,{R1-R3,R14}        ;Restore the other registers
+               ORRNES  PC,R14,#V_flag          ;Set error indicator if reqd
+               BICS    PC,R14,#V_flag          ;Otherwise clear it
+
+               LTORG
+
+;----- That's all folks -----------------------------------------------------
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/sh/app b/StraySrc/SDLS/DLLManager/sh/app
new file mode 100644 (file)
index 0000000..7f7abaa
--- /dev/null
@@ -0,0 +1,55 @@
+;
+; app.sh
+;
+; Handling of application blocks
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               IMPORT  app_init
+               IMPORT  app_checkQuit
+               IMPORT  app_findDLL
+               IMPORT  app_loseDLL
+               IMPORT  app_setname
+               IMPORT  app_fromtable
+               IMPORT  app_sfromtbl
+               IMPORT  app_findNamed
+               IMPORT  app_setBtable
+               IMPORT  app_appEntry
+               IMPORT  app_fixExtension
+               IMPORT  app_fix
+               IMPORT  app_listDLLs
+               IMPORT  app_listUsing
+               IMPORT  app_list
+               IMPORT  app_dying
+               IMPORT  app_kill
+               IMPORT  app_killAll
+               IMPORT  app_instvars
+               IMPORT  app_giveclib
+               IMPORT  app_appdata
+               IMPORT  app_findclib
+               IMPORT  app_readstkptr
+               IMPORT  app_setstkptr
+               IMPORT  app_prologue
+               IMPORT  app_restoreHandle
+               IMPORT  app_getHandle
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/sh/appblock b/StraySrc/SDLS/DLLManager/sh/appblock
new file mode 100644 (file)
index 0000000..c1a91da
--- /dev/null
@@ -0,0 +1,45 @@
+;
+; appblock.sh
+;
+; Definition of an application block
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               ^       0
+
+app_next       #       4                       ;Link to next application
+app_prev       #       4                       ;Link to previous application
+app_dlls       #       4                       ;List of DLLs attached
+app_cachedll   #       4                       ;Cached DLL handle
+app_cacheptr   #       4                       ;Cached pointer to DLL
+app_handle     #       4                       ;The application's start time
+app_clibdata   #       4                       ;The application's CLib data
+app_owndata    #       4                       ;The application's relocation
+app_name       #       12                      ;The application's name
+app_btable     #       4                       ;Pointer to app's entry list
+app_nametable  #       4                       ;Pointer to app's name list
+app_stackPtr   #       4                       ;DLL workspace stack pointer
+app_stack      #       4096                    ;DLL workspace stack
+
+app_strSize    #       0                       ;Size of this structure
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/sh/dll b/StraySrc/SDLS/DLLManager/sh/dll
new file mode 100644 (file)
index 0000000..462c7ab
--- /dev/null
@@ -0,0 +1,51 @@
+;
+; dll.sh
+;
+; Handling of DLL data structures
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               IMPORT  dll_find
+               IMPORT  dll_ensure
+               IMPORT  dll_check
+               IMPORT  dll_load
+               IMPORT  dll_findEntry
+               IMPORT  dll_appEntry
+               IMPORT  dll_showInfo
+               IMPORT  dll_writeTitle
+               IMPORT  dll_writeInfo
+               IMPORT  dll_list
+               IMPORT  dll_convertVersion
+               IMPORT  dll_field
+               IMPORT  dll_compare
+               IMPORT  dll_tentative
+               IMPORT  dll_confirm
+               IMPORT  dll_retrace
+               IMPORT  dll_freeAll
+               IMPORT  dll_dec
+               IMPORT  dll_instvars
+               IMPORT  dll_findWorkspace
+               IMPORT  dll_convreloc
+               IMPORT  dll_info
+               IMPORT  dll_datasize
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/sh/dllblock b/StraySrc/SDLS/DLLManager/sh/dllblock
new file mode 100644 (file)
index 0000000..37d2d16
--- /dev/null
@@ -0,0 +1,76 @@
+;
+; dllblock.sh
+;
+; Definition of a Dynamic Link Library header
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+dl_MAGIC       EQU     &004C4C44               ;The magic file number
+dl_VERSION     EQU     101                     ;The format version known
+
+               ^       0                       ;Start at 0!
+
+dl_next                #       4                       ;Link to next DLL
+dl_prev                #       4                       ;Link to previous DLL
+dl_wspace      #       0                       ;Workspace for non-shared DLL
+dl_clients     #       4                       ;Number of DLL clients
+dl_shared      #       4                       ;DLL's shared workspace ptr
+dl_extra       #       0                       ;Size of extra info
+
+; Note that dl_wspace and dl_clients share the same address.  dl_wspace is
+; present if and only  if dl_next==-1.  This is set up by DLL_Load as
+; necessary.  Also, the top bit of the clients field is used to indicate
+; that the count is `tentative' -- i.e. that all the associated DLLs have not
+; been found yet.
+
+dl_magic       #       4                       ;Magic DLL identification
+dl_bversion    #       4                       ;Version number of binder
+dl_name                #       4                       ;Address of DLL name string
+dl_copyright   #       4                       ;Address of copyright string
+dl_version     #       4                       ;DLL's version number
+dl_relocate    #       4                       ;Branch to relocation code
+dl_stubs       #       4                       ;Offset of CLib entry points
+dl_entries     #       4                       ;Number of entry points
+dl_enames      #       4                       ;Names of the entry points
+dl_eveneer     #       4                       ;Entry points of the veneers
+dl_dllBase     #       4                       ;Base of external DLL defs
+dl_dllLimit    #       4                       ;Limit of external DLL defs
+dl_instBase    #       4                       ;Base of DLL instance defs
+dl_instLimit   #       4                       ;Limit of DLL instance defs
+
+; --- Extra bits added in file format version 1.01 ---
+
+dl_zinitBase   #       4                       ;Pointer to zero-init base
+dl_zinitLimit  #       4                       ;Pointer to zero-init limit
+dl_appStubs    #       4                       ;Pointer to app entry stubs
+dl_appStubNames        #       4                       ;Pointer to app name table
+
+dl_strSize     #       0                       ;Size of this structure
+
+dl_tentative   EQU     &80000000               ;Tentative flag value
+
+; --- DLL entry point type bits, added in file format 1.01a ---
+
+dl_shortEntries        EQU     (1<<31)                 ;Short non-APCS entry points
+dl_noNames     EQU     (1<<30)                 ;Name table is omitted
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/sh/linkblock b/StraySrc/SDLS/DLLManager/sh/linkblock
new file mode 100644 (file)
index 0000000..e78f97f
--- /dev/null
@@ -0,0 +1,39 @@
+;
+; linkblock.sh
+;
+; Definition of application-dll link structure
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               ^       0
+
+lk_next                #       4                       ;Next item in app's list
+lk_prev                #       4                       ;Previous item in the list
+lk_dll         #       4                       ;Pointer to DLL structure
+lk_work                #       4                       ;Pointer to workspace
+lk_flags       #       4                       ;Various fun flags about it
+
+lk_strSize     #       0                       ;Size of this structure
+
+lk_tentative   EQU     2<<0                    ;Tentative bit
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/sh/messages b/StraySrc/SDLS/DLLManager/sh/messages
new file mode 100644 (file)
index 0000000..b63f926
--- /dev/null
@@ -0,0 +1,60 @@
+;
+; Message symbols [generated by msgAOF]
+;
+
+               [       :LNOT::DEF:msg__dfn
+               GBLL    msg__dfn
+
+               IMPORT  msg_errDivide
+               IMPORT  msg_errNoEntry
+               IMPORT  msg_errNoNames
+               IMPORT  msg_errBadVersion
+               IMPORT  msg_errInUse
+               IMPORT  msg_errFileNotFound
+               IMPORT  msg_errBadSWI
+               IMPORT  msg_errNoCLib
+               IMPORT  msg_errOldCLib
+               IMPORT  msg_errAppNotFound
+               IMPORT  msg_errAppNoEntry
+               IMPORT  msg_errDLLNotInMem
+               IMPORT  msg_errDLLNoMem
+               IMPORT  msg_errStackOvf
+               IMPORT  msg_errUnknownApp
+               IMPORT  msg_errLinkNotFound
+               IMPORT  msg_errDLLNotFound
+               IMPORT  msg_errNotADLL
+               IMPORT  msg_errTooNew
+               IMPORT  msg_errDLLTooOld
+               IMPORT  msg_errAppEntry
+               IMPORT  msg_errDLLEntry
+               IMPORT  msg_errNotShared
+               IMPORT  msg_appName
+               IMPORT  msg_noDLLsForApp
+               IMPORT  msg_dllHeader
+               IMPORT  msg_noDLLs
+               IMPORT  msg_appHeader
+               IMPORT  msg_noAppsForDLL
+               IMPORT  msg_noApps
+               IMPORT  msg_dinfoName
+               IMPORT  msg_dinfoAuthor
+               IMPORT  msg_dinfoVersion
+               IMPORT  msg_dinfoReferences
+               IMPORT  msg_dinfoEntries
+               IMPORT  msg_dinfoNone
+               IMPORT  msg_dinfoHidden
+               IMPORT  help_DLLs
+               IMPORT  synt_DLLs
+               IMPORT  help_DLLApps
+               IMPORT  synt_DLLApps
+               IMPORT  help_DLLInfo
+               IMPORT  synt_DLLInfo
+               IMPORT  help_DLLKillApp
+               IMPORT  synt_DLLKillApp
+               IMPORT  help_DLLReset
+               IMPORT  synt_DLLReset
+               IMPORT  help_DLLEnsure
+               IMPORT  synt_DLLEnsure
+
+               ]
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/sh/misc b/StraySrc/SDLS/DLLManager/sh/misc
new file mode 100644 (file)
index 0000000..d053690
--- /dev/null
@@ -0,0 +1,36 @@
+;
+; misc.sh
+;
+; Miscellaneous things for DLL Manager
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               IMPORT  misc_getCLib
+               IMPORT  misc_copyStubs
+               IMPORT  misc_strcmp
+               IMPORT  misc_memcpy
+               IMPORT  misc_zinit
+               IMPORT  misc_strcpy
+               IMPORT  misc_error
+               IMPORT  misc_subst
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/sh/suballoc b/StraySrc/SDLS/DLLManager/sh/suballoc
new file mode 100644 (file)
index 0000000..05b5e09
--- /dev/null
@@ -0,0 +1,31 @@
+;
+; suballoc.sh
+;
+; Handling of requests for small link blocks
+;
+;  © 199-19984 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               IMPORT  sub_alloc
+               IMPORT  sub_free
+               IMPORT  sub_die
+
+               END
diff --git a/StraySrc/SDLS/DLLManager/sh/wSpace b/StraySrc/SDLS/DLLManager/sh/wSpace
new file mode 100644 (file)
index 0000000..a152030
--- /dev/null
@@ -0,0 +1,59 @@
+;
+; wspace.sh
+;
+; Workspace layout for DLLManager
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               ^       0,R12
+dm__wStart     #       0
+
+               ; --- Application manager workspace ---
+
+app__list      #       4                       ;Head of application list
+app__cacheHnd  #       4                       ;Handle of cached application
+app__cachePtr  #       4                       ;Pointer to cached app block
+app__pidAddr   #       4                       ;Address of process ID
+
+               ; --- DLL manager workspace ---
+
+dll__list      #       4                       ;Head of DLL list
+
+               ; --- Memory manager workspace ---
+
+sub__blocks    #       4                       ;Pointer to block list
+sub__free      #       4                       ;Pointer to free list
+
+               ; --- Miscellaneous buffers ---
+
+misc__sharedBuf        #       256                     ;Shared scratch buffer
+misc__errorBuf #       260                     ;Shared error buffer
+
+misc__stubs    #       4*48 + 4*183            ;C library branch table
+
+               ; --- End of workspace ---
+
+dm__wSize      EQU     {VAR}-dm__wStart
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/SDLS/Makefile,fe1 b/StraySrc/SDLS/Makefile,fe1
new file mode 100644 (file)
index 0000000..e362d22
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all:
+       submake *.Makefile
+
+install:
+       submake *.Makefile -- install
+
+clean:
+       submake *.Makefile -- clean
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/SDLS/cdll/Makefile,fe1 b/StraySrc/SDLS/cdll/Makefile,fe1
new file mode 100644 (file)
index 0000000..3df6034
--- /dev/null
@@ -0,0 +1,184 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+PROGS = cdll dissect
+
+LIBS = libs:aof.o.aof libs:o.swiv libs:o.astubs
+
+OBJS = \
+       o.dllbinder \
+       o.binding o.cstub o.extentry \
+       o.decode o.error o.readdef \
+       o.crc32 o.hashtable
+
+VERSION = 1.09
+
+#----- Compiling things -----------------------------------------------------
+
+all: $(PROGS)
+
+cdll: $(OBJS) $(LIBS)
+       $(SETDATE) \
+               o.version \
+               _time="$(VERSION) [$(DATE)]" \
+               cright="$(CRIGHT)"
+       $(LD_APP) $(OBJS) $(LIBS) o.version
+       $(SQUEEZE)
+
+dissect: o.dissect $(LIBS)
+       $(LD_APP) o.dissect $(LIBS)
+
+install: $(PROGS)
+       $(INSTALL) $(PROGS) <SSR$BinDir>
+
+clean:
+       -$(RM) o.* cdll
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.dllbinder:   c.dllbinder
+o.dllbinder:   libs:h._time
+o.dllbinder:   h.error
+o.dllbinder:   h.hashtable
+o.dllbinder:   h.decode
+o.dllbinder:   h.readdef
+o.dllbinder:   h.binding
+o.dllbinder:   h.cstub
+o.dllbinder:   h.extentry
+o.binding:     c.binding
+o.binding:     h.binding
+o.binding:     h.readdef
+o.binding:     h.hashtable
+o.binding:     h.readdef
+o.binding:     libs:aof.h.aof
+o.binding:     libs:aof.h.chunk
+o.binding:     h.hashtable
+o.binding:     h.error
+o.cstub:       c.cstub
+o.cstub:       h.cstub
+o.cstub:       h.readdef
+o.cstub:       h.hashtable
+o.cstub:       h.readdef
+o.cstub:       libs:aof.h.aof
+o.cstub:       libs:aof.h.chunk
+o.cstub:       h.hashtable
+o.cstub:       h.error
+o.extentry:    c.extentry
+o.extentry:    h.extentry
+o.extentry:    h.readdef
+o.extentry:    h.hashtable
+o.extentry:    h.readdef
+o.extentry:    libs:aof.h.aof
+o.extentry:    libs:aof.h.chunk
+o.extentry:    h.hashtable
+o.extentry:    h.error
+o.decode:      c.decode
+o.decode:      h.decode
+o.decode:      h.hashtable
+o.decode:      libs:aof.h.chunk
+o.decode:      libs:aof.h.aof
+o.decode:      libs:aof.h.alf
+o.decode:      h.error
+o.error:       c.error
+o.error:       h.error
+o.readdef:     c.readdef
+o.readdef:     h.hashtable
+o.readdef:     h.error
+o.readdef:     h.readdef
+o.readdef:     libs:h.swiv
+o.readdef:     c:h.kernel
+o.readdef:     libs:h.swis
+o.hashtable:   c.hashtable
+o.hashtable:   h.hashtable
+o.hashtable:   h.crc32
+o.dissect:     c.dissect
+o.dissect:     libs:aof.h.chunk
+o.crc32: s.crc32
+o.crc32: libs:header
+o.crc32: libs:swis
diff --git a/StraySrc/SDLS/cdll/c/binding b/StraySrc/SDLS/cdll/c/binding
new file mode 100644 (file)
index 0000000..142e728
--- /dev/null
@@ -0,0 +1,417 @@
+/*
+ * binding.c
+ *
+ * Create DLL header and things
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+#include "binding.h"
+#include "readdef.h"
+#include "aof/aof.h"
+#include "aof/chunk.h"
+#include "hashtable.h"
+#include "error.h"
+
+typedef struct
+{
+  /* --- Basic parts of the header --- */
+
+  unsigned magic;
+  unsigned bversion;
+  unsigned name;
+  unsigned copyright;
+  unsigned version;
+  unsigned relocate;
+  unsigned stubs;
+  unsigned entries;
+  unsigned enames;
+  unsigned eveneer;
+  unsigned dllBase;
+  unsigned dllLimit;
+  unsigned instBase;
+  unsigned instLimit;
+
+  /* --- New bits added for v. 1.01 --- */
+
+  unsigned zinitBase;
+  unsigned zinitLimit;
+  unsigned appStub;
+  unsigned appNames;
+}
+bind__header;
+
+typedef struct
+{
+  aof_file f;
+  bind__header *h;
+  hashtable osym;
+}
+bind__thing;
+
+#define bind__MAGIC 0x004c4c44
+#define bind__VERSION 101
+
+static unsigned int nextOrd;
+
+static void bind__enames(char *p,unsigned ord,void *handle)
+{
+  bind__thing *t=handle;
+  int o; /* dummy for the aof... macros */
+
+  if (ord!=0xFFFFFFFF)
+  {
+    while (ord>nextOrd)
+    {
+      aof_byte(1,t->f.area);
+      nextOrd++;
+    }
+  }
+  if (hash_find(t->osym,p))
+  {
+    aof_string(p,t->f.area);
+    t->h->entries++;
+    if (ord!=0xFFFFFFFF)
+      nextOrd=ord+1;
+  }
+}
+
+static void bind__count(char *p,unsigned ord,void *handle)
+{
+  bind__thing *t=handle;
+  if (hash_find(t->osym,p))
+    t->h->entries++;
+}
+
+static void bind__entries(char *p,unsigned ord,void *handle)
+{
+  bind__thing *t=handle;
+  static int entry[4]={0xE92D0007,             /* STMFD   sp!,{a1-a3}  */
+                       0xE59FC000};            /* LDR     ip,=address  */
+  char buf[256];
+  if (ord!=0xFFFFFFFF)
+  {
+    static int duff[4];
+    while (ord>nextOrd)
+    {
+      aof_add(duff,t->f.area);
+      nextOrd++;
+    }
+  }
+  if (hash_find(t->osym,p))
+  {
+    entry[2]=aof_branch(t->f.area->next+8,sizeof(bind__header));
+    aof_reloc(p,t->f.area->next+12,0,&t->f);
+    sprintf(buf,"_dllEntry_%s",p);
+    aof_addsym(buf,t->f.area->next,0,4,&t->f);
+    aof_add(entry,t->f.area);
+    if (ord!=0xFFFFFFFF)
+      nextOrd=ord+1;
+  }
+}
+
+static void bind__appEntries(char *p,unsigned ord,void *handle)
+{
+  bind__thing *t=handle;
+  int zero=0;
+  if (ord!=0xFFFFFFFF)
+  {
+    while (ord>nextOrd)
+    {
+      aof_add(zero,t->f.area);
+      nextOrd++;
+    }
+  }
+  if (hash_find(t->osym,p))
+  {
+    aof_reloc(p,aof_add(zero,t->f.area),0,&t->f);
+    if (ord!=0xFFFFFFFF)
+      nextOrd=ord+1;
+  }
+}
+
+void binding(char *name,readdef_info *inf,hashtable osym)
+{
+  FILE *fp;
+
+  if (!inf->apptbl)
+  {
+    /* --- Don't check this lot if you can help it --- */
+
+    if (!inf->name[0])
+    {
+      if (!(inf->errored & rd_name))
+        error(NONAME);
+      inf->errored|=rd_name;
+    }
+    if (inf->version==-1)
+    {
+      if (!(inf->errored & rd_version))
+        error(NOVERSION);
+      inf->errored|=rd_version;
+      inf->version=100;
+    }
+    if (!inf->copyright[0])
+    {
+      if (!(inf->errored & rd_cright))
+        error(NOCRIGHT);
+      inf->errored|=rd_cright;
+    }
+    if (inf->errored & rd_name)
+      return;
+  }
+
+  fp=fopen(name,"wb");                 /* Open the output file         */
+  if (!fp)                             /* If the file wasn't opened    */
+    error(NOOPENOUT,name);             /* Better give an error         */
+  else
+  {
+    char _buf[sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry)];
+    chunk_header *h=(chunk_header *)&_buf; /* Allocate memory easily :-) */
+
+    aof_chunkinfo obj_idfn={0};
+    aof_chunkinfo obj_head={0};
+    aof_chunkinfo obj_area={0};
+    aof_chunkinfo obj_symt={0};
+    aof_chunkinfo obj_strt={0};
+    aof_chunkinfo reloc={0};
+    bind__thing t;
+
+    bind__header hdr;
+    int o;
+
+    static int prologue[]={0xE1A0000E, /* MOV     a1,lr        */
+                           0xE1A0100A, /* MOV     a2,sl        */
+                           0xE24F2058, /* ADR     a3,header    */
+                           0xEF04A30A, /* SWI     DLL_Prologue */
+                           0xE1A0E000, /* MOV     lr,a1        */
+                           0xE8BD0007, /* LDMFD   sp!,{a1-a3}  */
+                           0xE1A0F00C};        /* MOV     pc,ip        */
+
+    h->hdr.id=chunk_MAGIC;             /* Fill in magic thingy         */
+    h->hdr.maxChunks=h->hdr.numChunks=5; /* And number of chunks       */
+
+    if (!inf->apptbl)
+    {
+      /* --- Don't set up the header if we won't need it --- */
+
+      hdr.magic=bind__MAGIC;
+      hdr.bversion=bind__VERSION;
+      hdr.version=inf->version;
+      hdr.relocate=0xea000000;
+      hdr.stubs=0;
+      hdr.entries=0;
+      hdr.dllBase=0;
+      hdr.dllLimit=0;
+      hdr.instBase=0;
+      hdr.instLimit=0;
+      hdr.zinitBase=0;
+      hdr.zinitLimit=0;
+      hdr.appStub=0;
+      hdr.appNames=0;
+    }
+
+    t.f.area=&obj_area;
+    t.h=&hdr;
+    t.osym=osym;
+    t.f.symt=&obj_symt;
+    t.f.strt=&obj_strt;
+    t.f.reloc=&reloc;
+
+    aof_string("Straylight Dynamic Link Library building system 1.01",
+                 &obj_idfn);
+    aof_align(obj_idfn);
+
+    if (!inf->apptbl)
+    {
+      aof_add(hdr,&obj_area);
+      if (~inf->flags & rdFlag_shortEntry)
+        aof_add(prologue,&obj_area);
+      aof_int(0,&obj_strt);
+      aof_string("!!!DLL$$Header",&obj_strt);
+
+      hdr.name=aof_string(inf->name,&obj_area);
+      aof_roff(offsetof(bind__header,name),&t.f);
+      hdr.copyright=aof_string(inf->copyright,&obj_area);
+      aof_roff(offsetof(bind__header,copyright),&t.f);
+      hdr.enames=obj_area.next;
+      aof_roff(offsetof(bind__header,enames),&t.f);
+      nextOrd=0;
+      if (~inf->flags & rdFlag_noNames)
+        hash_enumOrdered(inf->sym,bind__enames,&t);
+      else
+        hash_enumOrdered(inf->sym,bind__count,&t);
+      if (inf->flags & rdFlag_shortEntry)
+        hdr.entries|=0x80000000u;
+      if (inf->flags & rdFlag_noNames)
+        hdr.entries|=0x40000000u;
+      aof_align(obj_area);
+      hdr.eveneer=obj_area.next;
+      aof_roff(offsetof(bind__header,eveneer),&t.f);
+      nextOrd=0;
+      if (~inf->flags & rdFlag_shortEntry)
+      {
+        hash_enumOrdered(inf->sym,bind__entries,&t);
+        hash_enumOrdered(inf->vsym,bind__entries,&t);
+      }
+      else
+      {
+        hash_enumOrdered(inf->sym,bind__appEntries,&t);
+        hash_enumOrdered(inf->vsym,bind__appEntries,&t);
+      }
+
+      aof_reloc_b("__RelocCode",offsetof(bind__header,relocate),&t.f);
+      if (~inf->flags & rdFlag_shortEntry)
+        aof_reloc("_kernel_init",offsetof(bind__header,stubs),1,&t.f);
+      aof_reloc("DLL$$ExternalTable$$Base",
+                offsetof(bind__header,dllBase),
+                1,
+                &t.f);
+      aof_reloc("DLL$$ExternalTable$$Limit",
+                offsetof(bind__header,dllLimit),
+                1,
+                &t.f);
+      aof_reloc("Image$$RW$$Base",offsetof(bind__header,instBase),0,&t.f);
+      aof_reloc("Image$$RW$$Limit",offsetof(bind__header,instLimit),0,&t.f);
+      aof_reloc("Image$$ZI$$Base",offsetof(bind__header,zinitBase),0,&t.f);
+      aof_reloc("Image$$ZI$$Limit",offsetof(bind__header,zinitLimit),0,&t.f);
+      aof_reloc("DLL$$AppEntryStubs",offsetof(bind__header,appStub),1,&t.f);
+      aof_reloc("DLL$$AppEntryNames",offsetof(bind__header,appNames),1,&t.f);
+
+      aof_fill(hdr,0,&obj_area);
+
+      {
+        aof_symbol sym={0};
+        sym.name=aof_string("_dll_findall",&obj_strt);
+        sym.defined=1;
+        sym.export=1;
+        sym.absolute=1;
+        sym.value=0;
+        aof_add(sym,&obj_symt);
+      }
+    }
+    else
+    {
+      aof_int(0,&obj_strt);
+      aof_string("DLL$$AppEntryDefinition",&obj_strt);
+
+      aof_addsym("_dll_appEntryStubs",
+                 obj_area.next,
+                 0,
+                 4,
+                 &t.f);
+      nextOrd=0;
+      if (~inf->flags & rdFlag_noNames)
+        hash_enumOrdered(inf->sym,bind__appEntries,&t);
+
+      aof_addsym("_dll_appEntryNames",
+                 obj_area.next,
+                 0,
+                 4,
+                 &t.f);
+      nextOrd=0;
+      hash_enumOrdered(inf->sym,bind__enames,&t);
+      { char c=0; aof_add(c,&obj_area); }
+      aof_align(obj_area);
+
+      /* --- Hack for link 5.00 --- *
+       *
+       * We IMPORT _dll_regAppEntry here so that link will grab the correct
+       * bits of DLLLib
+       */
+
+      {
+        aof_symbol sym={0};
+        sym.name=aof_string("_dll_regAppEntry",&obj_strt);
+        sym.defined=0;
+        sym.export=1;
+        aof_add(sym,&obj_symt);
+      }
+
+    }
+
+    aof_int((int)aof_RELOC,&obj_head);
+    aof_int(150,&obj_head);
+    aof_int(1,&obj_head);
+    aof_int(obj_symt.next/sizeof(aof_symbol),&obj_head);
+    aof_int(0,&obj_head);
+    aof_int(0,&obj_head);
+
+    aof_int(4,&obj_head);
+    aof_int(0x00002202,&obj_head);
+    aof_int(obj_area.next,&obj_head);
+    aof_int(reloc.next/8,&obj_head);
+    aof_int(0,&obj_head);
+
+    aof_addBlock(reloc.p,reloc.next,&obj_area);
+
+    aof_fill(obj_strt.next,0,&obj_strt);
+    aof_align(obj_strt);
+
+    memcpy(h->table[0].chunkName,"OBJ_IDFN",8);
+    memcpy(h->table[1].chunkName,"OBJ_HEAD",8);
+    memcpy(h->table[2].chunkName,"OBJ_AREA",8);
+    memcpy(h->table[3].chunkName,"OBJ_SYMT",8);
+    memcpy(h->table[4].chunkName,"OBJ_STRT",8);
+
+    o=sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry);
+
+    h->table[0].offset=o;
+    h->table[0].size=obj_idfn.next;
+    o+=obj_idfn.next;
+
+    h->table[1].offset=o;
+    h->table[1].size=obj_head.next;
+    o+=obj_head.next;
+
+    h->table[2].offset=o;
+    h->table[2].size=obj_area.next;
+    o+=obj_area.next;
+
+    h->table[3].offset=o;
+    h->table[3].size=obj_symt.next;
+    o+=obj_symt.next;
+
+    h->table[4].offset=o;
+    h->table[4].size=obj_strt.next;
+    o+=obj_strt.next;
+
+    fwrite(h,sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry),1,fp);
+    fwrite(obj_idfn.p,obj_idfn.next,1,fp);
+    fwrite(obj_head.p,obj_head.next,1,fp);
+    fwrite(obj_area.p,obj_area.next,1,fp);
+    fwrite(obj_symt.p,obj_symt.next,1,fp);
+    fwrite(obj_strt.p,obj_strt.next,1,fp);
+    fclose(fp);
+
+    free(obj_idfn.p);
+    free(obj_area.p);
+    free(obj_strt.p);
+    free(obj_head.p);
+    free(obj_symt.p);
+  }
+}
diff --git a/StraySrc/SDLS/cdll/c/cstub b/StraySrc/SDLS/cdll/c/cstub
new file mode 100644 (file)
index 0000000..d22306a
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * cstub.c
+ *
+ * Create DLL stublib
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+#include "cstub.h"
+#include "readdef.h"
+#include "aof/aof.h"
+#include "aof/chunk.h"
+#include "hashtable.h"
+#include "error.h"
+
+typedef struct
+{
+  aof_file f;
+  int areaname;
+  int abase;
+  hashtable osym;
+}
+cstub__thing;
+
+#define cstub__MAGIC 0x004c4c44
+#define cstub__VERSION 100
+
+static int term;
+
+static void cstub__enames(char *p,unsigned ord,void *handle)
+{
+  cstub__thing *t=handle;
+  if (ord==0xFFFFFFFF && hash_find(t->osym,p))
+    aof_string(p,t->f.area);
+}
+
+static void cstub__entries(char *p,unsigned ord,void *handle)
+{
+  cstub__thing *t=handle;
+  static int entry[1]={0xE3A0F000};            /* MOV  PC,#0           */
+  if (hash_find(t->osym,p))
+  {
+    aof_addsym(p,t->f.area->next-t->abase,0,t->areaname,&t->f);
+    if (ord==0xFFFFFFFF)
+    {
+      aof_add(entry,t->f.area);
+      term=1;
+    }
+    else
+      aof_add(ord,t->f.area);
+  }
+}
+
+void cstub(char *name,readdef_info *inf,hashtable osym)
+{
+  FILE *fp;
+  char buffer[256];
+
+  if (!inf->apptbl)
+  {
+    /* --- Don't check if we're creating application stubs --- */
+
+    if (!inf->name[0])
+    {
+      if (!(inf->errored & rd_name))
+        error(NONAME);
+      inf->errored|=rd_name;
+    }
+    if (inf->version==-1)
+    {
+      if (!(inf->errored & rd_version))
+        error(NOVERSION);
+      inf->errored|=rd_version;
+      inf->version=100;
+    }
+    if (inf->errored & rd_name)
+      return;
+  }
+
+  fp=fopen(name,"wb");                 /* Open the output file         */
+  if (!fp)                             /* If the file wasn't opened    */
+    error(NOOPENOUT,name);             /* Better give an error         */
+  else
+  {
+    char _buf[sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry)];
+    chunk_header *h=(chunk_header *)&_buf; /* Allocate memory easily :-) */
+
+    aof_chunkinfo obj_idfn={0};
+    aof_chunkinfo obj_head={0};
+    aof_chunkinfo obj_area={0};
+    aof_chunkinfo obj_symt={0};
+    aof_chunkinfo obj_strt={0};
+    aof_chunkinfo reloc={0};
+    cstub__thing t;
+
+    int o;
+    int osize=0;
+    int orelocs=0;
+
+    int sym_dllName;
+    int sym_dllEntries;
+    int sym_dllStubs;
+    int tmp;
+
+    t.f.area=&obj_area;
+    t.osym=osym;
+    t.f.symt=&obj_symt;
+    t.f.strt=&obj_strt;
+    t.f.reloc=&reloc;
+
+    h->hdr.id=chunk_MAGIC;             /* Fill in magic thingy         */
+    h->hdr.maxChunks=h->hdr.numChunks=5; /* And number of chunks       */
+
+    aof_string("Straylight Dynamic Link Library building system 1.01",
+                 &obj_idfn);
+    aof_align(obj_idfn);
+
+    aof_int(0,&obj_strt);
+
+    aof_int((int)aof_RELOC,&obj_head);
+    aof_int(150,&obj_head);
+    aof_int((inf->apptbl ? 1 : 3),&obj_head);
+    aof_int(obj_symt.next/sizeof(aof_symbol),&obj_head);
+    aof_int(0,&obj_head);
+    aof_int(0,&obj_head);
+
+    /* --- Do entry names for dll table --- */
+
+    if (inf->apptbl)
+      t.areaname=aof_string("DLL$$AppEntry",&obj_strt);
+    else
+      t.areaname=aof_string("DLL$$Strings",&obj_strt);
+    t.abase=obj_area.next;
+
+    if (!inf->apptbl)
+    {
+      sym_dllName=obj_symt.next/16;
+      aof_addsym("_dll_name",
+                 obj_area.next-t.abase,
+                 1,
+                 t.areaname,
+                 &t.f);
+
+      if (inf->dllpath)
+      {
+        sprintf(buffer,"%s[%s]",inf->dllpath,inf->name);
+        aof_string(buffer,&obj_area);
+      }
+      else
+      {
+        sprintf(buffer,"[%s]",inf->name);
+        aof_string(buffer,&obj_area);
+      }
+
+      sym_dllEntries=obj_symt.next/16;
+      aof_addsym("_dll_entries",
+                 obj_area.next-t.abase,
+                 1,
+                 t.areaname,
+                 &t.f);
+
+      /* --- Hack for link v. 5.00 --- *
+       *
+       * We IMPORT the symbol _dll_findall in order to ensure that DLLLib
+       * gets linked in.
+       */
+
+      {
+        aof_symbol sym={0};
+        sym.name=aof_string("_dll_findall",&obj_strt);
+        sym.defined=0;
+        sym.export=1;
+        aof_add(sym,&obj_symt);
+      }
+    }
+    else
+    {
+      aof_addsym("DLL$$AppEntryNames",
+                 obj_area.next-t.abase,
+                 0,
+                 t.areaname,
+                 &t.f);
+    }
+
+    hash_enumOrdered(inf->sym,cstub__enames,&t);
+
+    { char c=0; aof_add(c,&obj_area); }
+
+    aof_align(obj_area);
+
+    if (!inf->apptbl)
+    {
+      aof_int(t.areaname,&obj_head);
+      aof_int(0x00002202,&obj_head);
+      aof_int(obj_area.next-osize,&obj_head);
+      aof_int(reloc.next/8-orelocs,&obj_head);
+      aof_int(0,&obj_head);
+      aof_addBlock(reloc.p,reloc.next,&obj_area);
+      osize=obj_area.next;
+      orelocs=reloc.next/8;
+
+      /* --- Do entry veneers table --- */
+
+      t.areaname=aof_string("DLL$$Stubs",&obj_strt);
+      t.abase=obj_area.next;
+
+      sym_dllStubs=obj_symt.next/16;
+      aof_addsym("_dll_stubs",
+                 obj_area.next-t.abase,
+                 1,
+                 t.areaname,
+                 &t.f);
+    }
+    else
+    {
+      aof_addsym("DLL$$AppEntryStubs",
+                 obj_area.next-t.abase,
+                 0,
+                 t.areaname,
+                 &t.f);
+    }
+
+    term=0;
+    hash_enumOrdered(inf->sym,cstub__entries,&t);
+    if (!term)
+      aof_int(-1,&obj_area);
+
+    aof_align(obj_area);
+
+    aof_int(t.areaname,&obj_head);
+    aof_int(0x00002202,&obj_head);
+    aof_int(obj_area.next-osize,&obj_head);
+    aof_int(reloc.next/8-orelocs,&obj_head);
+    aof_int(0,&obj_head);
+    aof_addBlock(reloc.p,reloc.next,&obj_area);
+    osize=obj_area.next;
+    orelocs=reloc.next/8;
+
+    /* --- Do external DLL table area --- */
+
+    if (!inf->apptbl)
+    {
+      t.areaname=aof_string("DLL$$ExternalTable",&obj_strt);
+      t.abase=obj_area.next;
+
+      tmp=aof_int(0,&obj_area)-t.abase;
+      aof_add(tmp,&reloc);
+      aof_int(0x000A0000 | sym_dllName,&reloc);
+
+      aof_int(inf->version,&obj_area);
+
+      tmp=aof_int(0,&obj_area)-t.abase;
+      aof_add(tmp,&reloc);
+      aof_int(0x000A0000 | sym_dllEntries,&reloc);
+
+      tmp=aof_int(0,&obj_area)-t.abase;
+      aof_add(tmp,&reloc);
+      aof_int(0x000A0000 | sym_dllStubs,&reloc);
+
+      aof_align(obj_area);
+
+      aof_int(t.areaname,&obj_head);
+      aof_int(0x00002202,&obj_head);
+      aof_int(obj_area.next-osize,&obj_head);
+      aof_int(reloc.next/8-orelocs,&obj_head);
+      aof_int(0,&obj_head);
+      aof_addBlock(reloc.p,reloc.next,&obj_area);
+      osize=obj_area.next;
+      orelocs=reloc.next/8;
+    }
+
+    aof_fill(obj_strt.next,0,&obj_strt);
+    aof_align(obj_strt);
+
+    o=obj_symt.next/sizeof(aof_symbol);
+    aof_fill(o,12,&obj_head);
+
+    memcpy(h->table[0].chunkName,"OBJ_IDFN",8);
+    memcpy(h->table[1].chunkName,"OBJ_HEAD",8);
+    memcpy(h->table[2].chunkName,"OBJ_AREA",8);
+    memcpy(h->table[3].chunkName,"OBJ_SYMT",8);
+    memcpy(h->table[4].chunkName,"OBJ_STRT",8);
+
+    o=sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry);
+
+    h->table[0].offset=o;
+    h->table[0].size=obj_idfn.next;
+    o+=obj_idfn.next;
+
+    h->table[1].offset=o;
+    h->table[1].size=obj_head.next;
+    o+=obj_head.next;
+
+    h->table[2].offset=o;
+    h->table[2].size=obj_area.next;
+    o+=obj_area.next;
+
+    h->table[3].offset=o;
+    h->table[3].size=obj_symt.next;
+    o+=obj_symt.next;
+
+    h->table[4].offset=o;
+    h->table[4].size=obj_strt.next;
+    o+=obj_strt.next;
+
+    fwrite(h,sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry),1,fp);
+    fwrite(obj_idfn.p,obj_idfn.next,1,fp);
+    fwrite(obj_head.p,obj_head.next,1,fp);
+    fwrite(obj_area.p,obj_area.next,1,fp);
+    fwrite(obj_symt.p,obj_symt.next,1,fp);
+    fwrite(obj_strt.p,obj_strt.next,1,fp);
+    fclose(fp);
+
+    free(obj_idfn.p);
+    free(obj_area.p);
+    free(obj_strt.p);
+    free(obj_head.p);
+    free(obj_symt.p);
+  }
+}
diff --git a/StraySrc/SDLS/cdll/c/decode b/StraySrc/SDLS/cdll/c/decode
new file mode 100644 (file)
index 0000000..18c1a7e
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * decode.c
+ *
+ * Find all the symbols in an ALF or AOF file.
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "decode.h"
+#include "aof/chunk.h"
+#include "aof/aof.h"
+#include "aof/alf.h"
+#include "error.h"
+
+static int decode__findChunk(chunk_header *c,char *name)
+{
+  int i;
+  for (i=0;i<c->hdr.maxChunks;i++)
+  {
+    if (c->table[i].offset && !memcmp(c->table[i].chunkName,name,8))
+      return (i);
+  }
+  return (-1);
+}
+
+static int decode__listALF(chunk_header *c,
+                           hashtable h,
+                           FILE *fp,
+                           char *name,
+                           int entry)
+{
+  int size=c->table[entry].size;       /* Help the compiler a bit      */
+  char *data=malloc(size);             /* Allocate memory for chunk    */
+
+  name=name;
+
+  {
+    if (!data)
+      error(NOMEM);
+  }
+
+  {
+    /* --- Note to the squeamish --- *
+     *
+     * I've done naughty things with fpos_t here to avoid reading the file
+     * sequentially.  This file isn't doing anything particularly portable
+     * anyway, so this is no great hardship.
+     */
+
+    fpos_t off;                                /* To set file position         */
+    off.__lo=c->table[entry].offset;   /* Widge the position indicator */
+    fsetpos(fp,&off);                  /* Set the file offset nicely   */
+    fread(data,1,size,fp);             /* Read external names table    */
+  }
+
+  {
+    int i=0;                           /* Counter through data         */
+    alf_symTable *tbl;                 /* Pointer to actual structures */
+    while (i<size)                     /* Continue until no more       */
+    {
+      tbl=(alf_symTable *)(data+i);    /* Set up the pointer           */
+      if (!hash_add(h,tbl->data))      /* Try to add the symbol name   */
+        error(NOMEM);
+      i+=tbl->entryLength;             /* Bump the index along a bit   */
+    }
+  }
+
+  {
+    free(data);
+  }
+
+  return (0);
+}
+
+static int decode__listAOF(chunk_header *c,
+                           hashtable h,
+                           FILE *fp,
+                           char *name,
+                           int sym,
+                           int str)
+
+{
+  int sizeSym=c->table[sym].size;      /* Help the compiler a bit      */
+  int sizeStr=c->table[str].size;      /* Help the compiler a bit      */
+  aof_symbol *symbol=malloc(sizeSym);  /* Memory for symbol table      */
+  char *string=malloc(sizeStr);                /* Memory for string table      */
+  int symbols;                         /* Number of symbol entries     */
+  int headoff=0;                       /* Offset to AOF header chunk   */
+  int err=0;                           /* No errors yet                */
+
+  /* --- Check we got the memory --- */
+
+  {
+    if (!symbol || !string)
+      error(NOMEM);
+  }
+
+  if (!err)
+  {
+    if (headoff=decode__findChunk(c,"OBJ_HEAD"),headoff==-1)
+    {
+      error(BADFILE,name);
+      err=1;
+    }
+  }
+
+  if (!err)
+  {
+    /* --- Note to the squeamish --- *
+     *
+     * I've done naughty things with fpos_t here to avoid reading the file
+     * sequentially.  This file isn't doing anything particularly portable
+     * anyway, so this is no great hardship.
+     */
+
+    fpos_t off;                                /* To set file position         */
+
+    off.__lo=c->table[headoff].offset+12l; /* Find number of symbols   */
+    fsetpos(fp,&off);                  /* Set the file offset nicely   */
+    fread(&symbols,sizeof(symbols),1,fp); /* Read symbol count         */
+    off.__lo=c->table[sym].offset;     /* Widge the position indicator */
+    fsetpos(fp,&off);                  /* Set the file offset nicely   */
+    fread(symbol,1,sizeSym,fp);                /* Read symbol table            */
+    off.__lo=c->table[str].offset;     /* Widge the position indicator */
+    fsetpos(fp,&off);                  /* Set the file offset nicely   */
+    fread(string,1,sizeStr,fp);                /* Read string table            */
+  }
+
+  if (!err)
+  {
+    int i;                             /* Counter through data         */
+    for (i=0;i<symbols;i++)
+    {
+      if (symbol[i].defined && symbol[i].export)
+      {
+        if (!hash_add(h,string+symbol[i].name))
+          error(NOMEM);
+      }
+    }
+  }
+
+  {
+    free(string);
+    free(symbol);
+  }
+
+  return (err);
+}
+
+int decode(hashtable h,char *filename)
+{
+  chunk_header *chf=0;                 /* Ptr to block to read table   */
+  FILE *fp=fopen(filename,"rb");       /* Open for binary reading      */
+  int err=0;                           /* No errors yet                */
+
+  {
+    chunk_fixedHeader ch={0,0,0};      /* For reading in the header    */
+
+    if (!fp)                           /* If open failed,...           */
+    {
+      error(NOOPENIN,filename);                /* Report an error, and         */
+      err=1;                           /*   return gracefully          */
+    }
+    else
+    {
+      fread(&ch,sizeof(ch),1,fp);      /* Read the file's header       */
+      if (ch.id!=chunk_MAGIC)          /* Check it's a real chunk file */
+      {
+        error(BADFILE,filename);
+        err=1;
+      }
+      else
+      {
+        chf=malloc(sizeof(chunk_fixedHeader)+
+                   ch.maxChunks*sizeof(chunk_tableEntry));
+        if (!chf)                      /* If allocation failed         */
+          error(NOMEM);
+        chf->hdr=ch;
+        fread(chf->table,sizeof(chunk_tableEntry),ch.maxChunks,fp);
+      }
+    }
+  }
+
+  if (!err)
+  {
+    int index;                         /* Index of symbol table chunk  */
+    int string;                                /* Index of string table chunk  */
+
+    if (index=decode__findChunk(chf,"OFL_SYMT"),index!=-1)
+      decode__listALF(chf,h,fp,filename,index);
+    else if ( (index=decode__findChunk(chf,"OBJ_SYMT"),index!=-1) &&
+              (string=decode__findChunk(chf,"OBJ_STRT"),string!=-1))
+      decode__listAOF(chf,h,fp,filename,index,string);
+    else
+    {
+      error(BADFILE,filename);
+      err=1;
+    }
+  }
+
+  {
+    if (fp)
+      fclose(fp);                      /* Don't need this any more     */
+    free(chf);                         /* Get rid of that too          */
+  }
+
+  return (err);
+}
diff --git a/StraySrc/SDLS/cdll/c/dissect b/StraySrc/SDLS/cdll/c/dissect
new file mode 100644 (file)
index 0000000..d9553fc
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * dissect an aof file into areas
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "aof/chunk.h"
+
+#define aof_RELOC (0xC5E2D080ul)       /* Relocatable object type      */
+
+typedef struct
+{
+  unsigned long type;                  /* Type of object file          */
+  int version;                         /* Version number of the format */
+  int areas;                           /* Number of AREAs defined      */
+  int symbols;                         /* Number of symbols in table   */
+  int entryArea;                       /* Index of AREA with ENTRY att */
+  int entryOff;                                /* Offset in AREA for ENTRY     */
+}
+aof_fixedHeader;
+
+typedef struct
+{
+  int name;                            /* AREA name (OBJ_STRT offset)  */
+
+  int alignment                        :8;     /* AREA alignment (must be 2)   */
+
+  int                          :1;     /* Reserved bit                 */
+  int code                     :1;     /* AREA contains code           */
+  int common                   :1;     /* Common AREA definition       */
+  int commonRef                        :1;     /* Reference to common AREA     */
+  int zinit                    :1;     /* AREA is zero-initialised     */
+  int readonly                 :1;     /* AREA is (sort-of) readonly   */
+  int                          :1;     /* Reserved bit                 */
+  int debug                    :1;     /* AREA contains debug tables   */
+  int                          :16;    /* Reserved shortword           */
+
+  int size;                            /* Size of this AREA            */
+  int relocs;                          /* Number of relocations        */
+  int                          :32;    /* Reserved word                */
+}
+aof_areaEntry;
+
+typedef struct
+{
+  aof_fixedHeader hdr;                 /* The fixed header info        */
+  aof_areaEntry table[1];              /* AREA table (unsized array)   */
+}
+aof_header;
+
+typedef struct
+{
+  int name;                            /* Name string table entry      */
+
+  int defined                  :1;     /* Symbol defined in file       */
+  int export                   :1;     /* Symbol is exported globally  */
+  int absolute                 :1;     /* Symbol not relative to AREA  */
+  int ignoreCase               :1;     /* Symbol is not case sensitive */
+  int weak                     :1;     /* Symbol is weak external ref  */
+  int strong                   :1;     /* Symbol is strong global      */
+  int common                   :1;     /* Symbol is in a common AREA   */
+  int                          :32-7;  /* Pad out to integer boundary  */
+
+  int value;                           /* Value of the symbol          */
+  int area;                            /* Offset of AREA name          */
+}
+aof_symbol;
+
+typedef struct
+{
+  int offset;                          /* Offset of word to relocate   */
+  union
+  {
+    struct
+    {
+      int symbol               :16;    /* Symbol to relocate by/to     */
+      int field                        :2;     /* Field size to alter          */
+      int type                 :1;     /* Relocation type              */
+      int symreloc             :1;     /* Relocation is symbol-relative*/
+      int                      :12;    /* Reserved bits                */
+    }
+    type_1;                            /* Type 1 relocation directive  */
+
+    struct
+    {
+      int symbol               :24;    /* Symbol to relocate by/to     */
+      int field                        :2;     /* Field size to alter          */
+      int type                 :1;     /* Relocation type              */
+      int symreloc             :1;     /* Relocation is symbol-relative*/
+      int                      :3;     /* Reserved bits                */
+      int set_me               :1;     /* Set this bit for type 2      */
+    }
+    type_2;                            /* Type 2 relocation directive  */
+  }
+  t;
+}
+aof_relocstr;
+
+enum
+{
+  aof_BYTE,
+  aof_HALFWORD,
+  aof_FULLWORD
+};
+
+enum
+{
+  aof_ADDITIVE,
+  aof_PCRELATIVE
+};
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+static char *nicely(char *name)
+{
+  char *p=name;
+  while (*name)
+  {
+    if (!isalnum(*name))
+      *name='_';
+    name++;
+  }
+  if (strlen(p)>10)
+    p[10]=0;
+  return (p);
+}
+
+static int oscli(char *cmd,...)
+{
+  char buffer[256];
+  va_list ap;
+  va_start(ap,cmd);
+  vsprintf(buffer,cmd,ap);
+  va_end(ap);
+  return (system(buffer));
+}
+
+static int findChunk(chunk_header *c,char *name)
+{
+  int i;
+  for (i=0;i<c->hdr.maxChunks;i++)
+  {
+    if (c->table[i].offset && !memcmp(c->table[i].chunkName,name,8))
+      return (i);
+  }
+  return (-1);
+}
+
+static void get(void *p,FILE *fp,size_t size,size_t offset)
+{
+  fpos_t off;
+  off.__lo=offset;
+  fsetpos(fp,&off);
+  fread(p,size,1,fp);
+}
+
+static int dissect(char *aof,char *dir)
+{
+  FILE *fp;
+  FILE *out;
+  chunk_fixedHeader ch={0,0,0};
+  chunk_header *chf;
+  aof_header *header;
+  char *area;
+  char *string;
+  int h;
+  int a;
+  int s;
+  int bit=0;
+  char name[256];
+  int i;
+
+  oscli("cdir %s",dir);
+  fp=fopen(aof,"rb");
+  if (!fp)
+  {
+    fprintf(stderr,"couldn't open '%s'\n",aof);
+    return (1);
+  }
+  fread(&ch,sizeof(ch),1,fp);
+  if (ch.id!=chunk_MAGIC)
+  {
+    fprintf(stderr,"bad aof '%s'\n",aof);
+    return (1);
+  }
+  chf=malloc(sizeof(chunk_fixedHeader)+
+             ch.maxChunks*sizeof(chunk_tableEntry));
+  if (!chf)
+  {
+    fprintf(stderr,"no memory\n");
+    exit(1);
+  }
+  chf->hdr=ch;
+  fread(chf->table,sizeof(chunk_tableEntry),ch.maxChunks,fp);
+
+  h=findChunk(chf,"OBJ_HEAD");
+  a=findChunk(chf,"OBJ_AREA");
+  s=findChunk(chf,"OBJ_STRT");
+  if (h==-1 || a==-1 || s==-1)
+  {
+    fprintf(stderr,"bad aof '%s'\n",aof);
+    return (1);
+  }
+
+  header=malloc(chf->table[h].size);
+  area=malloc(chf->table[a].size);
+  string=malloc(chf->table[s].size);
+  if (!header || !area || !string)
+  {
+    fprintf(stderr,"no memory\n");
+    exit(1);
+  }
+
+  get(header,fp,chf->table[h].size,chf->table[h].offset);
+  get(area,fp,chf->table[a].size,chf->table[a].offset);
+  get(string,fp,chf->table[s].size,chf->table[s].offset);
+
+  for (i=0;i<header->hdr.areas;i++)
+  {
+    if (header->table[i].zinit)
+      continue;
+    sprintf(name,"%s.%s",dir,nicely(string+header->table[i].name));
+    out=fopen(name,"wb");
+    if (!out)
+    {
+      fprintf(stderr,"couldn't write '%s'\n",name);
+      continue;
+    }
+    fwrite(area+bit,1,header->table[i].size,out);
+    bit+=header->table[i].size+header->table[i].relocs*8;
+    fclose(out);
+  }
+  return (0);
+}
+
+int main(int argc,char *argv[])
+{
+  if (argc!=3)
+  {
+    fprintf(stderr,"dissect <aof> <dir>\n");
+    exit(1);
+  }
+  return (dissect(argv[1],argv[2]));
+}
diff --git a/StraySrc/SDLS/cdll/c/dllbinder b/StraySrc/SDLS/cdll/c/dllbinder
new file mode 100644 (file)
index 0000000..20c100b
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * dllbinder.c
+ *
+ * Entry point and things for the DLL Binder
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "_time.h"
+
+#include "error.h"
+#include "hashtable.h"
+#include "decode.h"
+#include "readdef.h"
+#include "binding.h"
+#include "cstub.h"
+#include "extentry.h"
+
+extern char cright[];
+
+static void cdll_readSymbols(char *p,void *handle)
+{
+  decode(handle,p);
+}
+
+static void cdll_writeName(char *p,void *handle)
+{
+  FILE *fp=handle;
+  fprintf(fp,"  %s\n",p);
+}
+
+static void cdll_notsubset(char *p)
+{
+  error(LOSTSYM,p);
+}
+
+int main(int argc,char *argv[])
+{
+
+  enum
+  {
+    NOWT=0,
+    DEF=1,
+    STUB=2,
+    BINDING=4,
+    OBJECT=8,
+    EXTERN=16,
+    PATH=32
+  };
+
+  char *deffile=0;                     /* Name of definition file      */
+  char *stubfile=0;                    /* Name of stublib file         */
+  char *bindfile=0;                    /* Name of binding file         */
+  char *extfile=0;                     /* Name of external veneer file */
+  char *dllfile=0;                     /* Name of DLL file to use      */
+  int helped=0;                                /* Have we given help?          */
+  hashtable objfiles;                  /* Names of objects specified   */
+  hashtable symbols;                   /* Symbols defined in deffile   */
+  hashtable objsym;                    /* Symbols defined in objects   */
+  hashtable veneered;                  /* Private symbols to veneer    */
+  int createdef=0;                     /* Do we create the def file?   */
+  int whatnext=DEF;                    /* What thing do we read next   */
+  int override=NOWT;                   /* What was the override tag?   */
+  int done=NOWT;                       /* What things we've done       */
+  int i;                               /* Loop counter                 */
+  int process=1;                       /* Do we process this time?     */
+  int apptbl=0;                                /* Is this for app extension?   */
+
+  error_setProgName(argv[0]);          /* Set up the program name      */
+
+  objfiles=hash_create();
+  symbols=hash_create();
+  veneered=hash_create();
+  objsym=hash_create();
+  if (!objfiles || !symbols || !objsym)
+    error(NOMEM);
+
+  for (i=1;i<argc;i++)
+  {
+    if (!cistrcmp(argv[i],"-help"))
+    {
+      printf(
+
+"%s: (help)\n"
+"\n"
+"Straylight Dynamic Link Library building system\n"
+"  version %s\n"
+"  %s\n"
+"\n"
+"Usage:\n"
+"\n"
+"  For a reminder of command syntax:\n"
+"    %s -help\n"
+"\n"
+"  To create a definition file from object files:\n"
+"    %s [[-def] <deffile>] -obj <objfile> [<objfile>]...\n"
+"\n"
+"  To create stub libraries and DLL headers:\n"
+"    %s [[-def] <deffile>] [[-stub] <stublib>] [[-hdr] <header>]\n"
+"      [-file <dllpath>]\n"
+"\n"
+"  To create application entry tables and extension stubs:\n"
+"    %s -app [[-def] <deffile>] [[-stub] <stublib>] [[-hdr] <header>]\n"
+"\n"
+"  To create external function entry points for module tasks:\n"
+"    %s [[-def] <deffile>] [-ext <extstub>]\n"
+"\n"
+"  All option switches may be abbreviated to single characters except\n"
+"  -help.\n"
+"\n",
+
+             error_progname(),
+             _time,
+             cright,
+             error_progname(),
+             error_progname(),
+             error_progname(),
+             error_progname(),
+             error_progname());
+      helped=1;
+    }
+    else if (argv[i][0]=='-')          /* Is it an option tag?         */
+    {
+      switch (argv[i][1])              /* Find second character        */
+      {
+        case 'a':
+          apptbl=1;
+          break;
+        case 'd':
+          override=DEF;
+          break;
+        case 's':
+          override=STUB;
+          break;
+        case 'h':
+          override=BINDING;
+          break;
+        case 'e':
+          override=EXTERN;
+          break;
+        case 'o':
+          override=OBJECT;
+          break;
+        case 'f':
+          override=PATH;
+          break;
+        default:
+          error(BADTAG,argv[i]);
+          break;
+      }
+      if (override & done)
+      {
+        error(DUPOPT,argv[i]);
+        process=0;
+        override=NOWT;
+      }
+    }
+    else
+    {
+      switch (override==NOWT ? whatnext : override)
+      {
+        case NOWT:
+          error(SILLYOPT,argv[i]);
+          break;
+        case DEF:
+          deffile=argv[i];
+          done|=DEF;
+          break;
+        case STUB:
+          if (createdef)
+          {
+            error(SORBNOBJ);
+            process=0;
+          }
+          else
+          {
+            stubfile=argv[i];
+            done|=STUB;
+          }
+          break;
+        case BINDING:
+          if (createdef)
+          {
+            error(SORBNOBJ);
+            process=0;
+          }
+          else
+          {
+            bindfile=argv[i];
+            done|=BINDING;
+          }
+          break;
+        case EXTERN:
+          if (createdef)
+          {
+            error(SORBNOBJ);
+            process=0;
+          }
+          else
+          {
+            extfile=argv[i];
+            done|=EXTERN;
+          }
+          break;
+        case OBJECT:
+          if (bindfile || stubfile)
+          {
+            error(SORBNOBJ);
+            process=0;
+          }
+          else if (apptbl)
+          {
+            error(APPNOEXT);
+            process=0;
+          }
+          else
+          {
+            if (!hash_add(objfiles,argv[i]))
+              error(NOMEM);
+            createdef=1;
+          }
+          break;
+        case PATH:
+          dllfile=argv[i];
+          break;
+      }
+      override=0;
+    }
+    if (!(done & DEF))
+      whatnext=DEF;
+    else if (createdef)
+      whatnext=OBJECT;
+    else if (!(done & STUB))
+      whatnext=STUB;
+    else if (!(done & BINDING))
+      whatnext=BINDING;
+    else
+      whatnext=NOWT;
+  }
+  if (!deffile)
+  {
+    if (!helped)
+      error(NODEF);
+    process=0;
+  }
+  if (!createdef && !bindfile && !stubfile && !extfile && !helped)
+    error(EASY);
+  else if (!process)
+  {
+    if (!helped)
+      error(BADCMDLINE);
+  }
+  else if (createdef)
+  {
+    FILE *fp=fopen(deffile,"w");
+    if (!fp)
+      error(NOOPENOUT,deffile);
+    else
+    {
+      hash_enumerate(objfiles,cdll_readSymbols,objsym);
+      fprintf(fp,";\n"
+                 "; cdll definition file for <name>\n"
+                 ";\n"
+                 "\n"
+                 "name \"<name>\"\n"
+                 "  version 1.00\n"
+                 "  author \"<author>\"\n"
+                 "\n"
+                 "; --- Exported symbols ---\n"
+                 "\n"
+                 "exports\n"
+                 "{\n");
+      hash_enumerate(objsym,cdll_writeName,fp);
+      fprintf(fp,"}\n"
+                 "\n"
+                 "; --- Object files ---\n"
+                 "\n"
+                 "objects\n"
+                 "{\n");
+      hash_enumerate(objfiles,cdll_writeName,fp);
+      fprintf(fp,"}\n");
+      fclose(fp);
+    }
+  }
+  else
+  {
+    readdef_info i;
+    i.sym=symbols;
+    i.obj=objfiles;
+    i.vsym=veneered;
+    i.apptbl=apptbl;
+    i.dllpath=dllfile;
+    readdef(deffile,&i);
+    hash_enumerate(objfiles,cdll_readSymbols,objsym);
+    hash_subset(objsym,symbols,cdll_notsubset);
+    hash_subset(objsym,veneered,cdll_notsubset);
+    if (bindfile)
+      binding(bindfile,&i,objsym);
+    if (stubfile)
+      cstub(stubfile,&i,objsym);
+    if (extfile)
+      extentry(extfile,&i,objsym);
+  }
+  error_show();
+  return (error_returnCode());
+}
diff --git a/StraySrc/SDLS/cdll/c/error b/StraySrc/SDLS/cdll/c/error
new file mode 100644 (file)
index 0000000..e5879d4
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * error.h
+ *
+ * Error messages and handling
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#define error__MAKETABLE
+#include "error.h"
+
+static char *error__progname;
+static int error__count[5];
+static int error__retcode=0;
+
+void error_setProgName(char *name)
+{
+  error__progname=strrchr(name,'.');
+  if (!error__progname)
+    error__progname=name;
+  else
+    error__progname++;
+}
+
+char *error_progname(void)
+{
+  return (error__progname);
+}
+
+void error(int message,...)
+{
+  static char const *types[]={"Informational",
+                              "Warning",
+                              "Error",
+                              "Serious error",
+                              "Fatal error"};
+
+  va_list ap;
+  va_start(ap,message);
+  fprintf(stderr,
+          "%s: (%s) ",
+          error__progname,
+          types[error__table[message].sev]);
+  vfprintf(stderr,error__table[message].msg,ap);
+  va_end(ap);
+  if (error__table[message].sev==error_FATAL)
+    exit(error_FATAL);
+  error__count[error__table[message].sev]++;
+  if (error__table[message].sev>error__retcode)
+    error__retcode=error__table[message].sev;
+}
+
+void error_show(void)
+{
+  if (error__retcode)
+  {
+    fprintf(stderr,
+            "%s: completed with %i warning%s, "
+            "%i error%s and %i serious error%s.\n",
+            error__progname,
+            error__count[error_WARN],
+            error__count[error_WARN]==1 ? "" : "s",
+            error__count[error_ERROR],
+            error__count[error_ERROR]==1 ? "" : "s",
+            error__count[error_SEVERE],
+            error__count[error_SEVERE]==1 ? "" : "s");
+  }
+}
+
+int error_returnCode(void)
+{
+  return (error__retcode);
+}
+
+extern void aof_error(void)
+{
+  error(0);
+}
diff --git a/StraySrc/SDLS/cdll/c/extentry b/StraySrc/SDLS/cdll/c/extentry
new file mode 100644 (file)
index 0000000..053f6dd
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * extentry.c
+ *
+ * Create DLL header and things
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+
+#include "extentry.h"
+#include "readdef.h"
+#include "aof/aof.h"
+#include "aof/chunk.h"
+#include "hashtable.h"
+#include "error.h"
+
+typedef struct
+{
+  aof_file f;
+  hashtable osym;
+  int symbol;
+}
+ext__thing;
+
+static void ext__entries(char *p,void *handle)
+{
+  ext__thing *t=handle;
+  aof_relocstr r;
+  static int entry[4]={0xE92D0007,             /* STMFD   sp!,{a1-a3}  */
+                       0xE59FC000,             /* LDR     ip,=address  */
+                       0xEA000000};            /* B       _dll_extentry */
+  char buf[256];
+  if (hash_find(t->osym,p))
+  {
+    r.offset=t->f.area->next+8;
+    r.t.type_1.symbol=t->symbol;
+    r.t.type_1.field=aof_FULLWORD;
+    r.t.type_1.type=aof_PCRELATIVE;
+    r.t.type_1.symreloc=1;
+    aof_add(r,t->f.reloc);
+
+    aof_reloc(p,t->f.area->next+12,0,&t->f);
+    sprintf(buf,"_extEntry_%s",p);
+    aof_addsym(buf,t->f.area->next,0,4,&t->f);
+    aof_add(entry,t->f.area);
+  }
+}
+
+void extentry(char *name,readdef_info *inf,hashtable osym)
+{
+  FILE *fp;
+
+  fp=fopen(name,"wb");                 /* Open the output file         */
+  if (!fp)                             /* If the file wasn't opened    */
+    error(NOOPENOUT,name);             /* Better give an error         */
+  else
+  {
+    char _buf[sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry)];
+    chunk_header *h=(chunk_header *)&_buf; /* Allocate memory easily :-) */
+
+    aof_chunkinfo obj_idfn={0};
+    aof_chunkinfo obj_head={0};
+    aof_chunkinfo obj_area={0};
+    aof_chunkinfo obj_symt={0};
+    aof_chunkinfo obj_strt={0};
+    aof_chunkinfo reloc={0};
+    ext__thing t;
+
+    int o;
+
+    h->hdr.id=chunk_MAGIC;             /* Fill in magic thingy         */
+    h->hdr.maxChunks=h->hdr.numChunks=5; /* And number of chunks       */
+
+    t.f.area=&obj_area;
+    t.osym=osym;
+    t.f.symt=&obj_symt;
+    t.f.strt=&obj_strt;
+    t.f.reloc=&reloc;
+
+    aof_string("Straylight Dynamic Link Library building system 1.01",
+                 &obj_idfn);
+    aof_align(obj_idfn);
+
+    aof_int(0,&obj_strt);
+    aof_string("DLL$$ExtEntry",&obj_strt);
+
+    {
+      aof_symbol sym={0};
+      sym.name=aof_string("_dll_extentry",&obj_strt);
+      sym.defined=0;
+      sym.export=1;
+      t.symbol=aof_add(sym,&obj_symt)/sizeof(aof_symbol);
+    }
+
+    hash_enumerate(inf->vsym,ext__entries,&t);
+
+    aof_int((int)aof_RELOC,&obj_head);
+    aof_int(150,&obj_head);
+    aof_int(1,&obj_head);
+    aof_int(obj_symt.next/sizeof(aof_symbol),&obj_head);
+    aof_int(0,&obj_head);
+    aof_int(0,&obj_head);
+
+    aof_int(4,&obj_head);
+    aof_int(0x00002202,&obj_head);
+    aof_int(obj_area.next,&obj_head);
+    aof_int(reloc.next/8,&obj_head);
+    aof_int(0,&obj_head);
+
+    aof_addBlock(reloc.p,reloc.next,&obj_area);
+
+    aof_fill(obj_strt.next,0,&obj_strt);
+    aof_align(obj_strt);
+
+    memcpy(h->table[0].chunkName,"OBJ_IDFN",8);
+    memcpy(h->table[1].chunkName,"OBJ_HEAD",8);
+    memcpy(h->table[2].chunkName,"OBJ_AREA",8);
+    memcpy(h->table[3].chunkName,"OBJ_SYMT",8);
+    memcpy(h->table[4].chunkName,"OBJ_STRT",8);
+
+    o=sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry);
+
+    h->table[0].offset=o;
+    h->table[0].size=obj_idfn.next;
+    o+=obj_idfn.next;
+
+    h->table[1].offset=o;
+    h->table[1].size=obj_head.next;
+    o+=obj_head.next;
+
+    h->table[2].offset=o;
+    h->table[2].size=obj_area.next;
+    o+=obj_area.next;
+
+    h->table[3].offset=o;
+    h->table[3].size=obj_symt.next;
+    o+=obj_symt.next;
+
+    h->table[4].offset=o;
+    h->table[4].size=obj_strt.next;
+    o+=obj_strt.next;
+
+    fwrite(h,sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry),1,fp);
+    fwrite(obj_idfn.p,obj_idfn.next,1,fp);
+    fwrite(obj_head.p,obj_head.next,1,fp);
+    fwrite(obj_area.p,obj_area.next,1,fp);
+    fwrite(obj_symt.p,obj_symt.next,1,fp);
+    fwrite(obj_strt.p,obj_strt.next,1,fp);
+    fclose(fp);
+
+    free(obj_idfn.p);
+    free(obj_area.p);
+    free(obj_strt.p);
+    free(obj_head.p);
+    free(obj_symt.p);
+  }
+}
diff --git a/StraySrc/SDLS/cdll/c/hashtable b/StraySrc/SDLS/cdll/c/hashtable
new file mode 100644 (file)
index 0000000..185ba75
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * hashtable.c
+ *
+ * Hash table handling for strings
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hashtable.h"
+#include "crc32.h"
+
+/*----- Constants ---------------------------------------------------------*/
+
+#define hash__SIZE 512                 /* A respectable size table     */
+                                       /* Note: must be power of 2     */
+
+/*----- Some good ol' data structures -------------------------------------*/
+
+typedef struct hash__link
+{
+  struct hash__link *next;             /* Link in hash table bucket    */
+  struct hash__link *left;             /* Link in ordinal tree         */
+  struct hash__link *right;            /* Link in ordinal tree         */
+  unsigned int ord;                    /* Ordinal value                */
+  char string[1];                      /* String (unsized array)       */
+}
+hash__link;
+
+typedef struct hash__table
+{
+  hash__link *tbl[hash__SIZE];         /* The actual hash table        */
+  hash__link *root;                    /* The ordinal tree root        */
+}
+hash__table;
+
+/*----- Private code ------------------------------------------------------*/
+
+#define hash__hash(s) (crc32(0,s,strlen(s),1) & (hash__SIZE - 1))
+
+static int hash__addToTree(hash__link **root,hash__link *l)
+{
+  if (*root)
+  {
+    if ((*root)->ord > l->ord)
+      return (hash__addToTree(&(*root)->left,l));
+    else if ((*root)->ord < l->ord || l->ord == 0xFFFFFFFF)
+      return (hash__addToTree(&(*root)->right,l));
+    else
+      return (1);
+  }
+  else
+  {
+    *root=l;
+    return (0);
+  }
+}
+
+static void hash__traverse(hash__link *l,
+                           void (*func)(char *string,
+                                        unsigned int ord,
+                                        void *handle),
+                           void *handle)
+{
+  if (l)
+  {
+    hash__traverse(l->left,func,handle);
+    func(l->string,l->ord,handle);
+    hash__traverse(l->right,func,handle);
+  }
+}
+
+static void hash__dump(char *string,unsigned int ord,void *handle)
+{
+  handle=handle;
+  printf(" ** %s (%08x)\n",string,ord);
+}
+
+/*----- Public code -------------------------------------------------------*/
+
+hashtable hash_create(void)
+{
+  return (calloc(1,sizeof(hash__table)));
+}
+
+int hash_find(hashtable h,char *string)
+{
+  int sh=hash__hash(string);
+  hash__link *l;
+  for (l=h->tbl[sh];l;l=l->next)
+  {
+    if (!strcmp(l->string,string))
+      return (1);
+  }
+  return (0);
+}
+
+int hash_add(hashtable h,char *string)
+{
+  return (hash_addWithOrd(h,string,0xFFFFFFFF));
+}
+
+int hash_addWithOrd(hashtable h,char *string,unsigned int ord)
+{
+  int sh=hash__hash(string);
+  hash__link *l;
+  if (hash_find(h,string))
+    return (1);
+  if (l=malloc(sizeof(hash__link)+strlen(string)),!l)
+    return (0);
+  strcpy(l->string,string);
+  l->ord=ord;
+  l->next=h->tbl[sh];
+  h->tbl[sh]=l;
+  l->left=l->right=0;
+  if (hash__addToTree(&h->root,l))
+  {
+    l->ord=0xFFFFFFFF;
+    hash__addToTree(&h->root,l);
+  }
+  return (1);
+}
+
+void hash_delete(hashtable h)
+{
+  hash__link *l;
+  hash__link *n;
+  int i;
+  for (i=0;i<hash__SIZE;i++)
+  {
+    for (l=h->tbl[i];l;l=n)
+    {
+      n=l->next;
+      free(l);
+    }
+  }
+  free(h);
+}
+
+int hash_subset(hashtable super,
+                hashtable sub,
+                void (*proc)(char *p))
+{
+  hash__link *l;
+  int i;
+  int s=1;
+  for (i=0;i<hash__SIZE;i++)
+  {
+    for (l=sub->tbl[i];l;l=l->next)
+    {
+      if (!hash_find(super,l->string))
+      {
+        s=0;
+        proc(l->string);
+      }
+    }
+  }
+  return (s);
+}
+
+void hash_dump(hashtable h)
+{
+  hash_enumOrdered(h,hash__dump,0);
+}
+void hash_enumerate(hashtable h,
+                    void (*func)(char *string,void *handle),
+                    void *handle)
+{
+  hash__link *l;
+  int i;
+  for (i=0;i<hash__SIZE;i++)
+  {
+    for (l=h->tbl[i];l;l=l->next)
+      func(l->string,handle);
+  }
+}
+
+void hash_enumOrdered(hashtable h,
+                      void (*func)(char *string,
+                                   unsigned int ord,
+                                   void *handle),
+                      void *handle)
+{
+  hash__traverse(h->root,func,handle);
+}
+
+int hash_count(hashtable h)
+{
+  int count=0;
+  hash__link *l;
+  int i;
+  for (i=0;i<hash__SIZE;i++)
+  {
+    for (l=h->tbl[i];l;l=l->next)
+      count++;
+  }
+  return (count);
+}
diff --git a/StraySrc/SDLS/cdll/c/readdef b/StraySrc/SDLS/cdll/c/readdef
new file mode 100644 (file)
index 0000000..8511379
--- /dev/null
@@ -0,0 +1,455 @@
+/*
+ * readdef.c
+ *
+ * Read DLL Binder definition files
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "hashtable.h"
+#include "error.h"
+#include "readdef.h"
+#include "swiv.h"
+#include "swis.h"
+
+#define CHUNKSIZE 40
+
+static char *readdef_token=0;
+
+static void addChar(char **buffer,int *length,int *size,char c)
+{
+  char *p;
+  if (*length==*size)
+  {
+    if (p=realloc(*buffer,*size+CHUNKSIZE),!p)
+      error(NOMEM);
+    *buffer=p;
+    (*size)+=CHUNKSIZE;
+  }
+  (*buffer)[(*length)++]=c;
+}
+
+#define add(c) addChar(&readdef_token,&len,&size,(c))
+
+int cistrcmp(const char *s1,const char *s2)
+{
+  char c1;
+  char c2;
+  while (*s1 || *s2)
+  {
+    c1=tolower(*(s1++));
+    c2=tolower(*(s2++));
+    if (c1!=c2)
+      return (c1-c2);
+  }
+  return (0);
+}
+
+enum
+{
+  _xxx,
+  _IDENT,
+  _STRING,
+  _BRA,
+  _KET,
+  _EQUAL,
+  _CONST,
+  _EOF
+};
+
+static char readdef__ungot[2];
+static int readdef__ungotc=0;
+
+#define GET(fp) (readdef__ungotc ? \
+                  readdef__ungot[--readdef__ungotc] : \
+                  getc(fp))
+
+#define UNGET(c) ((void)((c)==EOF ? \
+                   EOF : \
+                   (readdef__ungot[readdef__ungotc++]=(c))))
+
+static int readdef__getToken(FILE *fp)
+{
+  int ch;
+  int type=_xxx;
+  int qu;
+  int len=0;
+  int size=0;
+
+  if (readdef_token)
+    free(readdef_token);
+  readdef_token=0;
+
+  while (!type)
+  {
+    /* --- Skip whitespace --- */
+    while (isspace(ch=GET(fp)))
+      /* blank */;
+
+    switch (ch)
+    {
+      case ';':
+      case '|':
+      case '#':
+        while (ch=GET(fp),ch!='\n' && ch!=EOF)
+          /* blank */;
+        break;
+      case '/':
+        switch (ch=GET(fp))
+        {
+          case '*':
+            while (ch=GET(fp),ch!='*' ||
+                              (ch=GET(fp),UNGET(ch),ch!='/'))
+              /* blank */;
+            (void)GET(fp);
+            break;
+          case '/':
+            while (ch=GET(fp),ch!='\n' && ch!=EOF)
+              /* blank */;
+            break;
+          default:
+            UNGET(ch);
+            add('/');
+            break;
+        }
+        break;
+      case '{':
+        type=_BRA;
+        break;
+      case '}':
+        type=_KET;
+        break;
+      case '=':
+        type=_EQUAL;
+        break;
+      case EOF:
+        type=_EOF;
+        break;
+      case '\'':
+      case '\"':
+        qu=ch;
+        while (ch=GET(fp),1)
+        {
+          if (ch==qu)
+          {
+            ch=GET(fp);
+            if (ch!=qu)
+            {
+              UNGET(ch);
+              break;
+            }
+          }
+          if (ch==EOF)
+          {
+            error(QBFEOF,qu);
+            break;
+          }
+          else if (ch=='\n')
+          {
+            error(QBFNL,qu);
+            break;
+          }
+          add(ch);
+        }
+        add(0);
+        type=_STRING;
+        break;
+      default:
+        add(ch);
+        while (ch=GET(fp),ch!=EOF && !isspace(ch))
+          add(ch);
+        add(0);
+        UNGET(ch);
+        type=_IDENT;
+        break;
+    }
+  }
+  return (type);
+}
+
+static char *readdef__tokAsString(int type)
+{
+  switch (type)
+  {
+    case _EOF:
+      return ("<EOF>");
+    case _BRA:
+      return ("{");
+    case _KET:
+      return ("}");
+    case _EQUAL:
+      return ("=");
+    case _CONST:
+      return ("<integer>");
+    case _STRING:
+      return ("<string literal>");
+    case _IDENT:
+      return (readdef_token);
+  }
+  return (0);
+}
+
+static int readdef__getOrderedTable(FILE *fp,hashtable h)
+{
+  int done=0;
+  int tok;
+  char *name;
+  unsigned int ord;
+
+  switch (tok=readdef__getToken(fp))
+  {
+    case _BRA:
+      break;
+    default:
+      error(JUNKNOBRA,readdef__tokAsString(tok));
+      return (1);
+      break;
+  }
+
+  tok=readdef__getToken(fp);
+  while (!done)
+  {
+    switch (tok)
+    {
+      case _IDENT:
+        name=readdef_token;
+        readdef_token=0;
+        tok=readdef__getToken(fp);
+        ord=0xFFFFFFFF;
+        if (tok==_EQUAL)
+        {
+          tok=readdef__getToken(fp);
+          if (tok==_IDENT)
+          {
+            sscanf(readdef_token,"%i",&ord);
+            tok=readdef__getToken(fp);
+          }
+        }
+        if (!hash_addWithOrd(h,name,ord))
+        {
+          error(NOMEM);
+          return (1);
+        }
+        free(name);
+        break;
+      case _KET:
+        done=1;
+        break;
+      default:
+        error(JUNKNOKET,readdef__tokAsString(tok));
+        return (1);
+    }
+  }
+  return (0);
+}
+
+static int readdef__getTable(FILE *fp,hashtable h)
+{
+  int done=0;
+  int tok;
+
+  switch (tok=readdef__getToken(fp))
+  {
+    case _BRA:
+      break;
+    default:
+      error(JUNKNOBRA,readdef__tokAsString(tok));
+      return (1);
+      break;
+  }
+
+  while (!done)
+  {
+    switch (tok=readdef__getToken(fp))
+    {
+      case _IDENT:
+        if (!hash_add(h,readdef_token))
+        {
+          error(NOMEM);
+          return (1);
+        }
+        break;
+      case _KET:
+        done=1;
+        break;
+      default:
+        error(JUNKNOKET,readdef__tokAsString(tok));
+        return (1);
+    }
+  }
+  return (0);
+}
+
+static int readdef__getVersion(FILE *fp,int *v)
+{
+  int tok;
+  int minor;
+  int major;
+  char *dot;
+
+  switch (tok=readdef__getToken(fp))
+  {
+    case _IDENT:
+      dot=strchr(readdef_token,'.');
+      if (!dot)
+      {
+        sscanf(readdef_token,"%i",&major);
+        *v=major*100;
+      }
+      else
+      {
+        *dot=0;
+        major=atoi(readdef_token);
+        switch (strlen(dot+1))
+        {
+          case 0:
+            *v=major*100;
+            break;
+          case 1:
+            minor=atoi(dot+1);
+            *v=major*100+minor*10;
+            break;
+          case 2:
+            minor=atoi(dot+1);
+            *v=major*100+minor;
+            break;
+          default:
+            error(BADVER,readdef__tokAsString(tok));
+            return (1);
+        }
+      }
+      break;
+    default:
+      error(JUNKNOVER,readdef__tokAsString(tok));
+      return (1);
+  }
+  return (0);
+}
+
+static int readdef__getName(FILE *fp,char *name)
+{
+  int tok;
+
+  switch (tok=readdef__getToken(fp))
+  {
+    case _IDENT:
+    case _STRING:
+      strcpy(name,readdef_token);
+      break;
+    default:
+      error(JUNKNONAME,readdef__tokAsString(tok));
+      return (1);
+  }
+  return (0);
+}
+
+static int readdef__getCopyright(FILE *fp,char *name)
+{
+  int tok;
+  char timeBuff[5];
+
+  switch (tok=readdef__getToken(fp))
+  {
+    case _STRING:
+      timeBuff[0]=3;
+      _swi(OS_Word,_inr(0,1),14,timeBuff);
+      _swi(OS_ConvertDateAndTime,_inr(0,3),timeBuff,name,256,readdef_token);
+      break;
+    default:
+      error(JUNKNOCRIGHT,readdef__tokAsString(tok));
+      return (1);
+  }
+  return (0);
+}
+
+static int readdef__getItem(FILE *fp,readdef_info *info)
+{
+  int tok;
+
+  switch (tok=readdef__getToken(fp))
+  {
+    case _EOF:
+      return (-1);
+      break;
+    case _IDENT:
+      break;
+    default:
+      error(JUNKNOITEM,readdef__tokAsString(tok));
+      return (1);
+  }
+
+  if (!cistrcmp(readdef_token,"exports"))
+    return (readdef__getOrderedTable(fp,info->sym));
+  else if (!cistrcmp(readdef_token,"extentry"))
+    return (readdef__getTable(fp,info->vsym));
+  else if (!cistrcmp(readdef_token,"objects"))
+    return (readdef__getTable(fp,info->obj));
+  else if (!cistrcmp(readdef_token,"version"))
+    return (readdef__getVersion(fp,&info->version));
+  else if (!cistrcmp(readdef_token,"name"))
+    return (readdef__getName(fp,info->name));
+  else if (!cistrcmp(readdef_token,"author"))
+    return (readdef__getCopyright(fp,info->copyright));
+  else if (!cistrcmp(readdef_token,"NonAPCS"))
+  {
+    info->flags|=rdFlag_shortEntry;
+    return (0);
+  }
+  else if (!cistrcmp(readdef_token,"OmitNames"))
+  {
+    info->flags|=rdFlag_noNames;
+    return (0);
+  }
+  else
+  {
+    error(BADITEM,readdef_token);
+    return (1);
+  }
+}
+
+int readdef(char *file,readdef_info *info)
+{
+  FILE *fp=fopen(file,"r");
+
+  if (!fp)
+  {
+    error(NOOPENIN,file);
+    return(1);
+  }
+
+  info->version=-1;
+  *info->name=0;
+  *info->copyright=0;
+  info->errored=0;
+  info->flags=0;
+
+  while (readdef__getItem(fp,info)!=-1)
+    /* blank */;
+  fclose(fp);
+
+  return (0);
+}
diff --git a/StraySrc/SDLS/cdll/h/binding b/StraySrc/SDLS/cdll/h/binding
new file mode 100644 (file)
index 0000000..75e2ba9
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * binding.h
+ *
+ * Create DLL header and things
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __binding_h
+#define __binding_h
+
+#ifndef __readdef_h
+  #include "readdef.h"
+#endif
+
+#ifndef __hashtable_h
+  #include "hashtable.h"
+#endif
+
+void binding(char *name,readdef_info *inf,hashtable osym);
+
+#endif
diff --git a/StraySrc/SDLS/cdll/h/crc32 b/StraySrc/SDLS/cdll/h/crc32
new file mode 100644 (file)
index 0000000..b9fc2d0
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * crc32.h
+ *
+ * Calculates 32-bit CRCs (Cyclic Redundancy Checks)
+ *
+ * © 1993-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __crc32_h
+#define __crc32_h
+
+#ifndef __stddef_h
+  #include <stddef.h>
+#endif
+
+/*
+ * long crc32(long seed,void *data,size_t size,int diff)
+ *
+ * Use
+ *  Calculates the CRC for a block of data.  The system has been designed to
+ *  allow a CRC calculation to be carried out in stages, the result of
+ *  previous calculations being used for continuation.
+ *
+ * Parameters
+ *  long seed == 0 to start a calculation, or the result from the previous
+ *    one to continue.
+ *  void *data == pointer to the data to check
+ *  size_t size == size (in bytes) of the data (just this block)
+ *  int diff == the address difference between bytes to check (normally one,
+ *    for all bytes).
+ *
+ * Returns
+ *   The CRC for all the data checked so far.
+ */
+
+long crc32(long seed,void *data,size_t size,int diff);
+
+#endif
diff --git a/StraySrc/SDLS/cdll/h/cstub b/StraySrc/SDLS/cdll/h/cstub
new file mode 100644 (file)
index 0000000..af96d5b
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * cstub.h
+ *
+ * Create DLL stublib
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __cstub_h
+#define __cstub_h
+
+#ifndef __readdef_h
+  #include "readdef.h"
+#endif
+
+#ifndef __hashtable_h
+  #include "hashtable.h"
+#endif
+
+void cstub(char *name,readdef_info *inf,hashtable osym);
+
+#endif
diff --git a/StraySrc/SDLS/cdll/h/decode b/StraySrc/SDLS/cdll/h/decode
new file mode 100644 (file)
index 0000000..21cc0e7
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * decode.h
+ *
+ * Find all the symbols in an ALF file.  This will be extended in future to
+ * handle AOF files, and will be part of the DLL Binder.
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __decode_h
+#define __decode_h
+
+#ifndef __hashtable_h
+  #include "hashtable.h"
+#endif
+
+int decode(hashtable h,char *filename);
+
+#endif
diff --git a/StraySrc/SDLS/cdll/h/error b/StraySrc/SDLS/cdll/h/error
new file mode 100644 (file)
index 0000000..d9abf1b
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * error.h
+ *
+ * Error messages and handling
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __error_h
+#define __error_h
+
+typedef enum
+{
+  error_INFO,
+  error_WARN,
+  error_ERROR,
+  error_SEVERE,
+  error_FATAL
+}
+error_sev;
+
+/*----- A word to the wise ------------------------------------------------*
+ *
+ * There's some clever preprocessor jiggery-pokery going on here, which
+ * does all the tedious matching up of error names to numbers and severities
+ * and things.  Quite neat, really.
+ *
+ * To actually make the array of error strings *defined*, you should
+ * predefine the macro error__MAKETABLE.
+ */
+
+#ifdef error__MAKETABLE
+
+  #define __entry(sev,name,msg) sev , msg "\n" ,
+
+  static const struct
+  {
+    error_sev sev;
+    char *msg;
+  }
+  error__table[]={
+
+#else
+
+  #define __entry(sev,name,msg) name ,
+
+  enum
+  {
+
+#endif
+
+/* --- End of preprocessor trickery --- */
+
+  __entry(error_FATAL, NOMEM,          "Out of memory")
+
+  __entry(error_ERROR, BADFILE,        "'%s' is not a valid object file "
+                                       "or library -- ignored")
+
+  __entry(error_SEVERE,        BADNAME,        "Symbol '%s' not found in specified "
+                                       "object files")
+
+  __entry(error_WARN,  NOSYMS,         "No symbols specified -- reading "
+                                       "from object files")
+  __entry(error_ERROR, DUPSYM,         "Duplicate symbol '%s' found -- "
+                                       "ignoring")
+
+  __entry(error_WARN,  BADTAG,         "Unknown option tag '%s'")
+  __entry(error_ERROR, DUPOPT,         "Option '%s' already specified -- "
+                                       "duplicate ignored")
+  __entry(error_WARN,  SILLYOPT,       "Unexpected option '%s' ignored")
+  __entry(error_ERROR, SORBNOBJ,       "You can't specify -o and -s or -b")
+  __entry(error_ERROR, APPNOEXT,       "You can't specify -e and -app")
+  __entry(error_ERROR, NODEF,          "No definition file specified")
+  __entry(error_ERROR, NOSTUB,         "No stublib file specified")
+  __entry(error_ERROR, NOBIND,         "No DLL header file specified")
+  __entry(error_INFO,  BADCMDLINE,     "Exiting due to errors in command "
+                                       "line")
+
+  __entry(error_WARN,  LOSTSYM,        "Symbol '%s' not found in specified "
+                                       "object files")
+
+  __entry(error_SEVERE,        NOOPENOUT,      "Couldn't open file '%s' for "
+                                       "writing")
+  __entry(error_ERROR, NOOPENIN,       "Couldn't open file '%s' for "
+                                       "reading")
+
+  __entry(error_ERROR, JUNKNOITEM,     "Expected section name, found '%s'")
+  __entry(error_ERROR, JUNKNOBRA,      "Expected '{', found '%s'")
+  __entry(error_ERROR, BADITEM,        "Invalid item name '%s'")
+  __entry(error_ERROR, JUNKNOKET,      "Expected name or '}', found '%s'")
+  __entry(error_ERROR, JUNKNOVER,      "Expected version, found '%s'")
+  __entry(error_ERROR, JUNKNONAME,     "Expected DLL name, found '%s'")
+  __entry(error_ERROR, JUNKNOCRIGHT,   "Expected copyright string, found "
+                                       "'%s'")
+  __entry(error_ERROR, BADVER,         "Bad version number '%s'")
+  __entry(error_ERROR, QBFEOF,         "Missing %c before <EOF>, inserted")
+  __entry(error_ERROR, QBFNL,          "Missing %c before <newline>, "
+                                       "inserted")
+
+  __entry(error_WARN,  NOVERSION,      "No version number specified, "
+                                       "assuming version 1.00")
+  __entry(error_SEVERE,        NONAME,         "No DLL name specified")
+  __entry(error_WARN,  NOCRIGHT,       "No copyright string specified")
+
+  __entry(error_WARN,  EASY,           "Nothing to do!")
+
+/* --- Terminate entries --- */
+
+#ifdef error__MAKETABLE
+
+  };
+
+#else
+
+    __dummy
+  };
+
+#endif
+
+#undef __entry
+
+/* --- Functions --- */
+
+void error_setProgName(char *name);
+char *error_progname(void);
+void error(int message,...);
+void error_show(void);
+int error_returnCode(void);
+
+#endif
diff --git a/StraySrc/SDLS/cdll/h/extentry b/StraySrc/SDLS/cdll/h/extentry
new file mode 100644 (file)
index 0000000..d8c928f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * extentry.h
+ *
+ * Create DLL header and things
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __extentry_h
+#define __extentry_h
+
+#ifndef __readdef_h
+  #include "readdef.h"
+#endif
+
+#ifndef __hashtable_h
+  #include "hashtable.h"
+#endif
+
+void extentry(char *name,readdef_info *inf,hashtable osym);
+
+#endif
diff --git a/StraySrc/SDLS/cdll/h/hashtable b/StraySrc/SDLS/cdll/h/hashtable
new file mode 100644 (file)
index 0000000..488ed45
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * hashtable.h
+ *
+ * Hash table handling for strings
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __hashtable_h
+#define __hashtable_h
+
+typedef struct hash__table *hashtable;
+
+hashtable hash_create(void);
+int hash_find(hashtable h,char *string);
+int hash_add(hashtable h,char *string);
+int hash_addWithOrd(hashtable h,char *string,unsigned int ord);
+void hash_delete(hashtable h);
+int hash_subset(hashtable super,
+                hashtable sub,
+                void (*proc)(char *p));
+void hash_dump(hashtable h);
+void hash_enumerate(hashtable h,
+                    void (*func)(char *string,void *handle),
+                    void *handle);
+void hash_enumOrdered(hashtable h,
+                      void (*func)(char *string,
+                                   unsigned int ord,
+                                   void *handle),
+                      void *handle);
+int hash_count(hashtable h);
+
+#endif
diff --git a/StraySrc/SDLS/cdll/h/readdef b/StraySrc/SDLS/cdll/h/readdef
new file mode 100644 (file)
index 0000000..4461f0c
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * readdef.h
+ *
+ * Read DLL Binder definition files
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Dynamic Linking System (SDLS)
+ *
+ * SDLS is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * SDLS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with SDLS.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __readdef_h
+#define __readdef_h
+
+#ifndef __hashtable_h
+  #include "hashtable.h"
+#endif
+
+enum
+{
+  rd_name=1,
+  rd_version=2,
+  rd_cright=4
+};
+
+enum
+{
+  rdFlag_shortEntry=1,
+  rdFlag_noNames=2
+};
+
+typedef struct
+{
+  hashtable sym;
+  hashtable vsym;
+  hashtable obj;
+  int version;
+  char name[256];
+  char *dllpath;
+  char copyright[256];
+  int errored;
+  int apptbl;
+  unsigned flags;
+}
+readdef_info;
+
+int cistrcmp(const char *s1,const char *s2);
+int readdef(char *file,readdef_info *info);
+
+#endif
diff --git a/StraySrc/SDLS/cdll/ordinal b/StraySrc/SDLS/cdll/ordinal
new file mode 100644 (file)
index 0000000..916697f
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# ordinal
+#
+# Add ordinals to a cdll file
+#
+# © 1994 Straylight
+#
+
+BEGIN  {
+         count=0;
+         write=1;
+       }
+
+/=/    {
+         print $0,count;
+         count++;
+         write=0;
+       }
+
+       {
+         if (write)
+           print $0;
+         write=1;
+       }
diff --git a/StraySrc/SDLS/cdll/s/crc32 b/StraySrc/SDLS/cdll/s/crc32
new file mode 100644 (file)
index 0000000..482ec09
--- /dev/null
@@ -0,0 +1,168 @@
+;
+; crc32.s
+;
+; 32-bit CRC calculation
+;
+; © 1993-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Dynamic Linking System (SDLS)
+;
+; SDLS is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; SDLS is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with SDLS.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               AREA    |C$$Code|,CODE,READONLY
+
+;----- crc32 ----------------------------------------------------------------
+;
+; Calculates 32-bit Cyclic Redundancy Check values for a given chunk of
+; data.  A calculation may be performed in stages.
+;
+; The method used is the PKZip/Ethernet algorithm.  For reference, the
+; parameters to the Rocksoft^tm Model CRC Algorithm are:
+;
+; Name   : Straylight Cyclic Redundancy Check algorithm
+; Width  : 32
+; Poly   : 04C11DB7
+; Init   : FFFFFFFF
+; RefIn  : True
+; RefOut : True
+; XorOut : FFFFFFFF
+; Check  : CBF43926
+;
+; The routine is very small (and hopefully pretty quick, too).  The table
+; is rather large, though.
+;
+; The code can be called from any APCS-conformant langauge.  The C prototype
+; is
+;
+;      long crc32(     long seed,      /* R0==seed value (0 to start)  */
+;                      void *data,     /* R1==pointer to data to check */
+;                      size_t size,    /* R2==length of data           */
+;                      int diff);      /* R3==diff between check bytes */
+;
+; In normal use, the seed is 0 for the first call, and the previoud returned
+; value for subsequent calculations.
+;
+; The 'diff' value gives the difference in address between bytes to check,
+; so diff==1 means check all bytes, diff==2 means check every other byte,
+; and so on.
+;
+
+               EXPORT  crc32
+crc32          ROUT
+
+               STMFD   R13!,{R1-R4,R14}
+               MVN     R0,R0                   ;R0 = R0 XOR &FFFFFFFF!
+               ADR     R4,crctable             ;Point to my magic table
+
+00             LDRB    R14,[R1],R3             ;Get byte from stream
+               EOR     R14,R14,R0              ;XOR register with byte
+               AND     R14,R14,#&FF            ;Multiply to word, and mask
+               LDR     R14,[R4,R14,LSL #2]     ;Get word from table
+               EOR     R0,R14,R0,LSR #8        ;EOR with shifted register
+               SUBS    R2,R2,R3                ;Decrement counter
+               BGT     %b00                    ;If necessary, branch back
+               MVN     R0,R0                   ;R0 = R0 XOR &FFFFFFFF again
+               LDMFD   R13!,{R1-R4,PC}^
+
+               LTORG
+
+;----- The magic table ------------------------------------------------------
+;
+; The numbers in this table were generated using the Rocksoft^tm Model CRC
+; Algorithm Table Generation Table Program V1.0, written by Ross Williams.
+; Our thanks to him for placing this program in the public domain.
+;
+
+crctable       DCD     &00000000,&77073096,&EE0E612C,&990951BA
+               DCD     &076DC419,&706AF48F,&E963A535,&9E6495A3
+               DCD     &0EDB8832,&79DCB8A4,&E0D5E91E,&97D2D988
+               DCD     &09B64C2B,&7EB17CBD,&E7B82D07,&90BF1D91
+               DCD     &1DB71064,&6AB020F2,&F3B97148,&84BE41DE
+               DCD     &1ADAD47D,&6DDDE4EB,&F4D4B551,&83D385C7
+               DCD     &136C9856,&646BA8C0,&FD62F97A,&8A65C9EC
+               DCD     &14015C4F,&63066CD9,&FA0F3D63,&8D080DF5
+
+               DCD     &3B6E20C8,&4C69105E,&D56041E4,&A2677172
+               DCD     &3C03E4D1,&4B04D447,&D20D85FD,&A50AB56B
+               DCD     &35B5A8FA,&42B2986C,&DBBBC9D6,&ACBCF940
+               DCD     &32D86CE3,&45DF5C75,&DCD60DCF,&ABD13D59
+               DCD     &26D930AC,&51DE003A,&C8D75180,&BFD06116
+               DCD     &21B4F4B5,&56B3C423,&CFBA9599,&B8BDA50F
+               DCD     &2802B89E,&5F058808,&C60CD9B2,&B10BE924
+               DCD     &2F6F7C87,&58684C11,&C1611DAB,&B6662D3D
+
+               DCD     &76DC4190,&01DB7106,&98D220BC,&EFD5102A
+               DCD     &71B18589,&06B6B51F,&9FBFE4A5,&E8B8D433
+               DCD     &7807C9A2,&0F00F934,&9609A88E,&E10E9818
+               DCD     &7F6A0DBB,&086D3D2D,&91646C97,&E6635C01
+               DCD     &6B6B51F4,&1C6C6162,&856530D8,&F262004E
+               DCD     &6C0695ED,&1B01A57B,&8208F4C1,&F50FC457
+               DCD     &65B0D9C6,&12B7E950,&8BBEB8EA,&FCB9887C
+               DCD     &62DD1DDF,&15DA2D49,&8CD37CF3,&FBD44C65
+
+               DCD     &4DB26158,&3AB551CE,&A3BC0074,&D4BB30E2
+               DCD     &4ADFA541,&3DD895D7,&A4D1C46D,&D3D6F4FB
+               DCD     &4369E96A,&346ED9FC,&AD678846,&DA60B8D0
+               DCD     &44042D73,&33031DE5,&AA0A4C5F,&DD0D7CC9
+               DCD     &5005713C,&270241AA,&BE0B1010,&C90C2086
+               DCD     &5768B525,&206F85B3,&B966D409,&CE61E49F
+               DCD     &5EDEF90E,&29D9C998,&B0D09822,&C7D7A8B4
+               DCD     &59B33D17,&2EB40D81,&B7BD5C3B,&C0BA6CAD
+
+               DCD     &EDB88320,&9ABFB3B6,&03B6E20C,&74B1D29A
+               DCD     &EAD54739,&9DD277AF,&04DB2615,&73DC1683
+               DCD     &E3630B12,&94643B84,&0D6D6A3E,&7A6A5AA8
+               DCD     &E40ECF0B,&9309FF9D,&0A00AE27,&7D079EB1
+               DCD     &F00F9344,&8708A3D2,&1E01F268,&6906C2FE
+               DCD     &F762575D,&806567CB,&196C3671,&6E6B06E7
+               DCD     &FED41B76,&89D32BE0,&10DA7A5A,&67DD4ACC
+               DCD     &F9B9DF6F,&8EBEEFF9,&17B7BE43,&60B08ED5
+
+               DCD     &D6D6A3E8,&A1D1937E,&38D8C2C4,&4FDFF252
+               DCD     &D1BB67F1,&A6BC5767,&3FB506DD,&48B2364B
+               DCD     &D80D2BDA,&AF0A1B4C,&36034AF6,&41047A60
+               DCD     &DF60EFC3,&A867DF55,&316E8EEF,&4669BE79
+               DCD     &CB61B38C,&BC66831A,&256FD2A0,&5268E236
+               DCD     &CC0C7795,&BB0B4703,&220216B9,&5505262F
+               DCD     &C5BA3BBE,&B2BD0B28,&2BB45A92,&5CB36A04
+               DCD     &C2D7FFA7,&B5D0CF31,&2CD99E8B,&5BDEAE1D
+
+               DCD     &9B64C2B0,&EC63F226,&756AA39C,&026D930A
+               DCD     &9C0906A9,&EB0E363F,&72076785,&05005713
+               DCD     &95BF4A82,&E2B87A14,&7BB12BAE,&0CB61B38
+               DCD     &92D28E9B,&E5D5BE0D,&7CDCEFB7,&0BDBDF21
+               DCD     &86D3D2D4,&F1D4E242,&68DDB3F8,&1FDA836E
+               DCD     &81BE16CD,&F6B9265B,&6FB077E1,&18B74777
+               DCD     &88085AE6,&FF0F6A70,&66063BCA,&11010B5C
+               DCD     &8F659EFF,&F862AE69,&616BFFD3,&166CCF45
+
+               DCD     &A00AE278,&D70DD2EE,&4E048354,&3903B3C2
+               DCD     &A7672661,&D06016F7,&4969474D,&3E6E77DB
+               DCD     &AED16A4A,&D9D65ADC,&40DF0B66,&37D83BF0
+               DCD     &A9BCAE53,&DEBB9EC5,&47B2CF7F,&30B5FFE9
+               DCD     &BDBDF21C,&CABAC28A,&53B39330,&24B4A3A6
+               DCD     &BAD03605,&CDD70693,&54DE5729,&23D967BF
+               DCD     &B3667A2E,&C4614AB8,&5D681B02,&2A6F2B94
+               DCD     &B40BBE37,&C30C8EA1,&5A05DF1B,&2D02EF8D
+
+               END
diff --git a/StraySrc/SapphToys/!CApp/!Run,feb b/StraySrc/SapphToys/!CApp/!Run,feb
new file mode 100644 (file)
index 0000000..aa55947
--- /dev/null
@@ -0,0 +1,14 @@
+|
+| CApp 1.xx !Run file
+|
+| © 1994 Straylight
+|
+| This file version 1.00 (20 March 1994)
+|
+
+Set CApp$Dir <Obey$Dir>
+|IconSprites <CApp$Dir>.!Sprites
+
+WimpSlot -min 20K -max 20K
+
+Run <CApp$Dir>.!RunImage %*0
\ No newline at end of file
diff --git a/StraySrc/SapphToys/!CApp/Makefile,fe1 b/StraySrc/SapphToys/!CApp/Makefile,fe1
new file mode 100644 (file)
index 0000000..bab5ba0
--- /dev/null
@@ -0,0 +1,115 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -zps1 -ffah -Jlibs:csapph -Jlibs:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: !RunImage
+
+!RunImage: o.capp libs:lib.sapphdll libs:lib.csapph
+       $(SETDATE) o.version version="1.00 ($(DATE))" cright="$(CRIGHT)"
+       $(LD_APP) o.capp o.version libs:lib.sapphdll libs:lib.csapph
+       $(SQUEEZE)
+       $(SET_APP)
+
+install: !RunImage
+
+clean:
+       -$(RM) o.* !RunImage
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.capp:        c.capp
+o.capp:        libs:csapph.h.sapphire
+o.capp:        libs:h.swis
+o.capp:        libs:csapph.h.defHandler
+o.capp:        libs:csapph.h.errorBox
+o.capp:        libs:csapph.h.event
+o.capp:        libs:csapph.h.ibicon
+o.capp:        libs:csapph.h.menu
+o.capp:        libs:csapph.h.menuDefs
+o.capp:        libs:csapph.h.progInfo
+o.capp:        libs:csapph.h.resources
diff --git a/StraySrc/SapphToys/!CApp/UK b/StraySrc/SapphToys/!CApp/UK
new file mode 100644 (file)
index 0000000..785d397
--- /dev/null
@@ -0,0 +1,9 @@
+;
+; CApp messages
+;
+; © 1995 Straylight
+;
+
+caINF:Info...
+caQUIT:Quit
+caPUR:To prove it can be done!
diff --git a/StraySrc/SapphToys/!CApp/c/capp b/StraySrc/SapphToys/!CApp/c/capp
new file mode 100644 (file)
index 0000000..3af8103
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * capp.c
+ *
+ * A Sapphire application in C!
+ *
+ * © 1995-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * CApp is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * CApp is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CApp.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- External dependencies ---------------------------------------------*/
+
+/* --- Header files --- */
+
+#include "sapphire.h"
+#include "swis.h"
+
+/* --- Sapphire routines --- *
+ *
+ * Currently we have to declare these by hand.  Maybe things will get better
+ * in the future.
+ */
+
+#include "defHandler.h"
+#include "errorBox.h"
+#include "event.h"
+#include "ibicon.h"
+#include "menu.h"
+#include "menuDefs.h"
+#include "progInfo.h"
+#include "resources.h"
+
+/* --- A SWI --- */
+
+__swi(OS_Exit) void os_exit(void);
+
+/* --- Version strings --- */
+
+extern char cright[];
+extern char version[];
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- The application name --- *
+ *
+ * This is picked up by start.s and passed to sapphire_init.
+ */
+
+char appname[]="CApp";
+
+/* --- capp__menuHandler --- *
+ *
+ * The menu handling routine.  This is fairly straightforward.  Equipped
+ * with os_exit, we can quit the program on a `Quit' event, and progInfo
+ * displays a dialogue if you choose `Info...'.
+ */
+
+static _sapph(capp__menuHandler)(regset *r)
+{
+  switch (r->r[0])
+  {
+    case mEvent_select:
+    case mEvent_subMenu:
+      switch (r->r[1])
+      {
+        case 0:
+          _call(progInfo,_inr(0,2),
+                msgs_lookup("caPUR"),cright,version);
+          break;
+        case 1:
+          os_exit();
+          break;
+      }
+  }
+  return (0);
+}
+
+/* --- capp__ibHandler --- *
+ *
+ * Handles events on the icon bar.  Select displays a `Hello, world!'
+ * message.  Menu displays a menu.  The menu is contained within the
+ * hexgorp below.
+ */
+
+static _sapph(capp__ibHandler)(regset *r)
+{
+  static const unsigned menu[]={ /* Yuk! */
+
+    0x00000000,                                        /* Default title style */
+    0x70704143,                                        /* `CApp' */
+    0x00000000,
+
+    0x00000200,                                        /* Send subwarn events */
+    0x4E496163,                                        /* `caINF' */
+    0x00000046,
+
+    0x00000000,                                        /* Normal item style */
+    0x55516163,                                        /* `caQUIT' */
+    0x00005449,
+
+    0x80000000,                                        /* End of the block */
+
+  };
+
+  switch (r->r[0])
+  {
+    case ibEvent_select:
+      _call(errorBox,_inr(0,1),
+            strerror(1,"Hello, world! %i0",(int)scratchpad/24),
+            1);
+      break;
+    case ibEvent_menu:
+      _call(menu_create,_inr(0,3),menu,capp__menuHandler,0,0);
+      break;
+    case ibEvent_adjust:
+      _swi(Wimp_ReportError,_inr(0,2),
+           strerror(1,"%0 seems to be working",appname),1,appname);
+      break;
+  }
+
+  return (0);
+}
+
+
+/* --- sapph_main --- *
+ *
+ * This is the main program.  Well, almost.  I couldn't use `main' because
+ * the compiler messes up the output.  The code initialises the library
+ * units (yes! we can start executing C code before most of Sapphire is
+ * awake!), creates an icon on the icon bar, and handles events until
+ * something kills the application.
+ */
+
+_sapph(sapph_main)(void)
+{
+  char pollblock[256];
+  int e;
+
+  _call(resources_init,0);
+  _call(sapphire_libInit,0);
+  _call(ibicon_create,_inr(0,6),
+        "application",0,
+        -1,0,
+        capp__ibHandler,0,0);
+
+  for (;;)
+  {
+    /* --- Use _call here -- it needs testing --- */
+
+    if (!(_call(event_poll,_inr(0,1)|_out(0)|_return(_flags),
+                1,pollblock, &e) & _c))
+      _call(defHandler,_inr(0,1),e,pollblock);
+  }
+
+  return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/StraySrc/SapphToys/!ColDemo/!Run,feb b/StraySrc/SapphToys/!ColDemo/!Run,feb
new file mode 100644 (file)
index 0000000..6d47db5
--- /dev/null
@@ -0,0 +1,32 @@
+|
+| Colour Selector demo
+|
+| © 1998 Straylight
+|
+| This file version 1.00 (20 March 1994)
+|
+
+Set ColDemo$Dir <Obey$Dir>
+| IconSprites <ColDemo$Dir>.!Sprites
+
+/<ColDemo$Dir>.setSlot -appName ColDemo 28K 4K 4K
+
+If "<System$Path>"="" Then Error 0 System resources could not be found.  Please double-click a !System folder and reload.
+
+If "<Wimp$Scrap>"="" Then Error 0 Couldn't find Scrap folder.  Please double click a !Scrap folder (or !System if you don't have !Scrap) and reload.
+
+If "<DLL$Path>"="" Then Error 0 Couldn't find Dynamic Link libraries.  Please double click a !DLLs folder and reload.
+
+Set Alias$_RMEnsure RMEnsure %%0 0.00 RMLoad %%2 |m RMEnsure %%0 %%1
+_RMEnsure DLLManager 1.14 <DLL$Dir>.DLLManager
+_RMEnsure Sculptrix 2.01 <ColDemo$Dir>.Modules.Sculptrix
+_RMEnsure Sprinkle 1.00 <ColDemo$Dir>.Modules.Sprinkle
+_RMEnsure ColourTrans 0.53 System:Modules.Colours
+Unset Alias$_RMEnsure
+
+DLLEnsure [Sapphire.Core] 0.00
+DLLEnsure [Sapphire.Resources] 1.00
+
+/<ColDemo$Dir>.setSlot -appName ColDemo 28K 4K 4K
+
+Run <ColDemo$Dir>.!RunImage %*0
\ No newline at end of file
diff --git a/StraySrc/SapphToys/!ColDemo/Resources/Messages b/StraySrc/SapphToys/!ColDemo/Resources/Messages
new file mode 100644 (file)
index 0000000..223bdc7
--- /dev/null
@@ -0,0 +1,104 @@
+;
+; Sapphire messages
+;
+; © 1994 Straylight
+;
+
+; --- Note ---
+;
+; This file contains the actual message strings for all Sapphire message
+; tags.  The idea is that you can just dump the ones you really want into
+; your messages file and have done with it.
+
+;----- Miscellaneous strings ------------------------------------------------
+
+; --- Memory allocation ---
+
+allocNOMEM:Not enough memory
+hpNEMI:Not enough memory to intialise heap
+
+; --- Dialogue box handling ---
+
+dboxCRTERR:Couldn't create dialogue box: %0
+dboxNIND:Can't set text in non-indirected icon
+dbxDECLTWICE:Dialogue box already known to dbx
+ok:OK
+can:Cancel
+
+; --- Draw file handling ---
+
+drawTOONEW:This drawfile has an unrecognised format and cannot be rendered.
+drawBADFILE:This is not a drawfile.
+
+; --- Various standard dialogue boxes ---
+
+ebERRFRM:Error from %0
+noteFROM:Note from %0
+warnFROM:Warning from %0
+
+piHELP:This window shows you information about this version of {app}
+
+saDRAGICN:To save, drag the file icon to a directory viewer.
+sahDB:This is the save dialogue box.
+sahFICN:Drag this icon to a directory viewer or another application to save the file.
+sahWRT:Type a filename for the file here.
+sahOK:Click here to save the file under the name shown.
+
+; --- Menus ---
+
+mSOVF:Not enough memory to create menu -- increase menu_stackSize
+
+; --- Dealing with help messages ---
+
+helpOFLOW:Help message overflow
+
+; --- Key translation ---
+
+kstrF:F%i2
+kstrPRT:Print
+kstrTAB:Tab
+kstrCOPY:Copy
+kstrLEFT:Left
+kstrRIGHT:Right
+kstrDOWN:Down
+kstrUP:Up
+kstrINS:Insert
+kstrPDN:PageDown
+kstrPUP:PageUp
+kstrENTER:Enter
+kstrDEL:Delete
+kstrSPC:Space
+kstrESC:Esc
+kstrBSP:Backspace
+kstrRET:Return
+kstrHOME:Home
+kstrSH:Shift
+kstrCTL:Ctrl
+kstrKPD:Keypad
+
+; --- Loading resources ---
+
+rsprSLE:Error loading sprites: %0
+tplTNF:Template '%0' not found
+tplTLE:Error loading templates: %0
+
+; --- Handling errors ---
+
+reprtERR:Internal error: '%1'.  Click OK to continue, or Cancel to quit %0.
+reprtCONF:Are you sure you want to quit %0?  Click OK to continue, or Cancel to quit.
+
+; --- Data transfer ---
+
+saveDTDEAD:Data transfer failed, receiver dead
+
+; --- Standard dialogue box controls ---
+
+slNOSLIDE:Couldn't slide slider: %0
+
+; --- Handling background jobs ---
+
+thrNOCRT:Couldn't start background job: %0
+thrNOSEMCRT:Couldn't create semaphore: %0
+thrSEMINUSE:Can't destroy a semaphore while threads are waiting for it
+thrNOWAITSEM:Couldn't wait on semaphore: %0
+thrNOTATHRD:Only threads can wait on semaphores
diff --git a/StraySrc/SapphToys/!ColDemo/Resources/Sprites,ff9 b/StraySrc/SapphToys/!ColDemo/Resources/Sprites,ff9
new file mode 100644 (file)
index 0000000..8fcc828
Binary files /dev/null and b/StraySrc/SapphToys/!ColDemo/Resources/Sprites,ff9 differ
diff --git a/StraySrc/SapphToys/!ColDemo/Resources/Templates,fec b/StraySrc/SapphToys/!ColDemo/Resources/Templates,fec
new file mode 100644 (file)
index 0000000..d7c3954
Binary files /dev/null and b/StraySrc/SapphToys/!ColDemo/Resources/Templates,fec differ
diff --git a/StraySrc/SapphToys/!ColDemo/_Makefile,fe1 b/StraySrc/SapphToys/!ColDemo/_Makefile,fe1
new file mode 100644 (file)
index 0000000..3b76aa1
--- /dev/null
@@ -0,0 +1,118 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: !RunImage Modules.Sculptrix Modules.Sprinkle Modules.Constrain setSlot
+
+OBJ = o.coldemo o.colSelect o.rgb o.hsv libs:lib.sapphdll
+
+!RunImage: $(OBJ)
+       $(SETDATE) o.version version="1.00 ($(DATE))" cright="$(CRIGHT)"
+       $(LD_APP) $(OBJ) o.version
+       @|$(SQUEEZE)
+       @|$(SET_APP)
+
+Modules.Sculptrix: <SSR$ModDir>.Sculptrix
+       $(INSTALL) <SSR$ModDir>.Sculptrix Modules
+
+Modules.Sprinkle: <SSR$ModDir>.Sprinkle
+       $(INSTALL) <SSR$ModDir>.Sprinkle Modules
+
+Modules.Constrain: <SSR$ModDir>.Constrain
+       $(INSTALL) <SSR$ModDir>.Constrain Modules
+
+setSlot: <SSR$BinDir>.setSlot
+       $(INSTALL) <SSR$BinDir>.setSlot @
+
+install:
+
+clean:
+       -$(RM) o.* !RunImage Modules.Sculptrix setSlot
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/SapphToys/!ColDemo/s/colSelect b/StraySrc/SapphToys/!ColDemo/s/colSelect
new file mode 100644 (file)
index 0000000..5c91020
--- /dev/null
@@ -0,0 +1,461 @@
+;
+; colSelect.s
+;
+; The Colour Selector kernel
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sapphire library.
+;
+; Sapphire is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sapphire is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sapphire.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:alloc
+               GET     sapphire:dbox
+               GET     sapphire:errorBox
+               GET     sapphire:menu
+               GET     sapphire:menuDefs
+               GET     sapphire:msgs
+               GET     sapphire:pane
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx.stringSet
+
+               GET     sapphire:_cs.vars
+               GET     sapphire:_cs.models
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- colSelect ---
+;
+; On entry:    R0 == address of a colour block
+;              R1 == pointer to routine to call when done
+;              R2 == R10 to call routine with
+;              R3 == R12 to call routine with
+;
+; On exit:     May return error
+;
+; Use:         Displays a colour selector dialogue box.  It allows the user
+;              to edit a colour (understatement....)
+
+               EXPORT  colSelect
+colSelect      ROUT
+
+               BIC     R14,R14,#V_flag         ;Clear the V flag
+               STMFD   R13!,{R0-R4,R10,R14}    ;Save a load of registers
+
+               ; --- Try to create a workspace block ---
+
+               MOV     R0,#cs__dSize           ;Get my data size
+               BL      alloc                   ;Try to allocate the memory
+               BLCS    alloc_error             ;If it failed, get a message
+               BCS     %99colSelect            ;And tidy up as we go
+               MOV     R10,R0                  ;Look after this block
+
+               ; --- Now create a dialogue box ---
+
+               ADR     R0,cs__dbName           ;Point to the dialogue name
+               BL      dbox_create             ;Create the dialogue
+               BVS     %98colSelect            ;Tidy up if it failed
+               STR     R0,cs__frameDb          ;Save the dialogue handle
+               ADR     R1,cs__handler          ;The event handler
+               MOV     R2,R10                  ;Pass this R10 value
+               MOV     R3,R12                  ;And this R12 value
+               BL      dbox_eventHandler       ;Set up the handler
+               ADR     R1,cs__dbxBlock         ;Point to dbx information
+               BL      dbx_declare             ;Declare the block
+
+               ; --- Save the caller's information ---
+
+               LDR     R0,[R13,#0]             ;Load his colour's address
+               LDMIA   R0,{R1-R3}              ;Load the colour arguments
+               ADR     R14,cs__address         ;Point into the data block
+               STMIA   R14,{R0-R3}             ;And save all of that stuff
+
+               ; --- Set up the workspace ---
+
+               MOV     R14,#3                  ;Start on low resolution
+               STR     R14,cs__resolution      ;Save it in the workspace
+
+               ; --- Set up the initial model ---
+
+               BL      cs__initModel           ;Get a model index
+               BVS     %97colSelect            ;Clean up on an error
+               MOV     R4,R2                   ;Keep the model number
+               STR     R0,cs__modelDb          ;Save model's dialogue box
+               BL      dbox_window             ;Get the window handle
+               MOV     R3,R0                   ;Put model's db handle in R3
+               LDR     R0,cs__frameDb          ;Get frame db handle
+               MOV     R1,#dbOpen_persist+dbOpen_current
+               BL      dbox_open               ;Open the dialogue box
+               MOV     R1,#csIcon__rgb         ;The first model icon number
+               ADD     R1,R1,R2                ;Get the correct icon number
+               MOV     R2,#1                   ;Turn the icon on
+               BL      dbox_select             ;Select the icon
+               MOV     R2,R3                   ;Pane window handle
+               BL      dbox_window             ;Get the window handle
+               MOV     R1,#csIcon__models      ;The icon handle
+               BL      pane_add                ;Add the pane
+               BL      pane_open               ;Open the pane
+               BL      cs__setCaret            ;And give it the focus
+95colSelect    LDMFD   R13!,{R0-R4,R10,PC}^    ;Return to caller
+
+97colSelect    MOV     R4,R0                   ;Preserve R0
+               LDR     R0,cs__frameDb          ;Get the dialogue box handle
+               BL      dbox_destroy            ;Destroy the dialogue box
+               MOV     R0,R4                   ;Get R0 back
+98colSelect    MOV     R4,R0                   ;Preserve R0
+               MOV     R0,R10                  ;Point to allocated memory
+               BL      free                    ;Free it nicely
+               MOV     R0,R4                   ;Get R0 back
+99colSelect    ADD     R13,R13,#4              ;Don't load R0
+               LDMFD   R13!,{R1-R4,R10,R14}    ;Load registers
+               ORRS    PC,R14,#V_flag          ;Return with error
+
+               LTORG
+
+cs__dbName     DCB     "colSelect",0
+
+cs__dbxBlock   CONTROL csIcon__colour,colButton,R10,0,:INDEX: cs__colour
+               ECTRL
+               STRSET  csIcon__resDisp,R10,:INDEX: cs__resolution,                                     cs__resMenu,cs__resStrings,csIcon__resDisp
+               STRSET  csIcon__resMenu,R10,:INDEX: cs__resolution,                                     cs__resMenu,cs__resStrings,csIcon__resDisp
+               DBXEND
+
+cs__resMenu    MENU    "csRESMT"
+               ITEM    "csRESVH:Very high"
+               RADIO   0,0
+               ITEM    "csRESH:High"
+               RADIO   0,1
+               ITEM    "csRESM:Medium"
+               RADIO   0,2
+               ITEM    "csRESL:Low"
+               RADIO   0,3
+               MENUEND
+
+cs__resStrings DCB     "csRESVH:Very high",0
+               DCB     "csRESH:High",0
+               DCB     "csRESM:Medium",0
+               DCB     "csRESL:Low",0
+
+; --- cs__initModel ---
+;
+; On entry:    R2 == colour model number, or 0
+;
+; On exit:     R0 == dialogue box created by colour model, or error
+;              R2 == preserved, or index of RGB model
+;
+; Use:         Initialises a colour model dialogue box.
+
+cs__initModel  ROUT
+
+               CMP     R2,#cs__noModels        ;Is the model in range?
+               MOVHS   R2,#cMod_rgb            ;No -- use RGB then
+               ADD     PC,PC,R2,LSL #2         ;Call the function
+               DCB     "MDW!"
+
+00cs__initModel        B       rgb_open
+               B       hsv_open
+10cs__initModel
+
+cs__noModels   EQU     (%10-%00)/4
+
+; --- cs__setCaret ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets the caret in the current colour select pane window.
+
+cs__setCaret   ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               LDR     R0,cs__modelDb          ;Get the model dialogue
+               BL      dbox_window             ;And find its window handle
+               MOV     R1,#-1                  ;In no particular icon
+               MOV     R2,#&ff000000           ;Quite a long way away
+               ORR     R2,R2,#&00ff0000
+               MOV     R3,#0                   ;Doesn't really matter
+               MOV     R4,#&02000000           ;Hide caret, make it small
+               MOV     R5,#-1                  ;No index into icon, please
+               SWI     Wimp_SetCaretPosition   ;Set the caret's position
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+               LTORG
+
+; --- cs__handler ---
+;
+; On entry:    R0 == dialogue box event code
+;              R1-R9 == depend on the event
+;              R10 == colour selector data
+;              R12 == nothing much, actually -- corrupted on exit
+;
+; On exit:     --
+;
+; Use:         Handles events for the main dialogue frame
+
+cs__handler    ROUT
+
+               CMP     R0,#stringSet_event     ;Is this a string set event?
+               BEQ     cs__resMenuClk          ;Yes -- handle that
+
+               CMP     R0,#dbEvent_OK          ;Is it an OK event?
+               CMPNE   R0,#csIcon__ok          ;Or a click on OK?
+               BEQ     cs__ok                  ;Yes -- handle it then
+
+               CMP     R0,#dbEvent_help        ;Does someone want help?
+               BEQ     cs__getHelp             ;Yes -- deal with that too
+
+               SUB     R12,R0,#csIcon__rgb     ;Was it a model icon?
+               CMP     R12,#cs__noModels
+               BLO     cs__changeModel         ;Yes -- deal with it
+
+               MOVS    PC,R14
+
+               ; --- Handle an OK click/keypress ---
+
+cs__ok         ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R5,R1                   ;Remember mouse button state
+               MOV     R0,R9                   ;Get my dialogue handle
+               MOV     R1,#csIcon__ok          ;And the OK button
+               BL      dbox_slab               ;Press it in nicely
+
+               ; --- Find the actual colour he chose ---
+
+               BL      dbox_unslab             ;Unslab the button
+               LDMFD   R13!,{R0-R5,PC}^        ;And return to caller
+
+               LTORG
+
+               ; --- Give a help message if required ---
+
+cs__getHelp    B       dbox_help               ;Just let dbox do it all!
+
+               ; --- Handle the resolution menu button ---
+
+cs__resMenuClk ROUT
+
+               CMP     R1,#csIcon__resDisp     ;Is this the resolution one?
+               MOVNES  PC,R14                  ;No -- ignore it then
+
+               STMFD   R13!,{R0,R10,R14}       ;Save some registers
+               LDR     R10,cs__modelDb         ;Get the model's handle too
+               MOV     R0,#csEvent__newRes     ;The resolution's changed
+               BL      dbx_sendEvent           ;Send the event out
+               LDMFD   R13!,{R0,R10,PC}^       ;And return to caller
+
+               LTORG
+
+               ; --- Handle a model selection ---
+
+cs__changeModel        ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+               LDR     R1,cs__colour+col_model ;Load the existing model
+               CMP     R1,R12                  ;Is it the same?
+               LDMEQFD R13!,{R0-R3,PC}^        ;Yes -- return
+
+               ; --- Tell old model to update colour ---
+
+               STMFD   R13!,{R10}              ;Save my instance pointer
+               LDR     R10,cs__modelDb         ;Get the current panel dbox
+               MOV     R0,#csEvent__read       ;Tell it to read its settings
+               BL      dbx_sendEvent           ;Send it the event
+               LDMFD   R13!,{R10}              ;Restore the instance pointer
+
+               ; --- First try to get a new model dialogue ---
+
+               MOV     R2,R12                  ;Get the new colour model
+               BL      cs__initModel           ;Try to initialise it nicely
+               BVS     %90cs__changeModel      ;If it failed, report error
+
+               ; --- Now remove the old one ---
+
+               STMFD   R13!,{R0,R10}           ;Save some important regs
+               LDR     R10,cs__modelDb         ;Get the current panel dbox
+               MOV     R0,R10                  ;Get it in R0
+               BL      dbox_window             ;Find its window handle
+               MOV     R3,R0                   ;Keep this value nicely
+               SUB     R13,R13,#24             ;Space for a caret block
+               MOV     R1,R13                  ;Point to the caret block
+               SWI     Wimp_GetCaretPosition   ;Find the caret nicely
+               LDR     R0,[R13,#0]             ;Load the focus window handle
+               CMP     R0,R3                   ;Is it the panel?
+               MOVNE   R3,#0                   ;No -- clear the value then
+               ADD     R13,R13,#24             ;Restore the stack pointer
+               MOV     R0,#csEvent__close      ;Send a close event
+               BL      dbx_sendEvent           ;Send the event
+               LDMFD   R13!,{R0,R10}           ;Restore the registers again
+
+               ; --- Set up the new panel nicely ---
+
+               STR     R0,cs__modelDb          ;Store the new db handle
+               STR     R2,cs__colour+col_model ;And the new model type
+               BL      dbox_window             ;Get the new window handle
+               MOV     R2,R0                   ;This is the new pane
+               LDR     R0,cs__frameDb          ;Get the main dialogue box
+               BL      dbox_window             ;And get its window handle
+               MOV     R1,#csIcon__models      ;The main icon thingy
+               BL      pane_swap               ;Swap the pane over
+               CMP     R3,#0                   ;Was the caret in the panel
+               BLNE    cs__setCaret            ;Yes -- put it in the new one
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+90             MOV     R1,#1                   ;Only an OK button please
+               BL      errorBox                ;Call error box
+               LDMFD   R13!,{R0-R3,R14}        ;Return to caller
+               ORRS    PC,R14,#C_flag          ;Don't change the radio state
+
+               LTORG
+
+; --- cs_passBack ---
+;
+; On entry:    R0-R7 == dialogue box event information
+;              R10 == pointer to colour selector instance
+;
+; On exit:     --
+;
+; Use:         Passes an event back to the main colour selector frame dbox.
+
+               EXPORT  cs_passBack
+cs_passBack    ROUT
+
+               STMFD   R13!,{R10,R14}          ;Save some registers
+               LDR     R10,cs__frameDb         ;Get the dialogue handle
+               BL      dbx_sendEvent           ;Pass the event on
+               LDMFD   R13!,{R10,PC}^          ;And return to caller
+
+               LTORG
+
+; --- cs_colChange ---
+;
+; On entry:    R10 == currently selected dialogue box
+;
+; On exit:     --
+;
+; Use:         Updates the colour selector's colour display.
+
+               EXPORT  cs_colChange
+cs_colChange   ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R0,cs__frameDb          ;Load the frame handle
+               MOV     R1,#csIcon__colour      ;Get the colour button icon
+               BL      dbx_update              ;Redraw it nicely
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+; --- cs_immediate ---
+;
+; On entry:    R10 == currently selected dialogue box
+;
+; On exit:     CS if immediate operations are enabled, or CC
+;
+; Use:         Informs the caller whether sliders and arrows should cause
+;              immediate update of the dialogue box, or wait until the
+;              operation has completed.
+
+               EXPORT  cs_immediate
+cs_immediate   ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R0,cs__frameDb          ;Load the frame handle
+               MOV     R1,#csIcon__instant     ;Get instant effect switch
+               BL      dbox_isSelected         ;Is it selected?
+               LDMFD   R13!,{R0,R1,PC}         ;Return this state
+
+               LTORG
+
+; --- cs_resolution ---
+;
+; On entry:    R10 == currently selected dialogue box
+;
+; On exit:     R0 == quality value, from 0 (pixel) to 3 (grotty)
+;
+; Use:         Returns the current resolution value.  This is interpreted
+;              in a model-dependent manner.
+
+               EXPORT  cs_resolution
+cs_resolution  ROUT
+
+               LDR     R0,cs__resolution       ;Load the value out
+               MOVS    PC,R14                  ;Return to caller
+
+               LTORG
+
+;----- Icon numbers ---------------------------------------------------------
+
+csIcon__panel  EQU     0
+csIcon__modDisp        EQU     2
+csIcon__modMenu        EQU     3
+csIcon__sample EQU     4
+csIcon__resDisp        EQU     6
+csIcon__resMenu        EQU     7
+csIcon__instant        EQU     8
+csIcon__cancel EQU     9
+csIcon__ok     EQU     10
+
+;----- dbx controls ---------------------------------------------------------
+
+               EXPORT  colButton
+colButton      DCD     0,0
+               DCD     dbxMask_redraw
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+               LDR     R0,[R8,#0]              ;Get the RGB colour
+               MOV     R3,#&180                ;ColourTrans flags
+               MOV     R4,#0                   ;GCOL type
+               SWI     XColourTrans_SetGCOL    ;Set the colour
+
+               ; --- If error, try without dithering ---
+
+               LDRVS   R0,[R8,#0]              ;Get the RGB colour
+               MOVVS   R3,#&080                ;ColourTrans flags
+               MOVVS   R4,#0                   ;GCOL type
+               SWIVS   ColourTrans_SetGCOL     ;Set the colour
+
+               ; --- Do a CLG... cunning! ---
+
+               SWI     OS_WriteI+16            ;Plot the colour nicley
+
+               LDMFD   R13!,{R0-R4,PC}^        ;Return nicley then
+
+;----- Workspace ------------------------------------------------------------
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     cs__wSize
+               DCD     cs__wSpace
+               DCD     0
+               DCD     cs__init
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/SapphToys/!ColDemo/s/hsv b/StraySrc/SapphToys/!ColDemo/s/hsv
new file mode 100644 (file)
index 0000000..14113d3
--- /dev/null
@@ -0,0 +1,958 @@
+;
+; hsv.s
+;
+; HSV functions (TMA)
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:divide
+               GET     sapphire:fixedPt
+               GET     sapphire:screen
+               GET     sapphire:sqrt
+
+               GET     sapphire:dbx.dbx
+
+               GET     sapphire:string
+               GET     sapphire:note
+
+               GET     sapphire:_cs.kernel
+               GET     sapphire:_cs.vars
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- hsv_open ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Called by the colour picker
+
+               EXPORT  hsv_open
+hsv_open       ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Stack the link register
+               ADR     R0,hsv_dbName           ;Point to dialogue box name
+               BL      dbox_create             ;Create the dialogue box
+
+       ; --- TEMPORARY CODE ---
+
+               LDMVSFD R13!,{R1-R3,PC}         ;Return to caller
+               ADR     R1,hsv__dbh
+               MOV     R2,R10
+               MOV     R3,R12
+               BL      dbox_eventHandler
+               LDMVSFD R13!,{R1-R3,PC}         ;Return to caller
+               ADR     R1,hsv__dbxDef          ;Point to the control defn
+               BL      dbx_declare             ;Declare it to dbx nicely
+
+               LDMFD   R13!,{R1-R3,PC}         ;Return to caller
+
+
+hsv_dbName     DCB     "hsv",0
+
+hsv__dbxDef    CONTROL 0,hsvCircle,R10,0,0
+               ECTRL
+               DBXEND
+
+               LTORG
+
+hsv__dbh       ROUT
+
+               CMP     R0,#csEvent__close      ;Is this a close event?
+               MOVNES  PC,R14                  ;No -- return then
+               STMFD   R13!,{R0,R14}           ;Save registers
+               MOV     R0,R9
+               BL      dbox_destroy
+               LDMFD   R13!,{R0,PC}^
+
+               LTORG
+
+; --- hsv_plotCircle ---
+;
+; On entry:    R0 == x coord of centre of circle to plot
+;              R1 == y coord of centre of circle to plot
+;              R2 == x step (in OS units, must be power of 2)
+;              R3 == y step (in OS units, must be power of 2)
+;              R4 == value coordinate (in 16.16 form)
+;              R5 == pointer to graphics rectangle block
+;
+; On exit:     --
+;
+; Use:         Plots an HSV colour circle at the position specified.
+;              This should look really pretty as long as you're not using
+;              RISC OS 2 :-(.
+
+               EXPORT  hsv_plotCircle
+hsv_plotCircle ROUT
+
+               STMFD   R13!,{R0-R10,R12,R14}   ;Save a job lot of regs
+               MOV     R12,R5                  ;Keep pointer to graphics blk
+
+               ; --- Set up the radius value ---
+
+               MOV     R14,R4,LSR #9           ;Calculate the radius value
+               MUL     R10,R14,R14             ;Now square it and keep it
+
+               ; --- Work out the pixel sizes ---
+
+               BL      screen_getInfo          ;Find out about the screen
+               LDMIA   R0,{R6,R7}              ;Load the eign factors
+               MOV     R14,#1                  ;We're going to shift this
+               MOV     R6,R14,LSL R6           ;Calculate the x pixel size
+               MOV     R7,R14,LSL R7           ;And the y pixel size
+               STMFD   R13!,{R6,R7}            ;Save these for later use
+
+               ; --- Start the main loop off ---
+
+               LDR     R9,[R12,#12]            ;Get top of the rectangle
+               SUB     R9,R9,R1                ;Subtract the circle centre
+               CMP     R9,#127                 ;Is the rectangle too high?
+               MOVGT   R9,#127                 ;Yes -- start at circle top
+               SUB     R14,R3,#1               ;Turn ystep into bitmask
+               BIC     R9,R9,R14               ;And align to multiple nicely
+
+               ; --- Get start x position into R1 ---
+
+               LDR     R1,[R12,#0]             ;Get left hand side of area
+               LDR     R14,[R13,#8]            ;Load the centre position
+               SUB     R1,R1,R14               ;Subtract to get offset
+               CMP     R1,#-128                ;Is it too far to the left?
+               MOVLT   R1,#-128                ;Yes -- fix it up
+               SUB     R14,R2,#1               ;Turn xstep into bitmask
+               BIC     R1,R1,R14               ;Align to step value nicely
+
+               ; --- Get finish x position into R4 ---
+
+               LDR     R4,[R12,#8]             ;Get the right hand side pos
+               LDR     R0,[R13,#8]             ;Load the x centre position
+               SUB     R4,R4,R0                ;Convert to offset
+               CMP     R4,#128                 ;Is this off the right side?
+               MOVGT   R4,#128                 ;Yes -- stop being silly then
+
+               ; --- And now get finish y position into R5 ---
+
+               LDR     R5,[R12,#4]             ;Get the bottom pos
+               LDR     R0,[R13,#12]            ;Load the y centre position
+               SUB     R5,R5,R0                ;Convert to offset
+               SUB     R5,R5,R3                ;Get the bottom of the sqr
+               CMP     R5,#-128                ;Is this off the bottom?
+               MOVLT   R5,#-128                ;Yes -- don't be silly then
+
+               ; --- Plot a row ---
+
+00             MOV     R8,R1                   ;Start at beginning of row
+
+               ; --- Plot this rectangle ---
+
+01             LDMIA   R13,{R6,R7}             ;Load pixel widths and things
+               STMFD   R13!,{R1-R5,R8,R9}      ;Save some useful things
+               SUB     R4,R2,R6                ;xstep-dx
+               SUB     R5,R3,R7                ;ystep-dy
+
+               ; --- Calculate minx and maxx for given rectangle ---
+
+               MUL     R14,R9,R9               ;Get y^2
+               SUB     R6,R10,R14              ;Calculate minx
+               ADD     R0,R9,R5                ;y+ystep-dy
+               MUL     R14,R0,R0               ;(y+ystep-dy)^2
+               SUB     R7,R10,R14              ;Calculate maxx
+
+               ; --- Calculate various square values of x ---
+
+               MUL     R0,R8,R8                ;Get x^2
+               ADD     R14,R8,R2               ;Get x+xstep
+               MUL     R1,R14,R14              ;And square that too
+               CMP     R8,#0                   ;Is x negative
+               RSBLT   R0,R0,#0                ;Yes -- make R0 -ve
+               RSBLT   R1,R1,#0                ;...and make R1 -ve
+
+               ; --- Swap minx and maxx if we need to ---
+
+               MOV     R14,#0                  ;Clear our `swap' flag
+               CMP     R8,#0                   ;Is x < 0
+               EORGE   R14,R14,#1              ;No -- toggle swap flag
+               RSBLT   R6,R6,#0                ;Yes -- make it -ve
+               RSBLT   R7,R7,#0                ;...and that too
+               CMP     R9,#0                   ;Is y < 0
+               EORLT   R14,R14,#1              ;Yes -- toggle swap flag
+               TST     R14,#1                  ;Do we need to swap?
+               EORNE   R6,R6,R7                ;Yes -- swap them round
+               EORNE   R7,R6,R7
+               EORNE   R6,R6,R7
+
+               ; --- Is the rectangle outside the circle ---
+
+               CMP     R1,R6                   ;Is (x+xstep)^2<minx?
+               CMPLT   R8,#0                   ;Yes -- ensure x<0
+               BLT     %10hsv_plotCircle       ;It is -- plot a rectangle
+               CMP     R0,R7                   ;Is x^2>=maxx?
+               CMPGE   R8,#0                   ;Yes -- is x>=0
+               BLT     %20hsv_plotCircle       ;No -- Try an edge rectangle
+
+               ; --- Plot a blank square ---
+
+10             MOV     R0,#1                   ;Wimp colour 1
+               SWI     Wimp_SetColour          ;Set the colour
+               BL      hsv__plotRectangle      ;Plot the rectangle
+               B       %70hsv_plotCircle       ;And branch to the end
+
+               ; --- Is the rectangle on the circle edge? ---
+
+20             CMP     R8,#0                   ;Is x < 0?
+               CMPLT   R0,R7                   ;Is x^2<maxx?
+               BLT     %25hsv_plotCircle       ;Yes -- plot the circle
+               CMP     R8,#0                   ;Is x>=0
+               CMPGE   R1,R6                   ;Is (x+xstep)>=minx
+               BLT     %40hsv_plotCircle       ;No -- plot an entire square
+
+               ; --- Plot an edge square then ---
+
+25             MOV     R0,#1                   ;Wimp colour 1
+               SWI     Wimp_SetColour          ;Set the colour
+               BL      hsv__plotRectangle      ;Plot the rectangle
+               BL      hsv__setColour          ;Set the correct colour
+               ADD     R7,R9,R5                ;Our final loop value
+               ADD     R14,R13,#36             ;Point to centre coords
+               LDMIA   R14,{R3,R5}             ;Get the centre coordinates
+
+30             MUL     R14,R9,R9               ;y^2
+               SUBS    R0,R10,R14              ;Get r^2-y^2
+               BLT     %35hsv_plotCircle       ;Yes -- go round loop again
+       ;       BL      sqrt                    ;Calculate the square root
+
+               CMP     R8,#0                   ;Is x<0?
+               RSBLT   R1,R0,#0                ;Yes -- get xstart pos
+               ADDLT   R6,R8,R4                ;...and xend position
+               MOVGE   R1,R8                   ;No -- this xstart
+               LDRGE   R6,[R13,#28]            ;...get dx
+               SUBGE   R6,R0,R6                ;...and calc xend pos
+
+               CMP     R1,R6                   ;Is there anything to plot?
+               BGT     %35hsv_plotCircle       ;No -- skip this line out
+               ADD     R1,R1,R3                ;x0
+               ADD     R2,R9,R5                ;y0
+               MOV     R0,#4                   ;Move absolute
+               SWI     OS_Plot                 ;Do the move
+               MOV     R0,#5                   ;Plot solid line absolute
+               ADD     R1,R3,R6                ;x1
+               ADD     R2,R9,R5                ;y1
+               SWI     OS_Plot                 ;Do the move
+
+35             LDR     R14,[R13,#32]           ;Get dy
+               ADD     R9,R9,R14               ;Increment y value
+               CMP     R9,R7                   ;Are we at the end?
+               BLE     %30hsv_plotCircle       ;And keep ploting lines
+               B       %70                     ;Finished this square
+
+               ; --- Now plot an entire coloured square ---
+
+40             BL      hsv__setColour          ;Set the colour
+               BL      hsv__plotRectangle      ;Plot it then
+
+               ; --- Find which square to do next ---
+
+70             LDMFD   R13!,{R1-R5,R8,R9}      ;Get back registers
+
+               ADD     R8,R8,R2                ;Increment R8 nicely
+               CMP     R8,R4                   ;Have we finished a row?
+               BLT     %01hsv_plotCircle       ;No -- do some more then
+
+               SUB     R9,R9,R3                ;Move down to the next row
+               CMP     R9,R5                   ;Have we finished it yet?
+               BGE     %00hsv_plotCircle       ;No -- do the next row
+
+               ; --- We did it then! ---
+
+               ADD     R13,R13,#8              ;Skip past variable area
+               LDMFD   R13!,{R0-R10,R12,PC}^   ;Jubilations and things
+
+               LTORG
+
+; --- hsv__plotRectangle ---
+;
+; On entry:    R4 == width
+;              R5 == height
+;              R8 == x offset from centre
+;              R9 == y offset from centre
+;              R13+36 centre coordinates
+;
+; On exit:     R0-R2 corrupted
+
+hsv__plotRectangle ROUT
+
+               ADD     R0,R13,#36              ;Point to circle centre
+               LDMIA   R0,{R1,R2}              ;Load the coordinates
+               MOV     R0,#4                   ;Move cursor absolute
+               ADD     R1,R1,R8                ;To this x coord
+               ADD     R2,R2,R9                ;And this y coord
+               SWI     OS_Plot                 ;Do the move
+               MOV     R0,#97                  ;Rectangle fill relative
+               MOV     R1,R4                   ;This wide
+               MOV     R2,R5                   ;This high
+               SWI     OS_Plot                 ;Plot the rectangle
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- hsv__setColour ---
+;
+; On entry:    R0 == x coord
+;              R1 == y coord
+;              R10 == radius^2
+;              R13+52 == value
+;
+; On exit:     --
+
+hsv__setColour ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+               BL      fxp_pol                 ;Calculate hue
+               MOV     R3,R0                   ;Preserve angle
+
+               MUL     R14,R1,R1               ;Get y^2
+               MUL     R0,R2,R2                ;Get x^2
+               ADD     R0,R0,R14               ;Add them
+               MOV     R1,R10                  ;Get radius^2
+               MOV     R0,R0,LSL#16            ;Prepare for division
+               CMP     R1,#0                   ;Will we divide by 0?
+               BLNE    div_round               ;No -- perform the division
+               MOVEQ   R0,#0                   ;Yes -- make it 0 for luck
+               MOV     R1,R0                   ;The saturation
+               MOV     R0,R3                   ;Get hue back
+               LDR     R2,[R13,#76]            ;Get value
+               BL      hsv_HSVToRGB            ;Convert to RGB
+               RSB     R0,R0,R0,LSL#8          ;Multiple by 255
+               RSB     R1,R1,R1,LSL#8          ;Multiple by 255
+               RSB     R2,R2,R2,LSL#8          ;Multiple by 255
+               AND     R0,R0,#&FF0000          ;Ensure it's 0-255
+               AND     R1,R1,#&FF0000          ;Ensure it's 0-255
+               AND     R2,R2,#&FF0000          ;Ensure it's 0-255
+               MOV     R0,R0,LSR#8             ;Set up red component
+               ORR     R0,R0,R1                ;And green component
+               ORR     R0,R0,R2,LSL#8          ;And finally blue
+               MOV     R14,R0                  ;Preserve R0
+               MOV     R3,#&100                ;The colourTrans flags
+               MOV     R4,#0                   ;GCOL action
+               SWI     XColourTrans_SetGCOL    ;Set the colour
+               MOVVS   R3,#0                   ;Try without dither
+               MOVVS   R0,R14                  ;Get colour back
+               SWIVS   ColourTrans_SetGCOL     ;Set the colour
+
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- hsv__plot32k ---
+;
+; On entry:    R0 == left hand side of colour square to plot
+;              R1 == bottom edge of colour square to plot
+;              R2 == pointer to graphics window block
+;              R3 == pointer to screen information block
+;              R7 == unlimited minimum x position to plot
+;              R8 == unlimited minimum y position to plot
+;              R9 == unlimited maximum x position to plot
+;              R10 == unlimited maximum y position to plot
+;              On stack: saved {R0-R12,R14}
+;
+; On exit:     --
+;
+; Use:         Displays an HSV circle on the screen at a given location,
+;              in a 16bpp mode, using direct screen access.
+
+hsv__plot32k   ROUT
+
+               ; --- Limit the relative box positions ---
+
+               ADD     R4,R3,#screen_dx        ;Find the pixel positions
+               LDMIA   R4,{R4,R5}              ;Load them into registers
+
+               CMP     R7,#0                   ;Is min x too small?
+               MOVLT   R7,#0                   ;Yes -- raise it to 0
+               CMP     R8,#0                   ;Is min y too small?
+               MOVLT   R8,#0                   ;Yes --- raise that too
+               CMP     R9,#256                 ;Is the max x too large?
+               MOVGT   R9,#256                 ;Yes -- reduce it then
+               CMP     R10,#256                ;Is the max y too large?
+               MOVGT   R10,#256                ;Yes -- reduce it then
+               SUB     R9,R9,R4                ;Make this inclusive
+               SUB     R10,R10,R5              ;Make this inclusive too
+
+               ; --- Find address of thing on the screen ---
+
+               MOV     R5,R7                   ;Remember left hand offset
+               MOV     R6,R10                  ;And right hand one
+
+               SUB     R9,R9,R7                ;Work out width
+               SUB     R8,R10,R8               ;And height
+               ADD     R7,R7,R0                ;Work out left hand side
+               ADD     R10,R10,R1              ;And maximum y
+
+               SUB     R13,R13,#20             ;Space for our vdu vars
+               ADR     R0,hsv__vduVars         ;Point to the var numbers
+               MOV     R1,R13                  ;Point to our output block
+               SWI     OS_ReadVduVariables     ;Get the values nicely
+
+               ; --- Convert things to pixels sizes ---
+
+               LDMIA   R13!,{R3,R4}            ;Load out eig factors
+               MOV     R7,R7,LSR R3            ;Convert left hand side
+               MOV     R8,R8,LSR R4            ;And height
+               MOV     R9,R9,LSR R3            ;The width too
+               MOV     R10,R10,LSR R4          ;And the top coord
+
+               LDMIA   R13!,{R0,R1,R2}         ;Load other vdu vars
+               SUB     R14,R1,R10              ;Shift origin to top left
+               MLA     R0,R14,R2,R0            ;Work out address of row
+               ADD     R12,R0,R7,LSL #1        ;Work out left address
+               ADD     R11,R12,R9,LSL #1       ;Work out right hand side too
+               MOV     R9,R2                   ;Put scan line width in R9
+               MOV     R10,R8                  ;And height in R10
+
+               SUB     R8,R5,#128              ;Work out x start position
+               SUB     R7,R6,#128              ;And y start position
+
+               MOV     R14,#1                  ;Get a useful value
+               MOV     R6,R14,LSL R3           ;x step
+               MOV     R5,R14,LSL R4           ;y step
+               MOV     R4,R8                   ;Initial x value
+               MOV     R3,#&10000              ;Value
+
+               ; --- Plot the circle then ---
+
+10hsv__plot32k MOV     R0,#0                   ;Clear buffer register
+               MOV     R1,R12                  ;Get the current address
+
+               BL      hsv__getColour32        ;Get the colour then
+
+               TST     R1,#2                   ;Is this address aligned?
+               BEQ     %20hsv__plot32k         ;Yes -- start at main loop
+               LDR     R14,[R1,#-2]            ;No -- load word from here
+               MOV     R14,R14,LSL #16         ;Shift all the way up
+               ORR     R14,R0,R14,LSR #16      ;Build the replacement word
+               STR     R14,[R1,#-2]            ;And store in frame buffer
+               B       %25hsv__plot32k         ;Jump to end of loop
+
+               ; --- Now the main plotting loop ---
+
+20hsv__plot32k TST     R1,#2                   ;Is this an odd address?
+               STRNE   R0,[R1,#-2]             ;Yes -- done both half words
+
+25hsv__plot32k ADD     R1,R1,#2                ;Move onto next pixel
+               ADD     R8,R8,R6                ;Increment x position
+               CMP     R1,R11                  ;Are we at the line end?
+               BLLS    hsv__getColour32        ;No -- get the colour then
+               BLS     %20hsv__plot32k         ;...and go round for more
+
+               ; --- We've finished; do we have a half word left over? ---
+
+30hsv__plot32k TST     R1,#2                   ;Is the address odd?
+               BEQ     %35hsv__plot32k         ;No -- jump ahead
+               LDR     R14,[R1,#-2]            ;Yes -- read old word
+               MOV     R0,R0,LSR #16           ;Put buffer value in low hw
+               MOV     R14,R14,LSR #16         ;Shift down screen value too
+               ORR     R14,R0,R14,LSL #16      ;Build up correct word
+               STR     R14,[R1,#-2]            ;Store this word away
+
+               ; --- Move onto the next row ---
+
+35hsv__plot32k ADD     R12,R12,R9              ;Move left address down
+               ADD     R11,R11,R9              ;And the right address
+               SUB     R7,R7,R5                ;Decrement the y position
+               MOV     R8,R4                   ;Initial start x position
+               SUBS    R10,R10,#1              ;Decrement the line count
+               BCS     %10hsv__plot32k         ;And keep on going
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               LTORG
+
+hsv__vduVars   DCD     4,5                     ;X and Y eigen factors
+               DCD     149                     ;Start of display memory
+               DCD     12                      ;How high is the screen
+               DCD     6                       ;Width of scan line in pixels
+               DCD     -1
+
+; --- hsv__getColour32 ---
+;
+; On entry:    R0 == colour word so far
+;              R1 == current screen address
+;              R3 == value (16.16)
+;              R7 == y position
+;              R8 == x position
+;
+; On exit:     R0 == updated colour word
+;
+;
+; Use:         Determines the colour of the pixel at the given position
+;              for a 32k colour mode
+
+hsv__getColour32 ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Stack some regsiters
+
+               MOV     R5,R0                   ;Look after old colour
+               MUL     R2,R7,R7                ;Get y^2
+               MUL     R14,R8,R8               ;Get x^2
+               ADD     R2,R2,R14               ;Get x^2+y^2
+               CMP     R2,#&4000               ;Is this in range?
+               BCS     %50hsv__getColour32     ;No -- do really clever stuff
+
+               MOV     R0,R8                   ;Put x position in R0
+               MOV     R1,R7                   ;And x position in R1
+               BL      fxp_pol                 ;Calculate hue
+               MOV     R4,R0                   ;Preserve angle
+
+               MOV     R0,R2                   ;x^2 + y^2
+               MOV     R1,#&4000               ;Get radius^2
+               MOV     R0,R0,LSL#16            ;Prepare for division
+               CMP     R1,#0                   ;Will we divide by 0?
+               BLNE    div_round               ;No -- perform the division
+               MOVEQ   R0,#0                   ;Yes -- make it 0 for luck
+
+               MOV     R1,R0                   ;The saturation
+
+               MOV     R0,R4                   ;Get hue back
+               MOV     R2,R3                   ;Put value in R2
+               BL      hsv_HSVToRGB            ;Convert to RGB
+
+               RSB     R0,R0,R0,LSL#5          ;Multiple by 31
+               RSB     R1,R1,R1,LSL#5          ;Multiple by 31
+               RSB     R2,R2,R2,LSL#5          ;Multiple by 31
+               AND     R0,R0,#&1F0000          ;Ensure it's 0-31
+               AND     R1,R1,#&1F0000          ;Ensure it's 0-31
+               AND     R2,R2,#&1F0000          ;Ensure it's 0-31
+
+               ORR     R14,R0,R1,LSL #5        ;Red and green
+               ORR     R14,R14,R2,LSL #10      ;...blue
+
+               ORR     R0,R14,R5,LSR #16       ;Return colour number
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to caller
+
+               ; --- Position is out of range ---
+
+50             LDR     R14,[R1,#0]             ;Load halfword at address
+               MOV     R14,R14,LSL #16         ;Put it into top halfword
+               ORR     R0,R14,R5,LSR #16       ;Build up new colour value
+               LDMFD   R13!,{R1-R5,PC}^        ;And return to caller
+
+               LTORG
+
+; --- hsv__plot16m ---
+;
+; On entry:    R0 == left hand side of colour square to plot
+;              R1 == bottom edge of colour square to plot
+;              R2 == pointer to graphics window block
+;              R3 == pointer to screen information block
+;              R7 == unlimited minimum x position to plot
+;              R8 == unlimited minimum y position to plot
+;              R9 == unlimited maximum x position to plot
+;              R10 == unlimited maximum y position to plot
+;              On stack: saved {R0-R12,R14}
+;
+; On exit:     --
+;
+; Use:         Displays an HSV circle on the screen at a given location,
+;              in a 32bpp mode, using direct screen access.
+
+hsv__plot16m   ROUT
+
+               ; --- Limit the relative box positions ---
+
+               ADD     R4,R3,#screen_dx        ;Find the pixel positions
+               LDMIA   R4,{R4,R5}              ;Load them into registers
+
+               CMP     R7,#0                   ;Is min x too small?
+               MOVLT   R7,#0                   ;Yes -- raise it to 0
+               CMP     R8,#0                   ;Is min y too small?
+               MOVLT   R8,#0                   ;Yes --- raise that too
+               CMP     R9,#256                 ;Is the max x too large?
+               MOVGT   R9,#256                 ;Yes -- reduce it then
+               CMP     R10,#256                ;Is the max y too large?
+               MOVGT   R10,#256                ;Yes -- reduce it then
+               SUB     R9,R9,R4                ;Make this inclusive
+               SUB     R10,R10,R5              ;Make this inclusive too
+
+               ; --- Find address of thing on the screen ---
+
+               MOV     R5,R7                   ;Remember left hand offset
+               MOV     R6,R10                  ;And right hand one
+
+               SUB     R9,R9,R7                ;Work out width
+               SUB     R8,R10,R8               ;And height
+               ADD     R7,R7,R0                ;Work out left hand side
+               ADD     R10,R10,R1              ;And maximum y
+
+               SUB     R13,R13,#20             ;Space for our vdu vars
+               ADR     R0,hsv__vduVars         ;Point to the var numbers
+               MOV     R1,R13                  ;Point to our output block
+               SWI     OS_ReadVduVariables     ;Get the values nicely
+
+               ; --- Convert things to pixels sizes ---
+
+               LDMIA   R13!,{R3,R4}            ;Load out eig factors
+               MOV     R7,R7,LSR R3            ;Convert left hand side
+               MOV     R8,R8,LSR R4            ;And height
+               MOV     R9,R9,LSR R3            ;The width too
+               MOV     R10,R10,LSR R4          ;And the top coord
+
+               LDMIA   R13!,{R0,R1,R2}         ;Load other vdu vars
+               SUB     R14,R1,R10              ;Shift origin to top left
+               MLA     R0,R14,R2,R0            ;Work out address of row
+               ADD     R12,R0,R7,LSL #2        ;Work out left address
+               ADD     R11,R12,R9,LSL #2       ;Work out right hand side too
+               MOV     R9,R2                   ;Put scan line width in R9
+               MOV     R10,R8                  ;And height in R10
+
+               SUB     R8,R5,#128              ;Work out x start position
+               SUB     R7,R6,#128              ;And y start position
+
+               MOV     R14,#1                  ;Get a useful value
+               MOV     R6,R14,LSL R3           ;x step
+               MOV     R5,R14,LSL R4           ;y step
+               MOV     R4,R8                   ;Initial x value
+               MOV     R3,#&10000              ;Value
+
+               ; --- Plot the circle then ---
+
+10hsv__plot16m MOV     R1,R12                  ;Get the current address
+
+               ; --- Now the main plotting loop ---
+
+20hsv__plot16m BL      hsv__getColour16        ;Get the colour then
+               STR     R0,[R1],#4              ;Yes -- done both half words
+
+25hsv__plot16m ADD     R8,R8,R6                ;Increment x position
+               CMP     R1,R11                  ;Are we at the line end?
+               BLS     %20hsv__plot16m         ;...and go round for more
+
+               ; --- Move onto the next row ---
+
+30hsv__plot16m ADD     R12,R12,R9              ;Move left address down
+               ADD     R11,R11,R9              ;And the right address
+               SUB     R7,R7,R5                ;Decrement the y position
+               MOV     R8,R4                   ;Initial start x position
+               SUBS    R10,R10,#1              ;Decrement the line count
+               BCS     %10hsv__plot16m         ;And keep on going
+
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- hsv__getColour16--
+;
+; On entry:    R3 == value (16.16)
+;              R7 == y position
+;              R8 == x position
+;
+; On exit:     R0 == updated colour word
+;
+; Use:         Determines the colour of the pixel at the given position
+;              for a 32m colour mode
+
+hsv__getColour16 ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Stack some regsiters
+
+               MUL     R2,R7,R7                ;Get y^2
+               MUL     R4,R8,R8                ;Get x^2
+               ADD     R2,R2,R4                ;Get x^2+y^2
+               CMP     R2,#&4000               ;Is this in range?
+               LDRCS   R0,[R1,#0]              ;No -- load previous colour
+               LDMCSFD R13!,{R1-R4,PC}^        ;And return to caller
+
+               MOV     R0,R8                   ;Put x position in R0
+               MOV     R1,R7                   ;And x position in R1
+               BL      fxp_pol                 ;Calculate hue
+               MOV     R4,R0                   ;Preserve angle
+
+               MOV     R0,R2                   ;x^2 + y^2
+               MOV     R1,#&4000               ;Get radius^2
+               MOV     R0,R0,LSL#16            ;Prepare for division
+               CMP     R1,#0                   ;Will we divide by 0?
+               BLNE    div_round               ;No -- perform the division
+               MOVEQ   R0,#0                   ;Yes -- make it 0 for luck
+
+               MOV     R1,R0                   ;The saturation
+               MOV     R0,R4                   ;Get hue back
+               MOV     R2,R3                   ;Put value in R2
+               BL      hsv_HSVToRGB            ;Convert to RGB
+
+               RSB     R0,R0,R0,LSL#8          ;Multiple by 255
+               RSB     R1,R1,R1,LSL#8          ;Multiple by 255
+               RSB     R2,R2,R2,LSL#8          ;Multiple by 255
+               AND     R0,R0,#&FF0000          ;Ensure it's 0-255
+               AND     R1,R1,#&FF0000          ;Ensure it's 0-255
+               AND     R2,R2,#&FF0000          ;Ensure it's 0-255
+
+               ORR     R0,R2,R0,LSR #16        ;Get red & blue components
+               ORR     R0,R0,R1,LSR #8         ;And green
+
+               LDMFD   R13!,{R1-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- hsv__plotCircle ---
+;
+; On entry:    R0 == left hand side of colour square to plot
+;              R1 == bottom edge of colour square to plot
+;              R2 == pointer to graphics window block
+;
+; On exit:     --
+;
+; Use:         Dispatches to the most suitable hsv plotting routine for
+;              the given mode.
+
+hsv__plotCircle        ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save lots of registers
+
+               ; --- Work out the minimum coordinates ---
+
+               LDMIA   R2,{R7,R8,R9,R10}       ;Load the coordinates out
+               SUB     R7,R7,R0                ;Translate min x to relative
+               SUB     R8,R8,R1                ;Translate min y too
+               SUB     R9,R9,R0                ;Translate max x too
+               SUB     R10,R10,R1              ;Translate max y
+
+               ; --- Try to dispatch ---
+
+               MOV     R4,R0                   ;Look after left hand side
+
+               BL      screen_getInfo          ;Get screen info block
+               MOV     R3,R0                   ;Put it in R3
+               MOV     R0,R4                   ;And get left hand side back
+               LDR     R14,[R3,#screen_bpp]    ;Load current bits/pixel
+               CMP     R14,#16                 ;Is this a 32K mode?
+               BEQ     hsv__plot32k            ;Yes -- well, go to it
+               CMP     R14,#32                 ;Is this a 32K mode?
+               BEQ     hsv__plot16m
+
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- The dbx control ---
+
+hsvCircle      ROUT
+
+               DCD     0,0
+               DCD     dbxMask_redraw+dbxMask_click
+
+               CMP     R0,#dbxEvent_click
+               BEQ     %10
+
+               STMFD   R13!,{R0-R2,R10,R14}    ;Stack some registers
+               MOV     R10,R8                  ;Put dbox data in R10
+               MOV     R0,R2                   ;Put bottom left in R0
+               MOV     R1,R3                   ;And bottom right in R1
+               MOV     R2,R6                   ;Put graphics rectangle in R2
+               BL      hsv__plotCircle         ;Plot the circle then
+               LDMFD   R13!,{R0-R2,R10,PC}^    ;Return to caller
+
+10             STMFD   R13!,{R0-R5,R14}
+               MOV     R0,R10
+               BL      dbx_controlBBox
+               SUB     R4,R4,R2
+               SUB     R5,R5,R3
+               ADD     R0,R2,R4,LSR #1
+               ADD     R1,R3,R5,LSR #1
+               MOV     R2,#128
+               SWI     Constrain_Disc
+               LDMFD   R13!,{R0-R5,PC}^
+
+               LTORG
+
+               [ 0=1
+; --- sqrt ---
+;
+; On entry:    R0 == number to find square root of
+;
+; On exit:     R0 == square root of number passed in
+;
+; Use:         Calculates the square root of the number passed to
+;              the nearest integer
+
+sqrt           ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Stack some registers
+               MOV     R4,R0,LSR#2             ;Get an approximation
+               MOV     R3,#-1                  ;The old value
+               MOV     R2,R0                   ;Keep this value
+               MOV     R5,#10                  ;Maximum number of iterations
+
+00sqrt         MOV     R0,R2,ASR #1            ;Divide number to squareroot
+               MOVS    R1,R4                   ;By 2*our approximation
+               BEQ     %01sqrt                 ;Divide by 0 -- leave now
+               BL      div_round               ;Round result to nearest
+               ADD     R4,R0,R4,ASR #1         ;Add this to x/2
+
+               SUBS    R5,R5,#1                ;Decrement iteration count
+               BEQ     %01sqrt                 ;Too low -- skip to end
+
+               CMP     R4,R3                   ;Is solution same as last?
+               MOVNE   R3,R4                   ;No -- remember result
+               BNE     %00sqrt                 ;...and keep trying
+
+01sqrt         MOV     R0,R4                   ;Return root in R0
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to caller
+
+               LTORG
+               ]
+
+; --- HSV -> RGB conversion ---
+
+; --- div60 ---
+;
+; On entry:    R0 == integer to divide
+;
+; On exit:     R0 == quotient after division by 60
+;              R1 == remainder after division by 60
+;
+; Use:         Divides an integer very quickly by 60.
+;
+; [Generated by Straylight divc]
+
+div60          ROUT
+
+               STMFD R13!,{R2,R14}
+               MOVS R2,R0
+               RSBMI R0,R0,#0
+               MOV R1,R0
+
+               ADD R0,R0,R0,LSR#4
+               ADD R0,R0,R0,LSR#8
+               ADD R0,R0,R0,LSR#16
+
+               MOV R0,R0,LSR #6
+
+               RSB R14,R0,R0,LSL#4
+               MOV R14,R14,LSL#2
+
+               SUB R1,R1,R14
+               SUBS R1,R1,#60
+               ADDGE R0,R0,#1
+               ADDLT R1,R1,#60
+
+               CMP R2,#0
+               RSBMI R0,R0,#0
+               RSBMI R1,R1,#0
+               LDMFD R13!,{R2,PC}^
+
+               LTORG
+
+; --- hsv_HSVToRGB ---
+;
+; On entry:    R0 == hue
+;              R1 == saturation
+;              R2 == value
+;
+; On exit:     R0 == red
+;              R1 == green
+;              R2 == blue
+;
+; Use:         Convert a colour in HSV to the equivalent in RGB notation.
+;              All number are taken in 16.16 fixed point form. RGB values
+;              range from 0 to 1 on output.
+
+hsv_HSVToRGB   ROUT
+
+               STMFD   R13!,{R3-R7,R14}        ;Stack some registers
+
+               CMP     R0,#(360<<16)           ;Is hue 360?
+               MOVEQ   R0,#0                   ;Yes -- make it 0
+
+               MOV     R3,R1                   ;Put saturation in R3
+               BL      div60                   ;Divide hue by 60
+               BIC     R1,R0,#&FF0000          ;Get fractional part in R1
+               MOV     R0,R0,LSR#16            ;And integer part in R0
+
+               MOV     R4,R2,LSR#8             ;For multiplication
+               RSB     R5,R3,#1<<16            ;1-saturation (16.16 form)
+               MOV     R5,R5,LSR#8             ;Shift for division
+               MUL     R5,R4,R5                ;Minimum=value*(1-saturation)
+               MOV     R14,R3,LSR#8            ;Saturation >> 8
+               MOV     R6,R1,LSR#8             ;Fractional >> 8
+               MUL     R6,R14,R6               ;Saturation*fractional
+               RSB     R6,R6,#1<<16            ;1-(previous result)
+               MOV     R6,R6,LSR#8             ;Prepare for multiplication
+               MUL     R6,R4,R6                ;Inverse1=value*(prev result)
+               RSB     R7,R1,#1<<16            ;1-fractional
+               MOV     R7,R7,LSR#8             ;Prepare for multiplication
+               MUL     R7,R14,R7               ;Saturation*(1-fractional)
+               RSB     R7,R7,#1<<16            ;1-(sat*(1-fractional))
+               MOV     R7,R7,LSR#8             ;Prepare for multiplication
+               MUL     R7,R4,R7                ;Value*(1-(sat*(1-frac)))
+
+               ; --- Find out which section number we are in ---
+
+               CMP     R0,#0                   ;Section 0?
+               BNE     %10hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R2                   ;Red = value
+               MOV     R1,R7                   ;Green = inverse2
+               MOV     R2,R5                   ;Blue = minimum
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+10hsv_HSVToRGB CMP     R0,#1                   ;Section 1?
+               BNE     %20hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R6                   ;Red = inverse1
+               MOV     R1,R2                   ;Green = value
+               MOV     R2,R5                   ;Blue = minimum
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+20hsv_HSVToRGB CMP     R0,#2                   ;Section 2?
+               BNE     %30hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R5                   ;Red = minimum
+               MOV     R1,R2                   ;Green = value
+               MOV     R2,R7                   ;Blue = inverse2
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+30hsv_HSVToRGB CMP     R0,#3                   ;Section 3?
+               BNE     %40hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R5                   ;Red = minimum
+               MOV     R1,R6                   ;Green = inverse1
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+40hsv_HSVToRGB CMP     R0,#4                   ;Section 0?
+               BNE     %50hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R7                   ;Red = inverse2
+               MOV     R1,R5                   ;Green = minimum
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+50hsv_HSVToRGB CMP     R0,#5                   ;Section 0?
+               BNE     %60hsv_HSVToRGB         ;No -- try next one
+               MOV     R0,R2                   ;Red = value
+               MOV     R1,R5                   ;Green = minimum
+               MOV     R2,R6                   ;Blue = inverse1
+               LDMFD   R13!,{R3-R7,PC}^        ;Return to caller
+
+60hsv_HSVToRGB ADR     R0,convert__error       ;Point to the error message
+               SWI     OS_GenerateError        ;And generate an error
+
+convert__error DCD     1
+               DCB     "Fatal error: hsv_HSVToRGB -- section >5 reached",0
+
+               LTORG
+
+;----- Workspace layout -----------------------------------------------------
+
+               AREA    |Sapphire$$LibData|,CODE,READONLY
+
+               DCD     0
+               DCD     0
+               DCD     0
+               DCD     0
+
+;-- That's all, folks -------------------------------------------------------
+
+               END
diff --git a/StraySrc/SapphToys/!ColDemo/s/rgb b/StraySrc/SapphToys/!ColDemo/s/rgb
new file mode 100644 (file)
index 0000000..622bd2c
--- /dev/null
@@ -0,0 +1,1602 @@
+;
+; rgb.s
+;
+; Handling the RGB colour model dialogue box
+;
+; © 1994 Straylight
+;
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:dbox
+               GET     sapphire:divide
+               GET     sapphire:idle
+               GET     sapphire:roVersion
+               GET     sapphire:screen
+               GET     sapphire:win
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx.arrow
+               GET     sapphire:dbx.numWrite
+               GET     sapphire:dbx.slider
+
+               GET     sapphire:_cs.kernel
+               GET     sapphire:_cs.vars
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Sapphire$$Code|,CODE,READONLY
+
+; --- rgb_open ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Called by the colour picker
+
+               EXPORT  rgb_open
+rgb_open       ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Stack the link register
+               ADR     R0,rgb__dbName          ;Point to dialogue box name
+               BL      dbox_create             ;Create the dialogue box
+               LDMVSFD R13!,{R1-R3,PC}         ;Return now if it failed
+               STR     R0,[R13,#-4]!           ;Return dialogue handle in R0
+
+               ; --- Attach event handlers and things ---
+
+               ADR     R1,rgb__dbHandler       ;Point to my handler code
+               MOV     R2,R10                  ;Pass colour workspace in R10
+               MOV     R3,R12                  ;Pass my workspace in R12
+               BL      dbox_eventHandler       ;Register my event handler
+               ADR     R1,rgb__dbxDef          ;Point to the control defn
+               BL      dbx_declare             ;Declare it to dbx nicely
+
+               ; --- Set up the workspace ---
+
+               MOV     R0,#0                   ;Set the Red mapping
+               BL      rgb__setMapping         ;Set this as the mapping
+
+               ; --- Set up the dialogue box ---
+
+               LDR     R0,[R13,#0]             ;Load the dialogue handle
+               LDR     R1,rgb__mapping         ;Get the current mapping
+               ADD     R1,R1,R1,LSL #2         ;Multiply by icon offset (5)
+               ADD     R1,R1,#rgbIcon__radioR  ;Add on to get icon number
+               MOV     R2,#1                   ;Please select this icon
+               BL      dbox_select             ;Select the right one
+
+               MOV     R1,#rgbIcon__writeR     ;Get the red writable icon
+               LDR     R2,rgb__red             ;Find the red value
+               LDR     R2,[R2,#0]              ;Load the red value
+               BL      numWrite_set            ;Set it in the icon
+
+               MOV     R1,#rgbIcon__writeG     ;Get the green writable icon
+               LDR     R2,rgb__green           ;Find the green value
+               LDR     R2,[R2,#0]              ;Load the green value
+               BL      numWrite_set            ;Set it in the icon
+
+               MOV     R1,#rgbIcon__writeB     ;Get the blue writable icon
+               LDR     R2,rgb__blue            ;Find the blue value
+               LDR     R2,[R2,#0]              ;Load the blue value
+               BL      numWrite_set            ;Set it in the icon
+               LDMFD   R13!,{R0-R3,R14}        ;Return to caller
+
+rgb__dbName    DCB     "rgb",0
+
+rgb__dbxDef    CONTROL rgbIcon__square,rgbSquare,R10,0,0
+               ECTRL
+
+               SLIDER  rgbIcon__slide1,R10,:INDEX: rgb__sl1Val,                                        slFlag_horizontal + slFlag_colData,0,0,1,100
+               NUMWRT  rgbIcon__writeR,0,100
+               ARROW   rgbIcon__upR,1
+               ARROW   rgbIcon__downR,-1
+
+               SLIDER  rgbIcon__slide2,R10,:INDEX: rgb__sl2Val,                                        slFlag_vertical + slFlag_colData,0,0,1,100
+               NUMWRT  rgbIcon__writeG,0,100
+               ARROW   rgbIcon__upG,1
+               ARROW   rgbIcon__downG,-1
+
+               SLIDER  rgbIcon__slide3,R10,:INDEX: rgb__sl3Val,                                        slFlag_vertical + slFlag_colData,0,0,1,100
+               NUMWRT  rgbIcon__writeB,0,100
+               ARROW   rgbIcon__upB,1
+               ARROW   rgbIcon__downB,-1
+
+               DBXEND
+
+; --- rgb__dbHandler ---
+;
+; On entry:    R0 == dialogue box event code
+;              R1-R7 == depend on the event
+;              R9 == dialogue box handle of RGB panel
+;              R10 == pointer to colour selector workspace
+;              R12 == nothing much
+;
+; On exit:     --
+;
+; Use:         Handles events for the RGB panel.
+
+rgb__dbHandler ROUT
+
+               ; --- Dispatch events to their destinations ---
+
+               CMP     R0,#rgbIcon__radioR     ;Is it the red view button?
+               CMPNE   R0,#rgbIcon__radioG     ;Or the green view button?
+               CMPNE   R0,#rgbIcon__radioB     ;Or the blue view button?
+               BEQ     rgb__setView            ;Yes -- set the new view
+
+               CMP     R0,#csEvent__close      ;Is it a close panel event?
+               BEQ     rgb__closePanel         ;Yes -- destroy the dialogue
+
+               CMP     R0,#csEvent__newRes     ;Is it a resolution change?
+               BEQ     rgb__newRes             ;Yes -- update the piccy then
+
+               CMP     R0,#slider_event        ;Is it a slider event?
+               BEQ     rgb__slChange           ;Yes -- do something then
+
+               CMP     R0,#numWrite_event      ;Is it a writable event?
+               BEQ     rgb__wrChange           ;Yes -- do something then
+
+               CMP     R0,#arrow_event         ;Is it an arrow event?
+               BEQ     rgb__arChange           ;Yes -- do something then
+
+               STMFD   R13!,{R14}              ;Save a register
+               SUB     R14,R0,#rgbIcon__wCols  ;Is it a WIMP colour box?
+               CMP     R14,#16                 ;Check it's in range
+               BLO     rgb__wimpCol            ;Yes -- handle it then
+
+               LDMFD   R13!,{PC}^              ;Unknown -- return to caller
+
+               ; --- Change the panel view ---
+
+rgb__setView   ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               CMP     R0,#rgbIcon__radioG     ;Is it the green button?
+               MOVLT   R3,#0                   ;Lower -- it must be red
+               MOVEQ   R3,#1                   ;Equal -- must be green
+               MOVGT   R3,#2                   ;Greater -- must be blue
+               LDR     R1,rgb__mapping         ;Get the current mapping
+               CMP     R3,R1                   ;Is it the same?
+               LDMEQFD R13!,{R0-R3,PC}^        ;Yes -- return now then
+
+               ; --- Select the correct icon ---
+
+               MOV     R0,R9                   ;Load the dialogue handle
+               ADD     R1,R1,R1,LSL #2         ;Multiply by icon offset (5)
+               ADD     R1,R1,#rgbIcon__radioR  ;Add on to get icon number
+               MOV     R2,#0                   ;Please deselect this icon
+               BL      dbox_select             ;Select the right one
+
+               ADD     R1,R3,R3,LSL #2         ;Multiply by icon offset (5)
+               ADD     R1,R1,#rgbIcon__radioR  ;Add on to get icon number
+               MOV     R2,#1                   ;Please select this icon
+               BL      dbox_select             ;Select the right one
+
+               ; --- Update the dialogue box sliders etc. ---
+
+               MOV     R0,R9                   ;Get the dialogue box handle
+               MOV     R1,#rgbIcon__square     ;Get the colour square
+               BL      dbx_qUpdate             ;Get rid of the crosshair
+               MOV     R0,R3                   ;Pass mapping number
+               BL      rgb__setMapping         ;Redo all the mappings
+               BL      rgb__updateSliders      ;And redraw the sliders
+               MOV     R0,R9                   ;Get the dialogue box handle
+               MOV     R1,#rgbIcon__square     ;Get the colour square
+               BL      dbx_update              ;Redraw it nicely
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               ; --- Update the RGB colour cube view ---
+
+rgb__newRes    ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               MOV     R0,R9                   ;Get the dialogue handle
+               MOV     R1,#rgbIcon__square     ;Get the colour square
+               BL      dbx_qUpdate             ;Get rid of the crosshair
+               BL      dbx_update              ;Redraw it nicely
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               ; --- Update colour values ---
+
+rgb__slChange  ROUT
+
+               STMFD   R13!,{R0-R2,R4,R14}     ;Save some registers
+
+               ; --- Update the main dialogue's colour pot ---
+
+               BL      rgb__colUpdate          ;Update the colour pot
+
+               ; --- Now update the writable icon ---
+
+               LDR     R2,[R13,#8]             ;Load the slider icon
+               SUB     R4,R2,#rgbIcon__slide1  ;Get the slider axis number
+               LDR     R14,rgb__mapping        ;Load the mapping number
+               SUB     R1,R14,R4               ;Find the table index
+               ADR     R14,rgb__writeTbl+2     ;Point to the table
+               LDRB    R1,[R14,R1]             ;Load the icon number
+               MOV     R0,R9                   ;Put dialogue handle in R0
+               MOV     R2,R3                   ;Put slider value in R2
+               BL      numWrite_set            ;And put it in the icon
+
+               ; --- Now work out what else to update ---
+
+               CMP     PC,#0                   ;Clear the Z flag
+               BL      cs_immediate            ;Are we doing immediate ops?
+               LDRCC   R14,[R13,#4]            ;Load the subreason code
+               CMPCC   R14,#slider_sliding     ;Is the slider going still?
+               BLNE    rgb__zUpdate            ;No -- redraw colour square
+
+               BL      rgb__xyUpdate           ;Now move the crosshair
+
+90rgb__slChange        LDMFD   R13!,{R0-R2,R4,PC}^     ;Return to caller
+
+rgb__writeTbl  DCB     rgbIcon__writeR
+               DCB     rgbIcon__writeG
+               DCB     rgbIcon__writeB
+               DCB     rgbIcon__writeR
+               DCB     rgbIcon__writeG
+
+               ; --- He typed something into one of our icons ---
+
+rgb__wrChange  ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+
+               ; --- First, find the value this writable applies to ---
+
+               CMP     R1,#rgbIcon__writeG     ;Which writable icon is it?
+               MOVLT   R1,#0                   ;Red -- remember this map
+               MOVEQ   R1,#1                   ;Green -- remember this
+               MOVGT   R1,#2                   ;Blue -- remember this
+               ADR     R14,rgb__red            ;Point to the mappings
+               LDR     R14,[R14,R1,LSL #2]     ;Translate the colour
+               LDR     R0,[R14,#0]             ;Load the actual value
+               SUBS    R5,R0,R3                ;Is this our value?
+
+               ; --- He's changed the value -- update slider/colour ---
+
+               STRNE   R3,[R14,#0]             ;Save the new value away
+               BLNE    rgb__colUpdate          ;Redraw the colour pot
+               LDR     R0,rgb__mapping         ;Load the mapping number
+               SUB     R3,R1,R0                ;Work out the table index
+               ADR     R14,rgb__slideTbl+2     ;Point to slider icon table
+               LDRB    R1,[R14,R3]             ;Load the icon number
+               LDR     R0,cs__modelDb          ;Load the panel dialogue
+               BLNE    dbx_update              ;Redraw the slider nicely
+
+               ; --- Update the main piccy ---
+
+               CMPEQ   PC,#0                   ;Clear the Z flag
+               BL      cs_immediate            ;Are we doing immediate ops?
+               CMPCC   R2,#numWrite_change     ;Is he just typing numbers?
+               BLNE    rgb__zUpdate            ;No -- redraw colour square
+
+               BL      rgb__xyUpdate           ;Now move the crosshair
+
+90rgb__wrChange        LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+rgb__slideTbl  DCB     rgbIcon__slide2
+               DCB     rgbIcon__slide1
+               DCB     rgbIcon__slide3
+               DCB     rgbIcon__slide2
+               DCB     rgbIcon__slide1
+
+rgb__arChange  ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R4,R2                   ;Look after the bump
+
+               ; --- First, find the value this arrow applies to ---
+
+               CMP     R1,#rgbIcon__upG        ;Which writable icon is it?
+               CMPGT   R1,#rgbIcon__downG      ;There's two for green
+               MOVLT   R3,#0                   ;Red -- remember this map
+               MOVEQ   R3,#1                   ;Green -- remember this
+               MOVGT   R3,#2                   ;Blue -- remember this
+
+               ; --- Now bump the required writable icon ---
+
+               ADR     R14,rgb__writeTbl       ;Point to the icon table
+               LDRB    R1,[R14,R3]             ;Load the correct icon
+               MOV     R0,R9                   ;Pass dialogue in R0
+               BL      numWrite_bump           ;Apply the bump value
+
+               ; --- Now perform the update operation ---
+
+               CMPEQ   PC,#0                   ;Clear the Z flag
+               BL      cs_immediate            ;Are we doing immediates?
+               TEQCS   R4,#0                   ;And is the bump sensible?
+               BEQ     %90rgb__arChange        ;Immediate/end ==> return
+               MOV     R3,R2                   ;Get value in R3 nicely
+               MOVCS   R2,#1                   ;Update always if immediate
+               MOVCC   R2,#0                   ;Default is no update if not
+               TEQ     R4,#0                   ;And is the bump sensible?
+               MOVEQ   R2,#1                   ;No -- then force update
+               BL      rgb__wrChange           ;Handle writable update then
+
+90rgb__arChange        LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+               ; --- Close the panel to open a new one ---
+
+rgb__closePanel        ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R9                   ;Get the dialogue handle
+               BL      dbox_destroy            ;Kill off the dialogue
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               ; --- Handle a click on one of the WIMP colours ---
+               ;
+               ; The WIMP colour number resides in R14 at the moment :-/
+
+rgb__wimpCol   ROUT
+
+               STMFD   R13!,{R0,R1}            ;Save some registers
+               SUB     R13,R13,#80             ;Make space for palette block
+               MOV     R1,R13                  ;Point to my block
+               SWI     Wimp_ReadPalette        ;Read the WIMP palette
+               LDR     R1,[R13,R14,LSL #2]     ;Load the one we want
+               ADD     R13,R13,#80             ;Don't need this now
+
+               ; --- Under RISC OS <3.50, bodge palette entry ---
+               ;
+               ; Because of Acorn stupidity, the ReadPalette values have
+               ; blank lower nibbles.  According to Acorn, I must copy the
+               ; top nibbles into the bottom ones for ColourTrans to be
+               ; happy.  I assume that this has been sorted out on 3.50 and
+               ; later.
+
+               BL      rov_version             ;Get the RISC OS version
+               CMP     R0,#340                 ;It's almost 350 :-)
+               LDRLO   R14,=&F0F0F000          ;A nibble mask
+               ANDLO   R1,R1,R14               ;Clear bottom nibbles
+               ORRLO   R1,R1,R1,LSR #4         ;And duplicate top in bottom
+
+               STR     R1,cs__colour+col_rgb   ;Save this new colour
+               BL      rgb__setValues          ;And redo everything nicely
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rgb__setValues ---
+;
+; On entry:    R10 == address of colour selector instance data
+;
+; On exit:     --
+;
+; Use:         Updates all the values in the dialogue box from the colour
+;              word in the workspace (which is assumed to have changed).
+;              The colour mapping is assumed to still be valid, though.
+
+rgb__setValues ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Unpack the value from the colour RGB word ---
+
+               BL      rgb__unpack             ;Get the percentages out
+
+               ; --- Do the writable icons ---
+
+               LDR     R0,cs__modelDb          ;Get the dialogue handle
+               MOV     R1,#rgbIcon__writeR     ;Get the red writable icon
+               LDR     R2,rgb__red             ;Find the red value
+               LDR     R2,[R2,#0]              ;Load the red value
+               BL      numWrite_set            ;Set it in the icon
+
+               MOV     R1,#rgbIcon__writeG     ;Get the green writable icon
+               LDR     R2,rgb__green           ;Find the green value
+               LDR     R2,[R2,#0]              ;Load the green value
+               BL      numWrite_set            ;Set it in the icon
+
+               MOV     R1,#rgbIcon__writeB     ;Get the blue writable icon
+               LDR     R2,rgb__blue            ;Find the blue value
+               LDR     R2,[R2,#0]              ;Load the blue value
+               BL      numWrite_set            ;Set it in the icon
+
+               ; --- Now do the other controls ---
+
+               BL      rgb__updateSliders      ;Do the slider update
+               BL      cs_colChange            ;Redraw main colour pot
+               BL      rgb__zUpdate            ;Force a recache of z
+               BL      rgb__xyUpdate           ;And a recache of x and y
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rgb__updateSliders ---
+;
+; On entry:    R10 == address of colour selector instance data
+;
+; On exit:     --
+;
+; Use:         Redraws all the sliders.  Because the slider code is so
+;              amazingly intelligent, if the values haven't changed, the
+;              picture you see won't change either.
+
+rgb__updateSliders ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R0,cs__modelDb          ;Get the dialogue handle
+               MOV     R1,#rgbIcon__slide1     ;Get slider 1's number
+               BL      dbx_update              ;Redraw it quickly
+               MOV     R1,#rgbIcon__slide2     ;Get slider 2's number
+               BL      dbx_update              ;Redraw it quickly
+               MOV     R1,#rgbIcon__slide3     ;Get slider 3's number
+               BL      dbx_update              ;Redraw it quickly
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rgb__setMapping ---
+;
+; On entry:    R0 == rotation number (i.e. which colour is on z azis)
+;
+; On exit:     --
+;
+; Use:         Sets up the workspace so that the dialogue box displays the
+;              correct mapping.
+
+rgb__setMapping        ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Reset the mapping number and table ---
+
+               STR     R0,rgb__mapping         ;Save the mapping number
+               ADR     R1,rgb__mappingTbl      ;Point to the table
+               ADD     R1,R1,R0                ;Index it nicely
+
+               LDRB    R14,[R1],#1             ;Load the blue offset
+               ADD     R14,R10,R14             ;Add it to workspace ptr
+               STR     R14,rgb__blue           ;And store nicely
+               MOV     R2,#8                   ;The blue slider colour
+               STR     R2,[R14,#4]             ;Save it in the table
+
+               LDRB    R14,[R1],#1             ;Load the green offset
+               ADD     R14,R10,R14             ;Add it to workspace ptr
+               STR     R14,rgb__green          ;And store nicely
+               MOV     R2,#10                  ;The green slider colour
+               STR     R2,[R14,#4]             ;Save it in the table
+
+               LDRB    R14,[R1],#1             ;Load the red offset
+               ADD     R14,R10,R14             ;Add it to workspace ptr
+               STR     R14,rgb__red            ;And store nicely
+               MOV     R2,#11                  ;The red slider colour
+               STR     R2,[R14,#4]             ;Save it in the table
+
+               BL      rgb__unpack             ;Unpack colour def now
+
+               ; --- Set up the cached values for the diagram ---
+
+               LDR     R14,rgb__sl1Val         ;Load the x value
+               STR     R14,rgb__xPos           ;Save it in the cache
+               LDR     R14,rgb__sl2Val         ;Load the y value
+               STR     R14,rgb__yPos           ;Save it in the cache
+               LDR     R14,rgb__sl3Val         ;Load the z value
+               STR     R14,rgb__zPos           ;Save it in the cache
+
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+               ; --- The mapping table ---
+               ;
+               ; The table is done twice, to give it a `wraparound' effect.
+
+rgb__mappingTbl        DCB     :INDEX: rgb__sl1Val
+               DCB     :INDEX: rgb__sl2Val
+               DCB     :INDEX: rgb__sl3Val
+               DCB     :INDEX: rgb__sl1Val
+               DCB     :INDEX: rgb__sl2Val
+
+; --- rgb__unpack ---
+;
+; On entry:    R10 == address of colour selector instance data
+;
+; On exit:     --
+;
+; Use:         Unpacks the colour definition in the cs data into the
+;              slider values.
+
+rgb__unpack    ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some workspace
+               LDR     R2,cs__colour+col_rgb   ;Get the colour nicely
+
+               ; --- Set up the blue slider ---
+
+               MOV     R0,R2,LSR #24           ;Get the blue colour value
+               BL      rgb__colToPerC          ;Convert it to a percentage
+               LDR     R14,rgb__blue           ;Load the blue entry address
+               STR     R0,[R14]                ;Save the blue value in it
+
+               ; --- Now set up the green one ---
+
+               MOV     R0,R2,LSR #16           ;Get the green colour value
+               BL      rgb__colToPerC          ;Convert it to a percentage
+               LDR     R14,rgb__green          ;Load the green entry address
+               STR     R0,[R14]                ;Save the green value in it
+
+               ; --- Now set up the red one ---
+
+               MOV     R0,R2,LSR #8            ;Get the red colour value
+               BL      rgb__colToPerC          ;Convert it to a percentage
+               LDR     R14,rgb__red            ;Load the red entry address
+               STR     R0,[R14]                ;Save the red value in it
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rgb__colToPerC ---
+;
+; On entry:    R0 == colour to convert, from 0 to 255
+;
+; On exit:     R0 == colour as a percentage
+;
+; Use:         Converts a colour to a percentage.
+;
+; [Generated by Straylight divc]
+; Modified by MDW to (a) be unsigned, and (b) round to nearest.
+
+rgb__colToPerC ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               AND     R0,R0,#&FF              ;Mask off any other bits
+               ADD     R0,R0,R0,LSL #2         ;Multiply by 5 (x5)
+               ADD     R0,R0,R0,LSL #2         ;And by 5 again (x25)
+               MOV     R0,R0,LSL #2            ;And now by 4 (x100)
+               MOV     R1,R0                   ;Keep copy of dividend
+               ADD     R0,R0,#127              ;Make it round to nearest
+               ADD     R0,R0,R0,LSR #8         ;R0 = R0 x 256/255
+               ADD     R0,R0,R0,LSR #16        ;...
+               MOV     R0,R0,LSR #8            ;Div by 256 -- R0 = R0 / 255
+               RSB     R14,R0,R0,LSL #8        ;Multiply by 255
+               SUB     R1,R1,R14               ;Find the difference
+               SUBS    R1,R1,#255              ;This is the remainder
+               ADDGE   R0,R0,#1                ;If we overshot, bump quot
+               ADDLT   R1,R1,#255              ;And chop off remainder
+               LDMFD   R13!,{R1,PC}^           ;Return to caller
+
+               LTORG
+
+; --- rgb__perCToCol ---
+;
+; On entry:    R0 == colour percentage to convert
+;
+; On exit:     R0 == colour value, from 0-255
+;
+; Use:         Converts a percentage to a colour.
+
+rgb__perCToCol ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               RSB     R0,R0,R0,LSL #8         ;Multiply it by 255
+               ADD     R0,R0,#50               ;Add 50 to round to nearest
+               BL      div10                   ;Divide by 10
+               BL      div10                   ;And again (by 100)
+               LDMFD   R13!,{R1,PC}^           ;And return to caller
+
+               LTORG
+
+; --- rgb__colUpdate ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Updates the main dialogue's colour pot.
+
+rgb__colUpdate ROUT
+
+               STMFD   R13!,{R0,R2,R14}        ;Save some registers
+               MOV     R2,#0                   ;Clear prospective colour
+
+               LDR     R0,rgb__blue            ;Get the blue colour address
+               LDR     R0,[R0,#0]              ;Load the blue percentage
+               BL      rgb__perCToCol          ;Convert it to a real colour
+               ORR     R2,R2,R0,LSL #24        ;Move into R2 nicely
+
+               LDR     R0,rgb__green           ;Get the green colour address
+               LDR     R0,[R0,#0]              ;Load the green percentage
+               BL      rgb__perCToCol          ;Convert it to a real colour
+               ORR     R2,R2,R0,LSL #16        ;Move into R2 nicely
+
+               LDR     R0,rgb__red             ;Get the red colour address
+               LDR     R0,[R0,#0]              ;Load the red percentage
+               BL      rgb__perCToCol          ;Convert it to a real colour
+               ORR     R2,R2,R0,LSL #8         ;Move into R2 nicely
+
+               STR     R2,cs__colour+col_rgb   ;Save this as the new colour
+               LDMFD   R13!,{R0,R2,R14}        ;Restore registers
+               B       cs_colChange            ;Update the main box's colour
+
+               LTORG
+
+; --- rgb__zUpdate ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Updates everything following a change to the current z
+;              value.  It doesn't change the writable icon, but it does
+;              most other things.
+
+rgb__zUpdate   ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Make sure that the z coordinate changed ---
+
+               LDR     R2,rgb__sl3Val          ;Load current z slider pos
+               LDR     R0,rgb__zPos            ;Load the cached position
+               CMP     R0,R2                   ;Do they match?
+               LDMEQFD R13!,{R0-R2,PC}^        ;Yes -- nothing doing then
+
+               ; --- Remove crosshairs -- it looks nicer ---
+
+               LDR     R0,cs__modelDb          ;Load the model dialogue
+               MOV     R1,#rgbIcon__square     ;Get the colour square
+               BL      dbx_qUpdate             ;Get rid of the crosshair
+
+               ; --- Now recache the x and y coords to prevent flicker ---
+
+               STR     R2,rgb__zPos            ;Update the cache value
+               LDR     R14,rgb__sl1Val         ;Load the current x value
+               STR     R14,rgb__xPos           ;Save it away
+               LDR     R14,rgb__sl2Val         ;Load the current y value
+               STR     R14,rgb__yPos           ;Save it away
+
+               ; --- Redraw the main square ---
+
+               BL      dbx_update              ;Force a redraw of it
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+; --- rgb__xyUpdate ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Updates things following a change to either the x or y
+;              value.
+
+rgb__xyUpdate  ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               LDR     R0,rgb__xPos            ;Load cached x position
+               LDR     R1,rgb__yPos            ;Load cached y position
+               LDR     R2,rgb__sl1Val          ;And the current x pos
+               LDR     R3,rgb__sl2Val          ;And the current y pos
+               CMP     R0,R2                   ;Is the cached x right?
+               CMPEQ   R1,R3                   ;And is the cached y right?
+               LDMEQFD R13!,{R0-R3,PC}^        ;Yes -- return then
+
+               LDR     R0,cs__modelDb          ;Load the dialogue box handle
+               MOV     R1,#rgbIcon__square     ;Load the square icon
+               BL      dbx_qUpdate             ;Quickly redraw it
+               STR     R2,rgb__xPos            ;Recache the x position
+               STR     R3,rgb__yPos            ;Recache the y position
+               BL      dbx_qUpdate             ;Quickly redraw it
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+;----- Plotting the colour square -------------------------------------------
+
+; --- rgb_plotSquare ---
+;
+; On entry:    R0 == left hand side of colour square to plot
+;              R1 == bottom edge of colour square to plot
+;              R2 == which rotation we're plotting
+;              R3 == x step to plot in
+;              R4 == y step to plot in
+;              R5 == z-coordinate value (in 16.16 form)
+;              R6 == pointer to graphics window block
+;
+; On exit:     --
+;
+; Use:         Plots a cross-section through the RGB colour cube.
+
+               EXPORT  rgb_plotSquare
+rgb_plotSquare ROUT
+
+               STMFD   R13!,{R0-R12,R14}       ;Save a job-lot of registers
+
+               ; --- Work out the minimum coordinates ---
+
+               LDMIA   R6,{R8,R9,R11,R12}      ;Load the coordinates out
+               SUB     R7,R12,R1               ;Translate max y to relative
+               SUB     R12,R9,R1               ;Translate min y too
+               SUB     R10,R8,R0               ;Translate min x too
+               SUB     R11,R11,R0              ;Translate max x
+
+               ; --- See if we can do really clever things ---
+
+               STMFD   R13!,{R0,R11}           ;Save our R11 value
+               LDR     R11,[R13,#52]           ;Load the system R11 value
+               BL      screen_getInfo          ;Load the screen information
+               MOV     R8,R0                   ;Look after this address
+               LDMFD   R13!,{R0,R11}           ;Reload our local value
+               LDR     R14,[R8,#screen_bpp]    ;Load current bits/pixel
+               CMP     R14,#16                 ;Is this a 2byte/pixel mode?
+               BEQ     rgb__plot32k            ;Yes -- branch to special bit
+               CMP     R14,#32                 ;Is this a 4byte/pixel mode?
+               BEQ     rgb__plot16m            ;Yes -- branch to special bit
+
+               ; --- Work out rectangle edges ---
+
+               CMP     R10,#0                  ;Is min x too small?
+               MOVLT   R10,#0                  ;Yes -- raise it to 0
+               CMP     R12,#0                  ;Is min y too small?
+               MOVLT   R12,#0                  ;Yes --- raise that too
+               CMP     R11,#255                ;Is the max x too large?
+               MOVGT   R11,#255                ;Yes -- reduce it then
+               CMP     R7,#255                 ;Is the max y too large?
+               MOVGT   R7,#255                 ;Yes -- reduce it then
+
+               SUB     R8,R3,#1                ;Turn the x step to bitmask
+               SUB     R9,R4,#1                ;And the same for y step
+               BIC     R10,R10,R8              ;Round min x down to step
+               BIC     R12,R12,R9              ;And round min y down too
+               BIC     R11,R11,R8              ;Round max x down too
+               BIC     R7,R7,R9                ;And round down max y
+
+               STMFD   R13!,{R7,R10}           ;Save rel. min x and max y
+
+               ADD     R10,R10,R0              ;Now make min x absolute
+               ADD     R12,R12,R1              ;And make min y absolute
+               ADD     R11,R11,R0              ;And make max x absolute
+               ADD     R7,R7,R1                ;And make max y absolute
+
+               ; --- Now work out the z-value ---
+
+               RSB     R5,R5,R5,LSL #8         ;Multiply value by 255
+               ADD     R5,R5,#&8000            ;Make sure we round nicely
+               MOV     R5,R5,LSR #16           ;And make it 0-255
+
+               ; --- Work out the exclusive rectangle sizes ---
+
+               STMFD   R13!,{R11}              ;Save our R11 value
+               LDR     R11,[R13,#56]           ;Load the system R11 value
+               BL      screen_getInfo          ;Load the screen information
+               LDMFD   R13!,{R11}              ;Reload our local value
+
+               LDMIA   R0,{R8,R9}              ;Load the eigen factors out
+               MOV     R14,#1                  ;This will be shifted around
+               SUB     R8,R3,R14,LSL R8        ;Subtract x pixel from x step
+               SUB     R9,R4,R14,LSL R9        ;Subtract y pixel from y step
+
+               ; --- Work out all the shift values ---
+
+               CMP     R2,#0                   ;Is this the red rotation?
+               MOVEQ   R0,#24                  ;Yes -- then x is blue
+               MOVEQ   R1,#16                  ;And y is green
+               MOVEQ   R5,R5,LSL #8            ;And z is red
+
+               CMP     R2,#1                   ;Is this the green rotation?
+               MOVEQ   R0,#8                   ;Yes -- then x is red
+               MOVEQ   R1,#24                  ;And y is blue
+               MOVEQ   R5,R5,LSL #16           ;And z is green
+
+               CMP     R2,#2                   ;Is this the blue rotation?
+               MOVEQ   R0,#16                  ;Yes -- then x is green
+               MOVEQ   R1,#8                   ;And y is red
+               MOVEQ   R5,R5,LSL #24           ;And z is blue
+
+               ; --- Set up the initial palette word ---
+
+               LDMFD   R13!,{R14}              ;Load maximum y palette val
+               ORR     R5,R5,R14,LSL R1        ;Fit that into the palette
+
+               LDMFD   R13!,{R2}               ;Load minimum x palette val
+
+               ; --- Now for the main plotting loop ---
+
+00             MOV     R6,R10                  ;Start on the left hand side
+               MOV     R14,#255                ;Clear out nasty x palette
+               BIC     R5,R5,R14,LSL R0        ;Clear out the right byte
+               ORR     R5,R5,R2,LSL R0         ;And set up the min value
+
+               ; --- Plot the rectangle nicely ---
+
+10             STMFD   R13!,{R0-R4}            ;Save some registers for this
+
+               ; --- Nothing for it but to use ColourTrans ---
+               
+               MOV     R0,R5                   ;Get the palette entry
+               MOV     R3,#&100                ;Please try to dither it
+               MOV     R4,#0                   ;And have normal GCOL action
+               SWI     XColourTrans_SetGCOL    ;Try to set the colour up
+               MOVVS   R3,#0                   ;Try again without dithering
+               MOVVS   R0,R5                   ;Set the palette word again
+               SWIVS   ColourTrans_SetGCOL     ;Set the colour the old way
+
+15             MOV     R0,#4                   ;Move cursor absolute
+               MOV     R1,R6                   ;Get the current x coordinate
+               MOV     R2,R7                   ;And the current y coordinate
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#97                  ;Rectangle fill relative
+               MOV     R1,R8                   ;Rectangle width thingy
+               MOV     R2,R9                   ;Rectangle height thingy
+               SWI     OS_Plot                 ;Plot the rectangle
+               LDMFD   R13!,{R0-R4}            ;Restore a load of registers
+
+               ; --- Now move on to the next square ---
+
+               ADD     R6,R6,R3                ;Add on the x increment
+               CMP     R6,R11                  ;Have we gone too far?
+               ADDLE   R5,R5,R3,LSL R0         ;No -- add on the palette val
+               BLE     %10rgb_plotSquare       ;And go round again
+
+               SUB     R7,R7,R4                ;Subtract the y increment
+               CMP     R7,R12                  ;Have we gone too far?
+               SUBGE   R5,R5,R4,LSL R1         ;No -- subtract palette val
+               BGE     %00rgb_plotSquare       ;And do the next row nicely
+
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               ; --- Fast colour setting routines ---
+
+20             MOV     R1,R5,LSR #8            ;Get hardware colour value
+               MOV     R0,#0                   ;Set the colour
+               SWI     OS_SetColour            ;Set the colour really
+               B       %15rgb_plotSquare       ;And return to main loop
+
+25             AND     R0,R5,#&F800            ;Get the red bits out
+               MOV     R1,R0,LSR #11           ;Shift them down
+               AND     R0,R5,#&F80000          ;Get the green bits
+               ORR     R1,R1,R0,LSR #14        ;Move them in nicely
+               AND     R0,R5,#&F8000000        ;Get the blue bits too
+               ORR     R1,R1,R0,LSR #17        ;Move them in too
+               MOV     R0,#0                   ;Set a raw colour
+               SWI     OS_SetColour            ;Set the colour nicely
+               B       %15rgb_plotSquare       ;And return to main loop
+
+30             MOV     R14,#3                  ;Mask bits off quickly
+               AND     R0,R14,R5,LSR #12       ;Get the red bits
+               AND     R1,R14,R5,LSR #20       ;Get the green bits
+               AND     R2,R14,R5,LSR #28       ;And the blue bits
+               ADD     R1,R1,R1,LSL #2         ;Multiply green by 5
+               ADD     R2,R2,R0,LSL #1         ;Mult red by 2 and add in
+               ADD     R2,R2,R1                ;And add in weighted green
+               MOV     R1,R2,LSR #3            ;Get weighted average
+
+               AND     R0,R5,#&00C00000        ;Get top two green bits
+               ORR     R1,R1,R0,LSR #17        ;Shift into position
+               TST     R5,#&00004000           ;Get red bit two
+               ORRNE   R1,R1,#&4               ;If set, set in colour
+               TST     R5,#&40000000           ;Get blue bit two
+               ORRNE   R1,R1,#&8               ;If set, set in colour
+               TST     R5,#&00008000           ;Get red bit three
+               ORRNE   R1,R1,#&10              ;If set, set in colour
+               TST     R5,#&80000000           ;Get blue bit three
+               ORRNE   R1,R1,#&80              ;If set, set in colour
+
+               MOV     R0,#0                   ;Set raw colour
+               SWI     OS_SetColour            ;Do the colour setting
+               B       %15rgb_plotSquare       ;And return to main loop
+               
+               LTORG
+
+; --- rgb__plot32k ---
+;
+; On entry:    R0 == left side of square to plot
+;              R1 == bottom of square to plot
+;              R2 == rotation number
+;              R3 == x step for rectangles
+;              R4 == y step for rectangles
+;              R5 == current z-value (in 16.16)
+;              R6 == pointer to graphics window block
+;              R7 == unlimited relative max y position to plot
+;              R8 == pointer to screen info block
+;              R10 == unlimited relative min x position to plot
+;              R11 == unlimited relative max x position to plot
+;              R12 == unlimited relative min y position to plot
+;              On stack: saved {R0-R12,R14}
+;
+; On exit:     --
+;
+; Use:         Displays an RGB square on the screen at a given location,
+;              in a 16bpp mode, using direct screen access (TM).
+
+rgb__plot32k   ROUT
+
+               ; --- Prologue: Limit the relative box positions ---
+
+               ADD     R8,R8,#screen_dx        ;Find the pixel positions
+               LDMIA   R8,{R8,R9}              ;Load them into registers
+
+               CMP     R10,#0                  ;Is min x too small?
+               MOVLT   R10,#0                  ;Yes -- raise it to 0
+               CMP     R12,#0                  ;Is min y too small?
+               MOVLT   R12,#0                  ;Yes --- raise that too
+               CMP     R11,#256                ;Is the max x too large?
+               MOVGT   R11,#256                ;Yes -- reduce it then
+               CMP     R7,#256                 ;Is the max y too large?
+               MOVGT   R7,#256                 ;Yes -- reduce it then
+               SUB     R11,R11,R8              ;Make this inclusive
+               SUB     R7,R7,R9                ;Make this inclusive too
+
+               ; --- Act 1: Find addresses of things on the screen ---
+
+               ADD     R9,R0,R10               ;Work out left hand side
+               ADD     R8,R1,R7                ;Work out top of area
+               SUB     R10,R11,R10             ;Work out width of area
+               SUB     R7,R7,R12               ;And the height too
+
+               SUB     R12,R9,R0               ;Work out left offset again
+               SUB     R11,R8,R1               ;And the top offset too
+
+               SUB     R13,R13,#20             ;Space for our vdu vars
+               ADR     R0,rgb__vduVars         ;Point to the var numbers
+               MOV     R1,R13                  ;Point to our output block
+               SWI     OS_ReadVduVariables     ;Get the values nicely
+
+               ; --- Interlude: Set up rectangle sizes ---
+
+               CMP     R3,#8                   ;Make sure rectangles are >8
+               MOVCC   R3,#8                   ;If not, make them bigger
+               MOVCC   R4,#8                   ;(Width and height the same)
+               MOV     R14,R3,LSR #3           ;Work out colour increment
+
+               ; --- Reprise: Convert measurements to pixels ---
+
+               LDMIA   R13!,{R0,R1}            ;Load the x and y eig things
+               MOV     R3,R3,LSR R0            ;Convert pixel counters
+               MOV     R4,R4,LSR R1            ;Convert other pixel counter
+               MOV     R9,R9,LSR R0            ;Convert left hand side
+               MOV     R10,R10,LSR R0          ;Convert width of area
+               MOV     R7,R7,LSR R1            ;Convert area height
+               MOV     R8,R8,LSR R1            ;And the top position
+
+               ; --- Intermission: Pack up pixel counters ---
+               ;
+               ; We pack all this into a word containing the following:
+               ;
+               ; bits 31-24 == x counter reset value
+               ; bits 23-20 == y counter initial value
+               ; bits 19-16 == x counter initial value
+               ; bits 15- 8 == y counter reset value
+               ; bits  7- 0 == colour step value
+               ;
+               ; Can anyone say `Z80 programming techniques'?
+
+               MOV     R12,R12,LSR R0          ;Get left offset in pixels
+               SUB     R6,R3,#1                ;Get the h pixel count -1
+               AND     R0,R12,R6               ;Get the remainder thing
+               SUB     R0,R3,R0                ;And get the correct offset
+
+               ORR     R3,R4,R3,LSL #16        ;Pack x and y counters
+               ORR     R3,R14,R3,LSL #8        ;And move in the colour inc
+
+               RSB     R14,R11,#256            ;Get offset from top
+               MOV     R11,R11,LSR R1          ;Turn offset into pixels
+               MOV     R1,R14,LSR R1           ;Get top offset in pixels
+               SUB     R1,R1,#1                ;Subtract one for niceness
+               SUB     R6,R4,#1                ;Get the v pixel count -1
+               AND     R1,R1,R6                ;Get the remainder thing
+               SUB     R1,R4,R1                ;And get the correct offset
+               ORR     R0,R0,R1,LSL #4         ;Pack into 1 byte
+
+               ORR     R3,R3,R0,LSL #16        ;Put in initial values too
+
+               LDMIA   R13!,{R0,R1,R6}         ;Load other vdu vars
+               SUB     R14,R1,R8               ;Shift origin to top left
+               MLA     R0,R14,R6,R0            ;Work out address of row
+               ADD     R9,R0,R9,LSL #1         ;Work out left address
+               ADD     R8,R9,R10,LSL #1        ;Work out right hand side too
+
+               ; --- Act 2: Set up colour information ---
+
+               AND     R14,R3,#&FF             ;Get the colour step value
+               BIC     R10,R3,#&FF             ;Move packed init values away
+               
+               RSB     R5,R5,R5,LSL #8         ;Multiply z value by 255
+               MOV     R5,R5,LSR #19           ;And make it 0-31
+
+               AND     R3,R10,#&FF000000       ;Get the x pixel count reinit
+               SUB     R3,R3,#&01000000        ;Turn it into a bitmask
+               BIC     R3,R12,R3,LSR #24       ;Round colour down nicely
+               LDR     R12,[R13,#-20]          ;Get the xeig factor
+               MOV     R3,R3,LSL R12           ;Shift colour up to OS units
+               MOV     R3,R3,LSR #3            ;Get the x colour in 0-31
+
+               AND     R4,R10,#&0000FF00       ;Get the y pixel count reinit
+               SUB     R4,R4,#&00000100        ;Turn it into a bitmask
+               BIC     R4,R11,R4,LSR #8        ;Round colour down nicely
+               LDR     R11,[R13,#-16]          ;Get the yeig factor
+               MOV     R4,R4,LSL R11           ;Shift colour up to OS units
+               MOV     R4,R4,LSR #3            ;And the y one too please
+
+               MOV     R12,#&1F                ;This is a useful value
+
+               CMP     R2,#0                   ;Is this the red rotation?
+               MOVEQ   R0,R5,LSL #16           ;Build the colour up...
+               ORREQ   R0,R0,R4,LSL #21        ;Still doing that...
+               ORREQ   R0,R0,R3,LSL #26        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #26           ;And the x-init value
+               MOVEQ   R3,R14,LSL #21          ;Get the y increment right
+               MOVEQ   R4,R14,LSL #26          ;And the x increment
+               MOVEQ   R5,R12,LSL #26          ;Get the x-clear mask
+
+               CMP     R2,#1                   ;Is this the green rotation?
+               MOVEQ   R0,R3,LSL #16           ;Build the colour up...
+               ORREQ   R0,R0,R5,LSL #21        ;Still doing that...
+               ORREQ   R0,R0,R4,LSL #26        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #16           ;And the x-init value
+               MOVEQ   R3,R14,LSL #26          ;Get the y increment right
+               MOVEQ   R4,R14,LSL #16          ;And the x increment
+               MOVEQ   R5,R12,LSL #16          ;Get the x-clear mask
+
+               CMP     R2,#2                   ;Is this the blue rotation?
+               MOVEQ   R0,R4,LSL #16           ;Build the colour up...
+               ORREQ   R0,R0,R3,LSL #21        ;Still doing that...
+               ORREQ   R0,R0,R5,LSL #26        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #21           ;Get the x-init value
+               MOVEQ   R3,R14,LSL #16          ;Get the y increment right
+               MOVEQ   R4,R14,LSL #21          ;And the x increment
+               MOVEQ   R5,R12,LSL #21          ;Get the x-clear mask
+
+               ; --- Act 3. Initialise the pixel counts ---
+
+               MOV     R14,#&F                 ;For reading nibbles
+               AND     R12,R14,R10,LSR #16     ;Get the initial x value
+               AND     R2,R14,R10,LSR #20      ;Get the initial y value too
+               ORR     R2,R10,R2               ;Put that into the count reg
+               SWI     OS_EnterOS              ;Avoid problems with PhysMem
+
+               ; --- Act 4. Plot the bloody thing ---
+
+10rgb__plot32k MOV     R10,R9                  ;Get the current address
+               MOV     R11,#0                  ;Clear the buffer value
+               STMFD   R13!,{R12}              ;Save the x count value
+
+               ; --- Start plotting this row ---
+
+               TST     R10,#2                  ;Is this address aligned?
+               BEQ     %20rgb__plot32k         ;Yes -- start at main loop
+               LDR     R14,[R10,#-2]           ;No -- load word from here
+               MOV     R14,R14,LSL #16         ;Shift all the way up
+               ORR     R14,R0,R14,LSR #16      ;Build the replacement word
+               STR     R14,[R10,#-2]           ;And store in frame buffer
+               B       %25rgb__plot32k         ;Jump to end of loop
+
+               ; --- Main row plotting loop (time critical :-) ) ---
+
+20rgb__plot32k ORR     R11,R0,R11,LSR #16      ;Add colour into buffer
+               TST     R10,#2                  ;Is this an odd address?
+               STRNE   R11,[R10,#-2]           ;Yes -- done both halfwords
+
+25rgb__plot32k ADD     R10,R10,#2              ;Move on to next pixel
+               CMP     R10,R8                  ;Have we finished yet?
+               BHI     %30rgb__plot32k         ;No -- do the rest then
+               SUBS    R12,R12,#1              ;Decrement pixel counter
+               ADDEQ   R0,R0,R4                ;If cleared, add on colour
+               MOVEQ   R12,R2,LSR #24          ;And reinitialise counter
+               B       %20rgb__plot32k         ;Go round for more
+
+               ; --- We've finished; do we have a halfword left over? ---
+
+30rgb__plot32k TST     R10,#2                  ;Is the address odd?
+               LDRNE   R14,[R10,#-2]           ;Yes -- read the old word
+               MOVNE   R11,R11,LSR #16         ;Get buffer value in low hw
+               MOVNE   R14,R14,LSR #16         ;Get screen value in low hw
+               ORRNE   R14,R11,R14,LSL #16     ;Build correct word to write
+               STRNE   R14,[R10,#-2]           ;Store this word away
+
+               ; --- Now move on to the next row ---
+
+               LDMFD   R13!,{R12}              ;Unstack initial x counter
+               ADD     R9,R9,R6                ;Move start address down 1
+               ADD     R8,R8,R6                ;Move end address down 1
+               BIC     R0,R0,R5                ;Clear the x colour section
+               ORR     R0,R0,R1                ;Reintialise the x colour
+               SUB     R2,R2,#1                ;Decrement y counter
+               TST     R2,#&FF                 ;Is it now zero?
+               BICEQ   R2,R2,#&00FF0000        ;Clear unused byte in word
+               ORREQ   R2,R2,R2,LSR #8         ;Yes -- reinitialise
+               SUBEQ   R0,R0,R3                ;And increment the y colour
+               SUBS    R7,R7,#1                ;Decrement scan line counter
+               BCS     %10rgb__plot32k         ;And go back up again
+
+               TEQP    PC,#0                   ;Return to user mode
+               MOV     R0,R0                   ;Keep ARM ecstatically happy
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+rgb__vduVars   DCD     4,5                     ;X and Y eigen factors
+               DCD     149                     ;Start of display memory
+               DCD     12                      ;How high is the screen
+               DCD     6                       ;Width of scan line in pixels
+               DCD     -1
+
+               LTORG
+
+; --- rgb__plot16m ---
+;
+; On entry:    R0 == left side of square to plot
+;              R1 == bottom of square to plot
+;              R2 == rotation number
+;              R3 == x step for rectangles
+;              R4 == y step for rectangles
+;              R5 == current z-value (in 16.16)
+;              R6 == pointer to graphics window block
+;              R7 == unlimited relative max y position to plot
+;              R8 == pointer to screen info block
+;              R10 == unlimited relative min x position to plot
+;              R11 == unlimited relative max x position to plot
+;              R12 == unlimited relative min y position to plot
+;              On stack: saved {R0-R12,R14}
+;
+; On exit:     --
+;
+; Use:         Displays an RGB square on the screen at a given location,
+;              in a 32bpp mode, using direct screen access (TM).
+
+rgb__plot16m   ROUT
+
+               ; --- Prologue: Limit the relative box positions ---
+
+               ADD     R8,R8,#screen_dx        ;Find the pixel positions
+               LDMIA   R8,{R8,R9}              ;Load them into registers
+
+               CMP     R10,#0                  ;Is min x too small?
+               MOVLT   R10,#0                  ;Yes -- raise it to 0
+               CMP     R12,#0                  ;Is min y too small?
+               MOVLT   R12,#0                  ;Yes --- raise that too
+               CMP     R11,#256                ;Is the max x too large?
+               MOVGT   R11,#256                ;Yes -- reduce it then
+               CMP     R7,#256                 ;Is the max y too large?
+               MOVGT   R7,#256                 ;Yes -- reduce it then
+               SUB     R11,R11,R8              ;Make this inclusive
+               SUB     R7,R7,R9                ;Make this inclusive too
+
+               ; --- Act 1: Find addresses of things on the screen ---
+
+               ADD     R9,R0,R10               ;Work out left hand side
+               ADD     R8,R1,R7                ;Work out top of area
+               SUB     R10,R11,R10             ;Work out width of area
+               SUB     R7,R7,R12               ;And the height too
+
+               SUB     R12,R9,R0               ;Work out left offset again
+               SUB     R11,R8,R1               ;And the top offset too
+
+               SUB     R13,R13,#20             ;Space for our vdu vars
+               ADR     R0,rgb__vduVars         ;Point to the var numbers
+               MOV     R1,R13                  ;Point to our output block
+               SWI     OS_ReadVduVariables     ;Get the values nicely
+
+               ; --- Reprise: Convert measurements to pixels ---
+
+               LDMIA   R13!,{R0,R1}            ;Load the x and y eig things
+               MOV     R3,R3,LSR R0            ;Convert pixel counters
+               MOV     R4,R4,LSR R1            ;Convert other pixel counter
+               MOV     R9,R9,LSR R0            ;Convert left hand side
+               MOV     R10,R10,LSR R0          ;Convert width of area
+               MOV     R7,R7,LSR R1            ;Convert area height
+               MOV     R8,R8,LSR R1            ;And the top position
+
+               ; --- Intermission: Pack up pixel counters ---
+               ;
+               ; We pack all this into a word containing the following:
+               ;
+               ; bits 31-24 == x counter reset value
+               ; bits 23-20 == y counter initial value
+               ; bits 19-16 == x counter initial value
+               ; bits 15- 8 == y counter reset value
+               ; bits  7- 0 == colour step value
+               ;
+               ; Can anyone say `Z80 programming techniques'?
+
+               MOV     R12,R12,LSR R0          ;Get left offset in pixels
+               SUB     R6,R3,#1                ;Get the h pixel count -1
+               AND     R0,R12,R6               ;Get the remainder thing
+               SUB     R0,R3,R0                ;And get the correct offset
+
+               ORR     R3,R4,R3,LSL #16        ;Pack x and y counters
+               MOV     R3,R3,LSL #8            ;Move that up one byte
+
+               RSB     R14,R11,#256            ;Get offset from top
+               MOV     R11,R11,LSR R1          ;Turn offset into pixels
+               MOV     R1,R14,LSR R1           ;Get top offset in pixels
+               SUB     R1,R1,#1                ;Subtract one for niceness
+               SUB     R6,R4,#1                ;Get the v pixel count -1
+               AND     R1,R1,R6                ;Get the remainder thing
+               SUB     R1,R4,R1                ;And get the correct offset
+               ORR     R0,R0,R1,LSL #4         ;Pack into 1 byte
+
+               ORR     R3,R3,R0,LSL #16        ;Put in initial values too
+
+               LDMIA   R13!,{R0,R1,R6}         ;Load other vdu vars
+               SUB     R14,R1,R8               ;Shift origin to top left
+               MLA     R0,R14,R6,R0            ;Work out address of row
+               ADD     R9,R0,R9,LSL #2         ;Work out left address
+               ADD     R8,R9,R10,LSL #2        ;Work out right hand side too
+
+               ; --- Act 2: Set up colour information ---
+
+               BIC     R10,R3,#&FF             ;Move packed init values away
+               
+               RSB     R5,R5,R5,LSL #8         ;Multiply z value by 255
+               MOV     R5,R5,LSR #16           ;And make it 0-255
+
+               AND     R3,R10,#&FF000000       ;Get the x pixel count reinit
+               SUB     R3,R3,#&01000000        ;Turn it into a bitmask
+               BIC     R3,R12,R3,LSR #24       ;Round colour down nicely
+               LDR     R12,[R13,#-20]          ;Get the xeig factor
+               MOV     R3,R3,LSL R12           ;Shift colour up to OS units
+               AND     R14,R10,#&FF000000      ;Get the x reinit value
+               MOV     R14,R14,LSR #24         ;Bring it down to earth
+               MOV     R14,R14,LSL R12         ;And turn into OS units
+
+               AND     R4,R10,#&0000FF00       ;Get the y pixel count reinit
+               SUB     R4,R4,#&00000100        ;Turn it into a bitmask
+               BIC     R4,R11,R4,LSR #8        ;Round colour down nicely
+               LDR     R12,[R13,#-16]          ;Get the yeig factor
+               MOV     R4,R4,LSL R12           ;Shift colour up to OS units
+               AND     R11,R10,#&0000FF00      ;Get the y reinit value
+               MOV     R11,R11,LSR #8          ;Bring it down to earth
+               MOV     R11,R11,LSL R12         ;And turn into OS units
+
+               MOV     R12,#&FF                ;This is a useful value
+
+               CMP     R2,#0                   ;Is this the red rotation?
+               MOVEQ   R0,R5,LSL #0            ;Build the colour up...
+               ORREQ   R0,R0,R4,LSL #8         ;Still doing that...
+               ORREQ   R0,R0,R3,LSL #16        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #16           ;And the x-init value
+               MOVEQ   R3,R11,LSL #8           ;Get the y increment right
+               MOVEQ   R4,R14,LSL #16          ;And the x increment
+               MOVEQ   R5,R12,LSL #16          ;Get the x-clear mask
+
+               CMP     R2,#1                   ;Is this the green rotation?
+               MOVEQ   R0,R3,LSL #0            ;Build the colour up...
+               ORREQ   R0,R0,R5,LSL #8         ;Still doing that...
+               ORREQ   R0,R0,R4,LSL #16        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #0            ;And the x-init value
+               MOVEQ   R3,R11,LSL #16          ;Get the y increment right
+               MOVEQ   R4,R14,LSL #0           ;And the x increment
+               MOVEQ   R5,R12,LSL #0           ;Get the x-clear mask
+
+               CMP     R2,#2                   ;Is this the blue rotation?
+               MOVEQ   R0,R4,LSL #0            ;Build the colour up...
+               ORREQ   R0,R0,R3,LSL #8         ;Still doing that...
+               ORREQ   R0,R0,R5,LSL #16        ;Almost finished now...
+               MOVEQ   R1,R3,LSL #8            ;Get the x-init value
+               MOVEQ   R3,R11,LSL #0           ;Get the y increment right
+               MOVEQ   R4,R14,LSL #8           ;And the x increment
+               MOVEQ   R5,R12,LSL #8           ;Get the x-clear mask
+
+               ; --- Act 3. Initialise the pixel counts ---
+
+               MOV     R14,#&F                 ;For reading nibbles
+               AND     R12,R14,R10,LSR #16     ;Get the initial x value
+               AND     R2,R14,R10,LSR #20      ;Get the initial y value too
+               ORR     R2,R10,R2               ;Put that into the count reg
+
+               ; --- Act 4. Plot the bloody thing ---
+
+               SWI     OS_EnterOS              ;Avoid problems with PhysMem    
+
+10rgb__plot16m MOV     R10,R9                  ;Get the current address
+               MOV     R11,R12                 ;Initialise the x counter
+               
+               ; --- Main row plotting loop (time critical :-) ) ---
+
+20rgb__plot16m STR     R0,[R10],#4             ;Store this pixel
+
+25rgb__plot16m CMP     R10,R8                  ;Have we finished yet?
+               BHI     %30rgb__plot16m         ;No -- do the rest then
+               SUBS    R11,R11,#1              ;Decrement pixel counter
+               ADDEQ   R0,R0,R4                ;If cleared, add on colour
+               MOVEQ   R11,R2,LSR #24          ;And reinitialise counter
+               B       %20rgb__plot16m         ;Go round for more
+
+               ; --- We've finished; move on to next row ---
+
+30rgb__plot16m ADD     R9,R9,R6                ;Move start address down 1
+               ADD     R8,R8,R6                ;Move end address down 1
+               BIC     R0,R0,R5                ;Clear the x colour section
+               ORR     R0,R0,R1                ;Reintialise the x colour
+               SUB     R2,R2,#1                ;Decrement y counter
+               TST     R2,#&FF                 ;Is it now zero?
+               BICEQ   R2,R2,#&00FF0000        ;Clear unused byte in word
+               ORREQ   R2,R2,R2,LSR #8         ;Yes -- reinitialise
+               SUBEQ   R0,R0,R3                ;And increment the y colour
+               SUBS    R7,R7,#1                ;Decrement scan line counter
+               BCS     %10rgb__plot16m         ;And go back up again
+
+               TEQP    PC,#0                   ;Return to user mode
+               MOV     R0,R0                   ;Keep ARM ecstatically happy
+               LDMFD   R13!,{R0-R12,PC}^       ;Return to caller
+
+               LTORG
+
+; --- rgb__plotHair ---
+;
+; On entry:    R2 == x coordinate of cross
+;              R3 == y coordinate of cross
+;
+; On exit:     --
+;
+; Use:         Plots the crosshair on an RGB colour square to mark the
+;              current position nicely.
+
+rgb__plotHair  ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               MOV     R0,#4                   ;Move cursor absolute
+               MOV     R1,R2                   ;Get the x coordinate
+               SUB     R2,R3,#256              ;Move down a little bit
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#2                   ;Plot in logical inverse (!)
+               MOV     R1,#0                   ;No x movement please
+               MOV     R2,#512                 ;And plot upwards
+               SWI     OS_Plot                 ;Plot the vertical line
+
+               MOV     R0,#0                   ;Move cursor relative
+               MOV     R1,#-256                ;Move back a bit
+               MOV     R2,#-256                ;Move down a bit
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#2                   ;Plot in logical inverse (!)
+               MOV     R1,#512                 ;Plot the cross beam
+               MOV     R2,#0                   ;No y movement please
+               SWI     OS_Plot                 ;Plot the horizontal line
+
+               MOV     R0,#0                   ;Move cursor relative
+               MOV     R1,#-256                ;Move back a bit
+               MOV     R2,#0                   ;Move back to centre
+               SWI     OS_Plot                 ;Move the cursor there
+               MOV     R0,#146                 ;Circle relative
+               MOV     R1,#16                  ;Radius 16
+               MOV     R2,#0                   ;Don't screw up calculation
+               SWI     OS_Plot                 ;Plot the circle
+
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Custom dbx controls --------------------------------------------------
+
+; --- rgbSquare ---
+
+rgbSquare      ROUT
+
+               DCD     0,0
+               DCD     dbxMask_redraw + dbxMask_update + dbxMask_click
+
+               CMP     R0,#dbxEvent_update     ;Is it an update event?
+               BEQ     %10rgbSquare            ;Yes -- handle it
+               CMP     R0,#dbxEvent_click      ;Is it a click event?
+               BEQ     %20rgbSquare            ;Yes -- handle it
+
+               ; --- Deal with a redraw event ---
+
+               STMFD   R13!,{R0-R6,R10,R14}    ;Save some registers
+               MOV     R10,R8                  ;Get dbox data in R10
+               STMFD   R13!,{R2,R3}            ;Save bottom left corner
+
+               ; --- Sort out the resolution ---
+
+               BL      cs_resolution           ;Get the current resolution
+               CMP     R0,#0                   ;Is it pixel-level?
+               BLEQ    screen_getInfo          ;Yes -- get screen info
+               ADDEQ   R0,R0,#screen_dx        ;Point to the pixel size
+               LDMEQIA R0,{R3,R4}              ;And load the values
+               ADRNE   R14,rgb__resTable       ;Otherwise point at the table
+               ADDNE   R14,R14,R0              ;Find the correct entry
+               LDRNEB  R3,[R14,#0]             ;Load the square size
+               MOVNE   R4,R3                   ;And do it in both directions
+
+               ; --- Sort out the z value too ---
+
+               LDR     R0,rgb__zPos            ;Get the z slider value
+               MOV     R0,R0,LSL #16           ;Convert to 16.16 form
+               ADD     R0,R0,#50               ;Make it round to nearest
+               BL      div10                   ;Divide it by 10
+               BL      div10                   ;And again -- div by 100
+               MOV     R5,R0                   ;This is the z coordinate
+
+               ; --- Call the main plot code ---
+
+               LDMFD   R13!,{R0,R1}            ;Load the bottom left corner
+               LDR     R2,rgb__mapping         ;Get the colour mapping
+               BL      rgb_plotSquare          ;Do the plotting
+               LDMFD   R13!,{R0-R6,R10,R14}    ;Drop through to update code
+
+               ; --- Plot the crosshair as part of update ---
+
+10rgbSquare    STMFD   R13!,{R0-R5,R10,R14}    ;Save some registers
+               MOV     R10,R8                  ;Find my workspace address
+               SUB     R4,R4,R2                ;Get the icon width
+               SUB     R5,R5,R3                ;And the height
+               LDR     R0,rgb__xPos            ;Load cached x position
+               MUL     R0,R4,R0                ;Scale it to the width
+               ADD     R0,R0,#50               ;Round to nearest on divide
+               BL      div10                   ;And divide down
+               BL      div10                   ;And divide down again
+               ADD     R2,R2,R0                ;Find the x cross position
+               LDR     R0,rgb__yPos            ;Load cached y position
+               MUL     R0,R5,R0                ;Scale it to the height
+               ADD     R0,R0,#50               ;Round to nearest on divide
+               BL      div10                   ;And divide down
+               BL      div10                   ;And divide down again
+               ADD     R3,R3,R0                ;Find the y cross position
+               BL      rgb__plotHair           ;Plot the crosshair nicely
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;And return to caller
+
+rgb__resTable  DCB     0,4,8,16
+
+               ; --- Handle click events on the square ---
+
+20rgbSquare    TST     R2,#5                   ;Is it a real button click?
+               MOVEQS  PC,R14                  ;No -- ignore it then
+               STMFD   R13!,{R0-R5,R10,R14}    ;Save some registers
+
+               ; --- Start the drag operation ---
+
+               MOV     R0,R10                  ;Get dialogue handle
+               BL      dbx_controlBBox         ;Get the bonding box nicely
+               BL      dbox_window             ;Get the window handle
+               MOV     R1,#7                   ;User drag type
+               SUB     R13,R13,#56             ;Make a drag box on the stack
+               STMIA   R13,{R0,R1}             ;Save them away nicely
+               ADD     R14,R13,#24             ;Point to parent box
+               STMIA   R14,{R2-R5}             ;Save the bounding box here
+               MOV     R1,R13                  ;Point to my block
+               SWI     Wimp_DragBox            ;Set up the drag nicely
+               ADD     R13,R13,#56             ;Reclaim the stack space
+
+               ; --- Set up the handlers nicely ---
+
+               MOV     R10,R8                  ;Point to dbox data in R10
+               ADR     R0,rgb__ukEvents        ;Point to unknown handler
+               MOV     R1,#0                   ;Don't care about R4
+               MOV     R2,R10                  ;Pass dbox data in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_unknownHandler      ;Register the handler
+               MOVVC   R0,#2                   ;Call every TV frame
+               ADRVC   R1,rgb__idles           ;Point to the idle handler
+               BLVC    idle_handler            ;Register that too
+               BL      rgb__idles              ;Call idle handler now
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;Return to caller
+
+               LTORG
+
+; --- rgb__idles ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Handles idle events during a drag in the colour square.
+
+rgb__idles     ROUT
+
+               STMFD   R13!,{R0-R5,R10,R14}    ;Save some registers
+               LDR     R0,cs__modelDb          ;Get the dialogue box
+               MOV     R1,#rgbIcon__square     ;Get my icon handle
+               BL      dbx_controlBBox         ;Get my bounding box nicely
+               SUB     R13,R13,#20             ;Get a pointer block
+               MOV     R1,R13                  ;Point at it nicely
+               SWI     Wimp_GetPointerInfo     ;Find the pointer posn
+               LDMIA   R13,{R0,R1}             ;Load pointer coordinates
+               ADD     R13,R13,#20             ;Recover that block
+
+               ; --- Work out the new cross position ---
+
+               SUB     R4,R4,R2                ;Work out the icon width
+               SUB     R5,R5,R3                ;And the icon height
+               SUB     R2,R0,R2                ;Work out the x offset
+               SUB     R3,R1,R3                ;And the y offset
+
+               ADD     R2,R2,R2,LSL #2         ;Multiply x by 5
+               ADD     R2,R2,R2,LSL #2         ;Multiply x by 5 (x25)
+               MOV     R2,R2,LSL #2            ;Multiply x by 4 (x100)
+
+               ADD     R3,R3,R3,LSL #2         ;Multiply y by 5
+               ADD     R3,R3,R3,LSL #2         ;Multiply y by 5 (x25)
+               MOV     R3,R3,LSL #2            ;Multiply y by 4 (x100)
+
+               MOV     R0,R2                   ;Get the x value
+               MOV     R1,R4                   ;And the icon width
+               BL      div_round               ;Divide to get percentage
+               STR     R0,rgb__sl1Val          ;Save the x position
+
+               MOV     R0,R3                   ;Get the y value
+               MOV     R1,R5                   ;And the icon height
+               BL      div_round               ;Divide to get percentage
+               STR     R0,rgb__sl2Val          ;Save the y position
+
+               BL      rgb__xyUpdate           ;Redraw crosshairs if reqd
+               LDR     R0,cs__modelDb          ;Get the dialogue handle
+               MOV     R1,#rgbIcon__slide1     ;Get slider 1's number
+               BL      dbx_update              ;Redraw it quickly
+               MOV     R1,#rgbIcon__slide2     ;Get slider 2's number
+               BL      dbx_update              ;Redraw it quickly
+               BL      rgb__colUpdate          ;Redraw the colour button
+
+               ; --- Now update the correct icons ---
+
+               ADRL    R5,rgb__writeTbl+2      ;Point to icon number table
+               LDR     R14,rgb__mapping        ;And get the current mappiing
+               ADD     R5,R5,R14               ;Find the correct entry
+
+               LDRB    R1,[R5,#0]              ;Load the x icon
+               LDR     R2,rgb__sl1Val          ;Get the new x value
+               BL      numWrite_set            ;Put it in the icon
+               LDRB    R1,[R5,#-1]             ;Load the y icon
+               LDR     R2,rgb__sl2Val          ;Get the new y value
+               BL      numWrite_set            ;Put it in the icon
+               LDMFD   R13!,{R0-R5,R10,PC}^    ;And return to caller
+
+               LTORG
+
+; --- rgb__ukEvents ---
+;
+; On entry:    R0 == event code
+;
+; On exit:     CS if handled
+;
+; Use:         Handles unknown events during a drag in the RGB colour
+;              square.
+
+rgb__ukEvents  ROUT
+
+               CMP     R0,#7                   ;Is it a drag over event?
+               MOVNES  PC,R14                  ;No -- then return to caller
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               BL      rgb__idles              ;Get one last drag position
+               ADR     R0,rgb__ukEvents        ;Point to unknown handler
+               MOV     R1,#0                   ;Don't care about R4
+               MOV     R2,R10                  ;Pass dbox data in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      win_removeUnknownHandler ;Deregister the handler
+               MOVVC   R0,#2                   ;Call every TV frame
+               ADRVC   R1,rgb__idles           ;Point to the idle handler
+               BLVC    idle_removeHandler      ;Deregister that too
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Icon numbers ---------------------------------------------------------
+
+rgbIcon__square        EQU     0                       ;The main colour square
+rgbIcon__slide1        EQU     1                       ;The x slider (slider 1)
+rgbIcon__slide2        EQU     2                       ;The y slider (slider 2)
+rgbIcon__slide3        EQU     3                       ;The z slider (slider 3)
+
+rgbIcon__radioR        EQU     4                       ;The `Red' radio button
+rgbIcon__writeR        EQU     5                       ;The `Red' writable area
+rgbIcon__upR   EQU     6                       ;The `Red' up arrow button
+rgbIcon__downR EQU     7                       ;The `Red' down arrow button
+
+rgbIcon__radioG        EQU     9                       ;The `Green' radio button
+rgbIcon__writeG        EQU     10                      ;The `Green' writable area
+rgbIcon__upG   EQU     11                      ;The `Green' up arrow button
+rgbIcon__downG EQU     12                      ;The `Green' down arrow buttn
+
+rgbIcon__radioB        EQU     14                      ;The `Blue' radio button
+rgbIcon__writeB        EQU     15                      ;The `Blue' writable area
+rgbIcon__upB   EQU     16                      ;The `Blue' up arrow button
+rgbIcon__downB EQU     17                      ;The `Blue' down arrow button
+
+rgbIcon__wCols EQU     20                      ;Base of the WIMP colours
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/SapphToys/!DrawX/!Boot,feb b/StraySrc/SapphToys/!DrawX/!Boot,feb
new file mode 100644 (file)
index 0000000..0fa9710
--- /dev/null
@@ -0,0 +1,12 @@
+|
+| DrawX 1.xx !Boot file
+|
+| © 1994 Straylight
+|
+| This file version 1.00 (20 March 1994)
+|
+
+Set DrawX$Dir <Obey$Dir>
+IconSprites <DrawX$Dir>.!Sprites
+Set File$Type_AFF DrawFile
+Set Alias$@RunType_AFF Run <DrawX$Dir>.!Run %%*0
diff --git a/StraySrc/SapphToys/!DrawX/!Help b/StraySrc/SapphToys/!DrawX/!Help
new file mode 100644 (file)
index 0000000..56b6f97
--- /dev/null
@@ -0,0 +1,74 @@
+               ____
+              |    \   ___  ___         \  /
+              |     \ |     ___) | | (   ><
+              |_____/ |    (___( |_|__) /  \
+
+             ©   1 9 9 4   S t r a y l i g h t
+___________________________________________________________
+
+                        About DrawX
+
+DrawX is, essentially, a pointless utility.  It displays
+DrawFiles in windows and allows you to scale them, and save
+them into other applications.  It is slightly quicker at
+displaying DrawFiles than Draw is, but does the job no
+better, and is nowhere near as good as ArtWorks.  It
+provides no editing or organisational facilities, and is,
+in short, utterly useless in itself.
+
+So why have I just spent the last two days writing it?
+
+DrawX is a demonstration of Straylight's development tools
+and libraries.  It is written entirely in ARM assembler.
+It uses our Sapphire library.  Its templates were created
+using Glass.  It shows what can be done in two days of hard
+work and tedious debugging with a powerful library like
+Sapphire.
+
+It's also a way thumbing my nose at Acorn a bit for putting
+their DrawEx program in the C development system and trying
+to pretend it's a good thing to model your applications on:
+
+* It only allows one view at a time, unless you hack it.
+  Admittedly, this is a fairly good exercise.
+
+* The RAM loading is done very badly, but then again, what
+  do you expect when the documentation for xferrecv is so
+  awful?
+
+* It doesn't allow you to zoom in and out of the DrawFiles.
+
+* It doesn't support Help, which Acorn insists everything
+  must do.
+
+* It's far too big.  The image is 70K (that's my hacked one
+  which does do multiple windows).
+
+DrawX deals with all of these points.  It allows any number
+of windows to be open.  It does all its data transfer
+properly.  It does do zooming, with fit-to-screen and
+fit-to-window options and a zoom drag box too.  It supports
+Help on all its windows, and for menus under RISC OS 3.10
+and higher.  And the final image is 48K in size
+(uncompressed) so it's only slightly over half the size of
+DrawEx.  Compressed, the image is only 28K.
+
+Lastly, DrawX is a fairly good example of how to write
+Sapphire applications. It does everything a big application
+should do, only less so.  It conforms as fully to STASIS
+(our user interface standard) as I can make it.  In fact,
+it does so much that I had to change some bits of the
+library to allow it to work at all.  The only bad thing it
+does is to be all in one source file.  I never expected it
+to be quite as big as it is (over 2100 lines), but then
+again, we live and learn.
+
+I hope DrawX provides you with as much usefulness as it has
+provided me.  That won't be too difficult.  I can't imagine
+ever using it at all.
+                         _________
+
+                            Mark Wooding
+                            Straylight Development Centre
+                            23 August 1994
+___________________________________________________________
diff --git a/StraySrc/SapphToys/!DrawX/!Run,feb b/StraySrc/SapphToys/!DrawX/!Run,feb
new file mode 100644 (file)
index 0000000..77c61fc
--- /dev/null
@@ -0,0 +1,34 @@
+|
+| DrawX 1.xx !Run file
+|
+| © 1994 Straylight
+|
+| This file version 1.00 (20 March 1994)
+|
+
+Set DrawX$Dir <Obey$Dir>
+IconSprites <DrawX$Dir>.!Sprites
+Set File$Type_AFF DrawFile
+Set Alias$@RunType_AFF Run <DrawX$Dir>.!Run %%*0
+
+/<DrawX$Dir>.setSlot -appName DrawX 28K 4K 4K
+
+If "<System$Path>"="" Then Error 0 System resources could not be found.  Please double-click a !System folder and reload.
+
+If "<Wimp$Scrap>"="" Then Error 0 Couldn't find Scrap folder.  Please double click a !Scrap folder (or !System if you don't have !Scrap) and reload.
+
+If "<DLL$Path>"="" Then Error 0 Couldn't find Dynamic Link libraries.  Please double click a !DLLs folder and reload.
+
+Set Alias$_RMEnsure RMEnsure %%0 0.00 RMLoad %%2 |m RMEnsure %%0 %%1
+_RMEnsure DLLManager 1.14 <DLL$Dir>.DLLManager
+_RMEnsure Sculptrix 2.01 <DrawX$Dir>.Modules.Sculptrix
+_RMEnsure Sprinkle 1.00 <DrawX$Dir>.Modules.Sprinkle
+_RMEnsure ColourTrans 0.53 System:Modules.Colours
+Unset Alias$_RMEnsure
+
+DLLEnsure [Sapphire.Core] 0.00
+DLLEnsure [Sapphire.Resources] 1.00
+
+/<DrawX$Dir>.setSlot -appName DrawX 28K 4K 4K
+
+Run <DrawX$Dir>.!RunImage %*0
\ No newline at end of file
diff --git a/StraySrc/SapphToys/!DrawX/!Sprites,ff9 b/StraySrc/SapphToys/!DrawX/!Sprites,ff9
new file mode 100644 (file)
index 0000000..8a402df
Binary files /dev/null and b/StraySrc/SapphToys/!DrawX/!Sprites,ff9 differ
diff --git a/StraySrc/SapphToys/!DrawX/Choices b/StraySrc/SapphToys/!DrawX/Choices
new file mode 100644 (file)
index 0000000..623e0e6
--- /dev/null
@@ -0,0 +1,7 @@
+;
+; DrawX options
+;
+
+[DrawX]
+DefaultScale=100
+
diff --git a/StraySrc/SapphToys/!DrawX/Makefile,fe1 b/StraySrc/SapphToys/!DrawX/Makefile,fe1
new file mode 100644 (file)
index 0000000..ead801d
--- /dev/null
@@ -0,0 +1,373 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: !RunImage Modules.Sculptrix Modules.Sprinkle setSlot
+
+!RunImage: o.drawx libs:lib.sapphdll
+       $(SETDATE) o.version version="1.03 ($(DATE))" cright="$(CRIGHT)"
+       $(LD_APP) o.drawx o.version libs:lib.sapphdll
+       $(SQUEEZE)
+       $(SET_APP)
+
+Modules.Sculptrix: <SSR$ModDir>.Sculptrix
+       $(INSTALL) <SSR$ModDir>.Sculptrix Modules
+
+Modules.Sprinkle: <SSR$ModDir>.Sprinkle
+       $(INSTALL) <SSR$ModDir>.Sprinkle Modules
+
+setSlot: <SSR$BinDir>.setSlot
+       $(INSTALL) <SSR$BinDir>.setSlot @
+
+install:
+
+clean:
+       -$(RM) o.* !RunImage Modules.Sculptrix setSlot
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.drawx: s.drawx
+o.drawx: libs:header
+o.drawx: libs:swis
+o.drawx: libs:stream
+o.drawx: sapphire:sapphire
+o.drawx: sapphire:akbd
+o.drawx: sapphire:alloc
+o.drawx: sapphire:banner
+o.drawx: sapphire:buttons
+o.drawx: sapphire:cmdLine
+o.drawx: sapphire:dbox
+o.drawx: sapphire:defHandler
+o.drawx: sapphire:divide
+o.drawx: sapphire:drag
+o.drawx: sapphire:draw
+o.drawx: sapphire:errorBox
+o.drawx: sapphire:event
+o.drawx: sapphire:fastMove
+o.drawx: sapphire:flex
+o.drawx: sapphire:heap
+o.drawx: sapphire:help
+o.drawx: sapphire:hour
+o.drawx: sapphire:ibicon
+o.drawx: sapphire:idle
+o.drawx: sapphire:intKeys
+o.drawx: sapphire:libOpts
+o.drawx: sapphire:mbox
+o.drawx: sapphire:menu
+o.drawx: sapphire:menuDefs
+o.drawx: sapphire:msgs
+o.drawx: sapphire:progInfo
+o.drawx: sapphire:ptr
+o.drawx: sapphire:report
+o.drawx: sapphire:res
+o.drawx: sapphire:resources
+o.drawx: sapphire:screen
+o.drawx: sapphire:string
+o.drawx: sapphire:warning
+o.drawx: sapphire:wimp
+o.drawx: sapphire:win
+o.drawx: sapphire:winUtils
+o.drawx: sapphire:choices.choices
+o.drawx: sapphire:choices.options
+o.drawx: sapphire:choices.prefs
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:dbx.arrow
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:dbx.numWrite
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:xfer.load
+o.drawx: sapphire:xfer.save
+o.drawx: sapphire:xfer.saveAs
+o.drawx: s.drawx
+o.drawx: libs:header
+o.drawx: libs:swis
+o.drawx: libs:stream
+o.drawx: sapphire:sapphire
+o.drawx: sapphire:akbd
+o.drawx: sapphire:alloc
+o.drawx: sapphire:banner
+o.drawx: sapphire:buttons
+o.drawx: sapphire:cmdLine
+o.drawx: sapphire:dbox
+o.drawx: sapphire:defHandler
+o.drawx: sapphire:divide
+o.drawx: sapphire:drag
+o.drawx: sapphire:draw
+o.drawx: sapphire:errorBox
+o.drawx: sapphire:event
+o.drawx: sapphire:fastMove
+o.drawx: sapphire:flex
+o.drawx: sapphire:heap
+o.drawx: sapphire:help
+o.drawx: sapphire:hour
+o.drawx: sapphire:ibicon
+o.drawx: sapphire:idle
+o.drawx: sapphire:intKeys
+o.drawx: sapphire:libOpts
+o.drawx: sapphire:mbox
+o.drawx: sapphire:menu
+o.drawx: sapphire:menuDefs
+o.drawx: sapphire:msgs
+o.drawx: sapphire:progInfo
+o.drawx: sapphire:ptr
+o.drawx: sapphire:report
+o.drawx: sapphire:res
+o.drawx: sapphire:resources
+o.drawx: sapphire:screen
+o.drawx: sapphire:string
+o.drawx: sapphire:warning
+o.drawx: sapphire:wimp
+o.drawx: sapphire:win
+o.drawx: sapphire:winUtils
+o.drawx: sapphire:choices.choices
+o.drawx: sapphire:choices.options
+o.drawx: sapphire:choices.prefs
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:dbx.arrow
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:dbx.numWrite
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:xfer.load
+o.drawx: sapphire:xfer.save
+o.drawx: sapphire:xfer.saveAs
+o.drawx: s.drawx
+o.drawx: libs:header
+o.drawx: libs:swis
+o.drawx: libs:stream
+o.drawx: sapphire:sapphire
+o.drawx: sapphire:akbd
+o.drawx: sapphire:alloc
+o.drawx: sapphire:banner
+o.drawx: sapphire:buttons
+o.drawx: sapphire:cmdLine
+o.drawx: sapphire:dbox
+o.drawx: sapphire:defHandler
+o.drawx: sapphire:divide
+o.drawx: sapphire:drag
+o.drawx: sapphire:draw
+o.drawx: sapphire:errorBox
+o.drawx: sapphire:event
+o.drawx: sapphire:fastMove
+o.drawx: sapphire:flex
+o.drawx: sapphire:heap
+o.drawx: sapphire:help
+o.drawx: sapphire:hour
+o.drawx: sapphire:ibicon
+o.drawx: sapphire:idle
+o.drawx: sapphire:intKeys
+o.drawx: sapphire:libOpts
+o.drawx: sapphire:mbox
+o.drawx: sapphire:menu
+o.drawx: sapphire:menuDefs
+o.drawx: sapphire:msgs
+o.drawx: sapphire:progInfo
+o.drawx: sapphire:ptr
+o.drawx: sapphire:report
+o.drawx: sapphire:res
+o.drawx: sapphire:resources
+o.drawx: sapphire:screen
+o.drawx: sapphire:string
+o.drawx: sapphire:warning
+o.drawx: sapphire:wimp
+o.drawx: sapphire:win
+o.drawx: sapphire:winUtils
+o.drawx: sapphire:choices.choices
+o.drawx: sapphire:choices.options
+o.drawx: sapphire:choices.prefs
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:dbx.arrow
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:dbx.numWrite
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:xfer.load
+o.drawx: sapphire:xfer.save
+o.drawx: sapphire:xfer.saveAs
+o.drawx: s.drawx
+o.drawx: libs:header
+o.drawx: libs:swis
+o.drawx: libs:stream
+o.drawx: sapphire:sapphire
+o.drawx: sapphire:akbd
+o.drawx: sapphire:alloc
+o.drawx: sapphire:banner
+o.drawx: sapphire:buttons
+o.drawx: sapphire:cmdLine
+o.drawx: sapphire:dbox
+o.drawx: sapphire:defHandler
+o.drawx: sapphire:divide
+o.drawx: sapphire:drag
+o.drawx: sapphire:draw
+o.drawx: sapphire:errorBox
+o.drawx: sapphire:event
+o.drawx: sapphire:fastMove
+o.drawx: sapphire:flex
+o.drawx: sapphire:heap
+o.drawx: sapphire:help
+o.drawx: sapphire:hour
+o.drawx: sapphire:ibicon
+o.drawx: sapphire:idle
+o.drawx: sapphire:intKeys
+o.drawx: sapphire:libOpts
+o.drawx: sapphire:mbox
+o.drawx: sapphire:menu
+o.drawx: sapphire:menuDefs
+o.drawx: sapphire:msgs
+o.drawx: sapphire:progInfo
+o.drawx: sapphire:ptr
+o.drawx: sapphire:report
+o.drawx: sapphire:res
+o.drawx: sapphire:resources
+o.drawx: sapphire:screen
+o.drawx: sapphire:string
+o.drawx: sapphire:warning
+o.drawx: sapphire:wimp
+o.drawx: sapphire:win
+o.drawx: sapphire:winUtils
+o.drawx: sapphire:choices.choices
+o.drawx: sapphire:choices.options
+o.drawx: sapphire:choices.prefs
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:dbx.arrow
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:dbx.numWrite
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:xfer.load
+o.drawx: sapphire:xfer.save
+o.drawx: sapphire:xfer.saveAs
+o.drawx: s.drawx
+o.drawx: libs:header
+o.drawx: libs:swis
+o.drawx: libs:stream
+o.drawx: sapphire:sapphire
+o.drawx: sapphire:akbd
+o.drawx: sapphire:alloc
+o.drawx: sapphire:banner
+o.drawx: sapphire:buttons
+o.drawx: sapphire:cmdLine
+o.drawx: sapphire:dbox
+o.drawx: sapphire:defHandler
+o.drawx: sapphire:divide
+o.drawx: sapphire:drag
+o.drawx: sapphire:draw
+o.drawx: sapphire:errorBox
+o.drawx: sapphire:event
+o.drawx: sapphire:fastMove
+o.drawx: sapphire:flex
+o.drawx: sapphire:heap
+o.drawx: sapphire:help
+o.drawx: sapphire:hour
+o.drawx: sapphire:ibicon
+o.drawx: sapphire:idle
+o.drawx: sapphire:intKeys
+o.drawx: sapphire:libOpts
+o.drawx: sapphire:mbox
+o.drawx: sapphire:menu
+o.drawx: sapphire:menuDefs
+o.drawx: sapphire:msgs
+o.drawx: sapphire:progInfo
+o.drawx: sapphire:ptr
+o.drawx: sapphire:report
+o.drawx: sapphire:res
+o.drawx: sapphire:resources
+o.drawx: sapphire:screen
+o.drawx: sapphire:string
+o.drawx: sapphire:warning
+o.drawx: sapphire:wimp
+o.drawx: sapphire:win
+o.drawx: sapphire:winUtils
+o.drawx: sapphire:choices.choices
+o.drawx: sapphire:choices.options
+o.drawx: sapphire:choices.prefs
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:dbx.arrow
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:dbx.numWrite
+o.drawx: sapphire:dbx.dbx
+o.drawx: sapphire:xfer.load
+o.drawx: sapphire:xfer.save
+o.drawx: sapphire:xfer.saveAs
diff --git a/StraySrc/SapphToys/!DrawX/Resources/Messages b/StraySrc/SapphToys/!DrawX/Resources/Messages
new file mode 100644 (file)
index 0000000..47799d1
--- /dev/null
@@ -0,0 +1,74 @@
+;
+; DrawX messages
+;
+; © 1994 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; DrawX is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; DrawX is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with DrawX.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+piHELP:This window shows you information about this version of DrawX.
+drxPUR:Quick DrawFile viewer
+
+; --- Menus ---
+
+drxIMINFO:Info...
+drxIMQUIT:Quit
+
+drxhIM0:Click or move pointer right to see information about DrawX.
+drxhIM1:Click here to quit DrawX.
+
+drxMMINFO:Info...
+drxMMSAVE:Save...
+drxMMSCALE:Set scale...
+
+drxhMM0:Click or move pointer right to see information about the DrawFile in this window.
+drxhMM1:Click or move pointer right to save the DrawFile in this window.
+drxhMM2:Click or move pointer right to set the scale at which the DrawFile in the window is viewed.
+
+; --- The Scale dialogue ---
+
+drxhSCALE:This is the Scale dialogue box.
+drxhSCWRT:Type the scale you want in here.
+drxhSCUP:Click here to increase the scale.
+drxhSCDOWN:Click here to decrease the scale.
+drxhSCBUT:Click here to set the scale to %0.
+drxhSCSCN:Click here to scale the diagram so it just fits on the screen.
+drxhSCWIN:Click here to scale the diagram so it just fits in the window at its current size.
+drxhOK:Click here to accept the settings in this dialogue box.
+
+; --- Data transfer ---
+
+drxDEFN:DrawFile
+drxCSII:You can't save a DrawFile into itself.
+drxSVTB:Save DrawFile
+drxELF:Couldn't load file: %0
+drxESF:Couldn't save file: %0
+drxCWRT:File '%0' already exists.  Are you sure you want to replace it?
+drxRPL:Replace
+
+; --- Diagram management ---
+
+drxNEWERR:Couldn't create new diagram: %0
+drxUNT:<Untitled>
+
+; --- Other help messages ---
+
+drxhIB:This is the DrawX icon.|mClick here to open a new blank window.  Drop a DrawFile here to display it.  Click Menu to display the icon bar menu.
+
+drxhDIAG:This is a DrawX diagram window.|mDrag Select to zoom.  Click Menu to display the menu, which allows you to save the DrawFile or set its scale.  Drop a DrawFile here to view it in this window.
+
+drxhFINFO:This window shows you information about the DrawFile being viewed.
diff --git a/StraySrc/SapphToys/!DrawX/Resources/Sprites,ff9 b/StraySrc/SapphToys/!DrawX/Resources/Sprites,ff9
new file mode 100644 (file)
index 0000000..3208625
Binary files /dev/null and b/StraySrc/SapphToys/!DrawX/Resources/Sprites,ff9 differ
diff --git a/StraySrc/SapphToys/!DrawX/Resources/Templates,fec b/StraySrc/SapphToys/!DrawX/Resources/Templates,fec
new file mode 100644 (file)
index 0000000..c12a601
Binary files /dev/null and b/StraySrc/SapphToys/!DrawX/Resources/Templates,fec differ
diff --git a/StraySrc/SapphToys/!DrawX/s/drawX b/StraySrc/SapphToys/!DrawX/s/drawX
new file mode 100644 (file)
index 0000000..63b0aeb
--- /dev/null
@@ -0,0 +1,2192 @@
+
+; drawX.s
+;
+; An example of various Sapphire features (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; DrawX is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; DrawX is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with DrawX.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Notes ----------------------------------------------------------------
+;
+; This application is a DrawFile viewer -- not even slightly useful in
+; itself (although it uses the same amount of memory as Draw needs
+; workspace!), but it does provide quite a neat demonstration of the
+; following Sapphire features, and provides examples of how to use them:
+;
+; * dialogue boxes and custom dialogue box controls (arrow and numWrite)
+; * error handling
+; * memory management
+; * drawfile rendering
+; * data transfer
+; * menu handling
+; * command line processing
+; * loading preferences
+;
+; It demonstrates dragging objects inside windows -- the code is fairly
+; similar in structure to Glass's drag code, except that in the interests
+; of keeping code size down I've not done rotating dash boxes.
+;
+; The other interesting feature exhibited is that the image for this
+; application is just over half the size of the Acorn equivalent `DrawEx',
+; which (a) doesn't support multiple drawfiles unless you hack it, (b)
+; doesn't do zooming or dragging, and (c) doesn't support Help.
+;
+;                                                      Mark Wooding
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               ; --- Sapphire ---
+
+               GET     sapphire:sapphire
+
+               GET     sapphire:akbd
+               GET     sapphire:alloc
+               GET     sapphire:banner
+               GET     sapphire:buttons
+               GET     sapphire:cmdLine
+               GET     sapphire:dbox
+               GET     sapphire:defHandler
+               GET     sapphire:divide
+               GET     sapphire:drag
+               GET     sapphire:draw
+               GET     sapphire:errorBox
+               GET     sapphire:event
+               GET     sapphire:fastMove
+               GET     sapphire:flex
+               GET     sapphire:heap
+               GET     sapphire:help
+               GET     sapphire:hour
+               GET     sapphire:ibicon
+               GET     sapphire:idle
+               GET     sapphire:intKeys
+               GET     sapphire:libOpts
+               GET     sapphire:mbox
+               GET     sapphire:menu
+               GET     sapphire:menuDefs
+               GET     sapphire:msgs
+               GET     sapphire:progInfo
+               GET     sapphire:ptr
+               GET     sapphire:report
+               GET     sapphire:res
+               GET     sapphire:resources
+               GET     sapphire:screen
+               GET     sapphire:string
+               GET     sapphire:warning
+               GET     sapphire:wimp
+               GET     sapphire:win
+               GET     sapphire:winUtils
+
+               GET     sapphire:choices.choices
+               GET     sapphire:choices.options
+               GET     sapphire:choices.prefs
+
+               GET     sapphire:dbx.dbx
+               GET     sapphire:dbx.arrow
+               GET     sapphire:dbx.numWrite
+
+               GET     sapphire:xfer.load
+               GET     sapphire:xfer.save
+               GET     sapphire:xfer.saveAs
+
+               ; --- Other external symbols ---
+
+               IMPORT  version
+               IMPORT  cright
+
+;----- Constants ------------------------------------------------------------
+
+               ; --- Icon numbers ---
+
+bnr__version   EQU     4                       ;The version display area
+bnr__slider    EQU     6                       ;The progress slider bar
+
+scale__write   EQU     0                       ;The scale writable icon
+scale__up      EQU     1                       ;The scale up arrow button
+scale__down    EQU     2                       ;The scale down arrow button
+scale__toScreen        EQU     4                       ;The Scale to screen action
+scale__toWindow        EQU     5                       ;The Scale to window action
+scale__buttons EQU     6                       ;The 8 set scale buttons
+scale__ok      EQU     14                      ;And the OK button
+
+info__name     EQU     1                       ;The DrawFile name area
+info__size     EQU     3                       ;The file size area
+
+               ; --- Menu items ---
+
+im__info       EQU     0                       ;The program info option
+im__quit       EQU     1                       ;The quit application option
+
+mm__info       EQU     0                       ;The file info option
+mm__save       EQU     1                       ;The save drawfile option
+mm__scale      EQU     2                       ;The scale option
+
+               ; --- Other constants ---
+
+drawX__topY    EQU     940                     ;Maximum height for diagrams
+drawX__bottomY EQU     700                     ;Minimum height for diagrams
+drawX__startY  EQU     844                     ;Initial height for diagrams
+
+drawX__filetype        EQU     &AFF                    ;The filetype of a DrawFile
+
+;----- Data structures ------------------------------------------------------
+
+               ; --- Window blocks ---
+
+               ^       0
+dWin__window   #       4                       ;The window handle
+dWin__flags    #       4                       ;Various flags
+dWin__diagram  #       4                       ;Flex anchor for diagram
+dWin__diagSize #       4                       ;Size of the diagram
+dWin__scale    #       4                       ;Scale of diagram (as 16.16)
+dWin__extent   #       16                      ;The window's extent size
+dWin__filename #       256                     ;The diagram's filename
+dWin__titleBar #       256                     ;The diagram's title buffer
+dWin__size     #       0
+
+dwFlag__loaded EQU     (1<<0)                  ;File has a good filename
+dwFlag__hasDiag        EQU     (1<<1)                  ;There is an actual diagram
+dwFlag__saving EQU     (1<<2)                  ;This diagram is being saved
+dwFlag__tent   EQU     (1<<3)                  ;Diagram block is tentative
+
+               ; --- Preferences data ---
+
+               ^       0
+dPref__defScale        #       4                       ;Default document scale
+dPref__size    #       0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+drawX__wStart  #       4
+
+drawX__prefs   #       dPref__size             ;User's preferences
+drawX__winY    #       4                       ;y position for next window
+drawX__flags   #       4                       ;Various interesting flags
+drawX__pollBlk #       256                     ;The main polling block
+
+dxFlag__drag   EQU     (1<<0)                  ;In midst of drag operation
+dxFlag__ownPtr EQU     (1<<1)                  ;We own the mouse pointer
+
+drawX__wSize   EQU     {VAR}-drawX__wStart
+
+;----- Initialisation -------------------------------------------------------
+
+               AREA    |Client$$Code|,CODE,READONLY
+               ENTRY
+
+drawX__main    ROUT
+
+               ; --- Start up the library ---
+
+               ADR     R0,drawX__appName       ;Point to application name
+               MOV     R1,#drawX__wSize        ;Get my workspace size
+               MOV     R2,#0                   ;Default stack size
+               BL      sapphire_init           ;Initialise the library
+               BL      resources_init          ;Use shared resource DLL
+               BL      hour_init               ;Initialise hourglass system
+               BL      hour_on                 ;Turn on hourglass as needed
+
+               MOV     R0,#0                   ;This is the first pass
+               BL      drawX__cmdLine          ;Read the command line
+               SWICS   OS_Exit                 ;If helped, return to caller
+
+               ; --- Do various bits of initialisation ---
+
+               ADR     R0,drawX__banner        ;Point to banner block
+               MOV     R1,R12                  ;Pass setup code my R12 value
+               BL      banner                  ;Initialise the library
+               BL      drawX__init             ;Initialise workspace
+               BL      drawX__iconbar          ;Put the icon on the iconbar
+               BL      drawX__getPrefs         ;Load the preferences
+               BL      heap_useHeap            ;Allocate things from heap
+               BL      ptr_blinkOn             ;Enable caret blinking
+               MOV     R0,#1                   ;This is the second pass
+               BL      drawX__cmdLine          ;Parse the command line
+
+               ; --- Enter the main loop ---
+
+               BL      drawX__errors           ;Set up the error return pt
+00drawX__main  MOV     R0,#1                   ;Don't use idles pointlessly
+               ADR     R1,drawX__pollBlk       ;Point to my poll block
+               BL      event_poll              ;Get an event and handle it
+               BLCC    drawX__unknowns         ;Handle any unknown events
+               BLCC    defHandler              ;Supply a default action
+               B       %00drawX__main          ;And go round for another one
+
+drawX__appName DCB     "DrawX",0
+
+drawX__banner  BANNER
+               BNSLIDE bnr__slider
+               BNSETUP drawX__bnrSetup
+               BNEND
+
+; --- drawX__errors ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Sets up the error handler to return to this routine's return
+;              address
+
+drawX__errors  ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               BIC     R0,R14,#&FC000003       ;Set up the resume address
+               MOV     R1,R12                  ;Set up workspace on return
+               ADD     R2,R13,#16              ;And set up return stack ptr
+               BL      report_register         ;Set up the return point
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- drawX__init ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Initialises DrawX's workspace.
+
+drawX__init    ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+               MOV     R14,#drawX__startY      ;Default diagram height
+               STR     R14,drawX__winY         ;Save the y coordinate
+               MOV     R14,#0                  ;Clear the flags word
+               STR     R14,drawX__flags        ;Store that away
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- drawX__bnrSetup ---
+;
+; On entry:    R0 == banner dialogue handle
+;
+; On exit:     --
+;
+; Use:         Fills in fields of the opening banner dialogue box.
+
+drawX__bnrSetup        ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R1,#bnr__version        ;Get the version icon
+               LDR     R2,=version             ;Find the version string
+               BL      dbox_setField           ;Fill in the icon nicely
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- drawX__getPrefs ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Loads the application's preferences file.
+
+drawX__getPrefs        ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+
+               ; --- Initialise the preferences area ---
+
+               ADR     R0,drawX__prefs         ;Point to prefs buffer
+               ADR     R1,drawX__defaults      ;Point to default values
+               MOV     R2,#dPref__size         ;Size of the data
+               BL      fastMove                ;Initialise the buffer
+
+               ; --- Now read in the preferences ---
+
+               BL      prefs_find              ;Find the prefs chunk file
+               ADR     R1,drawX__appName       ;Use my name as the chunk
+               ADR     R2,drawX__optDefs       ;Point to options definition
+               ADR     R3,drawX__prefs         ;Point to preferences buffer
+               MOV     R4,#-1                  ;It's not in a flex block
+               BL      options_read            ;Read the preferences
+
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+drawX__defaults        DCD     100                     ;Initialise default scale
+
+drawX__optDefs OPTINT  dPref__defScale,"DefaultScale"
+               OPTEND
+
+               LTORG
+
+; --- drawX__cmdLine ---
+;
+; On entry:    R0 == 0 for first pass, 1 for second pass
+;
+; On exit:     CS if help given, CC otherwise
+;
+; Use:         Parses the DrawX command line, loading documents as required.
+
+drawX__cmdLine ROUT
+
+               STMFD   R13!,{R0-R4,R10,R14}    ;Save a load of registers
+               MOV     R4,R0                   ;Look after pass flag
+               SWI     OS_GetEnv               ;Find the command line
+               MOV     R1,R11                  ;Build in the scratchpad
+               BL      cl_next                 ;Skip the application name
+               BCC     %90drawX__cmdLine       ;If nothing there, skip
+               MOV     R3,R0                   ;Look after the cmdline ptr
+
+               ; --- The main parsing loop ---
+
+00             MOV     R0,R3                   ;Point to command line
+               ADR     R1,drawX__pollBlk       ;Build in the poll block
+               BL      cl_next                 ;Get next word from cmdline
+               BCC     %90drawX__cmdLine       ;If nothing there, skip
+
+               MOV     R3,R0                   ;Keep place in string
+               ADR     R0,drawX__cmdTable      ;Point to keyword table
+               BL      str_match               ;Find which name matches
+               ADDCS   PC,PC,R0,LSL #2         ;If match, use branch table
+               B       %05drawX__cmdLine       ;If no match, load file
+
+               B       %10drawX__cmdLine       ;Give help to the user
+               B       %15drawX__cmdLine       ;Enable Choices support
+               B       %20drawX__cmdLine       ;Use a Dynamic Area
+
+               ; --- Load a file ---
+
+05             TST     R4,#1                   ;Which pass is this?
+               BEQ     %00drawX__cmdLine       ;First -- don't load then
+
+               MOV     R0,R1                   ;Point to filename again
+               MOV     R10,#0                  ;No diagram handle yet
+               BL      drawX__loadFile         ;Try loading the file
+               BLVC    drawX__loaded           ;If loaded, make it nice
+               MOVVS   R1,#1                   ;Otherwise set up error
+               BLVS    drawX__loadFail         ;And tidy up after it
+               B       %00drawX__cmdLine       ;And parse more command line
+
+               ; --- Give command line help ---
+
+10             ADR     R0,drawX__cmdHelp       ;Point to command line help
+               MOV     R1,#0                   ;Use internal dictionary
+               LDR     R2,=version             ;Find my version string
+               SWI     OS_PrettyPrint          ;Print the string
+               ORR     R4,R4,#2                ;Remember we gave some help
+               B       %00drawX__cmdLine       ;And parse more command line
+
+               ; --- Enable the Choices application ---
+
+15             TST     R4,#1                   ;Is this the first pass?
+               MOVEQ   R0,#1                   ;Set Choices support on
+               BLEQ    choices_useChoices      ;Turn the support on
+               B       %00drawX__cmdLine       ;And parse more command line
+
+               ; --- Enable use of Dynamic Areas ---
+
+20             TST     R4,#1                   ;Is this the first pass?
+               ADREQ   R0,drawX__opts          ;Yes -- point to options
+               BLEQ    libOpts_register        ;And register them
+               B       %00drawX__cmdLine       ;And parse more command line
+
+               ; --- Return to caller nicely ---
+
+90             TST     R4,#2                   ;Did we give any help?
+               LDMFD   R13!,{R0-R4,R10,R14}    ;Restore registers
+               ORRNES  PC,R14,#C_flag          ;If so, set C flag on exit
+               BICEQS  PC,R14,#C_flag          ;Otherwise clear it
+
+drawX__cmdTable        DCB     "-help",0
+               DCB     "-choices",0
+               DCB     "-dynArea",0
+               DCB     0
+
+drawX__cmdHelp DCB     "DrawX v. ",27,0,13
+               DCB     13
+               DCB     "Usage: *DrawX [<options>] [<filename>]...",13
+               DCB     13
+               DCB     "Options allowed are:",13
+               DCB     13
+               DCB     "-choices",9,"Store options in Acorn's `Choices' "
+               DCB     "directory",13
+               DCB     "-dynArea",9,"Use a Dynamic Area for memory "
+               DCB     "management",13
+               DCB     0
+
+drawX__opts    LIBOPT  "FLEX"                  ;Tell flex to use a dynamic
+               DCD     1                       ;area if it can
+               LOEND
+
+               LTORG
+
+;----- The icon bar ---------------------------------------------------------
+
+; --- drawX__iconbar ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Installs the DrawX icon on the icon bar
+
+drawX__iconbar ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Save some registers
+               ADR     R0,drawX__sprName       ;Point to the sprite name
+               MOV     R1,#0                   ;No text required
+               MOV     R2,#-1                  ;Left hand side of iconbar
+               MOV     R3,#0                   ;Standard priority please
+               ADR     R4,drawX__ibHandler     ;Point to my event handler
+               MOV     R5,#0                   ;No value in R10
+               MOV     R6,R12                  ;Pass workspace in R12
+               BL      ibicon_create           ;Create the icon
+               SWIVS   OS_GenerateError        ;If it failed, kill the app
+               LDMFD   R13!,{R0-R6,PC}^        ;Return to caller
+
+drawX__sprName DCB     "!drawx",0
+
+               LTORG
+
+; --- drawX__ibHandler ---
+;
+; On entry:    R0 == icon bar event type
+;              R1-R9 == dependent on event type
+;
+; On exit:     --
+;
+; Use:         Handles events directed at the icon bar.
+
+drawX__ibHandler ROUT
+
+               CMP     R0,#ibEvent_help        ;Is it an event I recognise?
+               ADDLS   PC,PC,R0,LSL #2         ;Yes -- dispatch to handler
+               MOVS    PC,R14                  ;Otherwise return to caller
+
+               B       drawX__ibSelect         ;Handle a mouse click
+               B       drawX__ibMenu           ;Handle a Menu click
+               MOVS    PC,R14                  ;Ignore Adjust clicks
+               B       drawX__ibData           ;Handle a data save
+               B       drawX__ibData           ;Handle a data load
+               B       drawX__ibHelp           ;Handle help requests
+
+               ; --- Handle Select clicks on the icon ---
+
+drawX__ibSelect        STMFD   R13!,{R0,R1,R10,R14}    ;Save the link register
+               MOV     R0,#0                   ;No filename for the diagram
+               BL      drawX__newDiag          ;Create a new diagram
+               BLVC    drawX__setTitle         ;Set the window's title
+               BLVC    drawX__open             ;Open the window nicely
+               BLVC    drawX__cascade          ;If it worked, do cascading
+               MOVVS   R1,#1                   ;Otherwise report the error
+               BLVS    errorBox                ;With just an OK button
+               LDMFD   R13!,{R0,R1,R10,PC}^    ;Return to caller
+
+               ; --- Handle data transfer to the icon ---
+
+drawX__ibData  STMFD   R13!,{R0,R1,R10,R14}    ;Save some registers
+               BL      event_last              ;Find the last event code
+               LDR     R0,[R1,#40]             ;Load the data filetype
+               MOV     R10,#0                  ;No diagram created currently
+               BL      drawX__load             ;Load the file
+               LDMFD   R13!,{R0,R1,R10,PC}^    ;Return to caller
+
+               ; --- Handle menu clicks on the icon ---
+
+drawX__ibMenu  STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               ADR     R0,drawX__imDef         ;Point to the icon bar menu
+               ADR     R1,drawX__imHnd         ;Point to the handler code
+               MOV     R2,R10                  ;Pass my R10 value along
+               MOV     R3,R12                  ;And my workspace pointer
+               BL      menu_create             ;And create the menu
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               ; --- Define the icon bar menu ---
+
+drawX__imDef   MENU    "DrawX"
+               ITEM    "drxIMINFO"
+               SUBWARN
+               ITEM    "drxIMQUIT"
+               MENUEND
+
+               ; --- Handle help requests ---
+
+drawX__ibHelp  STMFD   R13!,{R0,R14}           ;Save some registers
+               ADR     R0,drawX__ibHlpMsg      ;Point to the message tag
+               BL      msgs_lookup             ;Translate the message
+               BL      help_add                ;Add it to the help message
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+drawX__ibHlpMsg        DCB     "drxhIB",0
+
+               LTORG
+
+; --- drawX__imHnd ---
+;
+; On entry:    R0 == menu event code
+;              R1 == item number in menu
+;
+; On exit:     --
+;
+; Use:         Handles events for the icon bar menu.
+
+drawX__imHnd   ROUT
+
+               CMP     R0,#mEvent_help         ;Is it a help request?
+               BEQ     %50drawX__imHnd         ;Yes -- handle it nicely
+               CMP     R0,#mEvent_select       ;Is it a normal selection?
+               CMPNE   R0,#mEvent_subMenu      ;Or opening a submenu
+               MOVNES  PC,R14                  ;No -- ignore it then
+
+               ; --- Handle a menu selection event ---
+
+               CMP     R1,#im__quit            ;Is it the `Quit' option?
+               SWIEQ   OS_Exit                 ;Yes -- quit the program
+               CMP     R1,#im__info            ;Or is it the `Info' option?
+               MOVNES  PC,R14                  ;No -- ignore the event
+
+               ; --- Display info about DrawX ---
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADR     R0,drawX__purpose       ;Point to the purpose string
+               BL      msgs_lookup             ;Translate the message tag
+               LDR     R1,=cright              ;Point to copyright string
+               LDR     R2,=version             ;Find the version/date string
+               BL      progInfo                ;Display the dialogue box
+               MOVVS   R1,#1                   ;If it failed, report error
+               BLVS    errorBox                ;With just an OK button
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+drawX__purpose DCB     "drxPUR",0
+
+               ; --- Handle help requests for the menu ---
+
+50drawX__imHnd STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               ADR     R0,drawX__imHlpMsg      ;Point to the help string
+               BL      menu_help               ;Add message to help string
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+drawX__imHlpMsg        DCB     "drxhIM",0
+
+               LTORG
+
+;----- Scale dialogue box ---------------------------------------------------
+
+; --- drawX__scale ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Displays a dialogue box allowing the user to scale the
+;              a draw file.
+
+drawX__scale   ROUT
+
+               STMFD   R13!,{R0-R3,R9,R14}     ;Save some registers
+
+               ; --- Create the dialogue box ---
+
+               ADR     R0,drawX__scaledb       ;Point to the dialogue name
+               BL      dbox_create             ;Try to create the dialogue
+               MOVVS   R1,#1                   ;If it failed, report the
+               BLVS    errorBox                ;error and quit
+               BVS     %90drawX__scale
+               MOV     R9,R0                   ;Look after the dbox handle
+
+               ; --- Set up the handler ---
+
+               ADR     R1,drawX__scHnd         ;Point to the handler
+               MOV     R2,R10                  ;Pass the diagram in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      dbox_eventHandler       ;Set up the event handler
+
+               ADR     R1,drawX__scaleDbx      ;Point to the dbx def
+               BL      dbx_declare             ;Register the control types
+
+               ; --- Fill in the dialogue box ---
+
+               BL      drawX__fillScale        ;Fill in the scale
+
+               ; --- Display it on the screen ---
+
+               MOV     R1,#dbOpen_pointer+dbOpen_trans
+               BL      dbox_open               ;Display the dialogue box
+
+90drawX__scale LDMFD   R13!,{R0-R3,R9,PC}^     ;Return to caller
+
+drawX__scaledb DCB     "scale",0
+
+drawX__scaleDbx        NUMWRT  scale__write,1,800
+               ARROW   scale__up,1
+               ARROW   scale__down,-1
+               DBXEND
+
+; --- drawX__fillScale ---
+;
+; On entry:    R9 == dialogue box handle
+;              R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Resets the scale dialogue box.
+
+drawX__fillScale ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               LDR     R2,[R10,#dWin__scale]   ;Load the current scale
+               ADD     R2,R2,R2,LSL #2         ;Multiply it by 5 (x5)
+               ADD     R2,R2,R2,LSL #2         ;Multiply it by 5 (x25)
+               MOV     R2,R2,LSR #14           ;Divide it by 2^14
+               MOV     R1,#scale__write        ;Find the writable icon
+               MOV     R0,R9                   ;Get the dialogue handle
+               BL      numWrite_set            ;Set the field up nicely
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- drawX__scHnd ---
+;
+; On entry:    R0 == dialogue box event code
+;              R1-R7 == depend on the event
+;              R9 == dialogue box handle
+;              R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Handles events for the scale dialogue box.
+
+drawX__scHnd   ROUT
+
+               ; --- Dispatch interesting events ---
+
+               CMP     R0,#arrow_event         ;Is it an arrow click?
+               BEQ     %10drawX__scHnd         ;Yes -- handle it then
+               CMP     R0,#dbEvent_OK          ;Is it an OK click?
+               CMPNE   R0,#scale__ok
+               BEQ     %30drawX__scHnd         ;Yes -- handle it then
+               CMP     R0,#scale__toScreen     ;Is it the to screen button?
+               BEQ     %50drawX__scHnd         ;Yes -- handle it then
+               CMP     R0,#scale__toWindow     ;Is it the to window button?
+               BEQ     %60drawX__scHnd         ;Yes -- handle it then
+               CMP     R0,#dbEvent_close       ;Is it a close event?
+               BEQ     %90drawX__scHnd         ;Yes -- kill the dbox
+               CMP     R0,#dbEvent_help        ;Is it a help event?
+               BEQ     %95drawX__scHnd         ;Yes -- give the user help
+
+               ; --- It must be one of the standard scale buttons ---
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               SUBS    R1,R0,#scale__buttons   ;Get the first one's handle
+               CMP     R1,#8                   ;Is it in range?
+               LDMCSFD R13!,{R0-R2,PC}^        ;No -- return then
+
+               ADR     R2,drawX__stdScale      ;Point to the table
+               LDR     R2,[R2,R1,LSL #2]       ;Load the correct one
+               MOV     R1,R0                   ;Get the actual icon handle
+               MOV     R0,R9                   ;Get the dialogue box
+               BL      dbox_slab               ;Slab the button in nicely
+               MOV     R1,#scale__write        ;Find the writable icon
+               BL      numWrite_set            ;And fill it in nicely
+               BL      dbox_unslab             ;Unslab the button now
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+drawX__stdScale        DCD     33,50,66,80,100,120,200,400
+
+               ; --- Handle an arrow click ---
+
+10drawX__scHnd STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R1,#scale__write        ;Find the writable icon
+               MOV     R0,R9                   ;Get the dialogue box
+               BL      numWrite_bump           ;Bump the writable icon
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               ; --- Handle an OK click ---
+
+30drawX__scHnd STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R0,R9                   ;Get the dialogue box
+               MOV     R1,#scale__ok           ;Find the OK button
+               BL      dbox_slab               ;Slab the button nicely
+
+               MOV     R1,#scale__write        ;Find the writable icon
+               BL      numWrite_read           ;Read the icon value
+               CMP     R2,#1                   ;Is the value too small?
+               MOVLT   R2,#1                   ;Yes -- force it bigger
+               MOV     R0,R2,LSL #16           ;Scale the value up
+               ADD     R0,R0,#50               ;Make it round to nearest
+               BL      div10                   ;Divide by 10 quickly
+               BL      div10                   ;Divide by 10 again (/100)
+               STR     R0,[R10,#dWin__scale]   ;This is the new scale
+               BL      drawX__doScale          ;Set the scale nicely
+
+               LDR     R14,[R13,#4]            ;Load the button status
+               CMP     R14,#1                  ;Is this an Adjust click?
+               MOVNE   R0,R9                   ;Not Adjust -- get dbox
+               BLNE    dbox_close              ;Close the window
+               BL      dbox_unslab             ;Unslab the icon
+               BLNE    dbox_destroy            ;And destroy the dbox
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               ; --- Scale the diagram to the screen ---
+
+50drawX__scHnd STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R1,R0                   ;Get the icon handle
+               MOV     R0,R9                   ;Get the dialogue box
+               BL      dbox_slab               ;Slab the button
+
+               BL      screen_getInfo          ;Get the screen information
+               ADD     R14,R0,#screen_width    ;Find the screen sizes
+               LDMIA   R14,{R0,R1}             ;Load them out
+               SUB     R0,R0,#44               ;Lose the scroll bar width
+               SUB     R1,R1,#88               ;And the titlebar height
+               B       %70drawX__scHnd         ;Do the scaling stuff
+
+               ; --- Scale the diagram to the window ---
+
+60drawX__scHnd STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R1,R0                   ;Get the icon handle
+               MOV     R0,R9                   ;Get the dialogue box
+               BL      dbox_slab               ;Slab the button
+
+               LDR     R14,[R10,#dWin__window] ;Load the window handle
+               STR     R14,[R11,#0]            ;Save it in the scratchpad
+               MOV     R1,R11                  ;Point at it there
+               SWI     Wimp_GetWindowState     ;Find the window's info
+               LDMIB   R11,{R0-R3}             ;Load all the coordinates
+               SUB     R0,R2,R0                ;Get the window width
+               SUB     R1,R3,R1                ;Get the window height
+
+               ; --- Scale the diagram to fit in R0,R1 ---
+
+70drawX__scHnd LDR     R14,[R10,#dWin__diagram] ;Find the diagram
+               ADD     R14,R14,#24             ;Find the bounding box
+               LDMIA   R14,{R2-R5}             ;Load the coordinates out
+               SUB     R4,R4,R2                ;Get the diagram width
+               SUB     R5,R5,R3                ;And the height
+               SUB     R0,R0,#32               ;Compensate for the clearance
+               SUB     R1,R1,#32               ;On all four edges
+               MOV     R0,R0,LSL #16           ;Scale the target sizes up
+               MOV     R3,R1,LSL #16
+
+               MOV     R1,R4                   ;Get the original width
+               BL      div_round               ;Get the x scale factor
+               MOV     R2,R0,LSL #8            ;Look after this value
+
+               MOV     R0,R3                   ;Get the y target size
+               MOV     R1,R5                   ;And the original height
+               BL      div_round               ;Get the y scale factor
+
+               CMP     R2,R0,LSL #8            ;Which one's smaller?
+               MOVGT   R2,R0,LSL #8            ;Take that one
+               STR     R2,[R10,#dWin__scale]   ;This is the new scale
+               BL      drawX__doScale          ;Do everything nicely
+
+               LDR     R14,[R13,#4]            ;Load the button status
+               CMP     R14,#1                  ;Is this an Adjust click?
+               BLEQ    drawX__fillScale        ;Yes -- reset writable area
+               MOVNE   R0,R9                   ;Not Adjust -- get dbox
+               BLNE    dbox_close              ;Close the window
+               BL      dbox_unslab             ;Unslab the icon
+               BLNE    dbox_destroy            ;And destroy the dbox
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+               ; --- Close the dialogue box ---
+
+90drawX__scHnd STMFD   R13!,{R0,R14}           ;Save some registers
+               MOV     R0,R9                   ;Get the dialogue handle
+               BL      dbox_destroy            ;Destroy the dialogue box
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               ; --- Get some help on the dialogue ---
+
+95drawX__scHnd STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADR     R0,drawX__scHlpMsg      ;Point to the help message
+               BL      msgs_lookup             ;Translate it nicely
+               BL      help_add                ;Add it into the message
+               SUB     R14,R1,#scale__buttons  ;Subtract the buttons base
+               CMP     R14,#8                  ;Is it in range?
+               BCS     %96drawX__scHnd         ;No -- skip to the end
+               MOV     R0,R9                   ;Get the dialogue handle
+               BL      dbox_getField           ;Read the icon text
+               ADR     R0,drawX__scButMsg      ;Point to the help text
+               BL      msgs_lookup             ;Translate the message
+               MOV     R1,R11                  ;Build it in the scratchpad
+               BL      str_subst               ;Build the string up
+               BL      help_add                ;Add this to the help message
+96drawX__scHnd BL      dbox_help               ;Get icon-specific stuff
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+drawX__scHlpMsg        DCB     "drxhSCALE",0
+drawX__scButMsg        DCB     "drxhSCBUT",0
+
+               LTORG
+
+; --- drawX__doScale ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Sets the diagram scale.  The tricky bit is ensuring that
+;              the bit the user was looking at is still vaguely visible.
+;              We assume that he's looking at the centre of the window and
+;              do our best to keep that in the centre of the scaled view.
+
+drawX__doScale ROUT
+
+               STMFD   R13!,{R0-R7,R14}        ;Save some registers
+
+               ; --- Work out where the user's looking ---
+
+               LDR     R14,[R10,#dWin__window] ;Load the diagram window
+               SUB     R13,R13,#36             ;Make space for a window blk
+               STR     R14,[R13,#0]            ;Save it in the block
+               MOV     R1,R13                  ;Point to it there
+               SWI     Wimp_GetWindowState     ;Read its current position
+               LDMIB   R13,{R0-R5}             ;Load all that lot out
+               SUB     R6,R2,R0                ;Get the window width
+               ADD     R4,R4,R6,ASR #1         ;Find the horizontal centre
+               SUB     R7,R3,R1                ;Get the window height
+               SUB     R5,R5,R7,ASR #1         ;Find the vertical centre
+
+               ; --- Find where that is, relatively ---
+
+               ADD     R14,R10,#dWin__extent   ;Find the window extent
+               LDMIA   R14,{R0-R3}             ;Load that lot out
+               ADD     R0,R0,#16               ;Compensate for the border
+               ADD     R1,R1,#16
+               SUB     R2,R2,#16
+               SUB     R3,R3,#16
+               SUB     R4,R4,R0                ;Get pos rel. to wind left
+               SUB     R5,R5,R1                ;Get pos rel. to wind bottom
+               SUB     R2,R2,R0                ;Get window extent width
+               SUB     R3,R3,R1                ;Get window extent height
+
+               MOV     R0,R4,LSL #16           ;Scale up horizontal pos
+               MOV     R1,R2                   ;Get extent width
+               BL      div_round               ;Find the proportion nicely
+               MOV     R4,R0                   ;Look after it
+
+               MOV     R0,R5,LSL #16           ;Scale up vertical pos
+               MOV     R1,R3                   ;Get extent height
+               BL      div_round               ;Find the proportion nicely
+               MOV     R5,R0                   ;Look after that too
+
+               ; --- Reset the extent and redo the scroll stuff ---
+
+               BL      drawX__setExtent        ;Set the new extent
+               ADD     R14,R10,#dWin__extent   ;Find the new window extent
+               LDMIA   R14,{R0-R3}             ;Load that lot out
+               ADD     R0,R0,#16               ;Compensate for the border
+               ADD     R1,R1,#16
+               SUB     R2,R2,#16
+               SUB     R3,R3,#16
+               SUB     R2,R2,R0                ;Get the new extent width
+               SUB     R3,R3,R1                ;Get the new extent height
+               MUL     R2,R4,R2                ;Work out the new relative
+               MUL     R3,R5,R3                ;scroll positions
+               ADD     R4,R0,R2,ASR #16        ;And convert them to
+               ADD     R5,R1,R3,ASR #16        ;absolute ones
+               SUB     R4,R4,R6,ASR #1         ;And uncentre them
+               ADD     R5,R5,R7,ASR #1         ;
+
+               ; --- Scroll the window nicely ---
+
+               ADD     R14,R13,#20             ;Point to the scroll offsets
+               STMIA   R14,{R4,R5}             ;Save them in there
+               MOV     R1,R13                  ;Point to the block
+               SWI     Wimp_OpenWindow         ;Open the window
+               ADD     R13,R13,#36             ;Reclaim the stack space
+
+               ; --- Redraw the window ---
+
+               LDR     R0,[R10,#dWin__window]  ;Load the window handle
+               ADD     R14,R10,#dWin__extent   ;Find the window extent
+               LDMIA   R14,{R1-R4}             ;Load the coordinates out
+               SWI     Wimp_ForceRedraw        ;Redraw the whole view
+               LDMFD   R13!,{R0-R7,PC}^        ;Return to caller
+
+               LTORG
+
+; --- drawX__setExtent ---
+;
+; On entry:    R10 == a diagram handle
+;
+; On exit:     --
+;
+; Use:         Resets the diagram window's extent so that the diagram
+;              fits inside it at its current scale.
+
+drawX__setExtent ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               LDR     R14,[R10,#dWin__diagram] ;Find the diagram address
+               ADD     R14,R14,#24             ;Point to the bounding box
+               LDMIA   R14,{R1-R4}             ;Load them out nicely
+               LDR     R0,[R10,#dWin__scale]   ;Load the scale factor
+               MOV     R0,R0,LSR #8            ;Scale that down a bit
+               MUL     R1,R0,R1                ;Scale up all the positions
+               MUL     R2,R0,R2
+               MUL     R3,R0,R3
+               MUL     R4,R0,R4
+               MOV     R14,#16                 ;Add a gap round the edge
+               RSB     R1,R14,R1,ASR #16       ;And scale them back down
+               RSB     R2,R14,R2,ASR #16
+               ADD     R3,R14,R3,ASR #16
+               ADD     R4,R14,R4,ASR #16
+               ADD     R14,R10,#dWin__extent   ;Point to the extent block
+               STMIA   R14,{R1-R4}             ;Save them away there
+               LDR     R0,[R10,#dWin__window]  ;Load the window handle
+               ADD     R1,R10,#dWin__extent    ;Point to the coordinates
+               SWI     Wimp_SetExtent          ;Set the new extent
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- drawX__refresh ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Refreshes a diagram after changing its extent
+
+drawX__refresh ROUT
+
+               STMFD   R13!,{R0-R4,R14}
+               LDR     R0,[R10,#dWin__window]  ;Load the window handle
+               STR     R0,[R11,#0]             ;Save it in the scratchpad
+               MOV     R1,R11                  ;Point to it there
+               SWI     Wimp_GetWindowState     ;Get the window's position
+               SWI     Wimp_OpenWindow         ;Open the window there
+               LDR     R0,[R10,#dWin__window]  ;Load the window handle
+               ADD     R14,R10,#dWin__extent   ;Find the window's extent
+               LDMIA   R14,{R1-R4}             ;Load the coordinates
+               SWI     Wimp_ForceRedraw        ;And clear the window
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+;----- The main window handler ----------------------------------------------
+
+; --- drawX__newDiag ---
+;
+; On entry:    R0 == pointer to filename, or 0 for none
+;
+; On exit:     VC and R10 == pointer to a pristine new diagram structure, or
+;              VS and R0 == pointer to error, and R10 corrupted
+;
+; Use:         Creates a new diagram block and window, and opens it on
+;              the screen.
+
+drawX__newDiag ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Allocate a block of memory for the diagram ---
+
+               MOV     R0,#dWin__size          ;Get the size of the block
+               BL      alloc                   ;Try to get the memory
+               BLCS    alloc_error             ;If no memory, get error
+               BCS     %99drawX__newDiag       ;And tidy everything up
+               MOV     R10,R0                  ;Look after the block handle
+
+               ; --- Fill in the block and set things up ---
+
+               MOV     R14,#0                  ;No diagram currently
+               STR     R14,[R10,#dWin__diagram] ;So clear the diagram
+               LDR     R0,drawX__prefs+dPref__defScale
+               MOV     R0,R0,LSL #16           ;Scale it up
+               ADD     R0,R0,#50               ;Round to nearest
+               BL      div10                   ;And divide by 10
+               BL      div10                   ;And again -- now in 16.16
+               STR     R0,[R10,#dWin__scale]   ;And save that too
+               MOV     R0,#0                   ;Left hand side
+               MOV     R1,#0                   ;Bottom edge
+               MOV     R2,#640                 ;Right hand side
+               MOV     R3,#512                 ;Top edge
+               ADD     R14,R10,#dWin__extent   ;Point to the extent block
+               STMIA   R14,{R0-R3}             ;Save the initial extent
+               MOV     R3,#0                   ;No flags currently
+
+               ; --- Work out the file's name ---
+
+               LDR     R0,[R13,#0]             ;Load the filename pointer
+               CMP     R0,#0                   ;Is it defined properly?
+               ORRNE   R3,R3,#dwFlag__loaded   ;Yes -- say the file's loaded
+               ADREQ   R0,drawX__untitled      ;No -- point to default
+               BLEQ    msgs_lookup             ;And translate the message
+               MOV     R1,R0                   ;This is the source string
+               ADD     R0,R10,#dWin__filename  ;Point to filename buffer
+               BL      str_cpy                 ;Copy it in there nicely
+
+               STR     R3,[R10,#dWin__flags]   ;Save the flags word away
+
+               ; --- Now create a new window ---
+
+               MOV     R0,R11                  ;Point at the scratchpad
+               ADR     R1,drawX__winDef        ;Point at the window def
+               MOV     R2,#drawX__winSize      ;Get the size of the window
+               BL      fastMove                ;Copy it to the scratchpad
+
+               LDMIB   R11,{R0-R2}             ;Load top and bottom y
+               SUB     R0,R2,R0                ;Get height in R0
+               LDR     R2,drawX__winY          ;Get current cascade coord
+               SUB     R0,R2,R0                ;Work out correct bottom
+               STMIB   R11,{R0-R2}             ;Store back in the scratchpad
+
+               ADD     R14,R10,#dWin__titleBar ;Point to the title buffer
+               STR     R14,[R11,#72]           ;Save this as buffer pointer
+
+               MOV     R1,R11                  ;Point to the scratchpad
+               SWI     XWimp_CreateWindow      ;Try to create the window
+               BVS     %98drawX__newDiag       ;If it failed, tidy up
+               STR     R0,[R10,#dWin__window]  ;Save the window handle
+
+               ; --- Register the window's event handler ---
+
+               ADR     R1,drawX__winHnd        ;Point to the handler
+               MOV     R2,R10                  ;Pass diagram block in R10
+               MOV     R3,R12                  ;And workspace in R12
+               BL      win_eventHandler        ;Register the event handler
+               BVS     %97drawX__newDiag       ;If it failed, tidy up
+
+               LDMFD   R13!,{R0-R3,R14}        ;Restore all the registers
+               BICS    PC,R14,#V_flag          ;And return with V clear
+
+               ; --- Various things went wrong ---
+
+97             MOV     R3,R0                   ;Look after error pointer
+               ADD     R1,R10,#dWin__window    ;Point at the window handle
+               SWI     Wimp_DeleteWindow       ;Don't want it any more
+               MOV     R0,R3                   ;Restore the error pointer
+
+98             MOV     R3,R0                   ;Look after error pointer
+               MOV     R0,R10                  ;Point at my diagram block
+               BL      free                    ;Don't want that any more
+               MOV     R0,R3                   ;Restore the error pointer
+
+99             ADD     R2,R0,#4                ;Point at the error text
+               ADR     R0,drawX__newErr        ;Point to error message
+               BL      msgs_error              ;Do clever things with it
+               ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R3,R14}        ;Unstack all the registers
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+drawX__newErr  DCD     1
+               DCB     "drxNEWERR",0
+
+drawX__untitled        DCB     "drxUNT",0
+
+drawX__winDef  DCD     320,0,960,512,0,0,-1    ;Initial window position
+               DCD     &ff000002               ;All gadgets, moveable
+               DCB     7,2,7,0,3,1,12,0        ;Normal window colours
+               DCD     0,0,640,512             ;Initial work area size
+               DCD     &00000139               ;Indirect the title text
+               DCD     (7<<12)                 ;Respond to click and drag
+               DCD     1                       ;Use Wimp sprite area FWIW
+               DCW     1,0                     ;Allow title bar hiding
+               DCD     0,-1,256                ;Title bar indirection stuff
+               DCD     0                       ;No icons defined
+
+drawX__winSize EQU     {PC}-drawX__winDef      ;Size of the window block
+
+               LTORG
+
+; --- drawX__winHnd ---
+;
+; On entry:    R0 == event code
+;              R1 == pointer to event data
+;              R10 == diagram handle
+;
+; On exit:     CS if I handled the event, CC otherwise
+;
+; Use:         Handles events directed at a diagram window.
+
+drawX__winHnd  ROUT
+
+               CMP     R0,#19                  ;Do I recognise the event?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch it then
+               MOVS    PC,R14                  ;Otherwise ignore it
+
+               MOVS    PC,R14                  ;NullReasonCode
+               B       drawX__redraw           ;RedrawWindowRequest
+               MOVS    PC,R14                  ;OpenWindowRequest
+               B       drawX__killDiag         ;CloseWindowRequest
+               B       drawX__ptrLeave         ;PointerLeavingWindow
+               B       drawX__ptrEnter         ;PointerEnteringWindow
+               B       drawX__click            ;MouseClicked
+               MOVS    PC,R14                  ;UserDragBox
+               MOVS    PC,R14                  ;KeyPressed
+               MOVS    PC,R14                  ;MenuSelection
+               MOVS    PC,R14                  ;ScrollRequest
+               MOVS    PC,R14                  ;LoseCaret
+               MOVS    PC,R14                  ;GainCaret
+               MOVS    PC,R14                  ;PollWordNonZero
+               MOVS    PC,R14                  ;UndefinedEvent_14
+               MOVS    PC,R14                  ;UndefinedEvent_15
+               MOVS    PC,R14                  ;UndefinedEvent_16
+               B       drawX__message          ;UserMessage
+               B       drawX__message          ;UserMessageRecorded
+
+               LTORG
+
+; --- drawX__killDiag ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     CS
+;
+; Use:         Destroys a diagram.
+
+drawX__killDiag        ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Kill the diagram itself, if it exists ---
+
+               LDR     R0,[R10,#dWin__diagram] ;Load the diagram anchor
+               CMP     R0,#0                   ;Is it a sensible value?
+               ADDNE   R0,R10,#dWin__diagram   ;Yes -- point to it then
+               BLNE    flex_free               ;And free the memory it used
+
+               ; --- Destroy the diagram's window ---
+
+               LDR     R0,[R10,#dWin__window]  ;Get the window handle
+               ADR     R1,drawX__winHnd        ;Point to the handler
+               MOV     R2,R10                  ;Pass diagram block in R10
+               MOV     R3,R12                  ;And workspace in R12
+               BL      win_removeEventHandler  ;Remove my event handler
+
+               ADD     R1,R10,#dWin__window    ;Point to the window handle
+               SWI     Wimp_DeleteWindow       ;Destroy the window
+
+               ; --- Destroy the diagram anchor block ---
+
+               MOV     R0,R10                  ;Point at the diagram block
+               BL      free                    ;Destroy it
+               LDMFD   R13!,{R0-R3,R14}        ;Return to caller
+               ORRS    PC,R14,#C_flag
+
+               LTORG
+
+; --- drawX__ptrEnter ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Makes the mouse pointer turn into a magnifying glass over
+;              a diagram window.
+
+drawX__ptrEnter        ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some regisers
+               LDR     R14,drawX__flags        ;Load the flags word
+               ORR     R14,R14,#dxFlag__ownPtr ;We own the pointer now
+               STR     R14,drawX__flags        ;Store the flags back
+
+               LDR     R14,[R10,#dWin__diagram] ;Load the diagram pointer
+               CMP     R14,#0                  ;Is it defined?
+               ADRNE   R0,drawX__ptrName       ;Yes -- point to the name
+               MOVNE   R1,#12                  ;Get the hot x position
+               MOVNE   R2,#6                   ;And the hot y position
+               BLNE    ptr_setShape            ;And set the pointer position
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+drawX__ptrName DCB     "ptr_zoom",0
+
+               LTORG
+
+; --- drawX__ptrLeave ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Makes the pointer look normal again when it leaves a
+;              diagram window.
+
+drawX__ptrLeave        ROUT
+
+               STMFD   R13!,{R14}              ;Save link register
+               LDR     R14,drawX__flags        ;Load the flags word
+               BIC     R14,R14,#dxFlag__ownPtr ;Don't own pointer any more
+               STR     R14,drawX__flags        ;Save the flags back
+               TST     R14,#dxFlag__drag       ;Are we dragging?
+               BLEQ    ptr_resetShape          ;No -- remove the pointer
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- drawX__redraw ---
+;
+; On entry:    R1 == pointer to a redraw block
+;              R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Redraws a diagram window.
+
+drawX__redraw  ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               SWI     Wimp_RedrawWindow       ;Start the redraw operation
+               CMP     R0,#0                   ;Is there anything to do?
+               BEQ     %90drawX__redraw        ;No -- skip to the end
+
+               ; --- Do a redraw of a diagram ---
+
+10drawX__redraw        LDR     R0,[R10,#dWin__scale]   ;Load the current scale
+               ADD     R14,R10,#dWin__diagram  ;Point to the diagram
+               LDMIA   R14,{R2,R3}             ;Load the address and size
+               CMP     R2,#0                   ;Is there a diagram at all?
+               BLNE    draw_render             ;Yes -- then render it
+               BL      drag_redraw             ;And redraw the drag box
+               SWI     Wimp_GetRectangle       ;Get another rectangle
+               CMP     R0,#0                   ;Is there more to do?
+               BNE     %10drawX__redraw        ;Yes -- do another rectangle
+
+               ; --- The redraw's over ---
+
+90drawX__redraw        LDMFD   R13!,{R0-R3,R14}        ;Restore registers
+               ORRS    PC,R14,#C_flag          ;Claim the event
+
+; --- drawX__message ---
+;
+; On entry:    R1 == pointer to a message block
+;              R10 == diagram handle
+;
+; On exit:     CC or CS, depending on whether I handled it
+;
+; Use:         Handles a message sent to a diagram window.
+
+drawX__message ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               LDR     R14,[R1,#16]            ;Load the message type
+               LDR     R0,=&502                ;Get the help message code
+               CMP     R0,R14                  ;Does it match?
+               BEQ     %10drawX__message       ;Yes -- deal with it then
+               CMP     R14,#1                  ;Is it a Message_DataSave?
+               CMPNE   R14,#3                  ;Or a Message_DataLoad?
+               LDMNEFD R13!,{R0,PC}^           ;No -- return to caller
+               LDR     R0,[R1,#40]             ;Load the filetype word
+               BL      drawX__load             ;Load the file
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+10             ADR     R0,drawX__viewHelp      ;Point to the message
+               BL      msgs_lookup             ;Translate it nicely
+               BL      help_add                ;Add it to the help message
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+drawX__viewHelp        DCB     "drxhDIAG",0
+
+               LTORG
+
+; --- drawX__open ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Opens a diagram window on the screen.
+
+drawX__open    ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R14,[R10,#dWin__window] ;Get the window handle
+               STR     R14,[R11,#0]            ;Save it in the scratchpad
+               MOV     R1,R11                  ;Point at it nicely
+               SWI     Wimp_GetWindowState     ;Find its current position
+               MOV     R14,#-1                 ;Bring it to the top
+               STR     R14,[R11,#28]           ;Save it in `behind' word
+               SWI     Wimp_OpenWindow         ;And open the new window
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- drawX__click ---
+;
+; On entry:    R1 == pointer to mouse click block
+;              R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Handles mouse clicks on a diagram.
+
+drawX__click   ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               LDR     R14,[R1,#8]             ;Load the button type
+               TST     R14,#&02                ;Is it a menu click?
+               BNE     %70drawX__click         ;Yes -- handle it then
+               LDR     R3,[R10,#dWin__diagram] ;Load the diagram pointer
+               CMP     R3,#0                   ;Is it valid?
+               TSTNE   R14,#&50                ;Yes -- some kind of drag?
+               BEQ     %90drawX__click         ;No -- ignore it then
+
+               ; --- Start a drag operation ---
+
+               LDR     R0,[R10,#dWin__window]  ;Load the window handle
+               MOV     R1,#0                   ;Give me update events
+               ADR     R2,drawX__dragHandler   ;Point to handler routine
+               MOV     R3,#0                   ;No magic number
+               MOV     R4,R10                  ;Pass diagram handle in R10
+               MOV     R5,R12                  ;Pass workspace in R12
+               BL      drag_start              ;Start the drag operation
+
+               LDR     R14,drawX__flags        ;Load the flags word
+               ORR     R14,R14,#dxFlag__drag   ;We're now dragging something
+               STR     R14,drawX__flags        ;Save the flags back
+               B       %90drawX__click         ;And return to caller
+
+               ; --- Handle a Menu click on the window ---
+
+70drawX__click ADR     R0,drawX__mainMenu      ;Point to the menu definition
+               ADR     R1,drawX__mmHnd         ;Point to the handler
+               MOV     R2,R10                  ;Pass diagram handle in R10
+               MOV     R3,R12                  ;Pass workspace in R12
+               BL      menu_create             ;Create the menu nicely
+
+90drawX__click LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+drawX__mainMenu        MENU    "DrawX"
+               ITEM    "drxMMINFO"
+               ISHADE  dWin__flags,dwFlag__hasDiag
+               SUBWARN
+               NOWARN
+               ITEM    "drxMMSAVE"
+               ISHADE  dWin__flags,dwFlag__hasDiag
+               SUBWARN
+               NOWARN
+               ITEM    "drxMMSCALE"
+               ISHADE  dWin__flags,dwFlag__hasDiag
+               SUBWARN
+               NOWARN
+               MENUEND
+
+               LTORG
+
+; --- drawX__dragHandler ---
+;
+; On entry:    R0 == event code
+;              R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Handles a drag box.
+
+drawX__dragHandler ROUT
+
+               CMP     R0,#7                   ;Is it in range?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch
+               MOVS    PC,R14                  ;Otherwise ignore it
+
+               B       drawX__redrawDragBox
+               B       drawX__redrawDragBox
+               B       drawX__redrawDragBox
+               MOVS    PC,R14
+               B       drawX__dragScroll
+               B       drawX__dragDone
+               B       drawX__dragCancel
+
+               LTORG
+
+; --- drawX__dragScroll ---
+;
+; On entry:    R1 == pointer to window state
+;
+; On exit:     --
+;
+; Use:         Scrolls the window during the drag.
+
+drawX__dragScroll ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               BL      drag_scroll             ;Read the scroll position
+               STMIA   R14,{R2,R3}             ;Save the new scroll position
+               SWI     Wimp_OpenWindow         ;Do the open operation
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+; --- drawX__unknowns ---
+;
+; On entry:    R0 == event code
+;              R1 == pointer to event data
+;
+; On exit:     CS if I handled it, CC if I didn't
+;
+; Use:         Handles unrecognised events.
+
+drawX__unknowns        ROUT
+
+               CMP     R0,#17                  ;Is it a UserMessage?
+               CMPNE   R0,#18                  ;Or a UserMessageRecorded?
+               MOVNES  PC,R14                  ;No -- ignore it then
+
+               ; --- Handle messages ---
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,[R1,#16]            ;Load the message action
+               CMP     R14,#5                  ;Is it Message_DataOpen?
+               LDMNEFD R13!,{PC}^              ;No -- ignore it then
+
+               STMFD   R13!,{R1,R10}           ;Save another register
+               LDR     R0,[R1,#40]             ;Load the filetype
+               MOV     R10,#0                  ;I don't have a diagram yet
+               BL      drawX__load             ;Load a new diagram
+               LDMFD   R13!,{R1,R10,R14}       ;Unstack the resulting regs
+               ORRCSS  PC,R14,#C_flag          ;If it loaded, set C flag
+               BICCCS  PC,R14,#C_flag          ;Otherwise clear it
+
+               LTORG
+
+; --- drawX__dragCancel ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Cancels the drag.
+
+drawX__dragCancel ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,drawX__flags        ;Load the current flags
+               BIC     R14,R14,#dxFlag__drag   ;Clear the dragging flag
+               STR     R14,drawX__flags        ;Save the flags back again
+               TST     R14,#dxFlag__ownPtr     ;Do we own the pointer?
+               BLEQ    ptr_resetShape          ;No -- clear the shape then
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- drawX__dragDone ---
+;
+; On entry:    R1 == pointer to window state
+;              R2,R3 == drag start position
+;              R4,R5 == drag end position
+;
+; On exit:     --
+;
+; Use:         Handles the end of a drag operation.
+
+
+drawX__dragDone        ROUT
+
+               STMFD   R13!,{R0-R7,R14}        ;Save some registers
+               BL      drawX__dragCancel       ;Cancel the drag
+
+               ; --- Now read the drag values ---
+
+               ADD     R14,R13,#8              ;Point to arguments on stack
+               LDMIA   R14,{R4-R7}             ;Move them to different regs
+
+               CMP     R4,R6                   ;Make sure they're the right
+               EORGT   R4,R4,R6                ;... way round
+               EORGT   R6,R4,R6
+               EORGT   R4,R4,R6
+               CMP     R5,R7
+               EORGT   R5,R5,R7
+               EORGT   R7,R5,R7
+               EORGT   R5,R5,R7
+
+               ; --- Get the window sizes ---
+
+               LDMIB   R1,{R0-R3}              ;Load the coordinates
+               SUB     R2,R2,R0                ;Get the window width
+               SUB     R3,R3,R1                ;And the window height
+
+               ; --- Work out the new scale factor ---
+
+               SUBS    R1,R6,R4                ;Get the drag box width
+               BEQ     %90drawX__dragDone      ;If it's bad, return now
+               ADD     R4,R4,R1,LSR #1         ;Find the box's centre
+               MOV     R0,R2,LSL #16           ;And the window width
+               MOV     R6,R2,LSR #1            ;Look after the width
+               BL      div_round               ;Do the division
+               MOV     R2,R0                   ;Look after the quotient
+
+               SUBS    R1,R7,R5                ;Get the drag box height
+               BEQ     %90drawX__dragDone      ;If it's bad, return now
+               ADD     R5,R5,R1,LSR #1         ;Find the box's centre
+               MOV     R0,R3,LSL #16           ;And the window height
+               BL      div_round               ;Do the division
+               MOV     R3,R3,LSR #1            ;Halve the height
+
+               CMP     R2,R0                   ;Which one's smaller?
+               MOVGT   R2,R0                   ;Use that one then
+               LDR     R7,[R10,#dWin__scale]   ;Load the current scale
+               MOV     R1,R7,LSR #8            ;Divide it down a bit
+               MOV     R2,R2,LSR #8            ;And divide the new one
+               MUL     R0,R2,R1                ;Multiply them up
+               CMP     R0,#&300                ;Is it smaller than 1%?
+               MOVLT   R0,#&300                ;Yes -- force it to 1%
+               CMP     R0,#&80000              ;Is it bigger than 800%?
+               MOVGT   R0,#&80000              ;Yes - force it to 800%
+               STR     R0,[R10,#dWin__scale]   ;Save the new scale factor
+               BL      drawX__setExtent        ;Set the new window extent
+               MOV     R0,R0,LSL #8            ;Scale up the new factor
+               MOV     R1,R7                   ;Get the old scale factor
+               BL      div_round               ;Get the scale difference
+
+               ; --- Set the new scroll positions ---
+
+               LDR     R1,[R13,#4]             ;Find the window state
+               MUL     R4,R0,R4                ;Multiply left drag box side
+               MUL     R5,R0,R5                ;And the top edge
+               RSB     R4,R6,R4,ASR #8         ;Scale them down a bit
+               ADD     R5,R3,R5,ASR #8         ;Scale them down a bit
+               ADD     R14,R1,#20              ;Point to the scroll pos
+               STMIA   R14,{R4,R5}             ;Save the new ones in there
+               SWI     Wimp_OpenWindow         ;Open the window nicely
+
+               ; --- Now redraw the window ---
+
+               LDR     R0,[R10,#dWin__window]  ;Load the window handle
+               ADD     R14,R10,#dWin__extent   ;Find the new extents
+               LDMIA   R14,{R1-R4}             ;Load them out nicely
+               SWI     Wimp_ForceRedraw        ;Redraw that lot nicely
+
+90             LDMFD   R13!,{R0-R7,PC}^        ;Return to caller
+
+               LTORG
+
+; --- drawX__mmHnd ---
+;
+; On entry:    R0 == menu event code
+;              R1 == item number
+;              R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Handles events for the main diagram menu.
+
+drawX__mmHnd   ROUT
+
+               CMP     R0,#mEvent_help         ;Does the user want help?
+               BEQ     %70drawX__mmHnd         ;Yes -- give him some
+               CMP     R0,#mEvent_subMenu      ;Is it a submenu event?
+               CMPNE   R0,#mEvent_select       ;Or a selection event?
+               MOVNES  PC,R14                  ;No -- then quit
+
+               ; --- Handle a menu selection ---
+
+               CMP     R1,#mm__scale           ;Is it one I recognise?
+               ADDLS   PC,PC,R1,LSL #2         ;Yes -- then deal with it
+               MOVS    PC,R14                  ;Otherwise ignore it
+
+               B       %10drawX__mmHnd         ;Display the info box
+               B       drawX__save             ;Start a save operation
+               B       drawX__scale            ;Display the scale dialogue
+
+               ; --- Display and handle the File info box ---
+
+10drawX__mmHnd STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               ADR     R0,drawX__fInfodb       ;Point to the dialogue name
+               BL      dbox_create             ;Try to create the dialogue
+               BVS     %30drawX__mmHnd         ;Handle an error if if failed
+
+               MOV     R3,R0                   ;Look after the dbox handle
+               ADD     R2,R10,#dWin__filename  ;Point to the file's name
+               MOV     R1,#info__name+(1<<31)  ;Get the right icon number
+               BL      dbox_setField           ;Set the field up nicely
+
+               LDR     R0,[R10,#dWin__diagSize] ;Load the diagram's size
+               MOV     R1,R11                  ;Point to the scratchpad
+               MOV     R2,#256                 ;Assume it's nice and big
+               SWI     OS_ConvertFileSize      ;Make it a nice size string
+               MOV     R2,R11                  ;Point at the string
+               MOV     R0,R3                   ;Get the dialogue handle
+               MOV     R1,#info__size          ;And find the size icon
+               BL      dbox_setField           ;Set the field up
+
+               ADR     R1,drawX__fInfoHlp      ;Point to the help text
+               BL      dbox_setClickDrag       ;Make dialogue box draggable
+               BL      mbox                    ;Display the dialogue box
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               ; --- Couldn't create the dialogue ---
+
+30drawX__mmHnd MOV     R1,#1                   ;Just an OK button please
+               BL      errorBox                ;Display the error message
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+drawX__fInfodb DCB     "drawInfo",0
+drawX__fInfoHlp        DCB     "drxhFINFO",0
+
+               ; --- Handle help requests for the menu ---
+
+70drawX__mmHnd STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               ADR     R0,drawX__mmHlpMsg      ;Point to the help string
+               BL      menu_help               ;Add message to help string
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+drawX__mmHlpMsg        DCB     "drxhMM",0
+
+               LTORG
+
+; --- drawX__redrawDragBox ---
+;
+; On entry:    R1 == pointer to redraw block
+;              R2,R3 == start positions
+;              R4,R5 == end positions
+;              R6,R7 == window origin
+;              R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Draws the drag box.
+
+drawX__redrawDragBox ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Save some registers
+
+               ; --- Set the coordinates up ---
+
+               MOV     R14,R6
+               ADD     R6,R5,R7
+               ADD     R5,R4,R14
+               ADD     R4,R3,R7
+               ADD     R3,R2,R14               ;Convert to screen coords
+
+               ; --- Set the correct colour ---
+
+               MOV     R0,#0                   ;Background colour is white
+               MOV     R1,#2                   ;Drag box is grey
+               BL      drag_eorColour          ;Set the EOR colour nicely
+
+               ; --- Plot the actual rectangle ---
+
+               MOV     R0,#4                   ;Move cursor absolute
+               MOV     R1,R3                   ;Get left hand side
+               MOV     R2,R4                   ;And bottom corner
+               SWI     OS_Plot                 ;And plot the first point
+               MOV     R0,#21                  ;Draw line absolute
+               MOV     R1,R5                   ;Get right hand side
+               MOV     R2,R4                   ;And bottom corner
+               SWI     OS_Plot                 ;And plot the bottom edge
+               MOV     R0,#53                  ;Draw line absolute
+               MOV     R1,R5                   ;Get right hand side
+               MOV     R2,R6                   ;And top corner
+               SWI     OS_Plot                 ;And plot the right hand edge
+               MOV     R0,#53                  ;Draw line absolute
+               MOV     R1,R3                   ;Get left hand side
+               MOV     R2,R6                   ;And top corner
+               SWI     OS_Plot                 ;And plot the top edge
+               MOV     R0,#61                  ;Draw line absolute
+               MOV     R1,R3                   ;Get left hand side
+               MOV     R2,R4                   ;And bottom corner
+               SWI     OS_Plot                 ;And plot the right edge
+
+90             LDMFD   R13!,{R0-R6,PC}^        ;Return to caller
+
+               LTORG
+
+; --- drawX__setTitle ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Updates a diagram window's title from its current state.
+
+drawX__setTitle        ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADD     R0,R10,#dWin__filename  ;Point to the filename
+               ADD     R1,R10,#dWin__titleBar  ;Point to the title buffer
+               LDR     R2,[R10,#dWin__window]  ;Load the window handle
+               BL      winUtils_setTitle       ;Set the window's title
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+               LTORG
+
+; --- drawX__cascade ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Updates the y position for the next diagram window so that
+;              it produces a pleasing `cascading' effect.
+
+drawX__cascade ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,drawX__winY         ;Load the current y position
+               SUB     R14,R14,#48             ;Decrement the counter
+               CMP     R14,#drawX__bottomY     ;Is it within range?
+               MOVLT   R14,#drawX__topY        ;No -- move it to the top
+               STR     R14,drawX__winY         ;Save the cascaded position
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+;----- Data transfer --------------------------------------------------------
+
+; --- drawX__save ---
+;
+; On entry:    R10 == diagram handle to save
+;
+; On exit:     --
+;
+; Use:         Saves a diagram.
+
+drawX__save    ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save lots of registers
+               LDR     R14,[R10,#dWin__flags]  ;Get the diagram's flags
+               TST     R14,#dwFlag__loaded     ;Does it have a nice name?
+               ADREQ   R0,drawX__defName       ;No -- find one then
+               BLEQ    msgs_lookup             ;Translate it nicely
+               ADDNE   R0,R10,#dWin__filename  ;Otherwise use the name
+               MOV     R2,R0                   ;Put the name in R2
+               LDR     R0,[R10,#dWin__diagSize] ;Load the diagram's size
+               LDR     R1,=drawX__filetype     ;Get the filetype nicely
+               ADR     R3,drawX__saveTbl       ;Point to the entry table
+               MOV     R4,R10                  ;Pass diagram handle in R10
+               MOV     R5,R12                  ;Pass workspace in R12
+               BL      saveAs                  ;Display the dialogue box
+               BVS     %90drawX__save          ;If it failed, deal with it
+
+               LDR     R14,[R10,#dWin__flags]  ;Load the flags word
+               ORR     R14,R14,#dwFlag__saving ;This window is saving
+               STR     R14,[R10,#dWin__flags]  ;Save the flags back
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+90drawX__save  MOV     R1,#1                   ;If it failed, report the
+               BL      errorBox                ;error with just an OK button
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+drawX__defName DCB     "drxDEFN",0
+
+drawX__saveTbl DCB     "drxSVTB",0
+               B       drawX__saveOver
+               B       drawX__saveFile
+               B       drawX__send
+               MOVS    PC,R14
+               B       drawX__saveFail
+
+; --- drawX__saveOver ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Clears the diagram's `saving' flag.
+
+drawX__saveOver        ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,[R10,#dWin__flags]  ;Load the flags word
+               BIC     R14,R14,#dwFlag__saving ;Window not saving any more
+               STR     R14,[R10,#dWin__flags]  ;Save the flags back
+               LDMFD   R13!,{PC}^              ;Return to caller
+
+               LTORG
+
+; --- drawX__saveFile ---
+;
+; On entry:    R0 == pointer to filename
+;              R1 == 0 if file is unsafe
+;              R10 == diagram handle
+;
+; On exit:     May return error
+;
+; Use:         Saves a diagram to a given file.
+
+drawX__saveFile        ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R2,R0                   ;Keep pointer to name
+               CMP     R1,#0                   ;Is the file safe?
+               ADDNE   R1,R10,#dWin__filename  ;Find the file's current name
+               BLNE    str_icmp                ;Do they match?
+               BEQ     %10drawX__saveFile      ;Either -- don't confirm
+               BL      res_exists              ;Does the file exist?
+               BCC     %10drawX__saveFile      ;No -- skip onwards then
+
+               ; --- Make sure user wants to overwrite file ---
+
+               ADR     R0,drawX__oWrite        ;Point to skeleton
+               BL      msgs_lookup             ;Translate the message
+               MOV     R1,R11                  ;Build in scratchpad
+               BL      str_subst               ;Build the warning message
+               ADR     R1,drawX__owWarn        ;Point to warning block
+               BL      warning                 ;Get a response
+               MOVCC   R0,#0                   ;If no then abort saving
+               BCC     %99drawX__saveFile      ;By making a null error
+
+10             MOV     R1,R2                   ;Get the filename in R1
+               MOV     R0,#10                  ;We're saving whole files
+               LDR     R2,=drawX__filetype     ;Get the filetype number
+               ADD     R14,R10,#dWin__diagram  ;Find the diagram address
+               LDMIA   R14,{R4,R5}             ;Load the address and size
+               ADD     R5,R4,R5                ;Convert size to limit ptr
+               SWI     XOS_File                ;Try to save the file
+               BVS     %99drawX__saveFile      ;If it failed, skip on
+
+               LDR     R14,[R13,#4]            ;Get the `safe' flag
+               CMP     R14,#0                  ;Is the file safe?
+               BEQ     %90drawX__saveFile      ;No -- skip to the end
+
+               ADD     R0,R10,#dWin__filename  ;Point to the filename
+               BL      str_cpy                 ;Copy the new one over
+               LDR     R14,[R10,#dWin__flags]  ;Load the flags word
+               ORR     R14,R14,#dwFlag__loaded ;File has a good name now
+               STR     R14,[R10,#dWin__flags]  ;Save the flags back
+               BL      drawX__setTitle         ;Set the window's title
+
+90             LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+99             ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R5,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;Return the error
+
+drawX__oWrite  DCB     "drxCWRT",0
+
+drawX__owWarn  BUTTON  "drxRPL"
+               BCANCEL
+               BUTEND
+
+               LTORG
+
+; --- drawX__send ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     R0 == pointer to diagram
+;              R1 == size of diagram
+;              CS
+;
+; Use:         Returns the diagram block so it can be sent to another
+;              application.
+
+drawX__send    ROUT
+
+               ADD     R0,R10,#dWin__diagram   ;Point to the diagram info
+               LDMIA   R0,{R0,R1}              ;Load the address and size
+               ORRS    PC,R14,#C_flag          ;No more data to send
+
+               LTORG
+
+; --- drawX__saveFail ---
+;
+; On entry:    R0 == pointer to an error, or 0
+;              R1 == 1
+;
+; On exit:     --
+;
+; Use:         Reports an error during a save attempt.
+
+drawX__saveFail        ROUT
+
+               CMP     R0,#0                   ;Is there an error
+               MOVEQS  PC,R14                  ;No -- return now then
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADD     R2,R0,#4                ;Point to error text
+               ADR     R0,drawX__badSave       ;Point to the message
+               BL      msgs_error              ;Translate it nicely
+               MOV     R1,#1                   ;Set up the button count
+               BL      errorBox                ;Report the error
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+drawX__badSave DCD     1
+               DCB     "drxESF",0
+
+               LTORG
+
+; --- drawX__load ---
+;
+; On entry:    R0 == filetype of data to send
+;              R10 == diagram handle, or 0 to create a new one
+;
+; On exit:     CS if it was handled, CC otherwise
+;
+; Use:         Loads a drawfile into a specified diagram, or into a newly
+;              created one.
+
+drawX__load    ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               LDR     R14,=drawX__filetype    ;Get the drawfile filetype
+               CMP     R0,R14                  ;Do they match properly?
+               BNE     %90drawX__load          ;No -- return then
+
+               ; --- Disallow save from a window to itself ---
+
+               CMP     R10,#0                  ;Is there a diagram?
+               LDRNE   R14,[R10,#dWin__flags]  ;Load the diagram's flags
+               TSTNE   R14,#dwFlag__saving     ;Is it currently saving?
+               BNE     %80drawX__load          ;Yes -- disallow this then
+
+               ; --- Start a load operation ---
+
+               ADR     R0,drawX__loadTbl       ;Point to the entry table
+               MOV     R1,R10                  ;Pass on the diagram handle
+               MOV     R2,R12                  ;And my workspace pointer
+               BL      load                    ;Start the load operation
+               LDMFD   R13!,{R0-R2,R14}        ;Unstack registers
+               ORRS    PC,R14,#C_flag          ;And say we handled it
+
+               ; --- Report an error about saving ---
+
+80drawX__load  ADR     R0,drawX__badLoad       ;Point to the error block
+               BL      msgs_error              ;Translate the message
+               MOV     R1,#1                   ;Only have an OK button
+               BL      errorBox                ;Report the error
+
+90drawX__load  LDMFD   R13!,{R0-R2,R14}        ;Unstack registers
+               BICS    PC,R14,#C_flag          ;And don't claim the event
+
+drawX__loadTbl B       drawX__newBuf
+               B       load_killBuf
+               B       load_extendBuf
+               B       drawX__doneBuf
+               B       drawX__loadFile
+               B       drawX__loaded
+               B       drawX__loadFail
+
+drawX__badLoad DCD     1
+               DCB     "drxCSII",0
+
+               LTORG
+
+; --- drawX__loadNew ---
+;
+; On entry:    R0 == pointer to name to create new diagram with
+;
+; On exit:     VC and R10 == pointer to diagram, or VS and R0 == pointer
+;              to error
+;
+; Use:         Creates a new diagram for a drawfile to be loaded into.
+
+drawX__loadNew ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               BL      drawX__newDiag          ;Create a new diagram
+               BVS     %99drawX__loadNew       ;Handle an error from that
+               LDR     R14,[R10,#dWin__flags]  ;Load the current flags
+               ORR     R14,R14,#dwFlag__tent   ;Remember it's tentative
+               STR     R14,[R10,#dWin__flags]  ;Save the flags back again
+               LDMFD   R13!,{R0-R3,R14}        ;Restore registers
+               BICS    PC,R14,#V_flag          ;And return with V clear
+
+99             ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R3,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+; --- drawX__killOld ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Removes the current drawfile being showin in the diagram.
+
+drawX__killOld ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               LDR     R0,[R10,#dWin__diagram] ;Load the diagram anchor
+               CMP     R0,#0                   ;Does it actually exist?
+               ADDNE   R0,R10,#dWin__diagram   ;Yes -- point at the anchor
+               BLNE    flex_free               ;And free the block
+               MOVNE   R14,#0                  ;Zero it out nicely
+               STRNE   R14,[R10,#dWin__diagram] ;Save the new anchor ptr
+               LDMFD   R13!,{R0,PC}^           ;Return to caller
+
+               LTORG
+
+; --- drawX__newBuf ---
+;
+; On entry:    R0 == pointer to leafname of file
+;              R1 == estimated size of file
+;              R10 == diagram handle, or 0 to create a new one
+;
+; On exit:     If all went well, VC and
+;                R0 == pointer to load buffer
+;                R1 == size of load buffer
+;                R2 == pointer to flex anchor
+;                R10 == diagram handle
+;              Otherwise, VS, R0 == pointer to error, and R1, R2 corrupted
+;
+; Use:         Creates a load buffer for loading a new diagram.
+
+drawX__newBuf  ROUT
+
+               STMFD   R13!,{R14}              ;Save the link register
+               CMP     R10,#0                  ;Is there a diagram?
+               BLEQ    drawX__loadNew          ;No -- get one then
+               BLNE    drawX__killOld          ;Yes -- destroy the old one
+               ADDVC   R2,R10,#dWin__diagram   ;If OK, point to anchor
+               BLVC    load_initBuf            ;And find a new buffer
+               LDMFD   R13!,{PC}               ;Return to caller
+
+               LTORG
+
+; --- drawX__doneBuf ---
+;
+; On entry:    R0 == pointer to diagram name
+;              R1 == actual size of diagram
+;              R2 == pointer to diagram flex anchor
+;              R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Wraps up a successful RAM receive of a draw file.
+
+drawX__doneBuf ROUT
+
+               STR     R1,[R10,#dWin__diagSize] ;Save the diagram size
+               B       load_doneBuf            ;And set the flex block up
+
+               LTORG
+
+; --- drawX__loadFile ---
+;
+; On entry:    R0 == pointer to leafname of file to load
+;              R1 == pointer to filename to read
+;              R10 == diagram handle, or 0 to create a new one
+;
+; On exit:     If all went well, VC and R10 == diagram handle
+;              Otherwise, VS, R0 == pointer to error
+;
+; Use:         Loads a diagram from a file.
+
+drawX__loadFile        STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               CMP     R10,#0                  ;Is there a diagram?
+               BLEQ    drawX__loadNew          ;No -- get one then
+               BLNE    drawX__killOld          ;Yes -- destroy the old one
+               MOVVS   R10,#0                  ;If no diagram, clear R10
+               ADDVC   R2,R10,#dWin__diagram   ;If OK, point to anchor
+               BLVC    load_file               ;And load the diagram
+               STRVC   R0,[R10,#dWin__diagSize] ;Save the diagram size
+               STRVS   R0,[R13,#0]             ;Otherwise return error
+               LDMFD   R13!,{R0-R2,PC}         ;Return to caller
+
+               LTORG
+
+; --- drawX__loaded ---
+;
+; On entry:    R10 == diagram handle
+;
+; On exit:     --
+;
+; Use:         Completes loading of a diagram.
+
+drawX__loaded  ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save lots of registers
+               LDR     R0,[R10,#dWin__diagram] ;Find the diagram address
+               BL      draw_checkValid         ;Make sure it's kosher
+               MOVVS   R1,#1                   ;If not, set R1 == 1
+               BLVS    drawX__loadFail         ;And kill off the diagram
+               BVS     %90drawX__loaded        ;And return
+
+               ; --- Set everything up for the new diagram ---
+
+               BL      drawX__setExtent        ;Set the extents
+               BL      drawX__refresh          ;Refresh the window contents
+               BL      drawX__setTitle         ;Set the title string
+               LDR     R14,[R10,#dWin__flags]  ;Load the diagram flags
+               TST     R14,#dwFlag__tent       ;Was it tentative?
+               BICNE   R14,R14,#dwFlag__tent   ;Diagram not tentative now
+               ORR     R14,R14,#dwFlag__hasDiag ;Diagram now has a drawfile
+               STR     R14,[R10,#dWin__flags]  ;Save the flags back again
+               BLNE    drawX__open             ;Yes -- open it on screen
+               BLNE    drawX__cascade          ;And cascade the thing too
+
+90drawX__loaded        LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- drawX__loadFail ---
+;
+; On entry:    R0 == pointer to error, or 0 if none
+;              R1 == 1
+;              R10 == diagram handle, or 0 if none
+;
+; On exit:     --
+;
+; Use:         Handles an error during loading a diagram.
+
+drawX__loadFail        ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               CMP     R10,#0                  ;Is there a diagram?
+               BEQ     %50drawX__loadFail      ;No -- just report error
+
+               ; --- Work out what to do ---
+               ;
+               ; If the window is new, delete it.  Otherwise just leave it
+               ; blank.
+
+               LDR     R14,[R10,#dWin__flags]  ;Load the flags word
+               TST     R14,#dwFlag__tent       ;Is it tentative?
+               BLNE    drawX__killDiag         ;Yes -- kill the diagram
+               BNE     %50drawX__loadFail      ;And skip ahead
+
+               ; --- Blank out a diagram ---
+
+               BIC     R14,R14,#dwFlag__loaded+dwFlag__hasDiag
+               STR     R14,[R10,#dWin__flags]  ;Save the flags back again
+               ADRL    R0,drawX__untitled      ;Point to the blank name
+               BL      msgs_lookup             ;Translate the message
+               MOV     R1,R0                   ;This is the source string
+               ADD     R0,R10,#dWin__filename  ;Point to filename buffer
+               BL      str_cpy                 ;Copy it over
+               BL      drawX__setTitle         ;Set the window's title
+               MOV     R1,#0                   ;Left hand side is 0
+               MOV     R2,#0                   ;Bottom edge is 0 too
+               MOV     R3,#640                 ;Window is 640 units wide
+               MOV     R4,#512                 ;And 512 units high
+               ADD     R14,R10,#dWin__extent   ;Point to the extent block
+               STMIA   R14,{R1-R4}             ;Save them all away
+               LDR     R0,[R10,#dWin__window]  ;Load the window handle
+               ADD     R1,R10,#dWin__extent    ;Point to the coordinates
+               SWI     Wimp_SetExtent          ;Set the new extent
+               BL      drawX__refresh          ;Refresh the window contents
+
+               ; --- Report the error ---
+
+50             LDR     R2,[R13,#0]             ;Load the error pointer
+               CMP     R2,#0                   ;Is it interesting?
+               ADDNE   R2,R2,#4                ;Yes -- point to error text
+               ADRNE   R0,drawX__loadErr       ;Point to the message
+               BLNE    msgs_error              ;Translate the error
+               MOVNE   R1,#1                   ;Only one button please
+               BLNE    errorBox                ;And report the error
+
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+drawX__loadErr DCD     1
+               DCB     "drxELF",0
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/SapphToys/!SWIlist/!Help b/StraySrc/SapphToys/!SWIlist/!Help
new file mode 100644 (file)
index 0000000..616e581
--- /dev/null
@@ -0,0 +1,191 @@
+                       __          ___
+                      (__  |     |  |  |     '  __ _|__
+                         \ |  |  |  |  |     | (__  |
+                      ___/ \__|__/ _|_ |____ ( ___) (__
+
+
+                      ©   1 9 9 5   S t r a y l i g h t
+
+_____________________________________________________________________________
+
+
+                                ABOUT SWILIST
+
+       If you use C or the objasm assembler, and you need to use SWIs, then
+       you'll probably want to have a file defining names for all the SWIs
+       you'll be using, which you can include in any files which need it.
+       SWIList is a small program designed to generate such files.
+
+       There are lots of programs which do this job, although SWIList
+       provides several important features which the others don't:
+
+         * It's language independent.  So you can use the same program to
+           generate SWI files for C, assembler, or any other language you
+           need.  All you have to do is describe the language to SWIList.
+
+         * It doesn't just scan the modules in memory.  You can drop module
+           files onto SWIList's icon in order to add their SWIs to the list.
+           SWIList also keeps a file of all the names so far, which you can
+           save, so you can add new modules easily when you obtain (or
+           write) them.
+
+_____________________________________________________________________________
+
+
+                               RUNNING SWILIST
+
+Introduction
+
+       SWIList runs when you double-click its icon in a Filer window.  It
+       will add its icon to the icon bar in the traditional way.  If you
+       haven't yet saved a SWI dump (see below), SWIList will take a little
+       while to read in all the modules currently loaded.
+
+
+The main menu
+
+       If you click /menu/ on the SWIList icon, the main menu will be
+       opened, from which you can choose the following options:
+
+       Info            Displays a dialogue box showing information about the
+                       SWIList application, including the version number,
+                       which you should note with any bug reports.
+
+       Save list       Displays a submenu of languages.  Choosing one of
+                       the items from this submenu opens a dialogue box
+                       which will let you save a SWI list file in the
+                       appropriate language.
+
+
+       Save dump       Displays a dialogue box which lets you save the
+                       `SWI dump' -- a file containing all the SWI names
+                       currently in memory.  More information about SWI
+                       dumps is given below.
+
+       Rescan modules  Discards all the SWI names currently in memory and
+                       rescans the loaded modules.  This can take a short
+                       while.
+
+       Quit            Removes the SWIList application from memory.
+
+
+SWI dumps
+
+       A *SWI dump* contains information about SWI names and numbers.  It's
+       a binary file, not intended for `user consumption'.  SWIList will
+       attempt to load the file `SWIdump' from its application directory
+       when it starts up; if it can't find this then it will scan the
+       modules in memory.  This feature allows you to add to the SWIs
+       currently recognised when new modules come along, rather than having
+       to redo the whole lot from scratch.
+
+
+Format files
+
+       In order to make SWIList language independent, all the information
+       about specific languages is contained in a file called `Format'
+       in SWIList's application directory.  You can alter the existing
+       formats, or ad your own for languages which aren't already supported
+       (e.g. Pascal).
+
+       The file's layout is fairly straightforward.  The description of
+       how to format each language is held in a `chunk', headed by the
+       name of the language in square brackets (`[', `]').  (Actually, this
+       isn't quite true -- the thing in the brackets is the menu item text,
+       so we've followed it with `...' because the item leads to a dialogue
+       box.)
+
+       SWIList's output files are structured, and the format description
+       echoes this.  At the top of an output file is a header.  Then, for
+       each SWI-providing module, there is a header line, and this is
+       followed by a piece of text for each individual SWI.  Finally, the
+       file is finished off with a footer.
+
+       The format for a language is divided into four sections, separated
+       by `%%'s:
+
+        1. The header text for the output.  This is where you'd set up any
+           macros needed, and ensure that the file is only included once,
+           if this is required.
+
+        2. The header line (or lines) for each module.  This is usually
+           just a comment.
+
+        3. The text to define each individual SWI.  Don't forget to define
+           the `X' versions of the SWIs here.
+
+        4. The footer text for the output file.
+
+       The text within each section can contain *format specifiers*, which
+       are replaced with appropriate text while the file is being written.
+       A format specifier begins with a `%' character.  The replacement text
+       is determined by the next character:
+
+       `%m'    Replaced by the name of the module whose SWIs are being
+               written.  This is usually used in the module separator lines.
+
+       `%s'    Replaced by the name of the SWI currently being defined.
+               This is intended to be used when defining the individual
+               SWIs.
+
+       `%n'    Replaced by the number of the SWI currently being defined.
+               The number is written in hex, so be sure to include the
+               appropriate specifier for the language (e.g. `&' in assembler
+               or `0x' in C).
+
+       `%x'    Replaced by the number of the `X' version of the SWI being
+               defined, also in hex.
+
+       `%p'    Replaced by a `%' character, just in case you need one.
+
+       `%d'    Replaced by the current date and time.  The default format
+               of the date is determined by an entry in SWIList's `Messages'
+               file, although you can supply your own by placing it in
+               square brackets immediately after the `%d'.  The syntax of
+               date formats is as described for the Alarm application,
+               and the SWI OS_ConvertDateAndTime.
+
+       For an example, which should help make everything clear, see the
+       `Format' file supplied.
+
+
+Choices
+
+       The Risc PC boot system sets up a system variable `Choices$Path'
+       which allows applications to find configuration files kept separately
+       from the application directory.  If you have a Risc PC, or have set
+       up the `Choices$Path' variable, SWIList will search for the `Format'
+       and `SWIDump' files there before it looks in its application
+       directory.
+
+_____________________________________________________________________________
+
+
+                               TECHNICAL THINGS
+
+       SWIList was written entirely in ARM Assembler.  It gobbles large
+       amounts of memory because it's using the Sapphire library which is
+       completely excessive for SWIList's fairly modest needs.  Some of the
+       more advanced features of SWIList would have been difficult to
+       implement without Sapphire however, and I doubt that I could have
+       been bothered.  For example:
+
+         * RAM transfer support, for both loading and saving (including
+           formatted SWI list files).
+
+         * The format file support.
+
+         * The dynamic menu of formats.
+
+         * All the little luxuries like pointer changing and DragASprite
+           support (including the icon being hidden when it's dragged).
+
+       So there!
+
+       The SWIList source code uses the BASIC assembler and Straylight's
+       BASIC Assembler Supplement (BAS), which allows AOF object files
+       to be generated from BASIC; the object was then linked to the
+       Sapphire library.  Sapphire was however written using Acorn's objasm
+       assembler, which was a considerably more pleasant experience.
+
+_____________________________________________________________________________
diff --git a/StraySrc/SapphToys/!SWIlist/!Run,feb b/StraySrc/SapphToys/!SWIlist/!Run,feb
new file mode 100644 (file)
index 0000000..566b39d
--- /dev/null
@@ -0,0 +1,30 @@
+|
+| SWIList 2.xx !Run file
+|
+| © 1994 Straylight
+|
+| This file version 1.00 (20 March 1994)
+|
+
+Set SWIList$Dir <Obey$Dir>
+IconSprites <SWIList$Dir>.!Sprites
+
+/<SWIList$Dir>.setSlot -appName SWIList 24K 4K 16K
+
+If "<System$Path>"="" Then Error 0 System resources could not be found.  Please double-click a !System folder and reload.
+
+If "<Wimp$Scrap>"="" Then Error 0 Couldn't find Scrap folder.  Please double click a !Scrap folder (or !System if you don't have !Scrap) and reload.
+
+If "<DLL$Path>"="" Then Error 0 Couldn't find Dynamic Link libraries.  Please double click a !DLLs folder and reload.
+
+Set Alias$_RMEnsure RMEnsure %%0 0.00 RMLoad %%2 |m RMEnsure %%0 %%1
+_RMEnsure DLLManager 1.14 <DLL$Dir>.DLLManager
+_RMEnsure Sculptrix 2.01 <SWIList$Dir>.Sculptrix
+Unset Alias$_RMEnsure
+
+DLLEnsure [Sapphire.Core] 1.00
+DLLEnsure [Sapphire.Resources] 1.00
+
+/<SWIList$Dir>.setSlot -appName SWIList 24K 4K 16K
+
+Run <SWIList$Dir>.!RunImage %*0
\ No newline at end of file
diff --git a/StraySrc/SapphToys/!SWIlist/!Sprites,ff9 b/StraySrc/SapphToys/!SWIlist/!Sprites,ff9
new file mode 100644 (file)
index 0000000..91d851a
Binary files /dev/null and b/StraySrc/SapphToys/!SWIlist/!Sprites,ff9 differ
diff --git a/StraySrc/SapphToys/!SWIlist/Format b/StraySrc/SapphToys/!SWIlist/Format
new file mode 100644 (file)
index 0000000..a75009b
--- /dev/null
@@ -0,0 +1,76 @@
+;
+; SWIList format file
+;
+; Defines output styles for SWIList
+;
+
+[Assembler...]
+;
+; swis.sh
+;
+; SWI names from numbers [generated %d[%zdy %mo %ce%yr] by SWIList]
+; You may freely distribute and modify this file.
+;
+
+               [       :LNOT::DEF:swis__dfn
+               GBLL    swis__dfn
+
+               MACRO
+               SWIDEF  $name,$number
+$name          EQU     $number
+X$name         EQU     $number :OR: &20000
+               MEND
+%%
+
+               ; --- %m SWIs ---
+
+%%
+               SWIDEF  %s,&%n
+%%
+
+               ]
+
+               END
+[C...]
+/*
+ * swis.h
+ *
+ * SWI names from numbers [generated %d[%zdy %mo %ce%yr] by SWIList]
+ * You may freely distribute and modify this file.
+ */
+
+#pragma force_top_level
+#pragma include_only_once
+
+#ifndef SWIS_H
+#define SWIS_H
+%%
+
+/* --- %m SWIs --- */
+
+%%
+#define %s 0x%n
+#define X%s 0x%x
+%%
+
+#endif
+[C++...]
+//
+// swis.h
+//
+// SWI names from numbers [generated %d[%zdy %mo %ce%yr] by SWIList]
+// You may freely distribute and modify this file.
+//
+
+#ifndef SWIS_H
+#define SWIS_H
+%%
+
+// --- %m SWIs ---
+
+%%
+#define %s 0x%n
+#define X%s 0x%x
+%%
+
+#endif
diff --git a/StraySrc/SapphToys/!SWIlist/Makefile,fe1 b/StraySrc/SapphToys/!SWIlist/Makefile,fe1
new file mode 100644 (file)
index 0000000..dc38b06
--- /dev/null
@@ -0,0 +1,107 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: !RunImage Sculptrix
+
+!RunImage: o.swilist
+       $(SETDATE) o.version version="2.08 ($(DATE))" cright="$(CRIGHT)"
+       $(LD_APP) o.swilist o.version libs:lib.sapphdll
+       $(SQUEEZE)
+       $(SET_APP)
+
+Sculptrix: <SSR$ModDir>.Sculptrix
+       $(INSTALL) <SSR$ModDir>.Sculptrix @
+
+install:
+
+clean:
+       $(RM) o.* !RunImage Sculptrix
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/SapphToys/!SWIlist/UK b/StraySrc/SapphToys/!SWIlist/UK
new file mode 100644 (file)
index 0000000..e2b7fac
--- /dev/null
@@ -0,0 +1,64 @@
+;
+; SWIList messages
+;
+; © 1995 Straylight
+;
+
+me:SWIList
+
+; --- The main menu ---
+
+slINF:Info...
+slhIM0:$mpr see information about $(me).
+slSVL:Save list
+slhIM1:$mpr save a list of SWI names and numbers.
+slSVD:Save dump...
+slhIM2:$mpr save a dump of the current SWIs.
+slSCN:Rescan modules
+slhIM3:Click SELECT to read SWI names from the modules currently in memory.
+slRFM:Refresh module
+slhIM4:$mpr read SWIs from a memory-resident module.
+slQUT/slQUTB:Quit
+slhIM4:Click SELECT to quit $(me).
+
+slMDS:Modules
+slKNL:Kernel
+
+slPUR:Generate SWI name/number tables
+piHELP:This window shows you information about this version of $(me).
+
+; --- Save dialogues ---
+
+slSVT:Save list
+slSDT:Save dump
+
+slSVFT:Save SWIs
+slhSVF:$mpr save a list of SWIs using the '%0' format.
+
+slOTQ:The SWI list has been modified.  Are you sure you want to quit SWIList?
+
+slhIB:This is the $me icon|mClick MENU to save a list of SWIs.
+
+slRPP:File '%0' already exists.  Do you want to replace it?
+slRPL:Replace
+
+; --- Miscellaneous error messages ---
+
+slMLE:Error building module list: %0
+slSFE:Error saving SWI list: %0
+slSDE:Error saving SWI dump: %0
+slNSS:No SWIs to save
+slNFD:No format loaded
+slCSII:SWIList can't save files into itself
+
+slSMAA:Error scanning module: %0
+slLFM:Error loading module: %0
+slLFM:Error loading SWI dump: %0
+
+; --- Help message abbreviations ---
+
+mpr:Move the pointer right to
+
+; --- Default date (%d) format ---
+
+slDFMT:%w3,%dy %m3 %ce%yr.%24:%mi:%se
diff --git a/StraySrc/SapphToys/!SWIlist/bs/swiList,ffb b/StraySrc/SapphToys/!SWIlist/bs/swiList,ffb
new file mode 100644 (file)
index 0000000..8a074b8
Binary files /dev/null and b/StraySrc/SapphToys/!SWIlist/bs/swiList,ffb differ
diff --git a/StraySrc/SapphToys/Makefile,fe1 b/StraySrc/SapphToys/Makefile,fe1
new file mode 100644 (file)
index 0000000..e362d22
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all:
+       submake *.Makefile
+
+install:
+       submake *.Makefile -- install
+
+clean:
+       submake *.Makefile -- clean
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/Sculptrix/!SConfig/!Run,feb b/StraySrc/Sculptrix/!SConfig/!Run,feb
new file mode 100644 (file)
index 0000000..1ba13ff
--- /dev/null
@@ -0,0 +1,2 @@
+RMEnsure Sculptrix 2.01 RMLoad <Obey$Dir>.Sculptrix
+Run <Obey$Dir>.LoadConfig <Obey$Dir>.SConfig
diff --git a/StraySrc/Sculptrix/!SConfig/Makefile,fe1 b/StraySrc/Sculptrix/!SConfig/Makefile,fe1
new file mode 100644 (file)
index 0000000..890774e
--- /dev/null
@@ -0,0 +1,109 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: loadConfig Sculptrix
+
+Sculptrix: <SSR$ModDir>.Sculptrix
+       $(INSTALL) <SSR$ModDir>.Sculptrix @
+
+loadConfig: o.loadConfig
+       $(SETDATE) o.version version="1.00 $(DATE), $(CRIGHT)"
+       $(LD_APP) o.loadConfig o.version
+
+install:
+
+clean:
+       -$(RM) o.* Sculptrix loadConfig
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.loadConfig: s.loadConfig
+o.loadConfig: libs:header
+o.loadConfig: libs:swis
+o.loadConfig: libs:stream
diff --git a/StraySrc/Sculptrix/!SConfig/s/loadConfig b/StraySrc/Sculptrix/!SConfig/s/loadConfig
new file mode 100644 (file)
index 0000000..ee7e378
--- /dev/null
@@ -0,0 +1,269 @@
+;
+; loadConfig.s
+;
+; Load a Sculptrix configuration file
+;
+; © 1997-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Revision history -----------------------------------------------------
+;
+; Version      By      Change
+;
+; 1.00         mdw     Initial version.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  version
+               IMPORT  |Image$$RW$$Limit|
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |App$$Code|,CODE,READONLY
+               ENTRY
+
+; --- main ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Loads a named Sculptrix file.  If we're currently in the
+;              desktop, and Sculptrix thinks that it's necessary, redraw
+;              the screen.
+
+main           ROUT
+
+               ; --- Set up some workspace ---
+
+               SWI     OS_GetEnv               ;Read environment information
+               ADR     R12,|Image$$RW$$Limit|  ;Get end of the program
+               ADD     R14,R12,#lc__wSize      ;Add on my requirements
+               CMP     R14,R1                  ;Do I have enough?
+               ADRCS   R0,lc__noRoom           ;No -- point to error
+               SWICS   OS_GenerateError        ;And report to the user
+
+               ; --- Read the arguments string ---
+
+00             LDRB    R14,[R0],#1             ;Load next byte out
+               CMP     R14,#&20                ;Is it a space or less?
+               BHI     %b00                    ;No -- keep going then
+00             CMP     R14,#&20                ;Is it exactly a space?
+               LDREQB  R14,[R0],#1             ;Yes -- fetch another one
+               BEQ     %b00                    ;And keep going
+               SUB     R1,R0,#1                ;Point back to last char
+
+               ADR     R0,lc__argDef           ;Point to description string
+               ADR     R2,lc__args             ;Point to the argument buffer
+               MOV     R3,#256                 ;Use up lots of buffer space
+               SWI     OS_ReadArgs             ;Read the arguments in
+
+               ; --- Inspect the arguments ---
+
+               LDR     R14,lc__wantHelp        ;Load the help flag
+               CMP     R14,#0                  ;Is it set?
+               BNE     lc__help                ;Yes -- give some help
+
+               LDR     R1,lc__filename         ;Load filename address
+               CMP     R1,#0                   ;Is this defined?
+               ADREQ   R0,lc__noFile           ;No -- point to an error
+               SWIEQ   OS_GenerateError        ;And return the error
+
+               ; --- Check the file's size for sanity ---
+
+               MOV     R0,#17                  ;Find out some file info
+               SWI     OS_File                 ;Read all about the file
+               TST     R0,#1                   ;Is this a file?
+               MOVEQ   R2,R0                   ;No -- get the object type
+               MOVEQ   R0,#19                  ;Return me an error please
+               SWIEQ   OS_File                 ;And get the error
+
+               CMP     R4,#256                 ;Is the file too big?
+               ADRCS   R0,lc__tooBig           ;Yes -- point to error
+               SWICS   OS_GenerateError        ;And report it to the user
+
+               ; --- Load the file into memory ---
+
+               MOV     R0,#16                  ;Load the file into memory
+               ADD     R2,R12,#512             ;Point to appropriate chunk
+               MOV     R3,#0                   ;Load where I said, please
+               SWI     OS_File                 ;Do that, please
+
+               ; --- Check the file's contents for sanity ---
+
+               LDR     R0,[R12,#512]           ;Load the first word
+               LDR     R14,lc__magic           ;Load what it should be
+               CMP     R0,R14                  ;These should be the same
+               ADRNE   R0,lc__notConf          ;Point to an error
+               SWINE   OS_GenerateError        ;And complain if they're not
+
+               ; --- Send the configuration to Sculptrix ---
+
+               ADD     R0,R12,#512 + 4         ;Point to actual config data
+               SWI     XSculptrix_SetConfig    ;Set the configuration
+
+               ; --- Error checking here ---
+               ;
+               ; I know for a fact, because I have the source code in front
+               ; of me, that Sculptrix_SetConfig never returns an error.
+               ; Therefore, if V is set right now, I know that Sculptrix
+               ; isn't actually there, and I can return a slightly more
+               ; useful error message.
+
+               ADRVS   R0,lc__noSculpt         ;Point to message
+               SWIVS   OS_GenerateError        ;And return it to caller
+
+               ; --- If C is clear, there's nothing to redraw ---
+               ;
+               ; Also, I may not have to do any redrawing because I was
+               ; told not to.
+
+               SWICC   OS_Exit                 ;C is clear: we're finished
+               LDR     R14,lc__noRedraw        ;Load the no-redraw flag
+               CMP     R14,#0                  ;Is it cleared?
+               SWINE   OS_Exit                 ;No -- we're done then
+
+               ; --- Initialise as a Wimp task ---
+
+               MOV     R0,#200                 ;Wimp version number
+               LDR     R1,lc__task             ;Load the magic number
+               ADR     R2,lc__progName         ;Point to program name
+               SWI     XWimp_Initialise        ;Start up as a Wimp app
+
+               ; --- Read the screen extents ---
+
+               ADR     R0,lc__vduVars          ;Point to VDU variables
+               ADR     R1,lc__vduBuff          ;And to the output buffer
+               SWI     OS_ReadVduVariables     ;Read them in please
+               LDMIA   R1!,{R1-R4}             ;Load the values out now
+               ADD     R3,R3,#1                ;Increment width
+               ADD     R4,R4,#1                ;And height
+               MOV     R3,R3,LSL R1            ;Shift width up to OS units
+               MOV     R4,R4,LSL R2            ;And the height too
+
+               ; --- Now do the redraw ---
+               ;
+               ; Note that I don't check for errors here.
+
+               MOV     R0,#-1                  ;Redraw the whole screen
+               MOV     R1,#0                   ;From the bottom left
+               MOV     R2,#0                   ;So set that up
+               SWI     XWimp_ForceRedraw       ;Redraw everything
+
+               ; --- That's it: I'm done now ---
+
+               SWI     OS_Exit                 ;That's it, then
+
+lc__noRoom     DCD     1
+               DCB     "Not enough memory for LoadConfig to initialise",0
+
+               ALIGN
+lc__argDef     DCB     "help/s,noredraw/s,",0
+
+lc__noFile     DCD     1
+               DCB     "You must specify a filename",0
+
+lc__tooBig     DCD     1
+               DCB     "Too large to be a Sculptrix configuration file",0
+
+lc__notConf    DCD     1
+               DCB     "This isn't a Sculptrix configuration file",0
+
+lc__noSculpt   DCD     1
+               DCB     "Sculptrix not loaded or too old",0
+
+lc__magic      DCB     "SXCF"
+
+lc__task       DCB     "TASK"
+
+lc__progName   DCB     "LoadConfig",0
+
+lc__vduVars    DCD     4,5,11,12,-1
+
+               LTORG
+
+; --- lc__help ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Reports a help message and quits.
+
+lc__help       ROUT
+
+               ADR     R0,lc__helpText         ;Point to help text
+               MOV     R1,#0                   ;Use system dictionary
+               ADR     R2,version              ;Point to version string
+               SWI     OS_PrettyPrint          ;Display the text
+               SWI     OS_Exit                 ;And exit nicely
+
+lc__helpText   DCB     "LoadConfig ",27,0,13
+               DCB     13
+               DCB     "Syntax: LoadConfig [<options>] <filename>",13
+               DCB     13
+               DCB     "Options (which may be abbreviated) are:",13
+               DCB     13
+               DCB     "-help",9,9,"Display this help text",13
+               DCB     "-noRedraw",9,"Suppress screen redraw",13
+               DCB     0
+
+               LTORG
+
+;----- Workspace layout -----------------------------------------------------
+
+               ^       0,R12
+lc__wStart     #       0
+
+               ; --- VDU variables ---
+
+lc__vduBuff    #       0                       ;VDU variables output buffer
+lc__xEig       #       4                       ;X EIG factor
+lc__yEig       #       4                       ;Y EIG factor
+lc__scrWidth   #       4                       ;Screen width
+lc__scrHeight  #       4                       ;Screen height
+
+               ; --- Arguments read from command line ---
+
+lc__args       #       0                       ;Argument buffer start
+lc__wantHelp   #       4                       ;Someone wants some help
+lc__noRedraw   #       4                       ;Don't redraw the screen
+lc__filename   #       4                       ;Address of the filename
+lc__argBuff    #       256 - 12                ;Rest of the argument buffer
+
+               ; --- Buffer for loading config files ---
+
+lc__loadBuf    #       0                       ;Buffer start address
+lc__confMagic  #       4                       ;Magic number on the front
+lc__confData   #       252                     ;Rest of the data
+
+lc__wSize      EQU     {VAR} - lc__wStart
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/!Setrix/!Help b/StraySrc/Sculptrix/!Setrix/!Help
new file mode 100644 (file)
index 0000000..670c349
--- /dev/null
@@ -0,0 +1,41 @@
+SETRIX v. 1.00
+
+
+       The '3D' look of dialogue boxes in Straylight applications is
+       created by a module called 'Sculptrix'.  This module is responsible
+       for drawing all the pushbuttons, group boxes, and other 3D borders
+       in the dialogue boxes.  The Setrix application allows you to
+       configure the look of these borders to suit your individual tastes.
+
+       To alter the appearance of Sculptrix's 3D borders, load the Setrix
+       application and click the icon which appears in the icon bar.
+       A dialogue box appears, showing various options.  At the top is
+       a table laid out as shown in the diagram below.
+
+
+                               Active       |        Shaded
+                          Dark   |  Light   |   Dark   |  Light
+                                 |          |          |
+              Normal:    [ ]    |   [ ]    |   [ ]    |   [ ]
+                                 |          |          |
+           Group box:    [ ]    |   [ ]    |   [ ]    |   [ ]
+
+
+       Each '[ ]' represents a coloured button in the dialogue box.  These
+       buttons allow you to edit the colours used by Sculptrix in its
+       borders.
+
+       To create the 3D effect, Sculptrix uses two colours: one darker
+       than the dialogue box background, and one lighter.  These colours
+       are shown in the `Dark' and `Light' columns of the table.
+
+       To help show that a dialogue box control is inactive, Sculptrix will
+       usually make the border fainter.  Sculptrix will use the colours
+       shown in the 'Shaded' half of the table under these circtumstances.
+
+       Finally, group boxes and separator bars may be drawn in different
+       colours to normal buttons: for example, you may want group boxes
+       to be dimmer than normal.  The colours in the 'Group box' row are
+       used for this purpose.
+
+
diff --git a/StraySrc/Sculptrix/!Setrix/!Run,feb b/StraySrc/Sculptrix/!Setrix/!Run,feb
new file mode 100644 (file)
index 0000000..91d399e
--- /dev/null
@@ -0,0 +1,30 @@
+|
+| Setrix 1.xx !Run file
+|
+| © 1995 Straylight
+|
+| This file version 1.00 (20 March 1994)
+|
+
+Set Setrix$Dir <Obey$Dir>
+IconSprites <Setrix$Dir>.!Sprites
+
+/<Setrix$Dir>.setSlot -appName Setrix 64K 4K
+
+If "<System$Path>"="" Then Error 0 System resources could not be found.  Please double-click a !System folder and reload.
+
+If "<Wimp$Scrap>"="" Then Error 0 Couldn't find Scrap folder.  Please double click a !Scrap folder (or !System if you don't have !Scrap) and reload.
+
+If "<DLL$Path>"="" Then Error 0 Couldn't find Dynamic Link libraries.  Please double click a !DLLs folder and reload.
+
+Set Alias$_RMEnsure RMEnsure %%0 0.00 RMLoad %%2 |m RMEnsure %%0 %%1
+_RMEnsure DLLManager 1.14 <DLL$Dir>.DLLManager
+_RMEnsure Sculptrix 2.01 <Setrix$Dir>.Modules.Sculptrix
+Unset Alias$_RMEnsure
+
+DLLEnsure [Sapphire.Core] 1.00
+DLLEnsure [Sapphire.Resources] 1.00
+
+/<Setrix$Dir>.setSlot -appName Setrix 64K 4K
+
+Run <Setrix$Dir>.!RunImage %*0
\ No newline at end of file
diff --git a/StraySrc/Sculptrix/!Setrix/!Sprites,ff9 b/StraySrc/Sculptrix/!Setrix/!Sprites,ff9
new file mode 100644 (file)
index 0000000..e54e501
Binary files /dev/null and b/StraySrc/Sculptrix/!Setrix/!Sprites,ff9 differ
diff --git a/StraySrc/Sculptrix/!Setrix/Makefile,fe1 b/StraySrc/Sculptrix/!Setrix/Makefile,fe1
new file mode 100644 (file)
index 0000000..4d7a29a
--- /dev/null
@@ -0,0 +1,282 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: !RunImage Modules.Sculptrix setSlot
+
+LIBS = libs:lib.sapphdll
+
+!RunImage: o.setrix $(LIBS)
+       $(SETDATE) o.version version="1.00 ($(DATE))" cright="$(CRIGHT)"
+       $(LD_APP) o.setrix o.version $(LIBS)
+       $(SQUEEZE)
+       $(SET_APP)
+
+Modules.Sculptrix: <SSR$ModDir>.Sculptrix
+       $(INSTALL) <SSR$ModDir>.Sculptrix Modules
+
+setSlot: <SSR$BinDir>.setSlot
+       $(INSTALL) <SSR$BinDir>.setSlot @
+
+install:
+
+clean:
+       -$(RM) o.* !RunImage Modules.Sculptrix setSlot
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.setrix: s.setrix
+o.setrix: libs:header
+o.setrix: libs:swis
+o.setrix: libs:stream
+o.setrix: sapphire:buttons
+o.setrix: sapphire:dbox
+o.setrix: sapphire:defHandler
+o.setrix: sapphire:errorBox
+o.setrix: sapphire:fastMove
+o.setrix: sapphire:flex
+o.setrix: sapphire:event
+o.setrix: sapphire:help
+o.setrix: sapphire:hour
+o.setrix: sapphire:ibicon
+o.setrix: sapphire:menu
+o.setrix: sapphire:menuDefs
+o.setrix: sapphire:msgs
+o.setrix: sapphire:progInfo
+o.setrix: sapphire:ptr
+o.setrix: sapphire:report
+o.setrix: sapphire:res
+o.setrix: sapphire:resources
+o.setrix: sapphire:sapphire
+o.setrix: sapphire:screen
+o.setrix: sapphire:seh
+o.setrix: sapphire:string
+o.setrix: sapphire:warning
+o.setrix: sapphire:choices.choices
+o.setrix: sapphire:dbx.colourPot
+o.setrix: sapphire:dbx.dbx
+o.setrix: sapphire:dbx.dbx
+o.setrix: sapphire:xfer.load
+o.setrix: sapphire:xfer.save
+o.setrix: sapphire:xfer.saveAs
+o.setrix: s.setrix
+o.setrix: libs:header
+o.setrix: libs:swis
+o.setrix: libs:stream
+o.setrix: sapphire:buttons
+o.setrix: sapphire:dbox
+o.setrix: sapphire:defHandler
+o.setrix: sapphire:errorBox
+o.setrix: sapphire:fastMove
+o.setrix: sapphire:flex
+o.setrix: sapphire:event
+o.setrix: sapphire:help
+o.setrix: sapphire:hour
+o.setrix: sapphire:ibicon
+o.setrix: sapphire:menu
+o.setrix: sapphire:menuDefs
+o.setrix: sapphire:msgs
+o.setrix: sapphire:progInfo
+o.setrix: sapphire:ptr
+o.setrix: sapphire:report
+o.setrix: sapphire:res
+o.setrix: sapphire:resources
+o.setrix: sapphire:sapphire
+o.setrix: sapphire:screen
+o.setrix: sapphire:seh
+o.setrix: sapphire:string
+o.setrix: sapphire:warning
+o.setrix: sapphire:choices.choices
+o.setrix: sapphire:dbx.colourPot
+o.setrix: sapphire:dbx.dbx
+o.setrix: sapphire:dbx.dbx
+o.setrix: sapphire:xfer.load
+o.setrix: sapphire:xfer.save
+o.setrix: sapphire:xfer.saveAs
+o.setrix: s.setrix
+o.setrix: libs:header
+o.setrix: libs:swis
+o.setrix: libs:stream
+o.setrix: sapphire:buttons
+o.setrix: sapphire:dbox
+o.setrix: sapphire:defHandler
+o.setrix: sapphire:errorBox
+o.setrix: sapphire:fastMove
+o.setrix: sapphire:flex
+o.setrix: sapphire:event
+o.setrix: sapphire:help
+o.setrix: sapphire:hour
+o.setrix: sapphire:ibicon
+o.setrix: sapphire:menu
+o.setrix: sapphire:menuDefs
+o.setrix: sapphire:msgs
+o.setrix: sapphire:progInfo
+o.setrix: sapphire:ptr
+o.setrix: sapphire:report
+o.setrix: sapphire:res
+o.setrix: sapphire:resources
+o.setrix: sapphire:sapphire
+o.setrix: sapphire:screen
+o.setrix: sapphire:seh
+o.setrix: sapphire:string
+o.setrix: sapphire:warning
+o.setrix: sapphire:choices.choices
+o.setrix: sapphire:dbx.colourPot
+o.setrix: sapphire:dbx.dbx
+o.setrix: sapphire:dbx.dbx
+o.setrix: sapphire:xfer.load
+o.setrix: sapphire:xfer.save
+o.setrix: sapphire:xfer.saveAs
+o.setrix: s.setrix
+o.setrix: libs:header
+o.setrix: libs:swis
+o.setrix: libs:stream
+o.setrix: sapphire:buttons
+o.setrix: sapphire:dbox
+o.setrix: sapphire:defHandler
+o.setrix: sapphire:errorBox
+o.setrix: sapphire:fastMove
+o.setrix: sapphire:flex
+o.setrix: sapphire:event
+o.setrix: sapphire:help
+o.setrix: sapphire:hour
+o.setrix: sapphire:ibicon
+o.setrix: sapphire:menu
+o.setrix: sapphire:menuDefs
+o.setrix: sapphire:msgs
+o.setrix: sapphire:progInfo
+o.setrix: sapphire:ptr
+o.setrix: sapphire:report
+o.setrix: sapphire:res
+o.setrix: sapphire:resources
+o.setrix: sapphire:sapphire
+o.setrix: sapphire:screen
+o.setrix: sapphire:seh
+o.setrix: sapphire:string
+o.setrix: sapphire:warning
+o.setrix: sapphire:choices.choices
+o.setrix: sapphire:dbx.colourPot
+o.setrix: sapphire:dbx.dbx
+o.setrix: sapphire:dbx.dbx
+o.setrix: sapphire:xfer.load
+o.setrix: sapphire:xfer.save
+o.setrix: sapphire:xfer.saveAs
+o.setrix: s.setrix
+o.setrix: libs:header
+o.setrix: libs:swis
+o.setrix: libs:stream
+o.setrix: sapphire:buttons
+o.setrix: sapphire:dbox
+o.setrix: sapphire:defHandler
+o.setrix: sapphire:errorBox
+o.setrix: sapphire:fastMove
+o.setrix: sapphire:flex
+o.setrix: sapphire:event
+o.setrix: sapphire:help
+o.setrix: sapphire:hour
+o.setrix: sapphire:ibicon
+o.setrix: sapphire:menu
+o.setrix: sapphire:menuDefs
+o.setrix: sapphire:msgs
+o.setrix: sapphire:progInfo
+o.setrix: sapphire:ptr
+o.setrix: sapphire:report
+o.setrix: sapphire:res
+o.setrix: sapphire:resources
+o.setrix: sapphire:sapphire
+o.setrix: sapphire:screen
+o.setrix: sapphire:seh
+o.setrix: sapphire:string
+o.setrix: sapphire:warning
+o.setrix: sapphire:choices.choices
+o.setrix: sapphire:dbx.colourPot
+o.setrix: sapphire:dbx.dbx
+o.setrix: sapphire:dbx.dbx
+o.setrix: sapphire:xfer.load
+o.setrix: sapphire:xfer.save
+o.setrix: sapphire:xfer.saveAs
diff --git a/StraySrc/Sculptrix/!Setrix/Resources/Messages b/StraySrc/Sculptrix/!Setrix/Resources/Messages
new file mode 100644 (file)
index 0000000..b1514ec
--- /dev/null
@@ -0,0 +1,114 @@
+;
+; Setrix messages
+;
+; © 1995 Straylight
+;
+
+; --- Icon bar ---
+
+sxhIB:$th $sx icon.  $sx allows you to $(cf)e the style of 3D buttons used in Straylight applications.|m$cst display the main $(db).
+
+; --- Program menu ---
+
+sxINF:Info...
+sxQUT:Quit
+
+sxhMN0:Click $s or move pointer right to show information about $(sx).
+sxhMN1:$cst quit $(sx).
+
+sxPUR:Configure Sculptrix border style
+
+sxOTQ:Configuration has not been saved.  Are you sure you want to quit?
+sxQTB:Quit
+
+; --- Loading and saving ---
+
+saveDTDEAD:Data transfer failed, receiver dead
+saDRAGICN:To save, drag the file icon to a directory viewer.
+sahDB:$th save $(db).
+sahFICN:Drag this icon to a directory viewer or another application to save the file.
+sahWRT:Type a filename for the file here.
+sahOK:Click here to save the file under the name shown.
+
+sxSVT:Save config
+sxSVERR:Error saving configuration file: %0
+sxCSI:You can't save configuration files back to Setrix
+sxBDCFG:This is not a Sculptrix configuration file
+sxLDERR:Error loading configuration file: %0
+
+sxRPLF:File '%0' already exists.  Do you want to replace it?
+sxRPLB:Replace
+
+; --- Main dialogue box ---
+
+sxhDB:$th main $(cf)ation $(db).
+
+sxhDBSTS:$cst $ch Straylight $(sgb).  $fbr 4.
+sxhDBACS:$cst $ch Acorn $(sgb).  $fbr 2.
+
+sxhDBOK:$cst accept the $set in this $(db).  If you have changed the $(set), the screen will be refreshed.
+sxhDBSV:$cst save the $(cf)ation.  A save $db will be displayed.
+sxhDBCAN:$cst discard the $set in this $(db), and continue using the current display style.
+
+sxhDB???:$cte $crest
+
+; --- Memory allocation ---
+
+allocNOMEM:Not enough memory
+hpNEMI:Not enough memory to intialise heap
+
+; --- Dialogue box handling ---
+
+dboxCRTERR:Couldn't create dialogue box: %0
+ok:OK
+can:Cancel
+
+cpTITLE:Edit colour
+
+; --- Various standard dialogue boxes ---
+
+ebERRFRM:Error from %0
+noteFROM:Note from %0
+warnFROM:Warning from %0
+
+piHELP:This window shows you information about this version of $(sx).
+
+; --- Menus ---
+
+mSOVF:Not enough memory to create menu -- increase menu_stackSize
+
+; --- Dealing with help messages ---
+
+helpOFLOW:Help message overflow
+
+; --- Loading resources ---
+
+msgsMLE:Error loading messages: %0
+rsprSLE:Error loading sprites: %0
+tplTNF:Template '%0' not found
+tplTLE:Error loading templates: %0
+
+; --- Handling errors ---
+
+sehNOHND:Fatal internal error: Uncaught exception thrown (type &%x0)
+rptERR:Internal error: '%1'.  Click Continue to try to resume, or Quit to stop %0.
+rptCONF:Are you sure you want to quit %0?  Click Continue to try to resume, or Quit to quit.
+rptUKEXC:Unknown exception (type &%x0)
+rptCONT:Continue
+rptQUIT:Quit
+
+; --- Abbreviations for help messages ---
+
+s:SELECT
+th:This is the
+cst:Click SELECT to
+sx:Setrix
+ch:choose
+sgb:style group boxes
+fbr:For best results, you should set the group box active colour to be colour
+sdb:settings in this dialogue box
+db:dialogue box
+cf:configur
+set:settings
+cte:Click to edit the
+crest:colour.  Clicking SELECT or ADJUST will cycle the colours, while clicking MENU will open a dialogue box.
diff --git a/StraySrc/Sculptrix/!Setrix/Resources/Sprites,ff9 b/StraySrc/Sculptrix/!Setrix/Resources/Sprites,ff9
new file mode 100644 (file)
index 0000000..6046754
Binary files /dev/null and b/StraySrc/Sculptrix/!Setrix/Resources/Sprites,ff9 differ
diff --git a/StraySrc/Sculptrix/!Setrix/Resources/Templates,fec b/StraySrc/Sculptrix/!Setrix/Resources/Templates,fec
new file mode 100644 (file)
index 0000000..20a9f09
Binary files /dev/null and b/StraySrc/Sculptrix/!Setrix/Resources/Templates,fec differ
diff --git a/StraySrc/Sculptrix/!Setrix/s/setrix b/StraySrc/Sculptrix/!Setrix/s/setrix
new file mode 100644 (file)
index 0000000..0ceb6b5
--- /dev/null
@@ -0,0 +1,1150 @@
+;
+; setrix.s
+;
+; Setup program for Sculptrix
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Revision history -----------------------------------------------------
+;
+; Version      By      Change
+;
+; 1.00         MDW     Initial version written to accompany Sculptrix 2.00
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sapphire:buttons
+               GET     sapphire:dbox
+               GET     sapphire:defHandler
+               GET     sapphire:errorBox
+               GET     sapphire:fastMove
+               GET     sapphire:flex
+               GET     sapphire:event
+               GET     sapphire:help
+               GET     sapphire:hour
+               GET     sapphire:ibicon
+               GET     sapphire:menu
+               GET     sapphire:menuDefs
+               GET     sapphire:msgs
+               GET     sapphire:progInfo
+               GET     sapphire:ptr
+               GET     sapphire:report
+               GET     sapphire:res
+               GET     sapphire:resources
+               GET     sapphire:sapphire
+               GET     sapphire:screen
+               GET     sapphire:seh
+               GET     sapphire:string
+               GET     sapphire:warning
+
+               GET     sapphire:choices.choices
+
+               GET     sapphire:dbx.colourPot
+               GET     sapphire:dbx.dbx
+
+               GET     sapphire:xfer.load
+               GET     sapphire:xfer.save
+               GET     sapphire:xfer.saveAs
+
+               IMPORT  cright
+               IMPORT  version
+
+;----- Icon handles ---------------------------------------------------------
+
+sxIcon__cols   EQU     12                      ;Main colour table
+sxIcon__hilite EQU     22                      ;Highlight colour
+sxIcon__slab   EQU     24                      ;Slabbed background
+sxIcon__ccGrp  EQU     26                      ;CC-style group box
+sxIcon__acGrp  EQU     27                      ;Acorn-style group box
+sxIcon__ok     EQU     28                      ;OK button
+sxIcon__save   EQU     29                      ;Save button
+sxIcon__cancel EQU     30                      ;Cancel button
+
+;----- Configuration blocks -------------------------------------------------
+
+               ^       0
+sxConf__magic  #       4                       ;Magic identifier word
+sxConf__flags  #       4                       ;Various flags
+sxConf__stdCols        #       2                       ;Standard colour pair
+sxConf__grpCols        #       2                       ;Group colour pair
+sxConf__shdCols        #       2                       ;Shaded normal colours
+sxConf__shgCols        #       2                       ;Shaded group colours
+sxConf__hilite #       1                       ;The highlight colour
+sxConf__slab   #       1                       ;The slabbing colour
+               #       2                       ;Alignment padding
+sxConf__size   #       0
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+sx__wStart     #       0
+
+sx__flags      #       4                       ;Various usefule flags
+sx__dbox       #       4                       ;The dialogue box handle
+sx__anchor     #       4                       ;A flex anchor for loading
+sx__config     #       sxConf__size            ;Configuration buffer
+sx__filename   #       256                     ;Filename buffer
+sx__pollBlk    #       256                     ;Block for Wimp_Poll
+
+sx__wSize      EQU     {VAR}-sx__wStart
+
+sxFlag__safe   EQU     (1<<0)                  ;File has been saved
+sxFlag__saving EQU     (1<<1)                  ;We're saving a file
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Client$$Code|,CODE,READONLY
+               ENTRY
+
+; --- main ---
+;
+; On entry:    --
+;
+; On exit:     Via OS_Exit
+;
+; Use:         Starts up the application.
+
+main           ROUT
+
+               ADR     R0,sx__appName          ;Point to the app name
+               LDR     R1,=sx__wSize           ;Get the workspace size
+               MOV     R2,#0                   ;Standard stack size
+               BL      sapphire_init           ;Set up the memory map
+               BL      sx__preInit             ;Do pre-initialisation
+               BL      sapphire_libInit        ;Crank up the library
+               BL      sx__init                ;Do other initialisation
+
+               BL      seh_throwErrors         ;Throw errors at ne, please
+               BL      report_catchAll         ;Install last error handler
+
+00             MOV     R0,#0                   ;Don't get idle events
+               ADR     R1,sx__pollBlk          ;Point to the poll block
+               BL      event_poll              ;Do some polling
+               BLCC    sx__unknowns            ;Handle unknowns ourselves
+               BLCC    defHandler              ;Do default handling
+               B       %b00                    ;And keep looping
+
+sx__appName    DCB     "Setrix",0
+
+               LTORG
+
+; --- sx__preInit ---
+;
+; On entry:    --
+;
+; On exit:     R0-R10 corrupted
+;
+; Use:         Does any initialisation required before Sapphire is started,
+
+sx__preInit    ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+               BL      hour_init               ;Initialise hourglass
+               BL      hour_on                 ;Turn on the hourglass
+               BL      resources_init          ;Fetch shared resources
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- sx__init ---
+;
+; On entry:    --
+;
+; On exit:     R0-R10 corrupted
+;
+; Use:         Initialises the rest of the application.
+
+sx__init       ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+               BL      sx__initWork            ;Initialise the workspace
+               BL      sx__loadConf            ;Load the config file
+               BL      ptr_blinkOn             ;Turn on the blinking cursor
+               BL      sx__iconBar             ;Set up the icon bar
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- sx__initWork ---
+;
+; On entry:    --
+;
+; On exit:     R0-R10 corrupted
+;
+; Use:         Sets up the workspace.
+
+sx__initWork   ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+
+               ; --- Set up some odd bits ---
+
+               MOV     R14,#0                  ;Clear the handle
+               STR     R14,sx__dbox            ;Store in the workspace
+
+               MOV     R14,#sxFlag__safe       ;The file is safe currently
+               STR     R14,sx__flags           ;Store the flags away
+
+               ; --- Set up default filename ---
+
+               MOV     R0,#0                   ;Use a default filename
+               BL      sx__setFilename         ;Set the filename, please
+
+               ; --- Set up the config buffer ---
+
+               LDR     R14,sx__magic           ;Load the magic number
+               ADR     R0,sx__config           ;Point to the config buffer
+               STR     R14,[R0],#4             ;Store it in there
+               MOV     R1,#sxConf__size-4      ;Size of my buffer
+               SWI     Sculptrix_ReadConfig    ;Read the configuration
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- sx__loadConf ---
+;
+; On entry:    --
+;
+; On exit:     R0-R10 corrupted
+;
+; Use:         Loads the default config file, if there is one.
+
+sx__loadConf   ROUT
+
+               STMFD   R13!,{R14}              ;Save the return address
+
+               MOV     R0,#1                   ;Enable use of `Choices'
+               BL      choices_useChoices      ;So do that, then
+
+               ADR     R0,sx__confFile         ;Point to the file name
+               MOV     R1,R11                  ;Build name in scratchpad
+               MOV     R2,#0                   ;Not going to write to it
+               BL      choices_find            ;Find the filename
+               BCC     %90sx__loadConf         ;If not there, skip on
+
+               MOV     R1,R0                   ;Point to the filename
+               ADR     R10,sx__config          ;Point to config block
+               BL      sx__ldFile              ;Try to load the file
+               BLVC    sx__ldDone              ;If OK, set it up nicely
+
+90sx__loadConf LDMFD   R13!,{PC}^              ;And return to caller
+
+sx__magic      DCB     "SXCF"
+sx__confFile   DCB     "Config",0
+
+               LTORG
+
+; --- sx__iconBar ---
+;
+; On entry:    --
+;
+; On exit:     R0-R10 corrupted
+;
+; Use:         Creates the icon bar icon.
+
+sx__iconBar    ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               ADR     R0,sx__ibSprite         ;Point to the sprite name
+               MOV     R1,#0                   ;No text, please
+               MOV     R2,#-1                  ;Put icon on the right
+               MOV     R3,#0                   ;No priority things, please
+               ADR     R4,sx__ibHandler        ;Point to the handler
+               ADR     R5,sx__config           ;No document passed in R10
+               MOV     R6,R12                  ;Pass workspace in R12
+               BL      ibicon_create           ;Create the icon, please
+               SWIVS   OS_GenerateError        ;If failed, raise an error
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+sx__ibSprite   DCB     "!setrix",0
+
+               LTORG
+
+; --- sx__ibHandler ---
+;
+; On entry:    R0 == event code
+;
+; On exit:     --
+;
+; Use:         Handles events for the icon bar icon.
+
+sx__ibHandler  ROUT
+
+               CMP     R0,#(%10-%00)/4         ;Is the event in range?
+               ADDCC   PC,PC,R0,LSL #2         ;Yes -- dispatch it then
+               MOVS    PC,R14                  ;Otherwise return now
+
+00             B       sx__showDbox
+               B       sx__ibCrtMenu
+               MOVS    PC,R14
+               B       sx__load
+               B       sx__load
+               B       sx__ibHelp
+10
+               ; --- Display the icon bar menu ---
+
+sx__ibCrtMenu  STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               ADR     R0,sx__ibMenu           ;Point to the menu block
+               ADR     R1,sx__mnHandler        ;Point to the handler
+               MOV     R2,R10                  ;Pass R10 to handler
+               MOV     R3,R12                  ;Pass R12 to handler
+               BL      menu_create             ;Create the menu, please
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+sx__ibMenu     MENU    "Setrix"
+               ITEM    "sxINF"
+               SUBWARN
+               ITEM    "sxQUT"
+               MENUEND
+
+               ; --- Give help to a user ---
+
+sx__ibHelp     STMFD   R13!,{R0,R14}           ;Save some registers
+               ADR     R0,sx__ibHelpTag        ;Point to help tag
+               BL      msgs_lookup             ;Translate the tag
+               BL      help_add                ;Add it to the help message
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+sx__ibHelpTag  DCB     "sxhIB",0
+
+               LTORG
+
+; --- sx__mnHandler ---
+;
+; On entry:    R0 == event code
+;              R1 == menu item number
+;
+; On exit:     --
+;
+; Use:         Handles events on the program menu.
+
+sx__mnHandler  ROUT
+
+               CMP     R0,#mEvent_help         ;A help request?
+               BEQ     sx__mnHelp              ;Yes -- give some help then
+
+               CMP     R0,#mEvent_select       ;Is it a click event?
+               CMPNE   R0,#mEvent_subMenu      ;Or a submenu warning?
+               MOVNES  PC,R14                  ;No -- ignore it then
+
+               CMP     R1,#(%10-%00)/4         ;Is the item known?
+               ADDCC   PC,PC,R1,LSL #2         ;Yes -- dispatch
+               MOVS    PC,R14                  ;Otherwise ignore the event
+
+00             B       sx__showInfo            ;Show program information
+               B       sx__quit                ;Quit the application
+10
+               ; --- Display the Info box ---
+
+sx__showInfo   STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADR     R0,sx__purpose          ;Point to the purpose string
+               BL      msgs_lookup             ;Translate the message
+               LDR     R1,=cright              ;Point to copyright message
+               LDR     R2,=version             ;Point to version string
+               BL      progInfo                ;Display the dialogue
+               MOVVS   R1,#1                   ;If error, get button layout
+               BLVS    errorBox                ;And report to the user
+               LDMFD   R13!,{R0-R2,PC}^        ;Return to caller
+
+sx__purpose    DCB     "sxPUR",0
+
+               ; --- Try to quit the program ---
+
+sx__quit       STMFD   R13!,{R14}              ;Save a register
+               BL      sx__okToQuit            ;Is it all right to quit?
+               SWICS   OS_Exit                 ;Yes -- do it then
+               LDMFD   R13!,{PC}^              ;Otherwise return
+
+               ; --- Give some help to the user ---
+
+sx__mnHelp     STMFD   R13!,{R0,R14}           ;Save some registers
+               ADR     R0,sx__mnHelpTag        ;Point to the message tag
+               BL      menu_help               ;Translate and add
+               LDMFD   R13!,{R0,PC}^           ;Return when done
+
+sx__mnHelpTag  DCB     "sxhMN",0
+
+               LTORG
+
+; --- sx__unknowns ---
+;
+; On entry:    R0 == event code
+;              R1 == pointer to event data
+;
+; On exit:     R2-R10 corrupted
+;              CS to claim
+;
+; Use:         Handles unknown events.  Specifically, it looks at PreQuit
+;              messages, and asks the user if it's OK to quit.
+
+sx__unknowns   ROUT
+
+               CMP     R0,#17                  ;Is this a message?
+               CMPNE   R0,#18                  ;Check both types
+               MOVNES  PC,R14                  ;No -- ignore it then
+
+               LDR     R2,[R1,#16]             ;Load the message code
+               CMP     R2,#8                   ;Is this a PreQuit message?
+               MOVNES  PC,R14                  ;No -- ignore it then
+
+               ; --- Handle a PreQuit message ---
+
+               STMFD   R13!,{R0,R1,R14}        ;Save a register
+               BL      sx__okToQuit            ;Ask the user if this is OK
+               BCS     %90sx__unknowns         ;Yes -- then return now
+
+               ; --- Acknowledge the message to prevent quitting ---
+
+               MOV     R0,R11                  ;Point to scratchpad
+               LDR     R2,[R1,#0]              ;Load the message size
+               BL      fastMove                ;Copy the message over
+
+               LDR     R14,[R11,#8]            ;This is a reply
+               STR     R14,[R11,#12]           ;Store the ref away
+               MOV     R0,#19                  ;Send as an acknowledgement
+               MOV     R1,R11                  ;Point to copied message
+               LDR     R2,[R11,#4]             ;Load the task handle
+               SWI     Wimp_SendMessage        ;Send the message on
+
+               ; --- Now return, claiming the event ---
+
+90sx__unknowns LDMFD   R13!,{R0,R1,R14}        ;Restore registers
+               ORRS    PC,R14,#C_flag          ;And return, claiming it
+
+               LTORG
+
+; --- sx__okToQuit ---
+;
+; On entry:    --
+;
+; On exit:     CS if we're allowed to quit
+;
+; Use:         Ensures that we're allowed to quit.  If we're in possession
+;              of unsaved data, we ask the user first.
+
+sx__okToQuit   ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+
+               ; --- Check whether the data needs saving ---
+
+               LDR     R14,sx__flags           ;Load my flags word
+               TST     R14,#sxFlag__safe       ;Is the flag set?
+               BNE     %90sx__okToQuit         ;Yes -- then return OK
+
+               ; --- Now ask the user before we go any further ---
+
+               ADR     R0,sx__quitMsg          ;Point to the message
+               BL      msgs_lookup             ;Translate into English
+               ADR     R1,sx__quitButts        ;Point to button block
+               BL      warning                 ;Ask the user nicely
+               BCS     %90sx__okToQuit         ;If OK, return this
+
+               LDMFD   R13!,{R0,R1,R14}        ;Restore registers
+               BICS    PC,R14,#C_flag          ;And return not OK
+
+90sx__okToQuit LDMFD   R13!,{R0,R1,R14}        ;Restore registers
+               ORRS    PC,R14,#C_flag          ;And return OK
+
+sx__quitButts  BUTTON  "sxQTB"
+               BCANCEL
+               BUTEND
+
+sx__quitMsg    DCB     "sxOTQ",0
+
+               LTORG
+
+;----- Dialogue box handling ------------------------------------------------
+
+; --- sx__showDbox ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Opens the main dialogue box, and sets it up.
+
+sx__showDbox   ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               LDR     R0,sx__dbox             ;Load dialogue box handle
+               CMP     R0,#0                   ;Is the dialogue box open?
+               BNE     %80sx__showDbox         ;Yes -- just bring it forward
+
+               ; --- Create the dialogue box ---
+
+               ADR     R0,sx__dbName           ;Point to the dialogue name
+               BL      dbox_create             ;Create the dialogue box
+               BVS     %90sx__showDbox         ;If failed, tidy up
+               STR     R0,sx__dbox             ;Store the new handle
+
+               ADR     R1,sx__dbHandler        ;Point to the handler
+               ADR     R2,sx__config           ;Point to config buffer
+               MOV     R3,R12                  ;Pass R12 pointer on
+               BL      dbox_eventHandler       ;Set up the event handler
+
+               ADR     R1,sx__dbControls       ;Point to dbx defs block
+               BL      dbx_declare             ;Set up the controls
+               BL      sx__dbReset             ;Reset the dialogue settings
+
+               ; --- Finally, display the dialogue on-screen ---
+
+80sx__showDbox MOV     R1,#dbOpen_current+dbOpen_persist
+               BL      dbox_open               ;Display the dialogue box
+               LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               ; --- Handle an error ---
+
+90sx__showDbox MOV     R1,#1                   ;Just an OK button
+               BL      errorBox                ;Display the error
+               LDMFD   R13!,{R0-R3,PC}^        ;And return
+
+sx__dbName     DCB     "setrix",0
+
+sx__dbControls COLPOT  sxIcon__cols+0,R10,sxConf__stdCols+0,0
+               COLPOT  sxIcon__cols+1,R10,sxConf__stdCols+1,0
+               COLPOT  sxIcon__cols+2,R10,sxConf__grpCols+0,0
+               COLPOT  sxIcon__cols+3,R10,sxConf__grpCols+1,0
+               COLPOT  sxIcon__cols+4,R10,sxConf__shdCols+0,0
+               COLPOT  sxIcon__cols+5,R10,sxConf__shdCols+1,0
+               COLPOT  sxIcon__cols+6,R10,sxConf__shgCols+0,0
+               COLPOT  sxIcon__cols+7,R10,sxConf__shgCols+1,0
+
+               COLPOT  sxIcon__hilite,R10,sxConf__hilite,0
+               COLPOT  sxIcon__slab,R10,sxConf__slab,0
+
+               DBXEND
+
+               LTORG
+
+; --- sx__dbClose ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Closes the dialogue box.
+
+sx__dbClose    ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               LDR     R0,sx__dbox             ;Load the dialogue handle
+               BL      dbox_writePos           ;Save the position back
+               BL      dbox_destroy            ;Get rid of the dialogue
+               MOV     R14,#0                  ;Clear the handle in wspace
+               STR     R14,sx__dbox            ;Store that away
+               LDMFD   R13!,{R0,PC}^           ;And return to caller
+
+               LTORG
+
+; --- sx__dbHandler ---
+;
+; On entry:    R0 == dialogue box event code
+;              R1-R7 == dependent on the event
+;
+; On exit:     --
+;
+; Use:         Handles events in the main dialogue box.
+
+sx__dbHandler  ROUT
+
+               CMP     R0,#sxIcon__ok          ;Is this an OK event?
+               CMPNE   R0,#dbEvent_OK          ;Check for a return press
+               BEQ     sx__dbOK                ;Yes -- handle the event
+
+               CMP     R0,#sxIcon__save        ;Is it the save icon?
+               BEQ     sx__dbSave              ;Yes -- handle that
+
+               CMP     R0,#sxIcon__cancel      ;Is this a cancel event
+               CMPNE   R0,#dbEvent_cancel      ;Check for an escape
+               BEQ     sx__dbCancel            ;Yes -- handle it
+
+               CMP     R0,#dbEvent_load        ;Is it a load event
+               CMPNE   R0,#dbEvent_save        ;Or a save -- I don't mind
+               BEQ     sx__load                ;Load the file
+
+               CMP     R0,#dbEvent_help        ;Is it a help event?
+               BEQ     sx__dbHelp              ;Yes -- give some help then
+
+               MOVS    PC,R14                  ;Otherwise, do nothing
+
+               ; --- Handle a click on the OK button ---
+
+sx__dbOK       STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R2,R1                   ;Remember this value
+               LDR     R0,sx__dbox             ;Load the dialogue handle
+               MOV     R1,#sxIcon__ok          ;Get the icon handle
+               BL      dbox_slab               ;Pop the icon in
+               BL      sx__dbRead              ;Read the icon settings
+               TST     R2,#1                   ;Is the adjust button down?
+               BLEQ    sx__dbClose             ;Maybe close the dialogue
+               BL      dbox_unslab             ;Unslab the button
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               ; --- Handle a click on the Save button ---
+
+sx__dbSave     STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               LDR     R0,sx__dbox             ;Load the dialogue handle
+               MOV     R1,#sxIcon__save        ;Get the icon handle
+               BL      dbox_slab               ;Pop the icon in
+               BL      sx__dbRead              ;Read the icon settings
+               BL      sx__save                ;Start the save box
+               BL      dbox_unslab             ;Unslab the button
+               LDMFD   R13!,{R0,R1,PC}^        ;And return to caller
+
+               ; --- Handle a click on the cancel button ---
+
+sx__dbCancel   STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               MOV     R2,R1                   ;Remember this value
+               LDR     R0,sx__dbox             ;Load the dialogue handle
+               MOV     R1,#sxIcon__cancel      ;Get the icon handle
+               BL      dbox_slab               ;Pop the icon in
+
+               ADD     R0,R10,#sxConf__flags   ;Point past the magic number
+               SWI     Sculptrix_ReadConfig    ;Read the config back
+
+               TST     R2,#1                   ;Is the adjust button down?
+               BLEQ    sx__dbClose             ;Maybe close the dialogue
+               BLNE    sx__dbReset             ;Maybe reset the settings
+
+               BL      dbox_unslab             ;Unslab the button
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               ; --- Give some help to a user ---
+
+sx__dbHelp     STMFD   R13!,{R0,R14}           ;Save some registers
+               ADR     R0,sx__dbHelpTag        ;Point to the message tag
+               BL      msgs_lookup             ;Translate the message
+               BL      help_add                ;Add it to the help message
+               BL      dbox_help               ;Read help from an icon
+               LDMFD   R13!,{R0,PC}^           ;Return when done
+
+sx__dbHelpTag  DCB     "sxhDB",0
+
+               LTORG
+
+; --- sx__dbReset ---
+;
+; On entry:    R0 == dialogue box handle
+;              R10 == pointer to config buffer
+;
+; On exit:     --
+;
+; Use:         Resets the settings shown in the dialogue box.
+
+sx__dbReset    ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Do the colour box ---
+
+               LDR     R0,sx__dbox             ;Load the dialogue handle
+               ADR     R2,sx__dbxList          ;Point to the icon number tbl
+00             LDRB    R1,[R2],#1              ;Load the next number out
+               CMP     R1,#&FF                 ;Is this the end?
+               BLNE    dbx_update              ;No -- update the icon
+               BNE     %b00                    ;And loop back
+
+               ; --- Set the radio buttons ---
+
+               LDR     R14,[R10,#sxConf__flags] ;Load the flags word
+               TST     R14,#1                  ;Is the `Acorn style' bit on?
+               MOVEQ   R1,#sxIcon__ccGrp       ;No -- turn on CC icon
+               MOVNE   R1,#sxIcon__acGrp       ;Yes -- turn on Acorn icon
+               BL      dbox_radio              ;Select the right one
+
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+sx__dbxList    DCB     sxIcon__cols+0
+               DCB     sxIcon__cols+1
+               DCB     sxIcon__cols+2
+               DCB     sxIcon__cols+3
+               DCB     sxIcon__cols+4
+               DCB     sxIcon__cols+5
+               DCB     sxIcon__cols+6
+               DCB     sxIcon__cols+7
+               DCB     sxIcon__hilite
+               DCB     sxIcon__slab
+               DCB     &FF
+
+               LTORG
+
+; --- sx__dbRead ---
+;
+; On entry:    R0 == dialogue box handle
+;
+; On exit:     --
+;
+; Use:         Reads the settings in the dialogue box, and maybe updates
+;              the screen.
+
+sx__dbRead     ROUT
+
+               STMFD   R13!,{R0,R1,R14}        ;Save some registers
+               MOV     R1,#sxIcon__acGrp       ;Find the Acorn button
+               BL      dbox_isSelected         ;Is the icon selected?
+               LDR     R14,[R10,#sxConf__flags] ;Load the flags word
+               ORRCS   R14,R14,#1              ;If on, set the flag
+               BICCC   R14,R14,#1              ;Otherwise clear it
+               STR     R14,[R10,#sxConf__flags] ;Store the flags back
+               LDR     R14,sx__flags           ;Load the main flags word
+               BIC     R14,R14,#sxFlag__safe   ;We've modified the file
+               STR     R14,sx__flags           ;Save them back now
+               BL      sx__update              ;Send it off to the module
+               LDMFD   R13!,{R0,R1,PC}^        ;Return to caller
+
+               LTORG
+
+; --- sx__update ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Updates the Sculptrix configuration.
+
+sx__update     ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               ADD     R0,R10,#sxConf__flags   ;Find the main block
+               SWI     Sculptrix_SetConfig     ;Set the configuration
+               BCC     %90sx__update           ;If nothing changed, return
+               BL      screen_getInfo          ;Read the information
+               ADD     R14,R0,#screen_width    ;Find the dimensions
+               LDMIA   R14,{R3,R4}             ;Load them out
+               MOV     R0,#-1                  ;Redraw the whole screen
+               MOV     R1,#0                   ;Start at the left
+               MOV     R2,#0                   ;And the bottom
+               SWI     Wimp_ForceRedraw        ;Refresh the screen
+90sx__update   LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+;----- Data transfer --------------------------------------------------------
+
+; --- sx__setFilename ---
+;
+; On entry:    R0 == pointer to filename, or 0
+;
+; On exit:     --
+;
+; Use:         Sets the filename used for saving.
+
+sx__setFilename        ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               CMP     R0,#0                   ;Do we want the default?
+               ADREQL  R0,sx__confFile         ;Yes -- use that then
+               ADR     R1,sx__filename         ;Point to output buffer
+               MOV     R2,#256                 ;Size of the buffer
+               ORR     R2,r2,#&C0000000        ;Suppress nasty transforms
+               SWI     OS_GSTrans              ;Do the copy
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+               LTORG
+
+; --- sx__replace ---
+;
+; On entry:    R0 == pointer to filename
+;              R1 == safeness flag
+;              R2 == pointer to old filename, or 0
+;
+; On exit:     CS if we can replace the file
+;
+; Use:         Finds out if it's safe to replace a file.
+
+sx__replace    ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               CMP     R1,#0                   ;Is the file safe?
+               BEQ     %90sx__replace          ;No -- then it's OK
+
+               MOVS    R1,R2                   ;Point to old filename
+               BEQ     %f00                    ;If none, we must ask
+               BL      str_icmp                ;Compare the strings
+               BEQ     %90sx__replace          ;If they match, carry on
+
+00             BL      res_exists              ;Does the file exist?
+               BCC     %90sx__replace          ;No -- then we can proceed
+
+               MOV     R2,R0                   ;Point to the filename
+               ADR     R0,sx__replMsg          ;Point to message skeleton
+               BL      msgs_lookup             ;Translate that for me
+               BL      str_buffer              ;Find a handy buffer
+               BL      str_subst               ;And build me a message
+               ADR     R1,sx__replButts        ;Point to buttons
+               BL      warning                 ;Ask the user about this
+               BCS     %90sx__replace          ;OK -- carry on then
+
+               LDMFD   R13!,{R0-R2,R14}        ;Restore registers
+               BICS    PC,R14,#C_flag          ;And say we mustn't do this
+
+90sx__replace  LDMFD   R13!,{R0-R2,R14}        ;Restore registers
+               ORRS    PC,R14,#C_flag          ;And say we can carry on
+
+sx__replButts  BUTTON  "sxRPLB"
+               BCANCEL
+               BUTEND
+
+sx__replMsg    DCB     "sxRPLF",0
+
+               LTORG
+
+; --- sx__save ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Starts a save operation.
+
+sx__save       ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R0,#sxConf__size        ;Size of the block
+               LDR     R1,=&FFD                ;Get the filetype (data)
+               ADR     R2,sx__filename         ;Point to filename buffer
+               ADR     R3,sx__savers           ;Point to saver block
+               MOV     R4,R10                  ;Point to block to save
+               MOV     R5,R12                  ;Pass workspace along too
+               BL      saveAs                  ;Save the file then
+               BVS     %80sx__save             ;If it failed, tidy up
+               LDR     R14,sx__flags           ;Load our flags word
+               ORR     R14,R14,#sxFlag__saving ;Set the saving flag
+               STR     R14,sx__flags           ;Save the flags back
+               B       %90sx__save             ;And return to caller
+
+80sx__save     MOV     R1,#1                   ;If it failed, get an OK box
+               BL      errorBox                ;And report the error
+90sx__save     LDMFD   R13!,{R0-R5,PC}^        ;Return when finished
+
+sx__savers     DCB     "sxSVT",0
+               B       sx__svClose
+               B       sx__svFile
+               B       sx__svSend
+               B       sx__svDone
+               B       sx__svFail
+
+               LTORG
+
+; --- sx__svClose ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Notes that the dialogue box has been closed.
+
+               EXPORT  sx__svClose
+sx__svClose    ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R14,sx__flags           ;Load our flags word
+               BIC     R14,R14,#sxFlag__saving ;Clear the saving flag
+               STR     R14,sx__flags           ;Save the flags back
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- sx__svFile ---
+;
+; On entry:    R0 == pointer to filename
+;              R1 == safeness flag
+;
+; On exit:     May return an error
+;
+; Use:         Saves the configuration to a file.
+
+sx__svFile     ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               ADR     R2,sx__filename         ;Point to current name
+               BL      sx__replace             ;Make sure we can replace
+               MOVCC   R0,#0                   ;If not, get null error
+               BCC     %90sx__svFile           ;And skip onwards
+
+               MOV     R1,R0                   ;Point to the filename
+               MOV     R0,#10                  ;Save whole file, please
+               LDR     R2,=&FFD                ;Get the filetype
+               MOV     R4,R10                  ;Point to the file info
+               ADD     R5,R4,#sxConf__size     ;Get the size information
+               SWI     XOS_File                ;Save the file, please
+               BVS     %90sx__svFile           ;If failed, skip on
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+90sx__svFile   ADD     R13,R13,#4              ;Don't restore R0
+               LDMFD   R13!,{R1-R5,PC}         ;Restore other registers
+
+               LTORG
+
+; --- sx__svSend ---
+;
+; On entry:    --
+;
+; On exit:     R0 == pointer to base
+;              R1 == length of data
+;              CS if this is the last block
+;
+; Use:         Sends data via RAM transfer.
+
+sx__svSend     ROUT
+
+               MOV     R0,R10                  ;Point to the data
+               MOV     R1,#sxConf__size        ;Get the size of the data
+               ORRS    PC,R14,#C_flag          ;And return with C set
+
+               LTORG
+
+; --- sx__svDone ---
+;
+; On entry:    R0 == pointer to filename, if file is safe
+;              R1 == safeness flag
+;
+; On exit:     --
+;
+; Use:         Sets up various nice things, if the file is saved properly.
+
+sx__svDone     ROUT
+
+               CMP     R1,#0                   ;Is the file safe?
+               MOVEQS  PC,R14                  ;No -- do nothing then
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+               BL      sx__setFilename         ;Change the filename
+               LDR     R14,sx__flags           ;Load the flags word
+               ORR     R14,R14,#sxFlag__safe   ;The file is safe, now
+               STR     R14,sx__flags           ;Store the flags back
+               LDMFD   R13!,{R1,PC}^           ;Return when done
+
+               LTORG
+
+; --- sx__svFail ---
+;
+; On entry:    R0 == pointer to error, or 0
+;
+; On exit:     --
+;
+; Use:         Tidies up after a botched save.
+
+sx__svFail     ROUT
+
+               CMP     R0,#0                   ;Is there something here?
+               MOVEQS  PC,R14                  ;No -- return then
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADD     R2,R0,#4                ;Point to error text
+               ADR     R0,sx__svError          ;Point to a skeleton thing
+               BL      msgs_error              ;Translate the error
+               MOV     R1,#1                   ;Just an OK box, please
+               BL      errorBox                ;Report the error
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+sx__svError    DCD     1
+               DCB     "sxSVERR",0
+
+               LTORG
+
+; --- sx__load ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Starts a load operation for a configuration file.
+
+sx__load       ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Make sure we're not the saver ---
+
+               LDR     R14,sx__flags           ;Load the flags word
+               TST     R14,#sxFlag__saving     ;Are we the saver?
+               BNE     %80sx__load             ;Yes -- oops
+
+               ; --- Start the load operation ---
+
+               ADR     R0,sx__loaders          ;Point to loaders block
+               MOV     R1,R10                  ;Pass data pointer
+               MOV     R2,R12                  ;Pass workspace in R12
+               BL      load                    ;Start the load operation
+               B       %90sx__load             ;And return to caller
+
+               ; --- Report error about saving into ourselves ---
+
+80sx__load     ADR     R0,sx__cantSave         ;Point to the error
+               BL      msgs_error              ;Translate the nastygram
+               MOV     R1,#1                   ;Just an OK button, please
+               BL      errorBox                ;Report the error
+90sx__load     LDMFD   R13!,{R0-R2,PC}^        ;Return when done
+
+sx__cantSave   DCD     1
+               DCB     "sxCSI",0
+
+sx__loaders    B       sx__ldInitBuf
+               B       load_killBuf
+               B       load_extendBuf
+               B       load_doneBuf
+               B       sx__ldFile
+               B       sx__ldDone
+               B       sx__ldFail
+
+               LTORG
+
+; --- sx__ldInitBuf ---
+;
+; On entry:    R0 == pointer to `filename'
+;              R1 == extimated size
+;              R2 == 0
+;
+; On exit:     R0 == pointer to buffer base
+;              R1 == pointer to buffer limit
+;              R2 == pointer to anchor
+;
+; Use:         Creates a buffer for the load job.
+
+sx__ldInitBuf  ROUT
+
+               MOV     R2,#0                   ;Clear the flex anchor
+               STR     R2,sx__anchor           ;Store this over the top
+               ADR     R2,sx__anchor           ;Point to the anchor
+               B       load_initBuf            ;And initialise the buffer
+
+               LTORG
+
+; --- sx__ldFile ---
+;
+; On entry:    R0 == pointer to `filename'
+;              R1 == pointer to real filename
+;              R2 == safeness indicator
+;
+; On exit:     --
+;
+; Use:         Loads a file into a buffer.
+
+sx__ldFile     ROUT
+
+               STMFD   R13!,{R0,R2,R14}        ;Save some registers
+               MOV     R2,#0                   ;Clear the flex anchor
+               STR     R2,sx__anchor           ;Store this over the top
+               ADR     R2,sx__anchor           ;Point to the anchor
+               BL      load_file               ;Load the file, please
+               STRVS   R0,[R13,#0]             ;If failed, return error
+               LDMFD   R13!,{R0,R2,PC}         ;And return to caller
+
+               LTORG
+
+; --- sx__ldDone ---
+;
+; On entry:    R0 == pointer to `filename'
+;              R1 == safeness indicator
+;
+; On exit:     --
+;
+; Use:         Handles a newly loaded file.
+
+sx__ldDone     ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               LDR     R1,sx__anchor           ;Load the base of the file
+               LDR     R2,[R1,#sxConf__magic]  ;Load the first word out
+               LDR     R14,sx__magic           ;Load the magic number
+               CMP     R2,R14                  ;Do these match up?
+               BNE     %80sx__ldDone           ;No -- complain then
+
+               ; --- Accept the data from the file ---
+
+               ADR     R0,sx__config           ;Point to my config buffer
+               MOV     R2,#sxConf__size        ;Get the block size
+               BL      fastMove                ;Copy the data over
+
+               ADR     R0,sx__anchor           ;Point to the anchor
+               BL      flex_free               ;Don't want it any more
+
+               ; --- Change information about the file ---
+
+               LDR     R0,[R13,#0]             ;Load the filename used
+               BL      sx__setFilename         ;Set this up nicely
+               LDR     R14,sx__flags           ;Load the flags word
+               ORR     R14,R14,#sxFlag__safe   ;The file is safe, now
+               STR     R14,sx__flags           ;Store the flags back
+
+               ; --- Update the dialogue box and screen ---
+
+               LDR     R0,sx__dbox             ;Load the dialogue handle
+               CMP     R0,#0                   ;Is it defined?
+               BLNE    sx__dbReset             ;Yes -- reset the settings
+               BL      sx__update              ;And update Sculptrix too
+               B       %90sx__ldDone           ;Finally return to caller
+
+               ; --- Not all was well with the world ---
+
+80sx__ldDone   ADR     R0,sx__anchor           ;Point to the anchor
+               BL      flex_free               ;Don't want it any more
+               ADR     R0,sx__badConfig        ;Point to error block
+               BL      msgs_error              ;Translate the message
+               MOV     R1,#1                   ;Just an OK box, please
+               BL      errorBox                ;And report the error
+
+90sx__ldDone   LDMFD   R13!,{R0-R2,PC}^        ;Return when done
+
+sx__badConfig  DCD     1
+               DCB     "sxBDCFG",0
+
+               LTORG
+
+; --- sx__ldFail ---
+;
+; On entry:    R0 == pointer to error
+;
+; On exit:     --
+;
+; Use:         Reports errors after a botched load.
+
+sx__ldFail     ROUT
+
+               CMP     R0,#0                   ;Is there anything to do?
+               MOVEQS  PC,R14                  ;No -- return then
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+               ADD     R2,R0,#4                ;Point to the error text
+               ADR     R0,sx__ldErr            ;Point to error block
+               BL      msgs_error              ;Translate the error
+               MOV     R1,#1                   ;Report with an OK box
+               BL      errorBox                ;Report it to the user
+               LDMFD   R13!,{R0-R2,PC}^        ;And return to caller
+
+sx__ldErr      DCD     1
+               DCB     "sxLDERR",0
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/Changes b/StraySrc/Sculptrix/Changes
new file mode 100644 (file)
index 0000000..577d816
--- /dev/null
@@ -0,0 +1,76 @@
+Sculptrix change history
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Version                By      Change
+
+1.00           MDW     Initial version written
+
+1.01           MDW     Added support for group boxes
+                       Fixed validation string parser -- will now search
+                       all `X' commands instead of just the first one
+
+1.02           MDW     Fixed problem with multiple unslab ops in one poll
+
+1.03           MDW     Stopped excessive redrawing in group box rendering
+
+1.04           MDW     Done strange things to make text+sprite icons nice
+                       Any contortions required are due solely to TMA.
+
+1.05           MDW     Filled in group box types 0 and 2 (ridge'n'plinth)
+
+1.06           MDW     Allowed user-changing of the 3D colours and things
+                       Also included different colours for shaded borders
+
+1.07           MDW     Fixed bug in Sculptrix_SlabIcon, which corrupted R0
+                       on exit.  Nothing has been affected by this, but we
+                       may as well get it right.
+
+1.08           MDW     Made colour change before toggling slab on slab ops
+                       Integrated colour change with toggle slab, now
+                       box_toggle does all Sculptrix_DoSlab needs to, so
+                       renamed box_toggle as swi_doslab.  Module therefore
+                       slightly smaller!
+
+1.09           TMA     Added type 7 border -- a writable type with its own
+                       black border. Less flickery than a Wimp type,
+                       however, the border is always 4 OS units.
+
+               MDW     Fixed writable border being black when it gets shaded
+
+1.10           MDW     Made writable border read colours from icon, and fill
+                       the whole icon with the background colour, rather
+                       than just the outside.  Basically, rewrote the
+                       border 7 rendering code.
+
+1.11           MDW     Fixed Sculptrix_SetSpriteArea bug -- I `found' my
+                       workspace twice.  Ooops.
+               MDW     Changed to use new Acorn-allocated SWI chunk number
+
+1.12           MDW     Improved shaded-icon checking to avoid branch.
+                       Added 10cs delay to unslab with window open in line
+                       with STASIS requirements.
+
+1.13           MDW     Fixed bug in mitre start position -- inserted RSB
+                       to make it go in the right direction.
+
+1.14           MDW     Removed filling in groupbox type 0 to allow dbx
+                       controls to be within group boxes.
+
+1.15           MDW     Modified rendering of `xs' icons to match new STEEL
+                       and Sapphire icon shading habits.  Added a 256-byte
+                       static buffer for group titles, to avoid dynamic
+                       allocation in mid-redraw,  Changed lots of signed
+                       compares to unsigned, which removes some redundancy.
+                       Fixed text+sprite handling to look in Wimp area
+                       if not in user area.  Added messages support.  Added
+                       border type 8 for partitions that fade properly
+                       (suggested by Alex Thoukydides).
+
+2.00           MDW     Complete rewrite and redesign, including many new
+                       features and reducing code size.  No noticeable
+                       performance loss, though.  See `NewVersion' for
+                       details of these changes.
+
+2.01           MDW     Bug fix: make the colour of shaded text+sprite icons
+                       correct by masking with %1011 instead of %1101.
+                       Documented a little internal cleverness.
diff --git a/StraySrc/Sculptrix/Makefile,fe1 b/StraySrc/Sculptrix/Makefile,fe1
new file mode 100644 (file)
index 0000000..e362d22
--- /dev/null
@@ -0,0 +1,100 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all:
+       submake *.Makefile
+
+install:
+       submake *.Makefile -- install
+
+clean:
+       submake *.Makefile -- clean
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/Sculptrix/NewVersion b/StraySrc/Sculptrix/NewVersion
new file mode 100644 (file)
index 0000000..a33edb1
--- /dev/null
@@ -0,0 +1,177 @@
+Sculptrix 2.00 changes
+
+
+The Sculptrix 2.00 project provided an opportunity to radically redesign
+and restructure the Sculptrix module, including some much-needed new
+functionality.  The original version wasn't particularly well-written, and
+the 15 revisions made to it since left us with a program which was extremely
+hard to maintain.
+
+The new version is split into ten source files, each with fairly clearly
+defined responsibilities:
+
+bbox.s -- calculates bounding boxes for Sculptrix icons.  Implements the
+    Sculptrix_BoundingBox SWI.
+
+border.s -- interprets the border description bytecode commands to draw
+    borders.
+
+colours.s -- handles icon colour reading and changing, including icons with
+    anti-aliased fonts (reads colour from the validation string).  Used
+    during slabbing.
+
+config.s -- handles reading and changing of border styles.
+
+plot.s -- handles plotting of borders given a border type word, by passing
+    a border definition to border.s.
+
+redraw.s -- high-level interface to redrawing borders.  Implements the
+    various Sculptrix SWIs concerning screen redraw, by calling plot.s.
+
+rule.s -- implements the low-level drawing primitives for 3D borders.
+
+sculptrix.s -- defines the module header and other external interfaces to
+    the operating system.
+
+slab.s -- handles slabbing of icons.
+
+utils.s -- contains various utility functions which don't fit anywhere else.
+
+vString.s -- parses validation strings, and places the information into a
+    border type word, which is used by other routines.
+
+
+
+The two main advances in the design of Sculptrix are border type words,
+and border definitions.
+
+
+Border type words encode all the information read from a validation string,
+except for the text field for group box icons, which is read into a temporary
+buffer.  This allows support for the old style Sculptrix validation commands
+to be local to the validation string parser -- the rest of the code only sees
+border type words.  The compatibility support can be removed easily, to make
+upgrading templates easy: when support is removed, only icons with new-style
+validation string commands have visible borders.  This was used to upgrade
+the Glass templates.
+
+
+A border definition describes how to draw a border.  Drawing borders in
+pure ARM assembler proved to be cumbersome, and prone to error.
+Sculptrix 2.00 solves the problem by defining a new bytecode language for
+drawing borders.  The language can be thought of as a `machine code' for a
+border-drawing processor.
+
+This fictional `processor' has one accumulator and two `rectangles' (the
+`icon' and `current' rectangles).  A rectangle consists of four integers
+labelled x0, y0, x1 and y1.  These values cannot be modified directly; they
+must be loaded into the accumulator, updated, and stored back.  The icon
+rectangle is read-only.
+
+There are instructions for transferring data between the rectangles and the
+accumulator, for setting the current colours, and for plotting `rules' and
+group titles.  A rule is generally a horizontal or vertical line (although
+in one special case, it's actually a rectangle), which may be mitred at the
+end.  The position of the rule is determined by the rule-plotting routine
+(written in ARM code), relative to the current rectangle position.  A group
+title is plotted using Wimp_PlotIcon using the current rectangle position
+and an icon flags word.
+
+The instruction set is descibed in the source file border.s.
+
+Note that there is no noticeable performance degredation as a result of using
+this technique.  I've tested the relative performance on some complex
+dialogue boxes with the cache off, with no significant differences.  It's
+possible that the new code is faster, since the interpreter probably fits
+in cache.  This means that Sculptrix is probably still the fastest 3D border
+renderer for RISC OS.
+
+
+An advance has been made in the support of text+sprite icons, originally
+included in version 1.04.  Sculptrix now supports all positions of the text
+within the bounding box, and will call Wimp_ForceRedraw, when necessary, to
+redraw the text.  In older versions of Sculptrix, `xs'-type icons could not
+be shaded, since the Wimp did not remove all of the correct anti-aliasing
+pixels.  The new version will detect whether the icon text is being anti-
+aliased (whether by its icon flags or due to the Wimp$Font setting under
+later versions of the Wimp) and if so force a redraw of the text to ensure
+that the background is correctly rendered.
+
+
+The validation string syntax for 3D borders has been redesigned.  The old
+syntax is still supported for compatibility, although its use is now
+deprecated.
+
+The new syntax is:
+
+  `xb' <type> [<flag>...] [`,'<text>]
+
+(Spaces in the above indicate where spaces are ignored in the syntax.)
+
+The <type> is one of the following letters:
+
+  a == action button (standard plinth, may be slabbed)
+  d == default button (surrounded by highlighted `moat', may be slabbed)
+  i == information display (pressed in area)
+  p == partition bar (pressed in, same colour as group boxes)
+  r == raised-up ridge
+  c == pressed-in channel
+  o == `offset' pressed-in area, used for sliders
+  w == writable border, with solid line around it
+  g == group box border
+
+The flags are as follows:
+
+  f == use group-box colours for the border
+  i == invert the icon
+
+There are many ways of duplicating effects: for example `xbif' means the
+same as `xbp', and `xbc' means the same as `xbri'.  The idea is that the
+letters indicate the purpose of the icon, rather than its visual style.
+The mapping of letters onto visual effects may change in future, to match
+changes in user interface styles.
+
+Note that borders are inverted when the type codes are in uppercase: this
+is for the benefit of the Sculptrix module, though -- you should use the
+`i' flag to invert icons.
+
+Group box borders may or may not contain text.  The presence of text is
+determined by the presence of the comma in the validation string command:
+`xbg' means no text, while `xbg,' mrans that the text is an empty string.
+If there is no text, no title icon is drawn, so the effect given is a ridge
+or channel in the correct style.  This use of borders for grouping is
+occasionally found in CC applications, and may be of use.
+
+
+The new version of Sculptrix has a different user interface for
+configuration.  Colour and style information can be stored in a (binary)
+file, and loaded via the *Sculptrix_LoadConfig command, for example during
+boot-up.  These files can be built using the Setrix application (provided)
+which allows easy configuration using a dialogue box.  Setrix currently
+needs a 64K wimpslot, since it is statically linked to Sapphire, although
+once a dynamically linkable Sapphire is available, this will be reduced.
+A wimpslot of 64K is fairly acceptable, though, considering that it supports
+the full data transfer protocol, the Choices system for storing
+configuration, and full error handling.  It is arguable that not all of these
+features are necessary in such an application, though.
+
+When it starts up, Setrix will try to find a `Config' file in Choices:Setrix,
+or in its application directory.  If it finds the file, it loads it, and
+sets the Sculptrix configuration from it.  If the file is not present,
+it reads the configuration from the Sculptrix module.  Thus, RiscPC owners
+are recommended to store a configuration file in Choices:Setrix, and
+place an obey file of the form
+
+  RMLoad <xyz$Dir>.Sculptrix
+  Sculptrix_LoadConfig Choices:Setrix.Config
+
+in their Choices:Boot.PreDesk directory.
+
+The file format for Sculptrix configuration files is very simple, and I
+can't be bothered to explain it here.  It's all in the Setrix source,
+anyway.
+
+
+Enjoy
+
+  [mdw]
diff --git a/StraySrc/Sculptrix/README b/StraySrc/Sculptrix/README
new file mode 100644 (file)
index 0000000..b22fab2
--- /dev/null
@@ -0,0 +1,115 @@
+SCULPTRIX
+~~~~~~~~~
+
+
+There's some Real documentation for Sculptrix, so I'll just say some
+words about the internals, and some historical ramblings.
+
+
+Wy does the world need another 3D button module?  Quite honestly, it
+doesn't.
+
+I was preparing to release the first version of SDLS when I realised
+that there was a complication.  Up until that point, we'd always used
+Simon Huntingdon's Interface module for our 3D bits.  SDLS only needed
+Interface for one component, the DLLMerge tool, but I wanted the world's
+first view of a Straylight Wimp program to be positive, and I wanted a
+sexy looking 3D interface.
+
+The problem was that SDLS had extremely permissive licensing.  We
+allowed SDLS to be included free of charge with any software, whether
+free or proprietary.  And I didn't think Mr Huntingdon was going to like
+that happening to his module.  I couldn't find the documentation for
+Interface, and Simon didn't appear to be a comp.sys.acorn regular, so I
+decided that the quickest way to resolve the problem was to write a 3D
+border module of my own.
+
+Some quick prototyping in BASIC (now lost forever) provided me with a
+good way of drawing corners in a mode-independent way.  The border
+plotting primitives were the first bits of Sculptrix 1.  I then wrote
+the code to fit these together, a bit of validation string parsing, and
+the module header, all in a fairly adhoc sort of way.  The result was
+Sculptrix 1.00.  It took a couple of days to get this far.  I'd not paid
+much attention to making the code tidy or readable.
+
+Sculptrix isn't the name I originally chose for the module.  I'd seen 3D
+boxes being called `sculpted' before, and I thought that sounded fairly
+reasonable.  I originally came up with the name `Skulptor', which I
+wasn't really happy with for two reasons; partly because it looked
+slightly too `k00l', but mainly because it was really difficult to type
+quickly.  For the curious, I intended the name `Sculptrix' as a fake
+feminine form of `Sculptor'.
+
+A major headache I was having at the time involved positioning group box
+titles.  I knew that everyone else was having this problem too, but I'm
+a bit perfectionist about my templates, and this problem vexed me
+greatly.  I decided that adding group box borders as a Sculptrix
+operation was an obvious solution.
+
+Other changes followed.  After fourteen revisions, the Sculptrix source
+code had stopped looking a mess and was approaching a disaster.  I
+decided that something drastic had to be done.
+
+There were two big sources of mess in the original Sculptrix:
+
+  * The border drawing routines were horrible.  Manipulating several
+    boxes, each using four registers, makes for some horrific ARM code.
+    The group box drawing code was particularly nasty.
+
+  * The validation string parsing was a total loss.  It was mostly adhoc
+    stuff.  Dispatching to the border operations was done in the code,
+    which became a royal pain.
+
+I dealt with the first problem by using a simple `border description
+language'.  By writing a pile of macros, I persuaded objasm to assemble
+a simple bytecode language which would draw borders.  The language
+called ARM routines to draw the sides of the border, but did all the
+necessary arithmetic using the bytecodes, which I'd designed fairly
+carefully to be able to do the jobs which needed to be done with minimum
+of fuss.  This made the job of writing borders easier; it made the code
+more readable; and it reduced the code size.  (Remarkably, Sculptrix 2
+is smaller than Sculptrix 1.)
+
+The border machine has a single register, a rectangle store, and a
+(read-only) icon rectangle store.  It can load values from either
+store, perform simple arithmetic (adding and subtracting immediate
+constants) and write back to the rectangle store.  The machine can also
+perform operations like selecting colours, finding the centre of an
+icon, and calling another piece of border code as a subroutine.
+
+The problems with validation string parsing were solved by introducing a
+concept of a `border type', which is a bitfield identifying the basic
+border shape and various optional flags to be applied to it.  Validation
+string parsing was centralised, and made table driven; I took the
+opportunity to rationalise the syntax at the same time.  The rest of the
+code happily passes border type codes around.
+
+Another major change with version 2 was the user configuration.  The
+initial version didn't have any configuration at all.  A later
+modification added some star-commands, which required understanding of
+hex notation and a strong stomach.  It was all most unsatisfactory.  The
+new version lost the star-commands, and provided a (binary)
+configuration file which could be edited using a natty GUI application.
+This made me feel much happier.
+
+
+Setrix is the first Sapphire application in the source release.
+Interested people should be able to learn a lot from its source code.
+Of particular interest are:
+
+  * The colour buttons in the dialogue box are all custom controls
+    handled entirely by Sapphire.
+
+  * The data transfer code, and how easy the ram transfer stuff is.
+    (It still amazes me that a RAM save routine is often three lines of
+    assembler, and that a RAM load is handled more-or-less entirely by
+    Sapphire.)
+
+I also like the way that the `load-from-file' routine used during Wimp
+loading of a file is just as useful for loading the initial config file.
+
+
+I'm rather proud of the job I made of Sculptrix in the end.  I hope you
+agree that my time was well spent.
+--
+[mdw]
diff --git a/StraySrc/Sculptrix/apcs/Makefile,fe1 b/StraySrc/Sculptrix/apcs/Makefile,fe1
new file mode 100644 (file)
index 0000000..5fb4519
--- /dev/null
@@ -0,0 +1,104 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Compiling things -----------------------------------------------------
+
+all: o.sculptrix
+
+o.sculptrix: o.scp_apcs
+       $(AR) -c o.sculptrix o.scp_apcs
+
+install:
+
+clean:
+       -$(RM) o.*
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.scp_apcs: libs:header
+o.scp_apcs: libs:swis
+o.scp_apcs: libs:stream
diff --git a/StraySrc/Sculptrix/apcs/h/sculptrix b/StraySrc/Sculptrix/apcs/h/sculptrix
new file mode 100644 (file)
index 0000000..295309e
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * sculptrix.h
+ *
+ * APCS interface to Sculptrix
+ *
+ * © 1997-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's Sculptrix.
+ *
+ * Sculptrix is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Sculptrix is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Sculptrix.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __sculptrix_h
+#define __sculptrix_h
+
+/*----- Notes -------------------------------------------------------------*
+ *
+ * The interfaces to Sculptrix have been written in assembler.  This has the
+ * benefit of making them very small and minimising procedure call overhead.
+ * It also has the disadvantage of not setting _kernel_last_oserror()
+ * properly.  If this is important, you should use _kernel_swi() directly.
+ *
+ * The SWI interface routines are safe to call from SVC mode (e.g. in a
+ * C module).
+ */
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Important types ---------------------------------------------------*/
+
+/* --- sculptrix_slabDesc --- *
+ *
+ * A Sculptrix slab descriptor.
+ */
+
+typedef struct sculptrix_slabDesc {
+  unsigned long window;                 /* Window containing button */
+  unsigned long icon;                   /* Icon handle of button */
+  unsigned colour;                      /* Old button colour, and flags */
+  unsigned long time;                   /* Time of the slab call */
+} sculptrix_slabDesc;
+
+enum {
+  scFlag_noButton = 1 << 8              /* Slab wasn't result of mouse */
+};
+
+/* --- sculptrix_config --- *
+ *
+ * A Sculptrix configuration block.
+ */
+
+typedef struct sculptrix_config {
+  unsigned flags;                       /* Flags word (see below) */
+  unsigned char nDark, nLight;          /* Normal dark and light colours */
+  unsigned char gDark, gLight;          /* Group box dark and light */
+  unsigned char snDark, snLight;        /* Shaded dark and light */
+  unsigned char sgDark, sgLight;        /* Shaded group dark and light */
+  unsigned char highlight;              /* Default button highlight colour */
+  unsigned char slab;                   /* Slabbed button colour */
+  unsigned char _reserved_a, _reserved_b; /* Two reserved bytes */
+  unsigned long _reserved_c, _reserved_d; /* And two words, for safety */
+} sculptrix_config;
+
+enum {
+  scFlag_acorn = 1 << 0                 /* Use nasty Acorn group boxes */
+};
+
+/* --- sculptrix_error --- *
+ *
+ * This is the type of error which Sculptrix SWIs return.  Depending on
+ * whether you're using RISC_OSLib or not, you may want these to return
+ * os_errors or _kernel_oserrors, or its own special type.  All these error
+ * structures have the same format and member names -- it's just a matter of
+ * naming the structure.
+ *
+ * The way we sort all this out is by allowing the client to set up a macro
+ * to tell us what to do.
+ */
+
+#if defined(sculptrix_USE_OS_ERROR)
+
+  #ifndef __os_h
+    #include "os.h"
+  #endif
+
+  typedef os_error sculptrix_error;
+
+#elif defined(sculptrix_USE_KERNEL_OSERROR)
+
+  #ifndef __kernel_h
+    #include "kernel.h"
+  #endif
+
+  typedef _kernel_oserror sculptrix_error;
+
+#elif !defined(sculptrix_error)
+
+  typedef struct sculptrix_error
+  {
+    int errnum;                         /* Error number */
+    char errmess[252];                  /* Error message text */
+  }
+  sculptrix_error;
+
+#endif
+
+/*----- Interface functions -----------------------------------------------*/
+
+/* --- sculptrix_redrawWindow --- *
+ *
+ * Arguments:  const void *redraw == pointer to a redraw block
+ *
+ * Returns:    Pointer to possible error
+ *
+ * Use:                Redraws the window's borders, in response to a
+ *             RedrawWindowRequest event from the Wimp.
+ *
+ *             Note that the redraw block is passed as a `void *' argument
+ *             because the type used to represent a redraw block is
+ *             dependent upon the library being used.
+ */
+
+extern sculptrix_error *sculptrix_redrawWindow(const void */*redraw*/);
+
+/* --- sculptrix_doSlab --- *
+ *
+ * Arguments:  unsigned long w == window handle
+ *             unsigned long i == icon handle
+ *             unsigned c == colour to set in the icon
+ *             unsigned *oc == address to store old colour, or null
+ *
+ * Returns:    Pointer to possible error
+ *
+ * Use:                Low-level slabbing operation.
+ */
+
+extern sculptrix_error *sculptrix_doSlab(unsigned long /*w*/,
+                                         unsigned long /*i*/,
+                                         unsigned /*c*/,
+                                         unsigned */*oc*/);
+
+/* --- sculptrix_slabIcon --- *
+ *
+ * Arguments:  unsigned long w == window handle
+ *             unsigned long i == icon handle
+ *             sculptrix_slabDesc *d == pointer to slab descriptor
+ *
+ * Returns:    Pointer to possible error
+ *
+ * Use:                Slabs an icon, and stores state information into the
+ *             descriptor, suitable for unslabbing later.
+ */
+
+extern sculptrix_error *sculptrix_slabIcon(unsigned long /*w*/,
+                                           unsigned long /*i*/,
+                                           sculptrix_slabDesc */*d*/);
+
+/* --- sculptrix_unslabIcon --- *
+ *
+ * Arguments:  sculptrix_slabDesc *d == pointer to slab descriptor
+ *
+ * Returns:    Pointer to possible error
+ *
+ * Use:                Unslabs an icon, using the state information stored in the
+ *             descriptor.
+ */
+
+extern sculptrix_error *sculptrix_unslabIcon(sculptrix_slabDesc */*d*/);
+
+/* --- sculptrix_boundingBox --- *
+ *
+ * Arguments:  void *i == pointer to an icon block
+ *
+ * Returns:    Zero if there was no Sculptrix border, or nonzero if there
+ *             was one.
+ *
+ * Use:                Reports the presence of a Sculptrix border, and if there was
+ *             one, adjusts the bounding box of the icon block passed to
+ *             include the border's size.
+ *
+ *             Note that the icon block is passed as a `void *' argument,
+ *             because the type used to represent an icon is dependent on
+ *             the library being used.
+ */
+
+extern int sculptrix_boundingBox(void */*i*/);
+
+/* --- sculptrix_plotIcon --- *
+ *
+ * Arguments:  const void *i == pointer to an icon block
+ *             const void *r == pointer to a redraw block
+ *
+ * Returns:    Pointer to possible error
+ *
+ * Use:                Plots an icon's border immediately.
+ *
+ *             Note that the icon and redraw blocks are passed as `void *'
+ *             arguments, because the types used to represent these blocks
+ *             depend on the library being used.
+ */
+
+extern sculptrix_error *sculptrix_plotIcon(const void */*i*/,
+                                           const void */*r*/);
+
+/* --- sculptrix_plotGroup --- *
+ *
+ * Arguments:  const void *i == pointer to icon block
+ *             const void *r == pointer to redraw block
+ *             const char *p == pointer to group box title
+ *
+ * Returns:    Pointer to possible error
+ *
+ * Use:                Plots a group box border.  Arguments of type `void *' used
+ *             again.
+ */
+
+extern sculptrix_error *sculptrix_plotGroup(const void */*i*/,
+                                            const void */*r*/,
+                                            const char */*p*/);
+
+/* --- sculptrix_setSpriteArea --- *
+ *
+ * Arguments:  const void *s == pointer to sprite area, or null for Wimp
+ *                     area
+ *
+ * Returns:    Pointer to possible error
+ *
+ * Use:                Sets the sprite area to be used when plotting `xs'-type
+ *             icons.  Note the deviation from the Sculptrix SWI interface
+ *             above -- a null pointer is passed to represent the Wimp pool
+ *             instead of the value 1 used by the SWI.
+ */
+
+extern sculptrix_error *sculptrix_setSpriteArea(const void *s);
+
+/* --- sculptrix_updateIcon --- *
+ *
+ * Arguments:  unsigned long w == window handle
+ *             unsigned long i == icon handle
+ *
+ * Returns:    Pointer to possible error
+ *
+ * Use:                Updates an icon's border.  Call this after modifying the
+ *             icon's shaded bit.
+ */
+
+extern sculptrix_error *sculptrix_updateIcon(unsigned long /*w*/,
+                                             unsigned long /*i*/);
+
+/* --- sculptrix_slabColour --- *
+ *
+ * Arguments:  --
+ *
+ * Returns:    The colour currently used for slabbing icons
+ *
+ * Use:                Returns the current slab colour.  Useful for handling
+ *             slabbing by hand.
+ */
+
+extern unsigned sculptrix_slabColour(void);
+
+/* --- sculptrix_setConfig --- *
+ *
+ * Arguments:  const sculptrix_config *cfg == pointer to configuration block
+ *
+ * Returns:    Zero if the configuration didn't change, nonzero if it did.
+ *
+ * Use:                Sets the Sculptrix configuration.
+ */
+
+extern int sculptrix_setConfig(const sculptrix_config */*cfg*/);
+
+/* --- sculptrix_readConfig --- *
+ *
+ * Arguments:  sculptrix_config *cfg == pointer to configuration buffer
+ *             unsigned long sz == size of buffer
+ *
+ * Returns:    Pointer to possible error
+ *
+ * use:                Reads the current Sculptrix configuration.
+ */
+
+extern sculptrix_error *sculptrix_readConfig(sculptrix_config */*cfg*/,
+                                             unsigned long /*sz*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/StraySrc/Sculptrix/apcs/s/scp_apcs b/StraySrc/Sculptrix/apcs/s/scp_apcs
new file mode 100644 (file)
index 0000000..d2d1268
--- /dev/null
@@ -0,0 +1,161 @@
+;
+; sculptrix.s
+;
+; Sculptrix SWI interface
+;
+; © 1997-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |C$$code|,CODE,READONLY
+
+; --- sculptrix_redrawWindow ---
+
+               EXPORT  sculptrix_redrawWindow
+sculptrix_redrawWindow
+               MOV     R12,R14
+               MOV     R1,R0
+               SWI     XSculptrix_RedrawWindow
+               MOVVC   R0,#0
+               MOVS    PC,R12
+
+; --- sculptrix_doSlab ---
+
+               EXPORT  sculptrix_doSlab
+sculptrix_doSlab
+               MOV     R12,R14
+               SWI     XSculptrix_DoSlab
+               MOVVSS  PC,R12
+               CMP     R3,#0
+               STRNE   R2,[R3]
+               MOV     R0,#0
+               MOVS    PC,R12
+
+; --- sculptrix_slabIcon ---
+
+               EXPORT  sculptrix_slabIcon
+sculptrix_slabIcon
+               MOV     R12,R14
+               SWI     XSculptrix_SlabIcon
+               MOVVC   R0,#0
+               MOVS    PC,R12
+
+; --- sculptrix_unslabIcon ---
+
+               EXPORT  sculptrix_unslabIcon
+sculptrix_unslabIcon
+               MOV     R12,R14
+               MOV     R2,R0
+               SWI     XSculptrix_UnslabIcon
+               MOVVC   R0,#0
+               MOVS    PC,R12
+
+; --- sculptrix_boundingBox ---
+
+               EXPORT  sculptrix_boundingBox
+sculptrix_boundingBox
+               MOV     R12,R14
+               MOV     R1,R0
+               SWI     XSculptrix_BoundingBox
+               MOVVS   R0,#0
+               MOVS    PC,R12
+
+; --- sculptrix_plotIcon ---
+
+               EXPORT  sculptrix_plotIcon
+sculptrix_plotIcon
+               MOV     R12,R14
+               SWI     XSculptrix_PlotIcon
+               MOVVC   R0,#0
+               MOVS    PC,R12
+
+; --- sculptrix_plotGroupBox ---
+
+               EXPORT  sculptrix_plotGroupBox
+sculptrix_plotGroupBox
+               MOV     R12,R14
+               MOV     R3,R2
+               MOV     R2,#0
+               SWI     XSculptrix_PlotGroupBox
+               MOVVC   R0,#0
+               MOVS    PC,R12
+
+; --- sculptrix_setSpriteArea ---
+
+               EXPORT  sculptrix_setSpriteArea
+sculptrix_setSpriteArea
+               MOV     R12,R14
+               CMP     R0,#0
+               MOVEQ   R0,#1
+               SWI     XSculptrix_SetSpriteArea
+               MOVVC   R0,#0
+               MOVS    PC,R12
+
+; --- sculptrix_updateIcon ---
+
+               EXPORT  sculptrix_updateIcon
+sculptrix_updateIcon
+               MOV     R12,R14
+               SWI     XSculptrix_UpdateIcon
+               MOVVC   R0,#0
+               MOVS    PC,R12
+
+; --- sculptrix_slabColour ---
+
+               EXPORT  sculptrix_slabColour
+sculptrix_slabColour
+               MOV     R12,R14
+               SWI     XSculptrix_SlabColour
+               MOVVS   R0,#14
+               MOVVC   R0,R2
+               MOVS    PC,R12
+
+; --- sculptrix_setConfig ---
+
+               EXPORT  sculptrix_setConfig
+sculptrix_setConfig
+               MOV     R12,R14
+               SWI     XSculptrix_SetConfig
+               MOVCS   R0,#1
+               MOVCC   R0,#0
+               MOVVS   R0,#0
+               MOVS    PC,R12
+
+; --- sculptrix_readConfig ---
+
+               EXPORT  sculptrix_readConfig
+sculptrix_readConfig
+               MOV     R12,R14
+               SWI     XSculptrix_ReadConfig
+               MOVVC   R0,#0
+               MOVS    PC,R12
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/old-vsn/README b/StraySrc/Sculptrix/old-vsn/README
new file mode 100644 (file)
index 0000000..a90aec2
--- /dev/null
@@ -0,0 +1,14 @@
+SCULPTRIX VERSION 1
+~~~~~~~~~~~~~~~~~~~
+
+The source in this directory is for version 1 of Sculptrix, which was
+never released to the public, and is considered defunct (which is one
+stage on from obsolete).
+
+Why have I included the source to Sculptrix 1 in the distribution?  This
+is a good question.  It provides a reference point for understanding how
+much better Sculptrix 2 is.  It shows that not everything Straylight
+touches turns to gold.  And it shows how not to write a 3D border
+drawing module.
+--
+[mdw]
diff --git a/StraySrc/Sculptrix/old-vsn/s/sculptrix b/StraySrc/Sculptrix/old-vsn/s/sculptrix
new file mode 100644 (file)
index 0000000..8135b7a
--- /dev/null
@@ -0,0 +1,2250 @@
+;
+; sculptrix.s
+;
+; Draws pretty 3D boxes
+;
+; © 1994 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Change history -------------------------------------------------------
+;
+; Version      By      Change
+; ~~~~~~~      ~~      ~~~~~~
+; 1.00         MDW     Initial version written
+;
+; 1.01         MDW     Added support for group boxes
+;                      Fixed validation string parser -- will now search
+;                      all `X' commands instead of just the first one
+;
+; 1.02         MDW     Fixed problem with multiple unslab ops in one poll
+;
+; 1.03         MDW     Stopped excessive redrawing in group box rendering
+;
+; 1.04         MDW     Done strange things to make text+sprite icons nice
+;                      Any contortions required are due solely to TMA.
+;
+; 1.05         MDW     Filled in group box types 0 and 2 (ridge'n'plinth)
+;
+; 1.06         MDW     Allowed user-changing of the 3D colours and things
+;                      Also included different colours for shaded borders
+;
+; 1.07         MDW     Fixed bug in Sculptrix_SlabIcon, which corrupted R0
+;                      on exit.  Nothing has been affected by this, but we
+;                      may as well get it right.
+;
+; 1.08         MDW     Made colour change before toggling slab on slab ops
+;                      Integrated colour change with toggle slab, now
+;                      box_toggle does all Sculptrix_DoSlab needs to, so
+;                      renamed box_toggle as swi_doslab.  Module therefore
+;                      slightly smaller!
+;
+; 1.09         TMA     Added type 7 border -- a writable type with its own
+;                      black border. Less flickery than a Wimp type,
+;                      however, the border is always 4 OS units.
+;
+;              MDW     Fixed writable border being black when it gets shaded
+;
+; 1.10         MDW     Made writable border read colours from icon, and fill
+;                      the whole icon with the background colour, rather
+;                      than just the outside.  Basically, rewrote the
+;                      border 7 rendering code.
+;
+; 1.11         MDW     Fixed Sculptrix_SetSpriteArea bug -- I `found' my
+;                      workspace twice.  Ooops.
+;              MDW     Changed to use new Acorn-allocated SWI chunk number
+;
+; 1.12         MDW     Improved shaded-icon checking to avoid branch.
+;                      Added 10cs delay to unslab with window open in line
+;                      with STASIS requirements.
+;
+; 1.13         MDW     Fixed bug in mitre start position -- inserted RSB
+;                      to make it go in the right direction.
+;
+; 1.14         MDW     Removed filling in groupbox type 0 to allow dbx
+;                      controls to be within group boxes.
+;
+; 1.15         MDW     Modified rendering of `xs' icons to match new STEEL
+;                      and Sapphire icon shading habits.  Added a 256-byte
+;                      static buffer for group titles, to avoid dynamic
+;                      allocation in mid-redraw,  Changed lots of signed
+;                      compares to unsigned, which removes some redundancy.
+;                      Fixed text+sprite handling to look in Wimp area
+;                      if not in user area.  Added messages support.  Added
+;                      border type 8 for partitions that fade properly
+;                      (suggested by Alex Thoukydides).
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     sh.messages
+               IMPORT  s_help
+
+;----- PLOT code numbers ----------------------------------------------------
+
+plot_MOVE      EQU     0
+plot_FORE      EQU     1
+plot_INVERSE   EQU     2
+plot_BACK      EQU     3
+
+plot_RELATIVE  EQU     0
+plot_ABSOLUTE  EQU     4
+
+plot_RECTFILL  EQU     96
+plot_LINE      EQU     0
+
+;----- VDU variable numbers -------------------------------------------------
+
+vdu_XEIG       EQU     4
+vdu_YEIG       EQU     5
+
+;----- Module header --------------------------------------------------------
+
+               AREA    |!!!Module$$Header|,CODE,READONLY
+
+               DCD     0                       ;Module start code
+               DCD     s_init                  ;Initialisation
+               DCD     s_die                   ;Finalisation
+               DCD     s_service               ;Service call
+               DCD     s_title                 ;Module title string
+               DCD     s_help                  ;Module help string
+               DCD     s_command               ;Command table
+               DCD     &4A2C0                  ;SWI chunk (temporary)
+               DCD     s_swic                  ;SWI handling
+               DCD     s_swin                  ;SWI names table
+               DCD     0                       ;SWI names code
+
+;----- Module strings -------------------------------------------------------
+
+s_title                DCB     "Sculptrix",0
+
+;----- SWI name table -------------------------------------------------------
+
+s_swin         DCB     "Sculptrix",0
+
+               DCB     "RedrawWindow",0
+               DCB     "DoSlab",0
+               DCB     "SlabIcon",0
+               DCB     "UnslabIcon",0
+               DCB     "BoundingBox",0
+               DCB     "PlotIcon",0
+               DCB     "PlotGroupBox",0
+               DCB     "SetSpriteArea",0
+               DCB     "UpdateIcon",0
+               DCB     "SlabColour",0
+
+               DCB     0
+
+;----- Command table --------------------------------------------------------
+
+s_command      DCB     "Sculptrix_Colours",0
+               DCD     cmd_colours
+               DCB     0,0,1,0
+               DCD     synt_colours
+               DCD     help_colours
+
+               DCB     "Sculptrix_GroupType",0
+               DCD     cmd_group
+               DCB     1,0,1,0
+               DCD     synt_group
+               DCD     help_group
+
+               DCD     0
+
+;----- Initialisation and finalisation --------------------------------------
+
+s_init         ROUT
+
+               STMFD   R13!,{R14}              ;Stack link register nicely
+
+               ; --- Get some workspace ---
+
+               MOV     R0,#6                   ;Allocate workspace
+               MOV     R3,#s_wsize             ;Make it *this* big
+               SWI     XOS_Module              ;Get me memory
+               LDMVSFD R13!,{PC}               ;Return if it barfed
+               STR     R2,[R12]                ;Stash the workspace pointer
+               MOV     R12,R2                  ;Move the pointer across
+
+               ; --- Set initial values ---
+
+               BL      vdu_set                 ;Set up the graphics vars
+               MOV     R0,#0                   ;Initial flags setting
+               STR     R0,s_flags              ;Store in the flags word
+               MOV     R0,#1                   ;Start using WIMP area
+               STR     R0,s_sarea              ;Store in sprite area word
+               MOV     R0,#&0400               ;Default colours
+               ORR     R0,R0,R0,LSL #16        ;Propagate to top half
+               MOV     R1,#&0200               ;Default colours
+               ORR     R1,R1,R1,LSL #16        ;Propagate to top half
+               MOV     R2,#&0C00
+               ORR     R2,R2,#&000E
+               ADR     R3,s_colours
+               STMIA   R3,{R0-R2}
+
+               ; --- I think that's it ---
+
+               LDMFD   R13!,{PC}^              ;Return to caller happy
+
+               LTORG
+
+s_die          ROUT
+
+               STMFD   R13!,{R11,R14}
+               MOV     R11,R12                 ;Keep the private word ptr
+               LDR     R12,[R12]               ;Find my workspace
+
+               ; --- Free my workspace ---
+
+               MOV     R0,#7                   ;Free RMA space
+               MOV     R2,R12                  ;Point to workspace
+               SWI     XOS_Module              ;Try to free the memory
+               MOV     R0,#0                   ;Gonna zero the private word
+               STR     R0,[R11]                ;Then zero it
+               LDMFD   R13!,{R11,PC}^          ;A happy bunny
+
+               LTORG
+
+;----- Service call handling ------------------------------------------------
+
+s_service      ROUT
+
+               CMP     R1,#&46                 ;Is it a mode change?
+               MOVNES  PC,R14                  ;No -- return
+
+               LDR     R12,[R12]               ;Get my workspaxe
+               B       vdu_set                 ;Set up the VDU variables
+
+
+;----- Command handlers -----------------------------------------------------
+
+; --- Sculptrix_Colours ---
+
+cmd_colours    ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save some registers
+               LDR     R12,[R12]               ;Locate my workspace pointer
+
+               ; --- If no argument, use the default ---
+
+               CMP     R1,#0                   ;Is there an argument?
+               ADREQ   R0,cmd__defCol          ;No -- point to default
+
+               ; --- Read normal 3D colours ---
+
+               LDRB    R2,[R0],#1              ;Get the first digit
+               BL      %50cmd_colours          ;Convert to binary
+               MOV     R3,R2,LSL #8            ;Look after it
+               LDRB    R2,[R0],#1              ;Get the next digit
+               BL      %50cmd_colours          ;Convert to binary
+               ORR     R3,R3,R2                ;Mix into the word nicely
+               ORR     R3,R3,R3,LSL #16        ;Propagate to upper half
+
+               ; --- Read shaded 3D colours ---
+
+               LDRB    R2,[R0],#1              ;Get the first digit
+               BL      %50cmd_colours          ;Convert to binary
+               MOV     R4,R2,LSL #8            ;Look after it
+               LDRB    R2,[R0],#1              ;Get the next digit
+               BL      %50cmd_colours          ;Convert to binary
+               ORR     R4,R4,R2                ;Mix into the word nicely
+               ORR     R4,R4,R4,LSL #16        ;Propagate to upper half
+
+               ; --- Read the other colours ---
+
+               LDRB    R2,[R0],#1              ;Get a digit
+               BL      %50cmd_colours          ;Convert to binary
+               MOV     R5,R2,LSL #8            ;Look after it
+               LDRB    R2,[R0],#1              ;Get a digit
+               BL      %50cmd_colours          ;Convert to binary
+               ORR     R5,R5,R2                ;Look after it
+
+               ; --- Now store these away nicely ---
+
+               ADR     R1,s_colours            ;Point to base address
+               STMIA   R1,{R3-R5}              ;Store them in workspace
+               LDMFD   R13!,{R1-R5,PC}^        ;Return to caller
+
+               ; --- Convert R2 to binary ---
+
+50cmd_colours  SUBS    R2,R2,#'0'              ;Convert a digit
+               CMP     R2,#10                  ;Is this bigger than 9?
+               SUBCS   R2,R2,#7                ;Yes -- convert from upper
+               CMP     R2,#16                  ;Still out of range?
+               SUBCS   R2,R2,#&20              ;Yes -- must have been lower
+               CMP     R2,#16                  ;Still out of range?
+               BCS     %51cmd_colours          ;Yes -- that's an error
+               MOVS    PC,R14                  ;Return to caller
+
+51cmd_colours  ADRL    R0,msg_errBadHex        ;Point to error message
+               LDMFD   R13!,{R1-R5,R14}        ;Unstack the registers
+               ORRS    PC,R14,#V_flag          ;Return to caller
+
+cmd__defCol    DCB     "4020CE",0
+
+               LTORG
+
+; --- Sculptrix_GroupType ---
+
+cmd_group      ROUT
+
+               LDRB    R0,[R0]                 ;Get the digit
+               LDR     R12,[R12]               ;Find my workspace
+               LDR     R1,s_flags              ;Load my flags word
+               BIC     R1,R1,#s_CHANNEL :OR: s_FAINTCHAN
+               CMP     R0,#'1'                 ;Is it a deep channel?
+               ORREQ   R1,R1,#s_CHANNEL
+               CMP     R0,#'2'                 ;Is it a shallow channel?
+               ORREQ   R1,R1,#s_CHANNEL :OR: s_FAINTCHAN
+               STR     R1,s_flags
+               MOVS    PC,R14
+
+               LTORG
+
+;----- SWI names and numbers etc --------------------------------------------
+
+s_swic         ROUT
+
+               LDR     R12,[R12]               ;Get my workspace neatly
+               CMP     R11,#(%01s_swic-%00s_swic)/4 ;Check SWI is in range
+               ADDCC   PC,PC,R11,LSL #2        ;Go to correct branch instr
+               B       %01s_swic               ;Branch to complain thing
+
+00s_swic       B       swi_redraw
+               B       swi_doslab
+               B       swi_slab
+               B       swi_unslab
+               B       swi_bbox
+               B       swi_ploticon
+               B       swi_plotgroup
+               B       swi_spritearea
+               B       swi_update
+               B       swi_slabcol
+
+01s_swic       ADRL    R0,msg_errBadSwi        ;Point to error message
+               ORRS    PC,R14,#V_flag          ;Return with an error
+
+               LTORG
+
+;----- SWI handling ---------------------------------------------------------
+
+; --- Sculptrix_RedrawWindow ---
+;
+; R1 == pointer to redraw block
+
+swi_redraw     ROUT
+
+               STMFD   R13!,{R0-R11,R14}       ;Stack registers
+
+               ; --- Find the window origin ---
+
+               MOV     R11,R1                  ;Keep the pointer nicely
+               BL      box_readRectangle       ;Find everything about rdrw
+
+               ; --- Now go through the icons ---
+
+               SUB     R13,R13,#40             ;Make way for an icon block
+               MOV     R1,R13                  ;Point to the block
+               LDR     R0,[R11,#0]             ;Get the window handle
+               MOV     R2,#0                   ;Start at icon 0
+               STMIA   R1,{R0,R2}              ;Store them in the block
+
+               ; --- Main loop -- go through each icon and plot ---
+
+00swi_redraw   SWI     XWimp_GetIconState      ;Read info into block
+               ADDVS   R13,R13,#44             ;Error -- reclaim stack space
+               LDMVSFD R13!,{R1-R11,PC}        ;And return to caller
+               LDR     R0,[R1,#24]             ;Get the flags word
+               CMP     R0,#1<<23               ;Is it only deleted?
+               ADDEQ   R13,R13,#40             ;Yes -- reclaim stack space
+               LDMEQFD R13!,{R0-R11,PC}^       ;And return to caller
+
+               ; --- Find out whether the icon is visible ---
+
+               ADD     R0,R1,#8                ;Point to coords block
+               LDMIA   R0,{R0,R2-R4}           ;Load the icon coordinates
+               CMP     R0,R7
+               CMPLE   R2,R8
+               CMPLE   R5,R3
+               CMPLE   R6,R4
+               BGT     %01swi_redraw           ;Not visible -- skip it
+
+               ADD     R0,R1,#8                ;Point to icon block
+               BL      box_ploticon
+
+               ; --- Ho-hum.  Now do the next one ---
+
+01swi_redraw   LDR     R0,[R1,#4]              ;Get the icon handle
+               ADD     R0,R0,#1                ;Bump it up a little
+               STR     R0,[R1,#4]              ;Store it back again
+               B       %00swi_redraw           ;And go round for another
+
+               LTORG
+
+; --- Sculptrix_DoSlab ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon number
+;              R2 == colour to slab to
+;
+; On exit:     R2 == old colour of icon, or -1 if icon couldn't be slabbed
+
+swi_doslab     ROUT
+
+               STMFD   R13!,{R0-R11,R14}       ;Stack registers
+               MOV     R9,R2                   ;Look after the colour
+               MOV     R2,#-1                  ;Store -1 in stacked R2
+               STR     R2,[R13,#8]             ;Return no colour currently
+
+               ; --- Find out if we need to do anything ---
+
+               SUB     R13,R13,#44             ;Make way for an icon def
+               STMIA   R13,{R0,R1}             ;Store icon handle and stuff
+               MOV     R1,R13                  ;Point to icon block
+               SWI     XWimp_GetIconState      ;Get the icon information
+               ADDVS   R13,R13,#48             ;If it failed, reclaim stack
+               LDMVSFD R13!,{R1-R11,PC}        ;And return the error
+
+               MOV     R3,#0                   ;Start from the beginning
+90swi_doslab   ADD     R0,R1,#8                ;Point to actual icon def
+               MOV     R2,#'X'                 ;Get the validation command
+               BL      box_findValid           ;Find the validation string
+               CMP     R2,#0                   ;Did it work?
+               ADDEQ   R13,R13,#44             ;No -- reclaim used stack
+               LDMEQFD R13!,{R0-R11,PC}^       ;And return to caller
+
+               ; --- Get the border type -- only 0 and 2 slab ---
+
+               LDRB    R0,[R2,#1]              ;Get the border type number
+               CMP     R0,#'0'                 ;Is it a normal action type?
+               CMPNE   R0,#'2'                 ;Or a default action type?
+               MOVNE   R3,R2                   ;No -- point to this place
+               BNE     %90swi_doslab           ;And loop back
+
+               ; --- It's a worthwhile icon ---
+
+               LDMIA   R1,{R0,R1}              ;Load window and icon handles
+               MOV     R8,R2                   ;Look after this pointer
+               MOV     R2,R9                   ;Get the colour wanted
+               BL      box_setcolour           ;Set the colour properly
+               STR     R2,[R13,#44+8]          ;Store it nicely away again
+               MOV     R1,R13                  ;Point at the block again
+
+               ; --- Update the border ---
+
+               LDRB    R0,[R8,#0]              ;Get the border command
+               EOR     R0,R0,#&20              ;Toggle its case
+               STRB    R0,[R8,#0]              ;Store it back again
+
+               LDR     R3,[R1,#24]             ;Load the icon flags
+               EOR     R3,R3,#&005F0000        ;Toggle ESG and shaded bit
+               TST     R3,#1<<22               ;Is the icon shaded?
+               TSTNE   R3,#&001F0000           ;No -- test the ESG bits
+               ADRNE   R11,s_colours           ;No -- use normal colours
+               ADREQ   R11,s_shadeCols         ;Yes -- use shaded colours
+
+               TST     R0,#&20                 ;Is it set now?
+               ADDEQ   R11,R11,#1              ;No -- use offset colours
+
+               ADD     R0,R1,#8                ;Point to icon def again
+               LDMIA   R0,{R3-R6}              ;Get icon coords
+               SUB     R3,R3,#4                ;Make space for border around
+               SUB     R4,R4,#4
+               ADD     R5,R5,#4
+               ADD     R6,R6,#4
+               STMIB   R1,{R3-R6}              ;That's now our update block
+               SWI     XWimp_UpdateWindow      ;Try and update it then
+               BVS     %01swi_doslab           ;If it failed skip this bit
+               CMP     R0,#0                   ;Is there anything to do?
+               BEQ     %01swi_doslab           ;No -- skip it too
+
+               ADD     R2,R1,#16               ;Point to y1
+               LDMIA   R2,{R8-R10}             ;Get coordinates from block
+               SUB     R10,R8,R10              ;Get y origin position
+               LDR     R8,[R2,#-12]            ;Get x0 value from block
+               SUB     R9,R8,R9                ;Get x origin position
+
+               ADD     R3,R3,#4                ;Point back to the icon block
+               ADD     R3,R3,R9
+               ADD     R4,R4,#4
+               ADD     R4,R4,R10
+               SUB     R5,R5,#4
+               ADD     R5,R5,R9
+               SUB     R6,R6,#4
+               ADD     R6,R6,R10
+
+00swi_doslab   ; --- Draw box (inline copy) ---
+               ;
+               ; We only draw the inner slabbed bit -- the rest doesn't
+               ; change even in the default type.
+
+               ADD     R2,R1,#4
+               STMIA   R2,{R3-R6}              ;Store adjusted coords away
+
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R2
+               BL      prim_left
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R2
+               BL      prim_right
+               BL      prim_bottom
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R2
+               BL      prim_top
+
+               ; --- Get another rectangle ---
+
+               SWI     XWimp_GetRectangle
+               CMP     R0,#0                   ;Have we anything to do?
+               BNE     %00swi_doslab           ;Yes -- do it then, dummy
+
+01swi_doslab   ADD     R13,R13,#44
+               LDMFD   R13!,{R0-R11,PC}^
+
+               LTORG
+
+; --- Sculptrix_SlabIcon ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;              R2 == pointer to 4 word slab descriptor to be filled in
+; On exit:     --
+
+swi_slab       ROUT
+
+               STMFD   R13!,{R0-R2,R10,R14}    ;Keep link register safe
+
+               ; --- Fill in the caller's descriptor block ---
+
+               MOV     R10,R2                  ;Keep the pointer safe
+               STMIA   R10,{R0,R1}             ;Stash the icon info away
+               SWI     XOS_ReadMonotonicTime   ;Read the current time
+               CMP     R1,#0                   ;Are mouse buttons pressed?
+               ADDEQ   R0,R0,#5                ;No -- then bump time on 5
+               STR     R0,[R10,#12]            ;Store in the descriptor
+
+               ; --- Slab the border in or out ---
+
+               LDR     R0,[R10,#0]             ;Reload window handle
+               LDRB    R2,s_slabcol            ;Get the slab colour nicely
+               BL      swi_doslab              ;Do the slabbing operation
+               LDMVSFD R13!,{R0-R2,R10,PC}     ;If it failed, return error
+
+               SUB     R13,R13,#20             ;Space for a pointer block
+               MOV     R1,R13                  ;Point to the block
+               SWI     XWimp_GetPointerInfo    ;Read current mouse state
+               LDR     R1,[R13,#8]             ;Load the button state
+               ADD     R13,R13,#20             ;Restore the stack pointer
+               CMP     R1,#0                   ;Are there buttons pressed?
+               ORREQ   R2,R2,#256              ;Yes -- set a flag bit then
+               STR     R2,[R10,#8]             ;Store the old icon colour
+
+               ; --- Say to pause on unslabs in flags ---
+
+               LDR     R14,s_flags             ;Get the flags word
+               BIC     R14,R14,#s_UNSLAB       ;Clear unslab bit
+               STR     R14,s_flags             ;Store flags word back
+
+               ; --- Return to caller ---
+
+               LDMFD   R13!,{R0-R2,R10,PC}^    ;Return to caller
+
+               LTORG
+
+; --- Sculptrix_UnslabIcon ---
+;
+; On entry:    R2 == pointer to descriptor filled in by Sculptrix_SlabIcon
+; On exit:     --
+
+swi_unslab     ROUT
+
+               STMFD   R13!,{R0-R2,R10,R14}    ;Stack my registers
+
+               ; --- Find out if we need to do any slabbing ---
+
+               LDR     R14,[R2,#8]             ;Get the icon colour
+               CMP     R14,#-1                 ;Is it nonslabbed?
+               LDMEQFD R13!,{R0-R2,R10,PC}^
+
+               ; --- Do we unslab quickly? ---
+
+               MOV     R10,R2                  ;Look after slab block
+               SUB     R13,R13,#36             ;To read the window state
+               LDR     R0,s_flags              ;Get the flags word
+               TST     R0,#s_UNSLAB            ;Is the unslab bit set?
+               BNE     %03swi_unslab           ;Yes -- skip past the wait
+
+               ; --- Wait the requisite quantity of time ---
+
+               LDR     R0,[R10,#0]             ;Get the window handle
+               MOV     R1,R13                  ;Point to the block
+               STR     R0,[R1,#0]              ;Store in the block
+               SWI     XWimp_GetWindowState    ;Get info about the window
+               BVS     %01swi_unslab           ;It must have been deleted
+
+               LDR     R0,[R1,#32]             ;Get the window flags
+               TST     R0,#1<<16               ;Is the window open?
+               BEQ     %01swi_unslab           ;And just wait the time out
+
+               ; --- Wait for the mouse to be released ---
+
+               LDR     R14,[R10,#8]            ;Load colour and flags bits
+               TST     R14,#256                ;Is the `no mouse' bit set?
+               BNE     %01swi_unslab           ;And do the wait operation
+
+00swi_unslab   SWI     XOS_Mouse               ;Read mouse information
+               CMP     R2,#0                   ;Are the buttons released?
+               BNE     %00swi_unslab           ;No -- keep waiting
+               B       %03swi_unslab           ;Do the actual unslab
+
+               ; --- Wait for the timer to elapse ---
+
+01swi_unslab   LDR     R1,[R10,#12]            ;Load the slab time
+               ADD     R1,R1,#10               ;Work out unslab time
+02swi_unslab   SWI     XOS_ReadMonotonicTime   ;Get the current time
+               CMP     R1,R0                   ;How do they compare?
+               BPL     %02swi_unslab           ;Too low -- go round again
+
+               ; --- Actually unslab the icon ---
+
+03swi_unslab   ADD     R13,R13,#36             ;Reclaim the stack space
+               LDMIA   R10,{R0-R2}             ;Get window, icon and colour
+               AND     R2,R2,#255              ;Clear flags bits etc.
+               BL      swi_doslab              ;Unslab the icon
+
+               ; --- Remember we've done this now ---
+
+               LDR     R0,s_flags              ;Get the flags word again
+               ORR     R0,R0,#s_UNSLAB         ;Set the unslab bit
+               STR     R0,s_flags              ;Store the flags word away
+
+               ; --- Return to caller ---
+
+               LDMFD   R13!,{R0-R2,R10,PC}^    ;Return to caller
+
+               LTORG
+
+; --- Sculptrix_BoundingBox ---
+;
+; On entry:    R1 == pointer to an icon block
+; On exit:     R0 == 0 if there was no border
+;              block updated to reflect border width
+
+swi_bbox       ROUT
+
+               STMFD   R13!,{R1-R6,R14}        ;Stash registers
+               MOV     R3,#0                   ;Start from the beginning
+00swi_bbox     MOV     R0,R1                   ;Point to block
+               MOV     R2,#'X'                 ;The correct magic command
+               BL      box_findValid           ;Find the validation string
+               CMP     R2,#0                   ;Was it not there?
+               MOVEQ   R0,#0                   ;Mark as nonpresent
+               LDMEQFD R13!,{R1-R6,PC}^        ;Then return
+               LDRB    R0,[R2,#1]              ;Get the border type
+               CMP     R0,#'g'                 ;It could be a group box
+               CMPNE   R0,#'G'                 ;Try both cases
+               BEQ     %02swi_bbox             ;If so, be clever
+
+               SUBS    R0,R0,#'0'              ;Turn into a number
+               CMP     R0,#6                   ;Is it type 6?
+               BEQ     %01swi_bbox             ;Yes -- be clever
+               CMP     R0,#9                   ;Is it too big?
+               MOVCS   R3,R2                   ;Not there if too high
+               BCS     %00swi_bbox             ;So try for another one
+               LDMIA   R1,{R3-R6}              ;Load the bounding box regs
+               ADR     R2,box_borders          ;Get the border size table
+               LDRB    R0,[R2,R0]              ;Load the border width
+               SUB     R3,R3,R0
+               SUB     R4,R4,R0
+               ADD     R5,R5,R0
+               ADD     R6,R6,R0
+               STMIA   R1,{R3-R6}              ;Store the sizes back
+               LDMFD   R13!,{R1-R6,PC}^        ;Return happy
+
+01swi_bbox     LDMIA   R1,{R3-R6}              ;Load the bounding box regs
+               SUB     R3,R3,#4
+               ADD     R5,R5,#4
+               STMIA   R1,{R3-R6}
+               MOV     R0,#1
+               LDMFD   R13!,{R1-R6,PC}^        ;Return happy
+
+02swi_bbox     LDMIA   R1,{R3-R6}              ;Load the bounding box regs
+               SUB     R3,R3,#8
+               SUB     R4,R4,#8
+               ADD     R5,R5,#8
+               ADD     R6,R6,#32
+               STMIA   R1,{R3-R6}
+               MOV     R0,#1
+               LDMFD   R13!,{R1-R6,PC}^        ;Return happy
+
+box_borders    DCB     4,8,12,8,4,4,0,12,4
+
+               ROUT
+
+; --- Sculptrix_PlotIcon ---
+;
+; On entry:    R0 == pointer to icon block
+;              R1 == pointer to redraw block
+
+swi_ploticon   ROUT
+
+               STMFD   R13!,{R0-R11,R14}       ;Stash loads of registers
+               LDMIA   R0,{R0,R2-R8}           ;Load the icon coordinates
+               STMFD   R13!,{R0,R2-R8}         ;Store them on the stack
+               BL      box_readRectangle       ;Get the graphics window size
+               MOV     R0,R13                  ;Point to the icon block
+               BL      box_ploticon            ;Plot the icon
+               ADD     R13,R13,#32             ;Reclaim the space
+               LDMFD   R13!,{R0-R11,PC}^       ;Return to caller
+
+               LTORG
+
+; --- Sculptrix_PlotGroup ---
+;
+; On entry:    R0 == pointer to icon block
+;              R1 == pointer to redraw block
+;              R2 == border type
+;              R3 == pointer to title string
+
+swi_plotgroup  ROUT
+
+               STMFD   R13!,{R0-R11,R14}       ;Stash loads of registers
+               LDMIA   R0,{R0,R4-R10}          ;Load the icon coordinates
+               STMFD   R13!,{R0,R4-R10}        ;Store them on the stack
+               BL      box_readRectangle       ;Get the graphics window size
+               MOV     R0,R13                  ;Point to the icon block
+               MOV     R1,R2                   ;Get border type number
+               MOV     R2,R3                   ;Get pointer to group string
+               BL      box_dogroup             ;Plot the icon
+               ADD     R13,R13,#32             ;Reclaim the space
+               LDMFD   R13!,{R0-R11,PC}^       ;Return to caller
+
+               LTORG
+
+; --- Sculptrix_SetSpriteArea ---
+;
+; On entry:    R0 == pointer to sprite area to use
+
+swi_spritearea ROUT
+
+               STR     R0,s_sarea              ;Save it as sprite area ptr
+               MOVS    PC,R14                  ;Return to caller
+
+; --- Sculptrix_UpdateIcon ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle to update
+
+swi_update     ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               SUB     R13,R13,#84             ;For icon and redraw blocks
+               STMIA   R13,{R0,R1}             ;Save the bits at the bottom
+               MOV     R1,R13                  ;Point to the icon block
+               SWI     XWimp_GetIconState      ;Find the icon's bits out
+               BVS     %99swi_update           ;If it failed, go ahead
+               ADD     R2,R13,#40              ;Point to the redraw block
+               LDR     R0,[R13,#0]             ;Get the window handle again
+               STR     R0,[R2,#0]              ;Store window handle at base
+               ADD     R0,R1,#8                ;Point to icon coordinates
+               LDMIA   R0,{R0,R1,R3,R14}       ;Load the coordinates
+               SUB     R0,R0,#16               ;Include the border nicely
+               SUB     R1,R1,#16
+               ADD     R3,R3,#16
+               ADD     R14,R14,#16
+               STMIB   R2,{R0,R1,R3,R14}       ;Save them out again
+               MOV     R1,R2                   ;Point to this block
+               SWI     XWimp_UpdateWindow      ;Start the window redraw
+               BVS     %99swi_update           ;If it failed, go ahead
+
+00swi_update   CMP     R0,#0                   ;Is this the end yet?
+               BEQ     %80swi_update           ;Yes -- finish up nicely
+               ADD     R0,R13,#8               ;Point to the icon block
+               BL      swi_ploticon            ;Plot the icon on the screen
+               SWI     XWimp_GetRectangle      ;Get the next redraw rect
+               B       %00swi_update           ;And draw that one too
+
+80swi_update   ADD     R13,R13,#84             ;Reclaim all that stack
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+99swi_update   ADD     R13,R13,#88             ;Reclaim stack + R0
+               LDMFD   R13!,{R1-R4,PC}         ;Return with V still set
+
+               LTORG
+
+; --- Scultrix_SlabColour ---
+;
+; On entry:    --
+;
+; On exit:     R2 == standard slabbing-in colour
+
+swi_slabcol    LDRB    R2,s_slabcol
+               MOVS    PC,R14
+
+;----- Icon box redrawing ---------------------------------------------------
+
+; --- box_readRectangle ---
+;
+; On entry:    R1 == pointer to a Wimp redraw block
+; On exit:     R1 corrupted
+;              R5-R8 == adjusted, window-relative mouse rectangle
+;              R9,R10 == screen coords of window origin
+
+box_readRectangle ROUT
+
+               CMP     R1,#0                   ;Is there a redraw block?
+               MOVEQ   R9,#0                   ;Yes -- don't translate box
+               MOVEQ   R10,#0
+               MOVEQS  PC,R14                  ;And return
+               ADD     R1,R1,#16               ;Point to y1
+               LDMIA   R1,{R8-R10}             ;Get coordinates from block
+               SUB     R10,R8,R10              ;Get y origin position
+               LDR     R8,[R1,#-12]            ;Get x0 value from block
+               SUB     R9,R8,R9                ;Get x origin position
+
+               ; --- Mangle the graphics rectangle ---
+
+               ADD     R1,R1,#12               ;Point to the graphics window
+               LDMIA   R1,{R5-R8}              ;Load the window posn
+               SUB     R5,R5,R9                ;Convert to window coords
+               SUB     R6,R6,R10
+               SUB     R7,R7,R9
+               SUB     R8,R8,R10
+
+               SUB     R5,R5,#16               ;Add a little bit of leeway
+               SUB     R6,R6,#32
+               ADD     R7,R7,#16
+               ADD     R8,R8,#16
+
+               MOVS    PC,R14
+
+               LTORG
+
+; --- box_ploticon ---
+;
+; On entry:    R0 == pointer to an icon block (writable)
+;              R5-R10 == as set by box_readRectangle
+; On exit:     R2-R4,R11 corrupted
+
+box_ploticon   ROUT
+
+               MOV     R3,#0
+00box_ploticon STMFD   R13!,{R14}
+               MOV     R2,#'X'                 ;Find X commands in valid
+               BL      box_findValid           ;Is it there?
+               LDMFD   R13!,{R14}              ;Get return address back
+               CMP     R2,#0                   ;Check
+               MOVEQS  PC,R14                  ;No -- return to caller
+
+               ; --- If the border has a capital letter, invert ---
+               ;
+               ; Also, choose the right colours for shaded boxes
+
+               LDR     R11,[R0,#16]            ;Get the icon flags word
+               EOR     R11,R11,#&005F0000      ;Toggle ESG and shaded bits
+               TST     R11,#1<<22              ;Is the icon shaded?
+               TSTNE   R11,#&001F0000          ;Or is ESG all set?
+               ADRNE   R11,s_colours           ;No -- use normal colours
+               ADREQ   R11,s_shadeCols         ;Yes -- use shaded colours
+
+               LDRB    R4,[R2,#0]              ;Get the command letter
+               TST     R4,#&20                 ;Is it upper case?
+               ADDEQ   R11,R11,#1              ;Yes -- use offset colours
+
+               ; --- Get the render type, and handle as required ---
+
+               LDRB    R3,[R2,#1]              ;Get the border type number
+               ORR     R4,R3,#&20              ;Convert to lower case
+
+               CMP     R4,#'g'                 ;Is it a group box type?
+               BEQ     box_plotgroup           ;Yes -- plot a group box
+
+               CMP     R4,#'s'                 ;Is it a gadget text/sprite?
+               BEQ     box_plottns             ;Yes -- plot cunningly
+
+               ; --- Dispatch normal group border numbers ---
+
+               SUB     R3,R3,#'0'              ;Convert to a digit
+               CMP     R3,#(%02box_ploticon-%01box_ploticon)/4
+               ADDCC   PC,PC,R3,LSL #2         ;Go to branch table
+               B       %03box_ploticon         ;Not found -- try next valid
+
+01box_ploticon B       brd0                    ;Standard plinth
+               B       brd1                    ;Group ridge/channel
+               B       brd2                    ;Default action button
+               B       brd3                    ;Writable wide border
+               B       brd0                    ;Nonslabbing standard plinth
+               B       brd5                    ;Plinth with ridge intersect
+               B       brd6                    ;Channel terminators
+               B       brd7                    ;Writable with black border
+               B       brd8                    ;Like 4, only different
+02box_ploticon
+
+03box_ploticon MOV     R3,R2                   ;Point to that command
+               B       %00box_ploticon         ;And find the next string
+
+               LTORG
+
+; --- box_setcolour ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;              R2 == colour to set
+; On exit:     R2 == old colour of icon
+
+box_setcolour  ROUT
+
+               STMFD   R13!,{R0,R1,R3-R5,R14}  ;Stack registers
+               MOV     R5,R2                   ;Keep the colour safe
+               SUB     R13,R13,#40             ;Make way for icon block
+               STMIA   R13,{R0,R1}             ;Set up icon block
+               MOV     R1,R13                  ;Point to block
+               SWI     XWimp_GetIconState      ;Get info about icon
+               ADDVS   R13,R13,#44             ;If it failed, reset stack
+               LDMVSFD R13!,{R1,R3-R5,PC}      ;And return the error
+
+               ; --- Check for fonts ---
+
+               LDR     R0,[R1,#24]             ;Get icon flags word
+               TST     R0,#1<<6                ;Check anti-aliased bit
+               BEQ     %00box_setcolour        ;Reset -- do it normally
+               ADD     R0,R1,#8                ;Point to icon definition
+               MOV     R2,#'F'                 ;Find F validation string
+               MOV     R3,#0                   ;Start from the beginning
+               BL      box_findValid           ;Find it
+               CMP     R2,#0                   ;Was it not there?
+               ADDEQ   R13,R13,#40             ;No -- reset stack ptr
+               LDMEQFD R13!,{R0,R1,R3-R5,PC}^  ;We did all we could
+               ADR     R0,box_hexdigits        ;Point to hex digits table
+               LDRB    R0,[R0,R5]              ;Get the right digit
+               LDRB    R5,[R2,#1]              ;Get the old colour
+               STRB    R0,[R2,#1]              ;Store in validation string
+               SUB     R2,R5,#'0'              ;Turn into a digit
+               CMP     R2,#10                  ;Is it a hex digit?
+               SUBCS   R2,R2,#7                ;Yes -- get the number
+               CMP     R2,#16                  ;Is it still too big?
+               SUBCS   R2,R2,#&20              ;It must have been lower case
+
+               ; --- Prod the icon into redrawing ---
+
+               MOV     R0,#0                   ;Don't set either flags mask
+               STR     R0,[R1,#8]              ;Set XOR mask
+               STR     R0,[R1,#12]             ;Set BIC mask
+               SWI     XWimp_SetIconState      ;Give the icon a little prod
+               ADDVC   R13,R13,#40             ;It worked fine
+               LDMVCFD R13!,{R0,R1,R3-R5,PC}^  ;So return happily
+               ADD     R13,R13,#44             ;If it failed, reset stack
+               LDMFD   R13!,{R1,R3-R5,PC}      ;And return the error
+
+               ; --- Just set the colours in the time-honoured way ---
+
+00box_setcolour        MOV     R2,#&F                  ;Only want 4 bits
+               AND     R2,R2,R0,LSR #28        ;Get old colour in R2
+               MOV     R0,R5,LSL #28           ;Shift colour into position
+               STR     R0,[R1,#8]              ;This is our XOR mask
+               MOV     R0,#&F0000000           ;Only change the colour
+               STR     R0,[R1,#12]             ;This is our BIC mask
+               SWI     XWimp_SetIconState      ;Give the icon a little prod
+               ADDVC   R13,R13,#40             ;It worked fine
+               LDMVCFD R13!,{R0,R1,R3-R5,PC}^  ;So return happily
+               ADD     R13,R13,#44             ;If it failed, reset stack
+               LDMFD   R13!,{R1,R3-R5,PC}      ;And return the error
+
+box_hexdigits  DCB     "0123456789ABCDEF",0
+
+               LTORG
+
+;----- Messing with validation strings --------------------------------------
+
+; --- box_findValid ---
+;
+; On entry:    R0 == pointer to icon block
+;              R2 == character to find in block (not case-sensitive)
+;              R3 == old pointer to search from, or 0
+; On exit:     R3,R4 corrupted
+;              R2 points to command string if found, or 0
+
+box_findValid  ROUT
+
+               STMFD   R13!,{R3}               ;Preserve for later use
+
+               ; --- Ensure the icon is text and indirected ---
+
+               LDR     R3,[R0,#16]             ;Get flags word
+               TST     R3,#1<<23               ;Is it deleted?
+               MOVEQ   R4,#&100                ;Can't put 101 in one instr
+               ORREQ   R4,R4,#&01              ;Check indirect and text
+               ANDEQ   R3,R3,R4                ;Mask the bits off
+               CMPEQ   R3,R4                   ;Were they both set?
+               MOVNE   R2,#0                   ;Couldn't find it
+               ADDNE   R13,R13,#4
+               MOVNES  PC,R14                  ;No -- return huffily
+
+               ; --- Find the validation string ---
+
+               LDR     R3,[R0,#24]             ;Get pointer to valid string
+               CMP     R3,#-1                  ;Is it empty?
+               MOVEQ   R2,#0                   ;Yes -- not found
+               ADDEQ   R13,R13,#4
+               MOVEQS  PC,R14
+
+               ; --- Start from the right index ---
+
+               ORR     R2,R2,#&20              ;Make valid char lower case
+               LDMFD   R13!,{R4}               ;Get search index
+               STMFD   R13!,{R14}              ;Need another register
+               CMP     R4,#0                   ;Is it the start?
+               MOVNE   R3,R4                   ;No -- start from old pos
+               BNE     %02box_findValid        ;And skip this command
+
+               ; --- Check the first char of a validation string ---
+
+00box_findValid        LDRB    R14,[R3],#1             ;Get a byte from string
+               ORR     R4,R14,#&20             ;Make lower case
+               CMP     R4,R2                   ;Is it a match?
+               SUBEQ   R2,R3,#1                ;Point back to character
+               LDMEQFD R13!,{PC}^              ;And return
+               MOV     R4,#0                   ;Not an excaped character
+
+               ; --- Skip ahead to the next validation string ---
+
+01box_findValid        CMP     R14,#' '                ;Is it a control char?
+               MOVCC   R2,#0                   ;Yes -- not found
+               LDMCCFD R13!,{PC}^              ;And return
+               CMP     R4,#1                   ;Are we escaping?
+               MOVEQ   R4,#0                   ;Yes -- done that now
+               BEQ     %02box_findValid        ;So skip this bit
+               CMP     R14,#';'                ;Is it a semicolon?
+               BEQ     %00box_findValid        ;Yes -- try a new command
+               CMP     R14,#'\'                ;Is it a backslash?
+               MOVEQ   R4,#1                   ;Yes -- escape next char
+02box_findValid        LDRB    R14,[R3],#1             ;Get another character
+               B       %01box_findValid        ;And try again
+
+               LTORG
+
+;----- Plot text+sprite icons -----------------------------------------------
+
+; --- box_plottns ---
+;
+; On entry:    R0 == pointer to an icon block (writable)
+;              R2 == pointer to the validation string command
+;              R5-R10 == set up by box_readRectangle
+
+box_plottns    ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack some registers
+
+               ; --- Now copy the sprite name into the buffer ---
+
+               LDR     R0,[R13,#0]             ;Find the icon pointer
+               MOV     R2,#'s'                 ;Find the sprite name
+               MOV     R3,#0                   ;Search from the beginning
+               BL      box_findValid           ;Find the string
+               CMP     R2,#0                   ;Did it find anything?
+               BEQ     %99box_plottns          ;No -- nothing to do then
+
+               ; --- Copy the sprite name into the buffer ---
+
+               ADR     R0,s_buffer             ;Point to my buffer
+               ADD     R2,R2,#1                ;Point to first sprite char
+00box_plottns  LDRB    R14,[R2],#1             ;Get the character
+               CMP     R14,#';'                ;Is it the string end?
+               CMPNE   R14,#','                ;Or the sprite name end?
+               CMPNE   R14,#&1F                ;Or the validation string end
+               MOVLS   R14,#0                  ;Yes -- null terminate
+               STRB    R14,[R0],#1             ;Store in the buffer
+               BHI     %00box_plottns          ;No -- loop round again
+
+               ; --- Now read the sprite information ---
+
+               STMFD   R13!,{R5,R6}            ;Save some registers
+               MOV     R0,#40                  ;Read sprite information
+               LDR     R1,s_sarea              ;Find the user's sprite area
+               ADR     R2,s_buffer             ;Point to the block
+               CMP     R1,#1                   ;Is it the wimp area
+               BEQ     %f05                    ;Yes -- skip on then
+               ORR     R0,R0,#&100             ;No -- say user sprite area
+               SWI     XOS_SpriteOp            ;So try to cope with that
+               BVC     %f06                    ;If OK skip onwards
+
+05             MOV     R0,#40                  ;Read sprite information
+               ADR     R2,s_buffer             ;Point to the block
+               SWI     XWimp_SpriteOp
+
+06             MOV     R0,R6                   ;Get the sprite's mode number
+               LDMFD   R13!,{R5,R6}            ;Unstack the registers
+               BVS     %99box_plottns          ;No sprite, no text
+
+               ; --- Find the width of the sprite, then ---
+
+               MOV     R1,#4                   ;Read XEigFactor
+               SWI     XOS_ReadModeVariable    ;Read the value then
+               BVS     %99box_plottns          ;No sprite mode, no text
+               MOV     R4,R3,LSL R2            ;Get sprite width in OS units
+
+               ; --- Plot the icon to avoid strangeness ---
+
+               LDR     R1,[R13,#0]             ;Get the icon block pointer
+               SWI     XWimp_PlotIcon          ;Plot the icon onto screen
+
+               ; --- Copy the text string into the buffer ---
+
+               LDR     R2,[R13,#8]             ;Find the validation string
+               ADD     R0,R2,#2                ;Point to the text string
+               ADR     R1,s_buffer             ;Point to the buffer start
+
+10box_plottns  LDRB    R14,[R0],#1             ;Get a byte from the string
+               CMP     R14,#'\'                ;Is it an escape?
+               BEQ     %11box_plottns          ;Yes -- handle it specially
+               CMP     R14,#';'                ;Or the next command?
+               CMPNE   R14,#&1F                ;Is it a control character
+               MOVLS   R14,#0                  ;Yes -- store a null byte
+               STRB    R14,[R1],#1             ;Store the character away
+               BHI     %10box_plottns          ;No -- loop round again
+               B       %12box_plottns          ;Yes -- branch away
+
+11box_plottns  LDRB    R14,[R0],#1             ;Get the escaped byte
+               CMP     R14,#32                 ;Is it a control character?
+               MOVCC   R14,#0                  ;Yes -- store a real term
+               STRB    R14,[R1],#1             ;Store the character away
+               BCS     %10box_plottns          ;And get another one
+
+               ; --- Now plot the text part ---
+
+12box_plottns  MOV     R0,#8                   ;Get the current font handle
+               SWI     XWimp_ReadSysInfo       ;Go and do that then
+               MOVVS   R0,#0                   ;If failed, assume system
+               CMP     R0,#0                   ;Is there a magic font?
+               LDR     R1,[R13,#0]             ;Find the icon block again
+               LDR     R0,[R1,#16]             ;Find the icon flags word
+               MOV     R14,#&FF000000          ;Mask for the old flags
+               ORRNE   R14,R14,#&00400000      ;If antialiased, copy shade
+               LDR     R2,=&00000111           ;Magic flags for text part
+               AND     R0,R0,R14               ;Keep original colours
+               ORR     R0,R0,R2                ;Mix 'n' match the icon flags
+               STR     R0,[R1,#16]             ;Store that back again
+               LDR     R0,[R1,#0]              ;Get left icon edge
+               ADD     R0,R0,R4                ;Offset by the right amount
+               STR     R0,[R1,#0]              ;Store it back again
+               ADR     R14,s_buffer            ;Find the buffer pointer
+               STR     R14,[R1,#20]            ;Point to the text string
+               MOV     R0,#-1                  ;No validation string pliz
+               STR     R0,[R1,#24]             ;Store it in the buffer
+               SWI     XWimp_PlotIcon          ;And stick it on the screen
+
+               ; --- Tidy up and leave ---
+
+99box_plottns  LDMFD   R13!,{R0-R4,PC}^        ;Return to caller if OK
+
+               LTORG
+
+;----- Plot group boxes -----------------------------------------------------
+
+; --- box_plotgroup ---
+;
+; On entry:    R0 == pointer to an icon block (writable)
+;              R2 == pointer to the validation string command
+;              R5-R10 == set up by box_readRectangle
+
+box_plotgroup  ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Stack some registers
+
+               ; --- Copy the string into the buffer ---
+
+               LDR     R2,[R13,#8]             ;Find the validation string
+               ADD     R0,R2,#3                ;Point to the text string
+               ADR     R1,s_buffer             ;Point to the buffer start
+
+00box_plotgroup        LDRB    R14,[R0],#1             ;Get a byte from the string
+               CMP     R14,#'\'                ;Is it an escape?
+               BEQ     %01box_plotgroup        ;Yes -- handle it specially
+               CMP     R14,#';'                ;Or the next command?
+               CMPNE   R14,#&1F                ;Is it a control character
+               MOVLS   R14,#0                  ;Yes -- terminate string
+               STRB    R14,[R1],#1             ;Store the character away
+               BHI     %00box_plotgroup        ;No -- loop round again
+               B       %02box_plotgroup        ;Yes -- branch away
+
+01box_plotgroup        LDRB    R14,[R0],#1             ;Get the escaped byte
+               CMP     R14,#32                 ;Is it a control character?
+               MOVCC   R14,#0                  ;Yes -- store a real term
+               STRB    R14,[R1],#1             ;Store the character away
+               BCS     %00box_plotgroup        ;And get another one
+
+               ; --- Now plot the group border ---
+
+02box_plotgroup        LDR     R0,[R13,#0]             ;Get the icon block pointer
+               LDRB    R1,[R2,#2]              ;Get the border type
+               SUB     R1,R1,#'0'              ;Convert to an integer
+               ADR     R2,s_buffer             ;Point to the string
+               BL      box_dogroup             ;Handle the actual plotting
+
+               ; --- Tidy up and leave ---
+
+03box_plotgroup        LDMFD   R13!,{R0-R2,PC}^        ;Return to caller if OK
+
+               LTORG
+
+; --- box_dogroup ---
+;
+; On entry:    R0 == pointer to coordinates box
+;              R1 == group border type number
+;              R2 == pointer to group title string
+
+box_dogroup    ROUT
+
+               STMFD   R13!,{R11,R14}          ;Store registers
+               LDR     R14,s_flags             ;Get the flags word
+               TST     R14,#s_CHANNEL          ;Does the user want channels?
+               EORNE   R1,R1,#1                ;Yes -- toggle channelness
+               ADR     R14,%02box_dogroup
+               CMP     R1,#(%02box_dogroup-%01box_dogroup)/4
+               ADDCC   PC,PC,R1,LSL #2         ;Go to branch table
+               LDMFD   R13!,{R11,PC}^          ;Return to caller
+
+01box_dogroup  B       grp0                    ;Standard ridge and plinth
+               B       grp1                    ;Acorn channel and gap
+               B       grp2                    ;Standard ridge and plinth
+               B       grp3                    ;Acorn channel and gap
+
+02box_dogroup  LDMFD   R13!,{R11,PC}           ;Return to caller
+
+;----- Drawing group borders ------------------------------------------------
+
+; --- grp_titleicon ---
+;
+; On entry:    R0 == pointer to icon coordinates to bodge
+;              R1 == left gap for icon title
+;              R2 == pointer to title string
+; On exit:     R0 == pointer to adjusted box
+
+grp_titleicon  ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Stash registers away nicely
+
+               ; --- Work out the length of the string ---
+
+               MOV     R5,#0                   ;Nothing counted yet
+00grp_titleicon        LDRB    R14,[R2,R5]             ;Get the next character
+               CMP     R14,#32                 ;Is it a control char?
+               ADD     R5,R5,#1                ;If not, bump the length
+               BCS     %00grp_titleicon        ;And loop round again
+
+               MOV     R0,#8                   ;Read the Wimp font handle
+               SWI     XWimp_ReadSysInfo       ;Try and find it
+               MOVVS   R5,R5,LSL #4            ;Multiply by 16
+               BVS     %01grp_titleicon        ;If not supported, ignore
+               CMP     R0,#0                   ;Is there a font used?
+               MOVEQ   R5,R5,LSL #4            ;Multiply by 16
+               BEQ     %01grp_titleicon        ;If not, skip ahead a bit
+
+               ; --- Work out the width of the string ---
+
+               MOV     R1,#1000                ;Just something big
+               MOV     R2,#1000                ;Something else big :-)
+               SWI     XFont_Converttopoints   ;Convert them to millipts
+               SWI     XFont_SetFont           ;Set this as the current font
+               MOV     R3,R2                   ;Move these coords now
+               MOV     R2,R1
+               LDR     R1,[R13,#8]             ;Find the string pointer
+               MOV     R4,#-1                  ;Don't split the string
+               SWI     XFont_StringWidth       ;Find the width of the string
+               MOV     R1,R2                   ;Move the coords back again
+               MOV     R2,R3
+               SWI     XFont_ConverttoOS       ;Convert back to OS units
+               ADD     R5,R1,#16               ;Get the string width
+
+               ; --- Now bodge the icon block ---
+
+01grp_titleicon        LDMIA   R13,{R0,R1}             ;Get block ptr and offset
+               LDMIA   R0,{R2,R3,R4,R14}       ;Get the icon coords
+               ADD     R2,R2,R1                ;Offset the left side
+               SUB     R3,R14,#20              ;Find bottom of group box
+               ADD     R4,R2,R5                ;Add on the string width
+               ADD     R14,R14,#28             ;Find the top of the icon
+               STMIA   R0,{R2,R3,R4,R14}       ;Store the modified coords
+
+               ; --- Bodge the rest of the icon ---
+
+               LDR     R2,[R13,#8]             ;Find the string pointer
+               STR     R2,[R0,#20]             ;Store this as data
+               MOV     R2,#-1                  ;No validation string
+               STR     R2,[R0,#24]             ;Store this away too
+               MOV     R2,#1                   ;It doesn't care about this
+               STR     R2,[R0,#28]             ;Store this as the length
+               LDR     R2,=&17000139           ;Icon flags word
+               STR     R2,[R0,#16]             ;Store this as icon flags
+
+               LDMFD   R13!,{R0-R5,PC}^        ;Return to caller
+
+; --- grp_fillBorder ---
+;
+; On entry:    R5-R8 == box coordinates (!)
+;              R9,R10 == window origin coordinates on the screen
+;
+; Removed in version 1.14
+
+ [ {FALSE}
+
+grp_fillBorder ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R0,#1                   ;Grey background
+               SWI     XWimp_SetColour         ;Set up the background
+               MOV     R0,#4                   ;Move absolute
+               ADD     R1,R5,R9                ;Translate left hand side
+               ADD     R2,R6,R10               ;Translate bottom edge
+               SWI     XOS_Plot                ;Move there
+               MOV     R0,#101                 ;Filled rectangle, absolute
+               ADD     R1,R7,R9                ;Translate right hand side
+               ADD     R2,R8,R10               ;Translate top edge
+               LDMIA   R12,{R3,R4}             ;Get the pixel sizes
+               SUB     R1,R1,R3                ;Chop a bit off the right
+               SUB     R2,R2,R4                ;Chop a bit off the top
+               SWI     XOS_Plot                ;Fill in the background
+               LDMFD   R13!,{R0-R4,PC}^        ;Restore the registers
+
+               LTORG
+ ]
+
+; --- grp 0 ---
+
+grp0           STMFD   R13!,{R1-R8,R14}        ;Stash registers
+
+               LDMIA   R0,{R5-R8}              ;Get the border coordinates
+               STMFD   R13!,{R5-R8}            ;Save them on the stack
+               MOV     R3,R0                   ;Keep this pointer safe
+;              BL      grp_fillBorder          ;Don't fill in 1.14
+
+               ; --- Translate the icon block ---
+
+               MOV     R1,#16                  ;Small offset here
+               BL      grp_titleicon           ;Find the icon position
+
+               ; --- Now display the main border ---
+
+               LDMIA   R0,{R5-R8}              ;Save this position
+               MOV     R0,R13                  ;Point to border position
+               MOV     R1,R3                   ;Point to title position
+               ADR     R11,s_colours           ;Point to colour table
+               BL      gborder                 ;Plot the group border
+
+               ; --- Now display the main title border ---
+
+               STMIA   R3,{R5-R8}              ;Restore saved position
+               MOV     R0,R3                   ;Point to the position
+               BL      brd5                    ;Plot the top plinth
+               STMIA   R0,{R5-R8}              ;Restore that again
+               MOV     R1,R0                   ;Point to the icon block
+               SWI     XWimp_PlotIcon          ;Now plot the icon on top
+               ADD     R13,R13,#16             ;Restore stack pointer
+               LDMFD   R13!,{R1-R8,PC}         ;Return to caller
+
+; --- grp 1 ---
+
+grp1           STMFD   R13!,{R1-R8,R14}        ;Stash registers
+
+               LDMIA   R0,{R5-R8}              ;Get the border coordinates
+               STMFD   R13!,{R5-R8}            ;Save them on the stack
+               MOV     R3,R0                   ;Keep this pointer safe
+
+               ; --- Translate the icon block ---
+
+               MOV     R1,#16                  ;Small offset here
+               BL      grp_titleicon           ;Find the icon position
+
+               ; --- Now display the main border ---
+
+               LDMIA   R0,{R5-R8}              ;Save this position
+               MOV     R0,R13                  ;Point to border position
+               MOV     R1,R3                   ;Point to title position
+               LDR     R11,s_flags             ;Get the flags word
+               TST     R11,#s_FAINTCHAN        ;Is it meant to be faint
+               ADREQ   R11,s_colours+1         ;Point to colour table
+               ADRNE   R11,s_shadeCols+1
+               BL      gborder                 ;Plot the group border
+
+               ; --- Now display the main title border ---
+
+               STMIA   R3,{R5-R8}              ;Restore saved position
+               MOV     R0,R3                   ;Point to the position
+               BL      brd6                    ;Plot the top thingy
+               STMIA   R0,{R5-R8}              ;Restore that again
+               MOV     R1,R0                   ;Point to the icon block
+
+               ; --- Stop the top bit from being filled ---
+
+               LDR     R0,[R1,#16]
+               BIC     R0,R0,#(1<<5)           ;Clear filled flag
+               STR     R0,[R1,#16]
+
+               SWI     XWimp_PlotIcon          ;Now plot the icon on top
+               ADD     R13,R13,#16             ;Restore stack pointer
+               LDMFD   R13!,{R1-R8,PC}         ;Return to caller
+
+; --- grp 2 ---
+
+grp2           STMFD   R13!,{R1-R8,R14}        ;Stash registers
+
+               LDMIA   R0,{R5-R8}              ;Get the border coordinates
+               STMFD   R13!,{R5-R8}            ;Save them on the stack
+               MOV     R3,R0                   ;Keep this pointer safe
+;              BL      grp_fillBorder          ;Don't fill in 1.14
+
+               ; --- Translate the icon block ---
+
+               MOV     R1,#32                  ;Large offset here
+               BL      grp_titleicon           ;Find the icon position
+
+               ; --- Now display the main border ---
+
+               LDMIA   R0,{R5-R8}              ;Save this position
+               MOV     R0,R13                  ;Point to border position
+               MOV     R1,R3                   ;Point to title position
+               ADR     R11,s_colours           ;Point to colour table
+               BL      gborder                 ;Plot the group border
+
+               ; --- Now display the main title border ---
+
+               STMIA   R3,{R5-R8}              ;Restore saved position
+               MOV     R0,R3                   ;Point to the position
+               BL      brd5                    ;Plot the top plinth
+               STMIA   R0,{R5-R8}              ;Restore that again
+               MOV     R1,R0                   ;Point to the icon block
+               SWI     XWimp_PlotIcon          ;Now plot the icon on top
+               ADD     R13,R13,#16             ;Restore stack pointer
+               LDMFD   R13!,{R1-R8,PC}         ;Return to caller
+
+; --- grp 3 ---
+
+grp3           STMFD   R13!,{R1-R8,R14}        ;Stash registers
+
+               LDMIA   R0,{R5-R8}              ;Get the border coordinates
+               STMFD   R13!,{R5-R8}            ;Save them on the stack
+               MOV     R3,R0                   ;Keep this pointer safe
+
+               ; --- Translate the icon block ---
+
+               MOV     R1,#32                  ;Small offset here
+               BL      grp_titleicon           ;Find the icon position
+
+               ; --- Now display the main border ---
+
+               LDMIA   R0,{R5-R8}              ;Save this position
+               MOV     R0,R13                  ;Point to border position
+               MOV     R1,R3                   ;Point to title position
+               LDR     R11,s_flags             ;Get the flags word
+               TST     R11,#s_FAINTCHAN        ;Is it meant to be faint
+               ADREQ   R11,s_colours+1         ;Point to colour table
+               ADRNE   R11,s_shadeCols+1
+               BL      gborder                 ;Plot the group border
+
+               ; --- Now display the main title border ---
+
+               STMIA   R3,{R5-R8}              ;Restore saved position
+               MOV     R0,R3                   ;Point to the position
+               BL      brd6                    ;Plot the top thingy
+               STMIA   R0,{R5-R8}              ;Restore that again
+               MOV     R1,R0                   ;Point to the icon block
+
+               ; --- Stop the top bit from being filled ---
+
+               LDR     R0,[R1,#16]
+               BIC     R0,R0,#(1<<5)           ;Clear filled flag
+               STR     R0,[R1,#16]
+
+               SWI     XWimp_PlotIcon          ;Now plot the icon on top
+               ADD     R13,R13,#16             ;Restore stack pointer
+               LDMFD   R13!,{R1-R8,PC}         ;Return to caller
+
+; --- gborder ---
+;
+; On entry:    R0 == pointer to icon coordinates block (writable)
+;              R1 == pointer to title icon coordinate
+;              R9 == x coord of window origin on screen
+;              R10 == y coord of window origin on screen
+;
+; Plots a group border such that it doesn't overlap the title icon at all.
+
+gborder                ROUT
+
+               STMFD   R13!,{R0-R5,R8,R14}     ;Stack registers away
+               MOV     R8,R1                   ;Keep this pointer safe
+
+               ; --- Now convert all the boxes to screen coords ---
+
+               LDMIA   R0,{R1-R4}              ;Get the straight box
+               BL      box_convert
+               STMIA   R0,{R1-R4}              ;Write it back nicely
+
+               SUB     R1,R1,#4                ;Now expand it a little
+               SUB     R2,R2,#4
+               ADD     R3,R3,#4
+               ADD     R4,R4,#4
+               STMFD   R13!,{R1-R4}            ;Stash them on the stack
+
+               LDMIA   R8,{R1-R4}              ;Get the title position
+               BL      box_convert
+
+               STMFD   R13!,{R1-R4}            ;Save them on the stack too
+
+               ; --- Now render all the parts except for the top ---
+
+               MOV     R1,R0
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               ADD     R0,R13,#16
+               BL      prim_left
+               MOV     R0,R1
+               BL      prim_right
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               ADD     R0,R13,#16
+               BL      prim_right
+               BL      prim_bottom
+               MOV     R0,R1
+               BL      prim_left
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_bottom
+
+               ; --- Now fix up the top coordinates ---
+
+               LDR     R0,[R13,#8]             ;Get right side of title box
+               ADD     R0,R0,#8                ;Move it clear of the group
+               LDR     R5,[R1,#0]              ;Get the old left hand side
+               STR     R0,[R1,#0]              ;Store as left side here
+               STR     R0,[R13,#16]            ;And left side for other one
+
+               ; --- Now render the left top sides ---
+
+               ADD     R0,R13,#16
+               BL      prim_top
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_top
+
+               ; --- Now get the right top sides ---
+
+               STR     R5,[R1,#0]              ;Store it back again
+               SUB     R5,R5,#4                ;Fiddle for outer border
+               STR     R5,[R13,#16]            ;Save in outer border block
+
+               LDR     R0,[R13,#0]             ;Get right hand side of this
+               SUB     R0,R0,#4                ;Move it over a little
+               STR     R0,[R1,#8]              ;Store as rightside here
+               STR     R0,[R13,#24]            ;And right side for other one
+
+               ; --- Now render the right top sides ---
+
+               MOV     R0,R1
+               BL      prim_top
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               ADD     R0,R13,#16
+               BL      prim_top
+
+               ; --- Return -- it's all over ---
+
+                ADD    R13,R13,#32             ;Restore the stack pointer
+
+               LDMFD   R13!,{R0-R5,R8,PC}^     ;Return to caller
+
+               LTORG
+
+;----- Draw the border types ------------------------------------------------
+;
+; All entry:   R0 == pointer to icon coordinates block (writable)
+;              R9 == x coord of window origin on screen
+;              R10 == y coord of window origin on screen
+
+; --- brd8 ---
+
+brd8           ROUT
+
+               STMFD   R13!,{R14}
+               LDR     R14,s_flags
+               TST     R14,#s_FAINTCHAN
+               ANDNE   R14,R11,#3
+               ADRNE   R11,s_shadeCols
+               ADDNE   R11,R11,R14
+               LDMFD   R13!,{R14}
+
+; --- brd0 ---
+
+brd0           ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack registers away
+               LDMIA   R0,{R1-R4}              ;Load the coordinates
+               BL      box_convert
+               STMIA   R0,{R1-R4}
+               MOV     R1,R0                   ;Keep pointer to box
+
+               ; --- Draw bits of the border ---
+
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_left
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_right
+               BL      prim_bottom
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_top
+
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- brd1 ---
+
+brd1           ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack registers away
+               SUB     R13,R13,#16             ;Make space for another blk
+               LDMIA   R0,{R1-R4}              ;Load the coordinates
+               BL      box_convert
+               STMIA   R0,{R1-R4}
+               SUB     R1,R1,#4
+               SUB     R2,R2,#4
+               ADD     R3,R3,#4
+               ADD     R4,R4,#4
+               STMIA   R13,{R1-R4}
+               MOV     R1,R0                   ;Keep pointer to box
+
+               ; --- Draw bits of the border ---
+
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R13
+               BL      prim_left
+               MOV     R0,R1
+               BL      prim_right
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R13
+               BL      prim_right
+               BL      prim_bottom
+               MOV     R0,R1
+               BL      prim_left
+               BL      prim_top
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R13
+               BL      prim_top
+               MOV     R0,R1
+               BL      prim_bottom
+
+               ADD     R13,R13,#16
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- brd2 ---
+
+brd2           ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack registers away
+               LDMIA   R0,{R1-R4}              ;Load the coordinates
+               BL      box_convert
+               STMIA   R0,{R1-R4}
+               SUB     R1,R1,#4
+               SUB     R2,R2,#4
+               ADD     R3,R3,#4
+               ADD     R4,R4,#4
+               STMFD   R13!,{R1-R4}
+               SUB     R1,R1,#4
+               SUB     R2,R2,#4
+               ADD     R3,R3,#4
+               ADD     R4,R4,#4
+               STMFD   R13!,{R1-R4}
+               MOV     R1,R0                   ;Keep pointer to box
+
+               ; --- Draw inside border ---
+
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_left
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_right
+               BL      prim_bottom
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_top
+
+               ; --- Draw rim around the middle ---
+               ;
+               ; It's overkill, but I'll use the calls below for this
+
+               LDR     R0,s_rimcol
+               SWI     XWimp_SetColour
+               ADD     R0,R13,#16
+               BL      prim_left
+               BL      prim_right
+               BL      prim_top
+               BL      prim_bottom
+
+               ; --- Draw surrounding border ---
+
+               BIC     R11,R11,#1              ;Round pointer downwards
+               LDR     R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R13
+               BL      prim_left
+               LDR     R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R13
+               BL      prim_right
+               BL      prim_bottom
+               LDR     R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R13
+               BL      prim_top
+
+               ADD     R13,R13,#32
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+; --- brd3 ---
+
+brd3           ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack registers away
+               LDMIA   R0,{R1-R4}              ;Load the coordinates
+               BL      box_convert
+               STMIA   R0,{R1-R4}
+               MOV     R1,R0                   ;Save this away
+
+               ; --- Fill in the inside section to overwrite marbling ---
+
+               MOV     R0,#1
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_left
+               BL      prim_right
+               BL      prim_bottom
+               BL      prim_top
+
+               LDMIA   R0,{R1-R4}
+               SUB     R1,R1,#4
+               SUB     R2,R2,#4
+               ADD     R3,R3,#4
+               ADD     R4,R4,#4
+               STMIA   R0,{R1-R4}
+               MOV     R1,R0                   ;Keep pointer to box
+
+               ; --- Draw bits of the border ---
+
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_left
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_right
+               BL      prim_bottom
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_top
+
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- brd5 ---
+
+brd5           ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack registers away
+               LDMIA   R0,{R1-R4}              ;Load the coordinates
+               BL      box_convert
+               STMIA   R0,{R1-R4}
+               SUB     R14,R4,R2               ;Get height of box
+               ADD     R2,R2,R14,LSR #1        ;Centre R2 in box
+               SUB     R4,R2,#4                ;Move thing to right place
+               ADD     R2,R2,#4                ;And copy across
+               SUB     R3,R1,#4                ;Set up the nick width
+               STMFD   R13!,{R1-R4}            ;Stash them on the stack
+               MOV     R1,R0                   ;Keep pointer to box
+
+               ; --- Draw bits of the border ---
+
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_left
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_right
+               BL      prim_bottom
+               MOV     R0,R13
+               BL      prim_top
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R1
+               BL      prim_top
+               LDMIA   R1,{R1-R3}
+               LDR     R2,[R13,#4]
+               ADD     R1,R3,#4
+               STMIA   R13,{R1-R3}
+               MOV     R0,R13
+               BL      prim_bottom
+
+               ADD     R13,R13,#16
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- brd6 ---
+
+brd6           ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Stack registers away
+               LDMIA   R0,{R1-R4}              ;Load the coordinates
+               BL      box_convert
+               STMIA   R0,{R1-R4}
+               SUB     R14,R4,R2               ;Get height of box
+               ADD     R2,R2,R14,LSR #1        ;Centre R2 in box
+               MOV     R4,R2                   ;Move thing to right place
+               SUB     R3,R1,#4                ;Set up the nick width
+               STMFD   R13!,{R1-R4}            ;Stash them on the stack
+               MOV     R1,R0                   ;Keep pointer to box
+
+               ; --- Draw bits of the border ---
+
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R13
+               BL      prim_left
+               LDRB    R0,[R11,#0]
+               SWI     XWimp_SetColour
+               MOV     R0,R13
+               BL      prim_top
+
+               LDMIA   R1,{R1-R3}
+               LDR     R2,[R13,#4]
+               ADD     R1,R3,#4
+               STMIA   R13,{R1-R3}
+
+               BL      prim_right
+               LDRB    R0,[R11,#1]
+               SWI     XWimp_SetColour
+               MOV     R0,R13
+               BL      prim_bottom
+
+               ADD     R13,R13,#16
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller
+
+               LTORG
+
+; --- brd7 ---
+
+brd7           ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Stack registers away
+               LDMIA   R0,{R1-R4}              ;Load the coordinates
+               BL      box_convert
+               STMFD   R13!,{R1-R4}
+               MOV     R10,R0                  ;Save this away
+               LDR     R9,[R10,#16]            ;Load the icon's flags
+
+               ; --- Find out about the icon's colours ---
+
+               TST     R9,#1<<6                ;Is it anti-aliased?
+               BEQ     %10brd7                 ;No -- skip this bit out then
+
+               BIC     R9,R9,#&ff000000        ;Clear out the font handle
+               MOV     R2,#'F'                 ;Find font validation strings
+               MOV     R3,#0                   ;Start from the beginning
+               BL      box_findValid           ;Find the colour command
+               CMP     R2,#0                   ;Was it not there at all?
+               ORREQ   R9,R9,#&07000000        ;No -- use default colours
+               BEQ     %10brd7                 ;And skip to the end
+
+               LDRB    R0,[R2,#1]              ;Load a byte from the string
+               SUB     R0,R0,#'0'              ;Turn it into a number
+               CMP     R0,#10                  ;Is it a letter, not a digit?
+               SUBCS   R0,R0,#7                ;Yes -- compensate for that
+               CMP     R0,#16                  ;Is it lowercase?
+               SUBCS   R0,R0,#&20              ;Yes -- deal with that case
+
+               LDRB    R1,[R2,#2]              ;Load the next byte too
+               SUB     R1,R1,#'0'              ;Turn it into a number
+               CMP     R1,#10                  ;Is it a letter, not a digit?
+               SUBCS   R1,R1,#7                ;Yes -- compensate for that
+               CMP     R1,#16                  ;Is it lowercase?
+               SUBCS   R1,R1,#&20              ;Yes -- deal with that case
+
+               ORR     R9,R9,R0,LSL #28        ;Fit the background colour in
+               ORR     R9,R9,R1,LSL #24        ;And the foreground colour
+
+               ; --- First plot the whole background ---
+
+10brd7         ADR     R14,s_dx                ;Point to the pixel sizes
+               LDMIA   R14,{R7,R8}             ;Load them out nicely
+               LDMFD   R13!,{R3-R6}            ;Load the coordinates out
+
+               TST     R9,#1<<5                ;Is the icon filled?
+               BEQ     %20brd7                 ;No -- skip this bit out
+
+               MOV     R0,R9,LSR #28           ;Get the background colour
+               AND     R0,R0,#&f               ;Clear all the other bits
+               SWI     XWimp_SetColour         ;Set the bit's colour
+
+               MOV     R0,#plot_MOVE+plot_ABSOLUTE
+               SUB     R1,R3,#4
+               SUB     R2,R4,#4
+               ADD     R1,R1,R7                ;Don't overlap the border
+               ADD     R2,R2,R8
+               SWI     XOS_Plot                ;Move to the bottom left
+
+               MOV     R0,#plot_RECTFILL+plot_ABSOLUTE+plot_FORE
+               ADD     R1,R5,#4
+               ADD     R2,R6,#4
+               SUB     R1,R1,R7,LSL #1
+               SUB     R2,R2,R8,LSL #1
+               SWI     XOS_Plot                ;Fill in the background
+
+               ; --- Plot the foreground border now ---
+
+20brd7         MOV     R0,R9,LSR #24           ;Get the foreground colour
+               AND     R0,R0,#&f               ;Clear all the other bits
+               SWI     XWimp_SetColour         ;Set the bit's colour
+
+               MOV     R0,#plot_MOVE+plot_ABSOLUTE
+               SUB     R1,R3,#4
+               SUB     R2,R4,#4
+               SWI     XOS_Plot                ;Move to the bottom left
+
+               MOV     R0,#plot_LINE+plot_ABSOLUTE+plot_FORE
+               ADD     R1,R5,#4
+               SUB     R1,R1,R7
+               SUB     R2,R4,#4
+               SWI     XOS_Plot                ;Plot the left hand side
+
+               MOV     R0,#plot_LINE+plot_ABSOLUTE+plot_FORE
+               ADD     R1,R5,#4
+               SUB     R1,R1,R7
+               ADD     R2,R6,#4
+               SUB     R2,R2,R8
+               SWI     XOS_Plot                ;Plot the top edge
+
+               MOV     R0,#plot_LINE+plot_ABSOLUTE+plot_FORE
+               SUB     R1,R3,#4
+               ADD     R2,R6,#4
+               SUB     R2,R2,R8
+               SWI     XOS_Plot                ;Plot the right hand side
+
+               MOV     R0,#plot_LINE+plot_ABSOLUTE+plot_FORE
+               SUB     R1,R3,#4
+               SUB     R2,R4,#4
+               SWI     XOS_Plot                ;Plot the bottom edge
+
+               ; --- Now plot a writable border (type 3) ---
+
+               LDMIA   R10,{R0-R3}             ;Load the coordinates
+               SUB     R0,R0,#4                ;Modify for the extra border
+               SUB     R1,R1,#4
+               ADD     R2,R2,#4
+               ADD     R3,R3,#4
+               STMIA   R10,{R0-R3}
+
+               LDMFD   R13!,{R0-R10,R14}       ;Restore all the registers
+               B       brd3                    ;And plot the writable border
+
+               LTORG
+
+
+;----- Mangle coordinates for the mode --------------------------------------
+
+; --- box_convert ---
+;
+; Converts box given in R1-R4 by translating to screen coords and rounding
+; down to pixel boundaries
+
+box_convert    ROUT
+
+               STMFD   R13!,{R0,R14}           ;Stash registers
+
+               ; --- Convert to screen coordinates ---
+
+               ADD     R1,R1,R9
+               ADD     R2,R2,R10
+               ADD     R3,R3,R9
+               ADD     R4,R4,R10
+
+               ; --- Round off to whole pixel sizes ---
+
+               LDR     R0,s_dx
+               LDR     R14,s_dy
+               SUB     R0,R0,#1
+               SUB     R14,R14,#1
+               BIC     R1,R1,R0
+               BIC     R2,R2,R14
+               BIC     R3,R3,R0
+               BIC     R4,R4,R14
+               LDMFD   R13!,{R0,PC}
+
+;----- Set up the VDU variables in the buffer -------------------------------
+
+; --- vdu_set ---
+
+vdu_set                ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Stack some registers
+               ADR     R0,vdu_wanted           ;Which ones do we want?
+               ADR     R1,s_dx                 ;Where do we want them?
+               SWI     XOS_ReadVduVariables    ;Read the values
+               LDMIA   R1,{R0,R2}              ;Read their values into regs
+               CMP     R2,#2                   ;Is this a high-pixel mode?
+               MOVEQ   R3,#2                   ;Yes -- use a default value
+               MOVNE   R3,#4
+               MOVNE   R3,R3,LSR R2            ;No -- divide up border
+               RSBNE   R3,R3,#4
+               MOV     R14,#1
+               MOV     R0,R14,LSL R0           ;Convert these to pixel sizes
+               MOV     R2,R14,LSL R2
+               STMIA   R1,{R0,R2,R3}           ;Store back in workspace
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+vdu_wanted     DCD     vdu_XEIG
+               DCD     vdu_YEIG
+               DCD     -1
+
+               LTORG
+
+;----- Plot primitives ------------------------------------------------------
+
+; --- prim_left ---
+;
+; Plots a vertical strip in the current foreground colour on the left of an
+; icon box.
+;
+; On entry:    R0 == pointer to the icon bounding box
+
+prim_left      ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Keep the stack pointer busy
+               MOV     R3,R0                   ;Keep the pointer safe
+               LDMIA   R3!,{R1,R2}             ;Get the bottom left coord
+               SUB     R1,R1,#4                ;Make way for the border
+               SUB     R2,R2,#4                ;Make way for the border
+               MOV     R0,#plot_MOVE+plot_ABSOLUTE
+               SWI     XOS_Plot                ;Move to first corner
+               LDR     R1,s_dx                 ;Get the pixel width
+               RSB     R1,R1,#4                ;Trim the width a little
+               LDR     R3,[R3,#4]              ;Get the top coordinate
+               SUB     R2,R3,R2                ;Find the height of the strip
+               LDR     R3,s_dy                 ;Get the y pixel size
+               SUB     R2,R2,R3                ;And add that in too
+               ADD     R2,R2,#4                ;And add the border width
+               MOV     R0,#plot_RECTFILL+plot_FORE+plot_RELATIVE
+               SWI     XOS_Plot                ;Plot the rectangle
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- prim_right ---
+;
+; Plots a vertical strip in the current foreground colour on the right of an
+; icon box.
+;
+; On entry:    R0 == pointer to the icon bounding box
+
+prim_right     ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Keep the stack pointer busy
+               ADD     R3,R0,#16               ;Point to the top of the box
+               LDMDB   R3!,{R1,R2}             ;Get the top right coord
+               LDR     R0,s_dy                 ;Get the y pixel size
+               SUB     R2,R2,R0
+               ADD     R2,R2,#4                ;Make way for the border
+               MOV     R0,#plot_MOVE+plot_ABSOLUTE
+               SWI     XOS_Plot                ;Move to first corner
+               LDR     R1,s_dx                 ;Get the pixel width
+               RSB     R1,R1,#4                ;Trim the width a little
+               LDR     R3,[R3,#-4]             ;Get the bottom coordinate
+               SUB     R2,R3,R2                ;Find the height of the strip
+               SUB     R2,R2,#4                ;And add the border width
+               MOV     R0,#plot_RECTFILL+plot_FORE+plot_RELATIVE
+               SWI     XOS_Plot                ;Plot the rectangle
+               LDMFD   R13!,{R0-R3,PC}^        ;Return to caller
+
+               LTORG
+
+; --- prim_bottom ---
+;
+; Plots a horizontal strip in the current foreground colour along the bottom
+; of an icon, with a little jagged bit on the left hand side.
+;
+; On entry:    R0 == pointer to icon block
+
+
+prim_bottom    ROUT
+
+               STMFD   R13!,{R0-R2,R7-R11,R14} ;Keep stack pointer moving
+
+               ; --- Load the variables we need ---
+
+               LDMIA   R0,{R9-R11}             ;Get useful coordinates out
+               LDR     R1,s_dx                 ;Get x pixel width
+               LDR     R8,s_dy                 ;Get y pixel width
+               LDR     R2,s_start              ;Get start X offset
+
+               ; --- Initialise variables for first loop ---
+
+               SUB     R9,R9,R2                ;Shift x0 back a little
+               SUB     R11,R11,R1              ;Shift x1 past icon edge
+               SUB     R2,R10,R8               ;Move y below the icon
+               ADD     R11,R11,#4              ;And make space for border
+               RSB     R7,R8,#4                ;Loop stops when R7==0
+
+               ; --- Draw a line (loop body) ---
+
+00prim_bottom  MOV     R0,#plot_MOVE+plot_ABSOLUTE
+               MOV     R1,R9
+               SWI     XOS_Plot                ;Move to the left of the line
+               MOV     R0,#plot_LINE+plot_FORE+plot_ABSOLUTE
+               MOV     R1,R11
+               SWI     XOS_Plot                ;Draw the line
+
+               ; --- Check if we've done (loop termination) ---
+
+               SUBS    R7,R7,R8                ;Decrement the counter
+               LDMLTFD R13!,{R0-R2,R7-R11,PC}^ ;Return to caller
+
+               ; --- Update coordinates (loop update) ---
+
+               SUB     R9,R9,R8                ;Move x coordinate back a bit
+               SUB     R2,R2,R8                ;Move y coordinate down a bit
+               B       %00prim_bottom          ;And do it all again
+
+               LTORG
+
+; --- prim_top ---
+;
+; Plots a horizontal strip in the current foreground colour along the top
+; of an icon, with a little jagged bit on the right hand side.
+;
+; On entry:    R0 == pointer to icon block
+
+
+prim_top       ROUT
+
+               STMFD   R13!,{R0-R2,R7-R11,R14} ;Keep stack pointer moving
+
+               ; --- Load the variables we need ---
+
+               LDMIA   R0,{R8-R11}             ;Get useful coordinates out
+               MOV     R9,R8                   ;Don't want y0
+               LDR     R1,s_dx                 ;Get x pixel width
+               LDR     R8,s_dy                 ;Get y pixel width
+               LDR     R2,s_start              ;Get start X offset
+
+               ; --- Initialise variables for first loop ---
+
+               SUB     R9,R9,#4                ;Make space for border
+               SUB     R10,R10,R1              ;Shift x1 past icon edge
+               ADD     R10,R10,R2              ;And add on the little bitty
+               MOV     R2,R11                  ;Move y above the icon
+               RSB     R7,R8,#4                ;Loop stops when R7==0
+
+               ; --- Draw a line (loop body) ---
+
+00prim_top     MOV     R0,#plot_MOVE+plot_ABSOLUTE
+               MOV     R1,R9
+               SWI     XOS_Plot                ;Move to the left of the line
+               MOV     R0,#plot_LINE+plot_FORE+plot_ABSOLUTE
+               MOV     R1,R10
+               SWI     XOS_Plot                ;Draw the line
+
+               ; --- Check if we've done (loop termination) ---
+
+               SUBS    R7,R7,R8                ;Decrement the counter
+               LDMLTFD R13!,{R0-R2,R7-R11,PC}^ ;Return to caller
+
+               ; --- Update coordinates (loop update) ---
+
+               ADD     R10,R10,R8              ;Move x coordinate on a bit
+               ADD     R2,R2,R8                ;Move y coordinate up a bit
+               B       %00prim_top             ;And do it all again
+
+               LTORG
+
+;----- Workspace layout -----------------------------------------------------
+
+               ^       0,R12
+
+s_wstart       #       0
+
+               ; --- Graphics variables ---
+
+s_dx           #       4                       ;Horizontal pixel size (OS)
+s_dy           #       4                       ;Vertical pixel size (OS)
+s_start                #       4                       ;Offset into corner for plot
+
+               ; --- Various other things ---
+
+s_flags                #       4                       ;Various Sculptix flags
+s_sarea                #       4                       ;The sprite area in tns icons
+
+               ; --- Colours ---
+
+s_colours      #       4                       ;Colours for the 3D bits
+s_shadeCols    #       4                       ;Colours for shaded 3D boxes
+s_slabcol      #       1                       ;Slabbing in colour
+s_rimcol       #       1                       ;Inner rim colour for type 2
+               #       2                       ;Padding to align
+
+               ; --- Misc buffers ---
+
+s_buffer       #       256                     ;A big buffer for things
+
+s_wend         #       0
+
+s_UNSLAB       EQU     (1<<0)                  ;We've unslabbed this poll
+s_CHANNEL      EQU     (1<<1)                  ;Use channels, not ridges
+s_FAINTCHAN    EQU     (1<<2)                  ;Draw channel boxes faintly
+
+s_wsize                EQU     s_wend-s_wstart
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/Makefile,fe1 b/StraySrc/Sculptrix/sculptrix/Makefile,fe1
new file mode 100644 (file)
index 0000000..21bf332
--- /dev/null
@@ -0,0 +1,192 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+OBJS = \
+       o.sculptrix \
+       o.bbox o.border o.colours o.config o.plot o.redraw o.slab \
+       o.rules o.utils o.vString \
+       o.messages
+
+VERSION = 2.01
+
+#----- Compiling things -----------------------------------------------------
+
+all: Sculptrix
+
+Sculptrix: $(OBJS)
+       $(SETDATE) \
+               o.version \
+               version="Sculptrix\t$(VERSION) ($(MODDATE)) $(CRIGHT)"
+       $(LD_MOD) $(OBJS) o.version
+       $(SET_MOD)
+
+o.messages: rsc.messages
+       msgaof rsc.messages o.messages sh.messages
+
+install: Sculptrix
+       $(INSTALL) Sculptrix <SSR$ModDir>
+
+clean:
+       -$(RM) o.* Sculptrix
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+o.sculptrix: s.sculptrix
+o.sculptrix: libs:header
+o.sculptrix: libs:swis
+o.sculptrix: libs:stream
+o.sculptrix: sh.bbox
+o.sculptrix: sh.config
+o.sculptrix: sh.plot
+o.sculptrix: sh.redraw
+o.sculptrix: sh.slab
+o.sculptrix: sh.vString
+o.sculptrix: sh.wSpace
+o.sculptrix: sh.messages
+o.bbox: s.bbox
+o.bbox: libs:header
+o.bbox: libs:swis
+o.bbox: libs:stream
+o.bbox: sh.vString
+o.bbox: sh.wSpace
+o.border: s.border
+o.border: libs:header
+o.border: libs:swis
+o.border: libs:stream
+o.border: sh.colours
+o.border: sh.wSpace
+o.border: sh.messages
+o.colours: s.colours
+o.colours: libs:header
+o.colours: libs:swis
+o.colours: libs:stream
+o.colours: sh.vString
+o.config: s.config
+o.config: libs:header
+o.config: libs:swis
+o.config: libs:stream
+o.config: sh.wSpace
+o.config: sh.messages
+o.plot: s.plot
+o.plot: libs:header
+o.plot: libs:swis
+o.plot: libs:stream
+o.plot: sh.border
+o.plot: sh.rules
+o.plot: sh.utils
+o.plot: sh.vString
+o.plot: sh.wSpace
+o.redraw: s.redraw
+o.redraw: libs:header
+o.redraw: libs:swis
+o.redraw: libs:stream
+o.redraw: sh.plot
+o.redraw: sh.vString
+o.redraw: sh.wSpace
+o.slab: s.slab
+o.slab: libs:header
+o.slab: libs:swis
+o.slab: libs:stream
+o.slab: sh.colours
+o.slab: sh.plot
+o.slab: sh.vString
+o.slab: sh.wSpace
+o.rules: s.rules
+o.rules: libs:header
+o.rules: libs:swis
+o.rules: libs:stream
+o.utils: s.utils
+o.utils: libs:header
+o.utils: libs:swis
+o.utils: libs:stream
+o.vString: s.vString
+o.vString: libs:header
+o.vString: libs:swis
+o.vString: libs:stream
+o.vString: sh.wSpace
diff --git a/StraySrc/Sculptrix/sculptrix/rsc/messages b/StraySrc/Sculptrix/sculptrix/rsc/messages
new file mode 100644 (file)
index 0000000..cda36b4
--- /dev/null
@@ -0,0 +1,21 @@
+;
+; Sculptrix messages
+;
+
+; --- Error messages ---
+
+errBadSwi:[&1E6]Unknown Sculptrix operation
+errBadOpcode:[1]Undefined instruction in border definition
+errBadConfig:[1]Bad Sculptrix configuration file
+errCfgBuff:[1]Buffer too small
+
+; --- *Commands ---
+
+config:{
+  *Sculptrix_LoadConfig loads a configuration file which defines the style \
+  for Sculptrix borders.  You can build Sculptrix configuration files using \
+  the Setrix application.  This command is intended to be used in boot \
+  sequences.
+  |
+  Syntax: *Sculptrix_LoadConfig |<filename>\
+}
diff --git a/StraySrc/Sculptrix/sculptrix/s/bbox b/StraySrc/Sculptrix/sculptrix/s/bbox
new file mode 100644 (file)
index 0000000..8a2c759
--- /dev/null
@@ -0,0 +1,106 @@
+;
+; bbox.s
+;
+; Bounding box calculations for Sculptrix borders
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.vString
+               GET     sh.wSpace
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- bbox_calc ---
+;
+; On entry:    R1 == pointer to icon block
+;
+; On exit:     R0 == 0 if there was no border, or nonzero otherwise
+;
+; Use:         Updates the block to represent the size of the border.
+
+               EXPORT  bbox_calc
+bbox_calc      ROUT
+
+               STMFD   R13!,{R1-R4,R14}        ;Save some registers
+               BL      vString_read            ;Read the validation string
+               BCC     %85bbox_calc            ;If no border, return
+
+               ; --- Work out where to go ---
+
+               AND     R14,R0,#&0000FF00       ;Extract the general code
+               CMP     R14,#(%10-%00)<<6       ;Check it's in range
+               ADDCC   PC,PC,R14,LSR #6        ;Yes -- dispatch it then
+               B       %85bbox_calc            ;Otherwise ignore it
+
+00             B       %10bbox_calc            ;A simple border type
+               B       %20bbox_calc            ;A group box
+               B       %85bbox_calc            ;A text+sprite icon
+
+               ; --- A normal icon ---
+
+10bbox_calc    AND     R0,R0,#&FF              ;Leave only the subtype
+               ADR     R14,bbox__table         ;Point to a smart table
+               LDRB    R0,[R14,R0]             ;Load the sizes out
+
+               LDMIA   R1,{R2-R4,R14}          ;Load the bounding box
+               SUB     R2,R2,R0                ;Modify the bounding box
+               SUB     R3,R3,R0
+               ADD     R4,R4,R0
+               ADD     R14,R14,R0
+               STMIA   R1,{R2-R4,R14}          ;Save modified box back
+               MOV     R0,#-1                  ;Return a mystic value
+               B       %90bbox_calc            ;And return to caller
+
+               ; --- A group box ---
+
+20bbox_calc    LDMIA   R1,{R2-R4,R14}          ;Load the bounding box
+               SUB     R2,R2,#8                ;Modify the bounding box
+               SUB     R3,R3,#8
+               ADD     R4,R4,#8
+               ADD     R14,R14,#32
+               STMIA   R1,{R2-R4,R14}          ;Save modified box back
+               MOV     R0,#-1                  ;Return a mystic value
+               B       %90bbox_calc            ;And return to caller
+
+               ; --- Return then ---
+
+85bbox_calc    MOV     R0,#0                   ;Nothing happened here
+90bbox_calc    LDMFD   R13!,{R1-R4,PC}^        ;Return to caller
+
+bbox__table    DCB     4,12,8,12,8
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/s/border b/StraySrc/Sculptrix/sculptrix/s/border
new file mode 100644 (file)
index 0000000..6639866
--- /dev/null
@@ -0,0 +1,330 @@
+;
+; border.s
+;
+; Plots borders given an icon block and a definition of the border shape
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.colours
+               GET     sh.wSpace
+
+               GET     sh.messages
+
+;----- The idea -------------------------------------------------------------
+;
+; We store the border shapes as commands in blocks, and then read them out
+; when plotting needs to be done.
+;
+; The commands are very simple, and are one byte wide each.  Some commands
+; have arguments which are stored in the following byte or word.  Whole
+; word arguments are preceded by padding to a word boundary.  It ends up
+; looking a bit like a simple `machine code'.
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- border_plot ---
+;
+; On entry:    R0 == pointer to border defintion
+;              R1 == pointer to icon block
+;              R2,R3 == window origin position
+;              R4 == pointer to colour table
+;              R5 == group box title width (optional)
+;              R6 == group box title address (optional)
+;
+; On exit:     May return an error
+;
+; Use:         Plots a border using the border definition.
+
+               EXPORT  border_plot
+border_plot    ROUT
+
+               STMFD   R13!,{R0-R11,R14}       ;Save lots of registers
+
+               ; --- Set up some environment ---
+
+               MOV     R10,R0                  ;Point at the border routine
+
+               ADR     R14,sculpt_vduVars      ;Point to the VDU variables
+               LDMIA   R14,{R7-R9}             ;Load these for the rule rtns
+
+               LDMIA   R1,{R4-R6,R14}          ;Load the icon position
+
+               SUB     R0,R7,#1                ;Turn this into a bitmask
+               BIC     R4,R4,R0                ;Mask the x coordinates
+               BIC     R6,R6,R0                ;To avoid nasty problems
+               SUB     R0,R8,#1                ;Turn this into a bitmask
+               BIC     R5,R5,R0                ;Mask the y coordinates
+               BIC     R14,R14,R0              ;To avoid nasty problems
+
+               ADD     R4,R4,R2                ;Convert to screen coords
+               ADD     R5,R5,R3                ;Convert to screen coords
+               ADD     R6,R6,R2                ;Convert to screen coords
+               ADD     R14,R14,R3              ;Convert to screen coords
+
+               STMFD   R13!,{R4-R6,R14}        ;These are initial reg values
+               MOV     R11,R13                 ;Remember this position
+
+               ; --- Now start executing ---
+
+border__main   LDRB    R14,[R10],#1            ;Load the next instruction
+               AND     R0,R14,#3               ;Fetch immediate op bits
+               BIC     R14,R14,#3              ;Clear them from the byte
+               CMP     R14,#(%10-%00)          ;Is instruction known?
+               ADDCC   PC,PC,R14               ;Yes -- dispatch it then
+               B       %10border_plot          ;If unknown, report error
+
+00             B       border__ret             ;End the routine
+               B       border__iLoad           ;Load a value from the icon
+               B       border__load            ;Load a stored value
+               B       border__ldCtr           ;Load a centrepoint
+               B       border__op              ;Do an op on the value
+               B       border__store           ;Store value in output blk
+               B       border__stdCol          ;Standard colour selection
+               B       border__colour          ;Other colour ops
+               B       border__plot            ;Plot a rule
+               B       border__skipTtl         ;Skip over the group title
+               B       border__plotGrp         ;Plot a group box
+               B       border__call            ;Call a subroutine
+
+10border_plot  ADRL    R0,msg_errBadOpcode     ;Point to the error message
+               ADD     R13,R11,#16+4           ;Restore the stack pointer
+               LDMFD   R13!,{R1-R11,R14}       ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               ; --- border__ret ---
+
+border__ret    CMP     R13,R11                 ;Are we at top level?
+               LDMCCFD R13!,{R10}              ;No -- restore our IP
+               BCC     border__main            ;And continue
+
+               ADD     R13,R11,#16             ;Restore stack pointer
+               LDMFD   R13!,{R0-R11,R14}       ;Restore registers
+               BICS    PC,R14,#V_flag          ;And return with glad tidings
+
+               ; --- border__iLoad ---
+
+border__iLoad  LDR     R6,[R1,R0,LSL #2]       ;Load the requested value
+border__round  TST     R0,#1                   ;Is this a y-coordinate?
+               ADDEQ   R6,R6,R2                ;No -- adjust by x origin
+               ADDNE   R6,R6,R3                ;Yes -- adjust by y origin
+               SUBEQ   R14,R7,#1               ;No -- get x width
+               SUBNE   R14,R8,#1               ;Yes -- get y width
+               BIC     R6,R6,R14               ;Round the value nicely
+               B       border__main            ;And get next instruction
+
+               ; --- border__load ---
+
+border__load   LDR     R6,[R11,R0,LSL #2]      ;Load the requested value
+               B       border__main            ;And get the next instruction
+
+               ; --- border__ldCtr ---
+
+border__ldCtr  ADD     R14,R1,R0,LSL #2        ;Find the correct bit
+               LDMIA   R14,{R5,R6,R14}         ;Load three values
+               ADD     R6,R5,R14               ;Add the two together
+               MOV     R6,R6,ASR #1            ;Divide by two
+               B       border__round           ;Now round the value to pixel
+
+               ; --- border__op ---
+
+border__op     LDRB    R14,[R10],#1            ;Load the next byte out
+               TST     R0,#1                   ;Which op is it?
+               ADDEQ   R6,R6,R14               ;Add -- do the add then
+               SUBNE   R6,R6,R14               ;Sub -- do that
+               B       border__main            ;And skip off merrily
+
+               ; --- border__store ---
+
+border__store  STR     R6,[R11,R0,LSL #2]      ;Store it (can't trash stk)
+               B       border__main            ;And return to loop
+
+               ; --- border__stdCol ---
+
+border__stdCol TST     R0,#2                   ;Doing complicated things?
+               BNE     %f00                    ;Yes -- skip forwards then
+               LDR     R14,[R11,#16 + 4*4]     ;Load the colour table addr
+               LDRB    R0,[R14,R0]             ;Load the colour out
+               SWI     XWimp_SetColour         ;Do the set
+               B       border__main            ;And loop back round
+
+00             LDR     R14,[R11,#16 + 4*4]     ;Load the colour table addr
+               BIC     R14,R14,#&03            ;Clear non-alignedness
+               STR     R14,[R11,#16 + 4*4]     ;Store the address back
+               B       border__main            ;And return to caller
+
+               ; --- border__colour ---
+
+border__colour CMP     R0,#0                   ;Is this set-from-icon?
+               BEQ     %f00                    ;Yes -- do this
+               CMP     R0,#1                   ;Do we indirect this?
+               LDRB    R0,[R10],#1             ;Load the argument byte
+               LDREQB  R0,[R12,R0]             ;Load the colour out
+               SWI     XWimp_SetColour         ;Set the colour
+               B       border__main            ;And loop back for more
+
+00             BL      colours_read            ;Read the colours out
+               MOV     R4,R0,LSR #4            ;Extract background colour
+               AND     R0,R0,#&F               ;Extract foreground colour
+               LDR     R14,[R1,#16]            ;Load the icon flags, please
+               TST     R14,#&00400000          ;Is icon /really/ shaded?
+               ANDNE   R0,R0,#2                ;Yes -- shade in simple way
+               SWI     XWimp_SetColour         ;Set the colour, please
+               ORR     R0,R4,#&80              ;Get the background colour
+               SWI     XWimp_SetColour         ;Set the colour, please
+               B       border__main            ;And continue
+
+               ; --- border__plot ---
+
+border__plot   ADD     R10,R10,#4+3            ;Word align instruction ptr
+               BIC     R10,R10,#3              ;And advance past the branch
+               STMFD   R13!,{R1-R3,R6}         ;Store useful values
+               LDMIA   R11,{R3-R6}             ;Load the coordinates
+               MOV     R14,PC                  ;Set up return address
+               SUB     PC,R10,#4               ;Call the branch instr
+               LDMFD   R13!,{R1-R3,R6}         ;Restore the registers
+               B       border__main            ;And rejoin the loop
+
+               ; --- border__skipTtl ---
+
+border__skipTtl        LDR     R14,[R11,#16 + 4*5]     ;Load the title width
+               ADD     R6,R6,R14               ;Add this on nicely
+               SUB     R14,R7,#1               ;Get x bitmask
+               BIC     R6,R6,R14               ;To be nice
+               B       border__main            ;Go forth and execute
+
+               ; --- border__plotGrp ---
+
+border__plotGrp        LDMIA   R11,{R4-R6,R14}         ;Load the coordinates
+
+               SUB     R4,R4,R2                ;Make them window relative
+               SUB     R5,R5,R3                ;Keep doing this a bit
+               SUB     R6,R6,R2
+               SUB     R14,R14,R3
+
+               SUB     R13,R13,#32             ;Make space for the block
+               STMIA   R13,{R4-R6,R14}         ;Store all them away
+               ADD     R10,R10,#4+3            ;Word align instruction ptr
+               BIC     R10,R10,#3              ;And skip past flags word
+
+               LDR     R4,[R10,#-4]            ;Load the flags word
+               LDR     R5,[R1,#16]             ;Load the original flags
+               BIC     R4,R4,#&0F400000        ;Clear the static flags
+               AND     R5,R5,#&0F400000        ;And mask the real flags
+               ORR     R4,R4,R5                ;Combine them nicely
+
+               LDR     R5,[R11,#16 + 4*6]      ;Get the title
+               MOV     R6,#-1                  ;No validation string
+               MOV     R14,#1                  ;A random buffer length
+               ADD     R0,R13,#16              ;Find a space nicely
+               STMIA   R0,{R4-R6,R14}          ;Save the icon data
+               MOV     R1,R13                  ;Point to this block
+               SWI     XWimp_PlotIcon          ;Do the icon plotting
+               ADD     R13,R13,#32             ;Restore the stack pointer
+               LDR     R1,[R11,#16 + 4*1]      ;Reload the icon pointer
+               B       border__main            ;Done that
+
+               ; --- border__call ---
+
+border__call   ADD     R10,R10,#4+3            ;Word align instruction ptr
+               BIC     R10,R10,#3              ;And advance past the branch
+               TST     R0,#1                   ;Do we save the old one?
+               STMNEFD R13!,{R10}              ;Yes -- save old IP on stack
+               LDR     R14,[R10,#-4]           ;Load the branch offset
+               ADD     R10,R10,R14             ;Find the new routine
+               B       border__main            ;Continue executing subrt
+
+               LTORG
+
+;----- Command codes --------------------------------------------------------
+;
+; We try to organise these in a way which makes it easy to decode.  The
+; bottom two bits end up as an immediate operand in most cases, allowing us
+; to select entries in the icon bounding box easily.
+
+               ^       -4
+
+               #       4
+bCmd_ret       EQU     {VAR}                   ;End border operation
+
+               #       4
+bCmd_ldix0     EQU     {VAR}+0                 ;Fetch X0 of the icon
+bCmd_ldiy0     EQU     {VAR}+1                 ;Fetch Y0 of the icon
+bCmd_ldix1     EQU     {VAR}+2                 ;Fetch X1 of the icon
+bCmd_ldiy1     EQU     {VAR}+3                 ;Fetch Y1 of the icon
+
+               #       4
+bCmd_ldx0      EQU     {VAR}+0                 ;Fetch last stored X0
+bCmd_ldy0      EQU     {VAR}+1                 ;Fetch last stored Y0
+bCmd_ldx1      EQU     {VAR}+2                 ;Fetch last stored X1
+bCmd_ldy1      EQU     {VAR}+3                 ;Fetch last stored Y1
+
+               #       4
+bCmd_ldhc      EQU     {VAR}+0                 ;Fetch horizontal centre
+bCmd_ldvc      EQU     {VAR}+1                 ;Fetch vertical centre
+
+               #       4
+bCmd_add       EQU     {VAR}+0                 ;Add next byte
+bCmd_sub       EQU     {VAR}+1                 ;Subtract next byte
+
+               #       4
+bCmd_stx0      EQU     {VAR}+0                 ;Store as the X0 parameter
+bCmd_sty0      EQU     {VAR}+1                 ;Store as the Y0 parameter
+bCmd_stx1      EQU     {VAR}+2                 ;Store as the X1 parameter
+bCmd_sty1      EQU     {VAR}+3                 ;Store as the Y1 parameter
+
+               #       4
+bCmd_dark      EQU     {VAR}+0                 ;Use the current `dark' col
+bCmd_light     EQU     {VAR}+1                 ;Use the current `light' col
+bCmd_raw       EQU     {VAR}+2                 ;Switch to uninverted colours
+
+               #       4
+bCmd_icon      EQU     {VAR}+0                 ;Set colours from icon
+bCmd_indCol    EQU     {VAR}+1                 ;Indirected colour
+bCmd_litCol    EQU     {VAR}+2                 ;Literal colour
+
+               #       4
+bCmd_plot      EQU     {VAR}+0                 ;Plot a rule (arg == branch)
+
+               #       4
+bCmd_skpt      EQU     {VAR}+0                 ;Skip past the `title'
+
+               #       4
+bCmd_group     EQU     {VAR}+0                 ;Plot a group box
+
+               #       4
+bCmd_jmp       EQU     {VAR}+0                 ;Jump to a routine
+bCmd_call      EQU     {VAR}+1                 ;Call subroutine
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/s/colours b/StraySrc/Sculptrix/sculptrix/s/colours
new file mode 100644 (file)
index 0000000..5b8476d
--- /dev/null
@@ -0,0 +1,138 @@
+;
+; colours.s
+;
+; Colour handling for Sculptrix
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.vString
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- colours_read ---
+;
+; On entry:    R1 == pointer to icon block
+;
+; On exit:     R0 == foreground in bits 0-3, background in bits 4-7
+;              CS if colours in validation string, and
+;                R14 == address of colours in there, or 0
+;
+; Use:         Works out colours of an icon.
+
+               EXPORT  colours_read
+colours_read   ROUT
+
+               ORR     R14,R14,#C_flag         ;Set C flag for exit
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               LDR     R14,[R1,#16]            ;Load the icon flags
+               TST     R14,#&40                ;Is the icon antialiased?
+               BNE     %50colours_read         ;Yes -- skip on then
+
+               MOV     R0,R14,LSR #24          ;Get the colours
+               LDMFD   R13!,{R1,R2,R14}        ;Restore registers
+               BICS    PC,R14,#C_flag          ;Colours not in valid string
+
+               ; --- Extract colours from string ---
+
+50colours_read MOV     R0,#'f'                 ;Find the validation command
+               MOV     R2,#0                   ;Start at the beginning
+               BL      vString_find            ;Locate the string
+               MOVCC   R14,#0                  ;If not found, clear ptr
+               MOVCC   R0,#&07                 ;Return black-on-white
+               BCC     %90colours_read         ;And skip on
+
+               ADD     R14,R2,#1               ;Point at the characters
+               LDRB    R0,[R14,#1]             ;Load the foreground colour
+               SUB     R0,R0,#'0'              ;Convert to digit
+               CMP     R0,#10                  ;Too big?
+               SUBCS   R0,R0,#7                ;Yes -- must be a letter
+               CMP     R0,#16                  ;Still too big?
+               SUBCS   R0,R0,#&20              ;Yes -- lowercase then
+
+               LDRB    R1,[R14,#0]             ;Load the background colour
+               SUB     R1,R1,#'0'              ;Convert to digit
+               CMP     R1,#10                  ;Too big?
+               SUBCS   R1,R1,#7                ;Yes -- must be a letter
+               CMP     R1,#16                  ;Still too big?
+               SUBCS   R1,R1,#&20              ;Yes -- lowercase then
+               ORR     R0,R0,R1,LSL #4         ;Merge the two together
+90colours_read LDMFD   R13!,{R1,R2,PC}^        ;And return to caller
+
+               LTORG
+
+; --- colours_set ---
+;
+; On entry:    R1 == pointer to icon /state/ block
+;              R2 == new background colour
+;
+; On exit:     R2 == old background colour
+;
+; Use:         Changes the background colour of an icon.
+
+               EXPORT  colours_set
+colours_set    ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+               ADD     R1,R1,#8                ;Point to the main icon data
+               BL      colours_read            ;Read the old colours
+               MOV     R0,R0,LSR #4            ;Shift down the colour
+               STR     R0,[R13,#8]             ;Return this in R2 later
+               BCS     %50colours_set          ;Handle anti-aliasing
+
+               MOV     R2,R2,LSL #28           ;Put colours in right place
+               MOV     R3,#&F0000000           ;Just change background colr
+               B       %70colours_set          ;And change the colour
+
+               ; --- Handle anti-aliasing ---
+
+50colours_set  CMP     R14,#0                  ;Can we do this?
+               BEQ     %90colours_set          ;No -- don't then
+               ADD     R2,R2,#'0'              ;Convert to decimal
+               CMP     R2,#'9'+1               ;Is it in range?
+               ADDCS   R2,R2,#7                ;No -- make it a letter
+               STRB    R2,[R14,#0]             ;Store background colour
+               MOV     R2,#0                   ;Don't change flags
+               MOV     R3,#0                   ;No, really, don't
+
+70colours_set  LDMDB   R1,{R0,R1}              ;Load window and icon handle
+               STMFD   R13!,{R0-R3}            ;Save them registers
+               MOV     R1,R13                  ;Point to the block
+               SWI     XWimp_SetIconState      ;Set the icon state
+               ADD     R13,R13,#16             ;Restore the stack
+90colours_set  LDMFD   R13!,{R0-R3,PC}^        ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/s/config b/StraySrc/Sculptrix/sculptrix/s/config
new file mode 100644 (file)
index 0000000..62ceed9
--- /dev/null
@@ -0,0 +1,215 @@
+;
+; config.s
+;
+; Configuration interface for Sculptrix
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.wSpace
+
+               GET     sh.messages
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- config_set ---
+;
+; On entry:    R0 == pointer to config buffer
+;
+; On exit:     CS if config has changed, else CC
+;
+; Use:         Reads the config buffer into workspace.
+
+               EXPORT  config_set
+config_set     ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R2,#0                   ;Clear some flags
+
+               ; --- Copy over the flags ---
+
+               LDRB    R14,[R0],#4             ;Load the flags out
+               LDR     R1,sculpt_flags         ;Load our current flags too
+               AND     R3,R1,#&FF              ;Get the appearance flags
+               CMP     R3,R14                  ;Is there a change here?
+               ORRNE   R2,R2,#1                ;Yes -- set the flag
+               BICNE   R1,R1,#&FF              ;And some of our own
+               ORRNE   R14,R14,R1              ;Merge the two sets together
+               STRNE   R14,sculpt_flags        ;And store back in workspace
+
+               ; --- Now deal with the colour sets ---
+
+               ADR     R1,sculpt_colours       ;Point to the colour tables
+               MOV     R3,#4                   ;There are four to do
+00             LDR     R14,[R0],#2             ;Load the next pair
+               MOV     R14,R14,LSL #16         ;Shift up to zero low half
+               ORR     R14,R14,R14,LSR #16     ;And shift down to copy
+               LDR     R4,[R1,#0]              ;Load the old word
+               CMP     R4,R14                  ;Do these match?
+               ORRNE   R2,R2,#1                ;No -- set the flag
+               STR     R14,[R1],#4             ;Store in my table
+               SUBS    R3,R3,#1                ;Decrement the counter
+               BNE     %b00                    ;Loop back for some more
+
+               ; --- Finally do the other pair ---
+
+               LDR     R14,[R0,#0]             ;Load the colours
+               LDR     R1,sculpt_hilight       ;Load the old ones
+               MOV     R1,R1,LSL #16           ;Shift up nicely
+               CMP     R1,R14,LSL #16          ;Do these match?
+               ORRNE   R2,R2,#1                ;No -- set the flag
+               STRNE   R14,sculpt_hilight      ;A hack, but it works
+
+               TST     R2,#1                   ;Did anything change
+               LDMFD   R13!,{R0-R4,R14}        ;Return when done
+               ORRNES  PC,R14,#C_flag
+               BICEQS  PC,R14,#C_flag
+
+               LTORG
+
+; --- config_read ---
+;
+; On entry:    R0 == pointer to a buffer
+;              R1 == size of the buffer
+;
+; On exit:     --
+;
+; Use:         Writes the config into a buffer
+
+               EXPORT  config_read
+config_read    ROUT
+
+               CMP     R1,#cBuff_size          ;Is the buffer big enough?
+               ADRCCL  R0,msg_errCfgBuff       ;No -- find the error
+               ORRCCS  PC,R14,#V_flag          ;And return it to caller
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Copy the flags ---
+
+               LDRB    R14,sculpt_flags        ;Load our flags
+               STR     R14,[R0],#4             ;Store in output block
+
+               ; --- Copy the colour tables ---
+
+               ADR     R1,sculpt_colours       ;Point to the table
+               MOV     R2,#4                   ;There are four to collect
+00             LDR     R14,[R1],#4             ;Load the next pair
+               STRB    R14,[R0],#1             ;Store low byte in block
+               MOV     R14,R14,LSR #8          ;Shift down by a byte
+               STRB    R14,[R0],#1             ;Store next byte away
+               SUBS    R2,R2,#1                ;Decrement counter
+               BNE     %b00                    ;And loop back until done
+
+               ; --- Finally do the other pair ---
+
+               LDR     R14,sculpt_hilight      ;A hack, but it works
+               STR     R14,[R0,#0]             ;Load the colours
+
+               LDMFD   R13!,{R0-R2,PC}^        ;Return when done
+
+               LTORG
+
+; --- config_load ---
+;
+; On entry:    R0 == pointer to filename
+;
+; On exit:     --
+;
+; Use:         Loads a configuration file.
+
+               EXPORT  config_load
+config_load    ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+               LDR     R12,[R12,#0]            ;Load my workspace pointer
+
+               ; --- Find out if the file is suitable ---
+
+               MOV     R1,R0                   ;Point to the filename
+               MOV     R0,#17                  ;Read file information
+               SWI     XOS_File                ;Read the information, then
+               BVS     %99config_load          ;If failed, return the error
+               TST     R0,#1                   ;Is it a real file?
+               BEQ     %98config_load          ;No -- build and error then
+
+               CMP     R4,#256                 ;Will it fit in my buffer?
+               ADRCSL  R0,msg_errBadConfig     ;No -- point to the error
+               BCS     %99config_load          ;And report the error
+
+               ; --- Load the file into my buffer ---
+
+               MOV     R0,#16                  ;Load the file, please
+               ADR     R2,sculpt_misc          ;Point to a buffer
+               MOV     R3,#0                   ;Please load it here
+               SWI     XOS_File                ;Do the file load op
+               BVS     %99config_load          ;If failed, return the error
+
+               ADR     R0,sculpt_misc          ;Point to the buffer
+               LDR     R1,[R0],#4              ;Load the first word out
+               LDR     R14,config__magic       ;Load a magic number
+               CMP     R1,R14                  ;Do these match up?
+               ADRNEL  R0,msg_errBadConfig     ;No -- point to the error
+               BNE     %99config_load          ;And report the error
+
+               BL      config_set              ;Set the configuration
+               LDMFD   R13!,{PC}^              ;Return when done
+
+               ; --- Returning errors ---
+
+98config_load  MOV     R2,R0                   ;Get the botched object type
+               MOV     R0,#19                  ;Return me a sensible error
+               SWI     XOS_File                ;Get the error message
+
+99             LDMFD   R13!,{R14}              ;Restore the return address
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+config__magic  DCB     "SXCF",0
+
+               LTORG
+
+;----- Config buffer structure ----------------------------------------------
+
+               ^       0
+cBuff_flags    #       4                       ;Various nice flags
+cBuff_stdCols  #       2                       ;Standard border colours
+cBuff_grpCols  #       2                       ;Group box colours
+cBuff_shdCols  #       2                       ;Shaded border colours
+cBuff_shgCols  #       2                       ;Shaded group colours
+cBuff_hilight  #       1                       ;Highlight colour for default
+cBuff_slab     #       1                       ;Slab background colour
+               #       2                       ;Alignment padding
+cBuff_size     #       0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/s/plot b/StraySrc/Sculptrix/sculptrix/s/plot
new file mode 100644 (file)
index 0000000..24e33bc
--- /dev/null
@@ -0,0 +1,616 @@
+;
+; plot.s
+;
+; Plots border types
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.border
+               GET     sh.rules
+               GET     sh.utils
+               GET     sh.vString
+
+               GET     sh.wSpace
+
+;----- Macros ---------------------------------------------------------------
+
+               MACRO
+$label         DCO     $addr
+$label         DCD     $addr-{PC}
+               MEND
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- plot_border ---
+;
+; On entry:    R0 == pointer to border type
+;              R1 == pointer to icon block
+;              R2,R3 == window origin position
+;
+; On exit:     May return an error
+;
+; Use:         Plots the given border type.
+
+               EXPORT  plot_border
+plot_border    ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               AND     R14,R0,#&0000FF00       ;Extract the general code
+               CMP     R14,#(%10-%00)<<6       ;Check it's in range
+               ADDCC   PC,PC,R14,LSR #6        ;Yes -- dispatch it then
+               LDMFD   R13!,{PC}               ;Otherwise ignore it
+
+00             B       plot__simple            ;Plot something simple
+               B       plot__group             ;Plot a group box
+               B       plot__tns               ;Plot a text+sprite icon
+10
+               LTORG
+
+; --- plot__simple ---
+;
+; On entry:    R0 == pointer to border type
+;              R1 == pointer to icon block
+;              R2,R3 == window origin position
+;
+; On exit:     May return an error
+;
+; Use:         Plots a simple border type.
+
+plot__simple   ROUT
+
+               STMFD   R13!,{R4}               ;Save some registers
+
+               ; --- Sort out which colour to use ---
+
+               ADR     R4,sculpt_colours       ;Point to colour tables
+               LDR     R14,[R1,#16]            ;Load the icon flags
+               EOR     R14,R14,#&005F0000      ;Toggle shade and ESG bits
+               TST     R14,#&00400000          ;Test the shaded bit
+               TSTNE   R14,#&001F0000          ;And then the ESG bits
+               ADDEQ   R4,R4,#8                ;If shaded, select table
+               TST     R0,#vsFlag_fade         ;Is the icon faded?
+               ADDNE   R4,R4,#4                ;Yes -- then fade it
+               TST     R0,#vsFlag_invert       ;Is the icon inverted?
+               ADDNE   R4,R4,#1                ;Yes -- invert it
+
+               ; --- Now plot the thing ---
+
+               ADR     R14,plot__table         ;Point to the table
+               AND     R0,R0,#&FF              ;Extract the subtype
+               LDR     R0,[R14,R0,LSL #2]!     ;Load the offset out
+               ADD     R0,R14,R0               ;Add on to find the address
+               BL      border_plot             ;Go and plot it then
+               LDMFD   R13!,{R4,PC}            ;Return when finished
+
+plot__table    DCO     plot__action
+               DCO     plot__default
+               DCO     plot__ridge
+               DCO     plot__write
+               DCO     plot__offset
+
+               LTORG
+
+; --- plot_group ---
+;
+; On entry:    R0 == pointer to border type
+;              R1 == pointer to icon block
+;              R2,R3 == window origin position
+;              R6 == pointer to group title
+;
+; On exit:     May return an error
+;
+; Use:         Plots a group box.
+
+               EXPORT  plot_group
+plot_group     ROUT
+
+               STMFD   R13!,{R4-R6,R14}        ;Save some registers
+               B       %f00                    ;And skip on...
+
+plot__group    STMFD   R13!,{R4-R6}            ;Save some registers
+               ADR     R6,sculpt_misc          ;Point to string in buffer
+
+               ; --- Sort out the text width ---
+
+00             MOV     R0,R6                   ;Point to the text string
+               BL      utils_strWidth          ;Work out the width, please
+               ADD     R5,R0,#16               ;Add some extra each side
+
+               ; --- Work out the group colours ---
+
+               ADR     R4,sculpt_groupCol      ;Point to group colour table
+               LDR     R14,[R1,#16]            ;Load the icon flags
+               EOR     R14,R14,#&005F0000      ;Toggle shade and ESG bits
+               TST     R14,#&00400000          ;Test the shaded bit
+               TSTNE   R14,#&001F0000          ;And then the ESG bits
+               ADDEQ   R4,R4,#8                ;If shaded, select table
+               LDR     R14,sculpt_flags        ;Load the flags word
+               TST     R14,#scFlag_acorn       ;Acorn style group box?
+               ADDNE   R4,R4,#1                ;Yes -- invert colours then
+               ADREQ   R0,plot__stdGroup       ;No -- point to standard rtn
+               ADRNE   R0,plot__acnGroup       ;Yes -- use Acorn one
+               BL      border_plot             ;Plot the group box
+               LDMFD   R13!,{R4-R6,PC}         ;Return when done
+
+               LTORG
+
+; --- plot__tns ---
+;
+; On entry:    R0 == pointer to border type
+;              R1 == pointer to icon block
+;              R2,R3 == window origin position
+;
+; On exit:     --
+;
+; Use:         Plots a text+sprite icon.
+
+plot__tns      ROUT
+
+               STMFD   R13!,{R0-R6}            ;Save lots of registers
+               SWI     XWimp_PlotIcon          ;Plot the sprite
+               BL      plot_tnsBBox            ;Find the icon bounding box
+               BCC     %90plot__tns            ;If that failed, return now
+
+               ; --- Now plot the icon ---
+
+70plot__tns    SUB     R13,R13,#32             ;Make space for icon block
+               STMIA   R13,{R0-R3}             ;Save them away, please
+
+               BIC     R4,R4,#&00000006        ;Clear border and sprite bits
+               BIC     R4,R4,#&00200000        ;Clear selected bit
+
+               MOV     R0,#8                   ;Get the current font handle
+               SWI     XWimp_ReadSysInfo       ;Do that, please
+               MOVVS   R0,#0                   ;If not known, assume none
+               CMP     R0,#0                   ;Do we have a font?
+               TSTEQ   R4,#&60                 ;Is the icon anti-aliased?
+               BEQ     %80plot__tns            ;No -- skip ahead then
+
+               ; --- See if the icon's shaded ---
+               ;
+               ; If it is, fix it so that it looks right.  In keeping with
+               ; the WindowManager's simpleminded view of colour selection,
+               ; this just involves clearing some bits.
+
+               MVN     R14,R4                  ;Invert all the bits, please
+               TST     R14,#&00400000          ;Test the shaded bit
+               TSTNE   R14,#&001F0000          ;And then the ESG bits
+               BICEQ   R4,R4,#&0B000000        ;If shaded, change colour
+
+               ; --- Now fill in the rest of the data ---
+
+80plot__tns    BIC     R4,R4,#&00400000        ;Clear shaded bit anyway
+               ADR     R5,sculpt_misc          ;Point to the text buffer
+               MOV     R6,#-1                  ;No validation string
+               MOV     R14,#1                  ;A random string length
+
+               ADD     R0,R13,#16              ;Point into the buffer
+               STMIA   R0,{R4-R6,R14}          ;Store them away
+               MOV     R1,R13                  ;Point to the icon block
+               SWI     XWimp_PlotIcon          ;Plot the icon, please
+               ADD     R13,R13,#32             ;Restore the stack pointer
+
+90plot__tns    LDMFD   R13!,{R0-R6,PC}^        ;Return to caller when done
+
+               LTORG
+
+; --- plot_tnsBBox ---
+;
+; On entry:    R1 == pointer to an icon block
+;
+; On exit:     CS if sprite found, and
+;                R0-R3 == bounding box of icon
+;                R4 == icon flags word (modified)
+;              else CC and registers preserved
+;
+; Use:         Works out where the text of the icon ought to be.  (Actually
+;              the box returned is too wide, although this will probably
+;              be good enough for most purposes.)
+
+               EXPORT  plot_tnsBBox
+plot_tnsBBox   ROUT
+
+               STMFD   R13!,{R0-R6,R14}        ;Save some registers
+
+               LDR     R4,[R1,#16]             ;Load the icon flags
+               AND     R14,R4,#&218            ;Extract the position bits
+               CMP     R14,#&010               ;Only vertical centring?
+               BEQ     %50plot_tnsBBox         ;Yes -- this is trickier
+
+               LDMIA   R1,{R0-R3}              ;Load the icon data
+
+               ; --- Work out where to put the icon ---
+
+               MOV     R14,R14,LSR #3          ;Shift the bits down
+               TST     R4,#&200                ;Is it right aligned?
+               EORNE   R14,R14,#&44            ;Yes -- move the bit down
+               ADR     R6,plot__alignTbl       ;Point to a table
+               LDRB    R6,[R6,R14]             ;Load the entry we want
+               EOR     R4,R4,R6,LSL #2         ;And jiggle the bits
+
+               ADR     R6,plot__psnTbl         ;Point to position table
+               LDRB    R6,[R6,R14]             ;Load the magic number
+               CMP     R6,#1                   ;Which is it?
+               ADDEQ   R1,R1,R3                ;Centre -- add them up
+               MOVEQ   R1,R1,ASR #1            ;Divide by two
+               SUBEQ   R1,R1,#18               ;And move down a bit
+               ADDLE   R3,R1,#36               ;Bottom -- sort it
+               SUBGT   R1,R3,#36               ;Top -- sort it
+
+               B       %90plot_tnsBBox         ;Return because it worked
+
+               ; --- Handle the sprite data ---
+
+50plot_tnsBBox MOV     R0,#'s'                 ;Search for an `s' command
+               MOV     R2,#0                   ;Start from the beginning
+               BL      vString_find            ;Find the validation string
+               BCC     %99plot_tnsBBox         ;If not found, ignore it
+
+               ADR     R1,sculpt_small         ;Point to a buffer
+               ADD     R2,R2,#1                ;Skip past the `s'
+00             LDRB    R14,[R2],#1             ;Load a byte
+               CMP     R14,#','                ;A different sprite?
+               CMPNE   R14,#';'                ;A different command?
+               CMPNE   R14,#&1F                ;Or the end of the string?
+               MOVLS   R14,#0                  ;Any of them -- take a zero
+               STRB    R14,[R1],#1             ;Store that away
+               BHI     %b00                    ;And keep looping until done
+
+               ; --- Read the sprite information ---
+
+               ADR     R2,sculpt_small         ;Point to small buffer
+               LDR     R1,sculpt_sprArea       ;Load the area pointer
+               CMP     R1,#1                   ;Is this the Wimp area?
+               BEQ     %f00                    ;Yes -- skip onwards
+
+               MOV     R0,#40                  ;Read sprite information
+               ORR     R0,R0,#&100             ;Set the user area bit
+               SWI     XOS_SpriteOp            ;Read the information
+               BVC     %f01                    ;If OK, skip onwards
+
+00             MOV     R0,#40                  ;Read sprite information
+               SWI     XWimp_SpriteOp          ;Read the information
+               BVS     %99plot_tnsBBox         ;If failed quit now
+
+               ; --- Sort out the sprite width ---
+
+01             MOV     R0,R6                   ;Get the sprite mode
+               MOV     R1,#4                   ;Read the x EIG factor
+               SWI     XOS_ReadModeVariable    ;Try to do that
+               BVS     %99plot_tnsBBox         ;If failed quit now
+               BCS     %99plot_tnsBBox         ;If failed quit now
+               MOV     R5,R3,LSL R2            ;Work out the width now
+
+               ; --- Play with the icon data now ---
+
+               LDR     R1,[R13,#4]             ;Load the icon address
+               LDMIA   R1,{R0-R4}              ;Load all that information
+               ADD     R0,R0,R5                ;Move the left hand side over
+
+               ADD     R1,R1,R3                ;Centre -- add them up
+               MOV     R1,R1,ASR #1            ;Divide by two
+               SUB     R1,R1,#18               ;And move down a bit
+               ADD     R3,R1,#36               ;Sort out the upper limit
+
+               ; --- Return to caller ---
+
+90plot_tnsBBox ADD     R13,R13,#20             ;Don't restore R0-R4
+               LDMFD   R13!,{R5,R6,R14}        ;Restore other registers
+               ORRS    PC,R14,#C_flag          ;And return C set on exit
+
+99plot_tnsBBox LDMFD   R13!,{R0-R6,R14}        ;Restore other registers
+               BICS    PC,R14,#C_flag          ;And return a failed result
+
+               ; --- Alignment table ---
+               ;
+               ; Each entry contains an EOR mask which should be applied to
+               ; the icon flags for the text icon.  In order to make them
+               ; fit into single bytes, they're all shifted right two
+               ; places.  This lets me know whether the text needs to be
+               ; centred or whatever in those cases where it's not actually
+               ; obvious from the original flags.
+
+plot__alignTbl DCB     0,0,0,&80
+               DCB     0,0,&80,&02
+
+               ; --- Position table ---
+               ;
+               ; Each entry contains a value used to position the icon
+               ; vertically.  Zero means that the text is at the bottom of
+               ; the icon, one means that it's in the middle, and two means
+               ; that it's at the top.
+
+plot__psnTbl   DCB     0,0,0,1
+               DCB     0,2,1,1
+
+               LTORG
+
+;----- Group box routines ---------------------------------------------------
+
+; --- plot__stdGroup ---
+
+plot__stdGroup ROUT
+
+               BCALL   plot__gBorder
+               BCALL   plot__findPlinth
+               BCALL   plot__plinth
+
+               BDARK
+               BLDIY1
+               BSTY1
+               BLDIX0
+               BSTX0
+               BADD    16-4
+               BSTX1
+               BPLOT   rule_top
+
+               BLIGHT
+               BLDIY1
+               BADD    8
+               BSTY0
+               BLDIX0
+               BADD    16+4
+               BSKIPT
+               BSTX0
+               BSTX1
+               BPLOT   rule_bottom
+
+               BCALL   plot__findPlinth
+               BGROUP  &17000139
+               BRET
+
+               LTORG
+
+; --- plot__acnGroup ---
+
+plot__acnGroup ROUT
+
+               BCALL   plot__gBorder
+
+               BLDIY1
+               BADD    4
+               BSTY0
+               BSTY1
+               BLDIX0
+               BADD    16-4
+               BSTX0
+               BSTX1
+               BDARK
+               BPLOT   rule_right
+               BLIGHT
+               BPLOT   rule_top
+
+               BLDIX0
+               BADD    16+4
+               BSKIPT
+               BSTX0
+               BSTX1
+               BLIGHT
+               BPLOT   rule_left
+               BDARK
+               BPLOT   rule_bottom
+
+               BCALL   plot__findPlinth
+               BGROUP  &17000119
+               BRET
+
+               LTORG
+
+; --- plot__gBorder ---
+
+plot__gBorder  ROUT
+
+               BDARK
+               BPLOT   rule_left
+               BLIGHT
+               BPLOT   rule_right
+               BPLOT   rule_bottom
+
+               BCALL   plot__stepOut
+               BPLOT   rule_left
+               BDARK
+               BPLOT   rule_right
+               BPLOT   rule_bottom
+
+               BLDIX0
+               BSTX0
+               BADD    16-4
+               BSTX1
+               BLDIY1
+               BSTY1
+               BPLOT   rule_pTop
+               BADD    4
+               BSTY1
+               BLDX0
+               BSUB    4
+               BSTX0
+               BLIGHT
+               BPLOT   rule_pTop
+
+               BADD    16+4+4
+               BSKIPT
+               BSTX0
+               BLDIX1
+               BADD    4
+               BSTX1
+               BPLOT   rule_top
+               BSUB    4
+               BSTX1
+               BLDIY1
+               BSTY1
+               BDARK
+               BPLOT   rule_top
+               BRET
+
+               LTORG
+
+; --- plot__findPlinth ---
+
+plot__findPlinth ROUT
+
+               BLDIX0
+               BADD    16
+               BSTX0
+               BSKIPT
+               BSTX1
+               BLDIY1
+               BSUB    20
+               BSTY0
+               BADD    48
+               BSTY1
+               BRET
+
+               LTORG
+
+;----- Border definition routines -------------------------------------------
+
+; --- plot__plinth ---
+
+plot__plinth   ROUT
+
+               BLIGHT
+               BPLOT   rule_left
+               BDARK
+               BPLOT   rule_right
+               BPLOT   rule_bottom
+               BLIGHT
+               BPLOT   rule_top
+               BRET
+
+               LTORG
+
+; --- plot__invPlinth ---
+
+plot__invPlinth        ROUT
+
+               BDARK
+               BPLOT   rule_left
+               BLIGHT
+               BPLOT   rule_right
+               BPLOT   rule_bottom
+               BDARK
+               BPLOT   rule_top
+               BRET
+
+               LTORG
+
+; --- plot__ring ---
+
+plot__ring     ROUT
+
+               BPLOT   rule_left
+               BPLOT   rule_right
+               BPLOT   rule_pTop
+               BPLOT   rule_pBottom
+               BRET
+
+               LTORG
+
+; --- plot__stepOut ---
+
+plot__stepOut  ROUT
+
+               BLDX0
+               BSUB    4
+               BSTX0
+               BLDY0
+               BSUB    4
+               BSTY0
+               BLDX1
+               BADD    4
+               BSTX1
+               BLDY1
+               BADD    4
+               BSTY1
+               BRET
+
+               LTORG
+
+; --- plot__action ---
+
+plot__action   ROUT
+
+               BJMP    plot__plinth
+
+               LTORG
+
+; --- plot__default ---
+
+plot__default  ROUT
+
+               BCALL   plot__plinth
+               BCALL   plot__stepOut
+               BINDCOL sculpt_hilight
+               BCALL   plot__ring
+               BCALL   plot__stepOut
+               BRAW
+               BCALL   plot__invPlinth
+               BRET
+
+               LTORG
+
+; --- plot__ridge ---
+
+plot__ridge    ROUT
+
+               BCALL   plot__invPlinth
+               BCALL   plot__stepOut
+               BCALL   plot__plinth
+               BRET
+
+               LTORG
+
+; --- plot__write ---
+
+plot__write    ROUT
+
+               BCALL   plot__stepOut
+               BICON
+               BPLOT   rule_border
+;              BJMP    plot__offset            ;Redundant
+
+; --- plot__offset ---
+
+plot__offset   ROUT
+
+               BLITCOL 1
+               BCALL   plot__ring
+               BCALL   plot__stepOut
+               BCALL   plot__invPlinth
+               BRET
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/s/redraw b/StraySrc/Sculptrix/sculptrix/s/redraw
new file mode 100644 (file)
index 0000000..ba45f42
--- /dev/null
@@ -0,0 +1,362 @@
+;
+; redraw.s
+;
+; Redrawing windows and icons
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.plot
+               GET     sh.vString
+               GET     sh.wSpace
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- redraw_window ---
+;
+; On entry:    R1 == pointer to redraw block
+;
+; On exit:     May return an error
+;
+; Use:         Redraws all the icons in a window.
+
+               EXPORT  redraw_window
+redraw_window  ROUT
+
+               STMFD   R13!,{R0-R11,R14}       ;Save lots of registers
+               BL      redraw__info            ;Read in the information
+
+               ; --- Start on the icons ---
+
+               SUB     R13,R13,#40             ;Make space for an icon
+               LDR     R8,[R1,#0]              ;Load the window handle
+               MOV     R11,#0                  ;Start from icon 0
+               STMIA   R13,{R8,R11}            ;Store them in the block
+
+               ; --- Main redrawing loop ---
+
+00             MOV     R1,R13                  ;Point to my block
+               SWI     XWimp_GetIconState      ;Read the icon information
+               BVS     %99redraw_window        ;If failed, return
+               LDR     R14,[R13,#24]           ;Load the icon flags
+               CMP     R14,#&00800000          ;Is the icon deleted only?
+               BEQ     %90redraw_window        ;Yes -- there are no more
+
+               ADD     R1,R13,#8               ;Find the actual icon block
+               LDMIA   R1,{R8-R10,R14}         ;Load the coordinates
+               CMP     R4,R10                  ;See if we need to plot it
+               CMPLE   R5,R14
+               CMPLE   R8,R6
+               CMPLE   R9,R7
+               BLLE    redraw__icon            ;Yes -- plot it then
+               BVS     %99redraw_window        ;If failed, return
+
+               ADD     R11,R11,#1              ;Increment the icon number
+               STR     R11,[R13,#4]            ;Store in the block
+               B       %b00                    ;And loop round some more
+
+               ; --- We're finished here now ---
+
+90redraw_window        ADD     R13,R13,#40             ;Restore stack pointer
+               LDMFD   R13!,{R0-R11,PC}^       ;Return to caller when done
+
+99redraw_window        ADD     R13,R13,#40+4           ;Don't restore R0
+               LDMFD   R13!,{R1-R11,R14}       ;And return with V set
+               ORRS    PC,R14,#V_flag
+
+               LTORG
+
+; --- redraw_icon ---
+;
+; On entry:    R0 == pointer to icon block
+;              R1 == pointer to redraw block
+;
+; On exit:     May return an error
+;
+; Use:         Redraws a single icon.
+
+               EXPORT  redraw_icon
+redraw_icon    ROUT
+
+               STMFD   R13!,{R0-R10,R14}       ;Stack some registers
+               BL      redraw__info            ;Get the redraw information
+               MOV     R1,R0                   ;Point to the redraw block
+               BL      redraw__icon            ;Yes -- plot it then
+               LDMVCFD R13!,{R0-R10,PC}^       ;If OK, return happy
+
+               ADD     R13,R13,#4              ;Don't restore R0
+               LDMFD   R13!,{R1-R10,R14}       ;And return when done
+               ORRS    PC,R14,#V_flag
+
+               LTORG
+
+; --- redraw__icon ---
+;
+; On entry:    R1 == pointer to icon block
+;              R2,R3 == window origin position
+;
+; On exit:     --
+;
+; Use:         Redraws an icon.
+
+redraw__icon   ROUT
+
+               STMFD   R13!,{R4,R14}           ;Save some registers
+               BL      vString_read            ;Read icon validation string
+               BLCS    plot_border             ;If there's a border, plot
+               LDMFD   R13!,{R4,R14}           ;And return to caller
+               BICVCS  PC,R14,#V_flag
+               ORRVSS  PC,R14,#V_flag
+
+               LTORG
+
+; --- redraw_group ---
+;
+; On entry:    R0 == pointer to icon block
+;              R1 == pointer to redraw block
+;              R2 == `border type' (ignored in Sculptrix 2.00)
+;              R3 == pointer to title string
+;
+; On exit:     --
+;
+; Use:         Plots a group box.
+
+               EXPORT  redraw_group
+redraw_group   ROUT
+
+               STMFD   R13!,{R0-R11,R14}       ;Save some registers
+               MOV     R11,R3                  ;Look after this value
+               BL      redraw__info            ;Read redraw information
+               MOV     R1,R0                   ;Point to the redraw block
+               LDMIA   R1,{R8-R10,R14}         ;Load the coordinates
+               CMP     R4,R10                  ;See if we need to plot it
+               CMPLE   R5,R14
+               CMPLE   R8,R6
+               CMPLE   R9,R7
+               BGT     %90redraw_group         ;No -- quit now
+
+               MOVS    R6,R11                  ;Is there a title string?
+               MOVEQ   R0,#vsBrd_ridge+vsFlag_fade+vsFlag_invert
+               LDREQ   R14,sculpt_flags        ;Load the flags word
+               TSTEQ   R14,#scFlag_acorn       ;Acorn style group box?
+               BICEQ   R0,R0,#vsFlag_invert    ;No -- don't invert it then
+               CMP     R6,#0                   ;Find out again...
+               BLNE    plot_group              ;Plot it then
+               BLEQ    plot_border             ;Work out which is which
+               BVS     %95redraw_group         ;If it failed, return error
+
+90redraw_group LDMFD   R13!,{R0-R11,PC}^       ;And return to caller
+
+95redraw_group ADD     R13,R13,#4
+               LDMFD   R13!,{R1-R11,R14}       ;And return with V set
+               ORRS    PC,R14,#V_flag
+
+               LTORG
+
+; --- redraw_update ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;
+; On exit:     --
+;
+; Use:         Updates an icon.
+
+               EXPORT  redraw_update
+redraw_update  ROUT
+
+               STMFD   R13!,{R0-R8,R14}        ;Save some registers
+               SUB     R13,R13,#84             ;For icon and redraw blocks
+               STMIA   R13,{R0,R1}             ;Store the icon block away
+               MOV     R1,R13                  ;Point to the block
+               SWI     XWimp_GetIconState      ;Read the icon information
+               BVS     %99redraw_update        ;If failed, return error
+
+               ; --- Read the validation string out ---
+
+               ADD     R1,R13,#8               ;Point to the icon data
+               BL      vString_read            ;Read the button type
+               BCC     %90redraw_update        ;If nothing to do, skip
+               MOV     R8,R0                   ;Remember this type code
+               AND     R14,R0,#&0000FF00       ;Extract the type code
+               CMP     R14,#vsCode_tns         ;Is it a text+sprite?
+               BEQ     %50redraw_update        ;Yes -- deal differently
+
+               ; --- Start the update job ---
+
+10redraw_update        LDMIA   R1,{R2-R5}              ;Load the coordinates out
+               SUB     R2,R2,#16               ;Extent to include everything
+               SUB     R3,R3,#16
+               ADD     R4,R4,#16
+               ADD     R5,R5,#32
+
+               ADD     R1,R13,#40              ;Point to the update block
+               LDR     R0,[R13,#0]             ;Load the window handle
+               STMIA   R1,{R0,R2-R5}           ;Store all that lot
+               SWI     XWimp_UpdateWindow      ;Start the update job
+               BVS     %99redraw_update        ;If failed, return error
+
+               CMP     R0,#0                   ;If nothing to do...
+               BEQ     %90redraw_update        ;Return now
+
+               BL      redraw__info            ;Get redraw information
+
+               ; --- Do the main upate loop ---
+
+00             MOV     R0,R8                   ;Get the border type
+               ADD     R1,R13,#8               ;Point to the icon data
+               BL      plot_border             ;Plot the icon, please
+               ADDVC   R1,R13,#40              ;Point to the redraw block
+               SWIVC   XWimp_GetRectangle      ;Get the next rectangle
+               BVS     %99redraw_update        ;If failed, return error
+               CMP     R0,#0                   ;Is there any more to do?
+               BNE     %b00                    ;Yes -- go and do it then
+
+               B       %90redraw_update        ;Tidy up and return
+
+               ; --- Handle a text+sprite icon ---
+               ;
+               ; This is a bit complicated.  If the icon is anti-aliased
+               ; then a simple update won't redraw the text properly, so
+               ; we have to redraw the text in a flickery way.  We'll try to
+               ; avoid this.
+
+50redraw_update        MOV     R0,#8                   ;Read the anti-aliased font
+               SWI     XWimp_ReadSysInfo       ;Go and do that, please
+               MOVVS   R0,#0                   ;If unknown, assume no font
+               ADD     R1,R13,#8               ;Find the icon data
+               CMP     R0,#0                   ;Is there a font?
+               LDREQ   R14,[R13,#24]           ;Load the icon flags
+               TSTEQ   R14,#&40                ;Check for anti-aliasing
+               BEQ     %10redraw_update        ;None -- behave as normal
+
+               BL      plot_tnsBBox            ;Find the text bounding box
+               MOV     R4,R3                   ;Shift up through registers
+               MOV     R3,R2
+               MOV     R2,R1
+               MOV     R1,R0
+               LDR     R0,[R13,#0]             ;Load the window handle
+               SWI     XWimp_ForceRedraw       ;And schedule a redraw
+               BVS     %99redraw_update        ;If failed, return error
+
+               ; --- Tidy up and return ---
+
+90redraw_update        ADD     R13,R13,#84             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R8,R14}        ;Restore registers
+               BICS    PC,R14,#V_flag          ;And return with V clear
+
+99redraw_update        ADD     R13,R13,#84+4           ;Restore stack pointer
+               LDMFD   R13!,{R1-R8,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+; --- redraw__info ---
+;
+; On entry:    R1 == pointer to redraw block
+;
+; On exit:     R2,R3 == window origin
+;              R4-R7 == clipping rectangle (adjusted)
+;
+; Use:         Works out information about the redraw op.
+
+redraw__info   ROUT
+
+               CMP     R1,#0                   ;Is there a redraw block?
+               BEQ     %50redraw__info         ;No -- handle specially
+
+               ; --- Work out the window origin position ---
+
+               LDR     R2,[R1,#4]              ;Load the x0 position
+               ADD     R4,R1,#16               ;Find the other bits
+               LDMIA   R4,{R3-R5}              ;Load them out
+               SUB     R2,R2,R4                ;Find the x origin value
+               SUB     R3,R3,R5                ;And the y origin value
+
+               ; --- Now play with the clipping rectangle ---
+
+               ADD     R4,R1,#28               ;Find the clipping rectangle
+               LDMIA   R4,{R4-R7}              ;Load the rectangle out
+
+               SUB     R4,R4,R2                ;Convert to window coords
+               SUB     R5,R5,R3
+               SUB     R6,R6,R2
+               SUB     R7,R7,R3
+
+               ; --- Extend to include our borders ---
+
+20redraw__info SUB     R4,R4,#16               ;Extend to fit borders
+               SUB     R5,R5,#32
+               ADD     R6,R6,#16
+               ADD     R7,R7,#16
+
+               MOVS    PC,R14
+
+               ; --- Read graphics info to determine things ---
+
+50redraw__info STMFD   R13!,{R0,R1,R14}        ;Save some registers
+
+               ; --- Read VDU variables which we need ---
+
+               ADR     R0,redraw__vduVars      ;Point to variables list
+               ADR     R1,sculpt_misc          ;Point to a handy buffer
+               SWI     XOS_ReadVduVariables    ;Read the variables
+               LDMIA   R1,{R0-R7}              ;Load all of them out
+
+               ; --- Now sort out the graphics window ---
+
+               ADD     R6,R6,#1                ;Make the border exclusive
+               ADD     R7,R7,#1                ;To match the Wimp's
+               ADD     R5,R2,R5,LSL R0         ;Convert, and add on origin
+               ADD     R6,R3,R6,LSL R1
+               ADD     R7,R2,R7,LSL R0
+               ADD     R8,R3,R8,LSL R1
+
+               ; --- Sort out the origin positon ---
+
+               MOV     R2,#0                   ;Easy -- use the screen posn
+               MOV     R3,#0                   ;This will be all right
+               LDMFD   R13!,{R0,R1,R14}        ;Restore registers
+               B       %20redraw__info         ;Now transform the clip area
+
+               ; --- The VDU variables we need ---
+
+redraw__vduVars        DCD     4,5                     ;X and Y EIG factors
+               DCD     136,137                 ;Current origin position
+               DCD     128,129,130,131         ;Graphics window position
+               DCD     -1                      ;End of the list
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/s/rules b/StraySrc/Sculptrix/sculptrix/s/rules
new file mode 100644 (file)
index 0000000..d42717d
--- /dev/null
@@ -0,0 +1,365 @@
+;
+; rules.s
+;
+; Draws horizontal and vertical rules for Sculptrix borders
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- The main idea --------------------------------------------------------
+;
+; In the new version of Sculptrix, we define border types in terms of
+; a collection of rules, which may be horizontal and vertical.  The positions
+; of these rules relative to the icon, and their colours, are determined
+; by a `border definition', which is parsed elsewhere.  This calls the
+; rule drawing routines through a standardised interface.
+;
+; On entry to a rule routine, the colour has already been set up, through
+; a call to Wimp_SetColour, or similar.  Coordinates for the rule to plot
+; are passed in R3-R6, although all the registers may not have sensible
+; values.  Values of dx, dy, and `start' are passed in R7, R8, and R9
+; respectively.
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- rule_left ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == bottom y position
+;              R5 == unused
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a vertical rule in the current colour.
+
+               EXPORT  rule_left
+rule_left      ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+
+               MOV     R0,#move+abs            ;Move cursor absolute
+               SUB     R1,R3,#4                ;Get the x position sorted
+               SUB     R2,R4,#4                ;And the y position
+               SWI     XOS_Plot                ;Move the graphics cursor
+
+               MOV     R0,#rectfill+abs+fore   ;Now do the rectangle fill
+               SUB     R1,R3,R7                ;Find the x limit
+               SUB     R2,R6,R8                ;And the y limit
+               ADD     R2,R2,#4                ;Provide some overlap
+               SWI     XOS_Plot                ;Do that, please
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- rule_right ---
+;
+; On entry:    R3 == unused
+;              R4 == bottom y position
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a vertical rule in the current colour.
+
+               EXPORT  rule_right
+rule_right     ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+
+               MOV     R0,#move+abs            ;Move cursor absolute
+               MOV     R1,R5                   ;Get the x position sorted
+               SUB     R2,R4,#4                ;And the y position
+               SWI     XOS_Plot                ;Move the graphics cursor
+
+               MOV     R0,#rectfill+abs+fore   ;Now do the rectangle fill
+               SUB     R1,R5,R7                ;Find the x limit
+               ADD     R1,R1,#4                ;Move over, for niceness
+               SUB     R2,R6,R8                ;And the y limit
+               ADD     R2,R2,#4                ;Provide some overlap
+               SWI     XOS_Plot                ;Do that, please
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- rule_top ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == unused
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a horizontal rule in the current colour.
+
+               EXPORT  rule_top
+rule_top       ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+
+               ; --- Set up for the loop ---
+
+               ADD     R4,R6,#4                ;A limit for the loop
+               SUB     R5,R5,R7                ;Step back a pixel
+               ADD     R5,R5,R9                ;And move on one too
+
+               ; --- Now do the plotting ---
+
+00             MOV     R0,#move+abs            ;Move cursor absolute
+               SUB     R1,R3,#4                ;Get the x position
+               MOV     R2,R6                   ;And the y position
+               SWI     XOS_Plot                ;Go and do that then
+               MOV     R0,#line+abs+fore       ;Draw line absolute
+               MOV     R1,R5                   ;Get the x limit value
+               MOV     R2,R6                   ;And the old y position
+               SWI     XOS_Plot                ;Go and do that, please
+
+               ADD     R5,R5,R8                ;Extend the mitring
+               ADD     R6,R6,R8                ;Move up by a pixel
+               CMP     R6,R4                   ;Have we reached the end?
+               BLT     %b00                    ;No -- look back then
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- rule_bottom ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == unused
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a horizontal rule in the current colour.
+
+               EXPORT  rule_bottom
+rule_bottom    ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+
+               ; --- Set up for the loop ---
+
+               SUB     R6,R4,R8                ;Drop down a pixel to start
+               SUB     R4,R4,#4                ;A limit for the loop
+               SUB     R3,R3,R9                ;And move on one too
+               SUBS    R14,R7,R8               ;Which pixel size is bigger?
+               ADDPL   R3,R3,R14               ;Bodge for flattened modes
+               SUB     R5,R5,R7                ;Sort out right hand side
+
+               ; --- Now do the plotting ---
+
+00             MOV     R0,#move+abs            ;Move cursor absolute
+               MOV     R1,R3                   ;Get the x position
+               MOV     R2,R6                   ;And the y position
+               SWI     XOS_Plot                ;Go and do that then
+               MOV     R0,#line+abs+fore       ;Draw line absolute
+               ADD     R1,R5,#4                ;Get the x limit value
+               MOV     R2,R6                   ;And the old y position
+               SWI     XOS_Plot                ;Go and do that, please
+
+               SUB     R3,R3,R8                ;Extend the mitring
+               SUB     R6,R6,R8                ;Move up by a pixel
+               CMP     R6,R4                   ;Have we reached the end?
+               BGE     %b00                    ;No -- look back then
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- rule_pTop ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == unused
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a horizontal rule in the current colour, without
+;              mitring.
+
+               EXPORT  rule_pTop
+rule_pTop      ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+
+               MOV     R0,#move+abs            ;Move cursor absolute
+               SUB     R1,R3,#4                ;Sort out left hand side
+               MOV     R2,R6                   ;And the y position
+               SWI     XOS_Plot                ;Move the cursor
+
+               MOV     R0,#rectfill+abs+fore   ;Plot the rectangle
+               SUB     R1,R5,R7                ;Sort out the overhang
+               ADD     R1,R1,#4                ;And add some overlap
+               SUB     R2,R6,R8                ;Set the y position
+               ADD     R2,R2,#4                ;Move up a little
+               SWI     XOS_Plot                ;And plot the rectangle
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- rule_pBottom ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == unused
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a horizontal rule in the current colour, without
+;              mitring.
+
+               EXPORT  rule_pBottom
+rule_pBottom   ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+
+               MOV     R0,#move+abs            ;Move cursor absolute
+               SUB     R1,R3,#4                ;Sort out left hand side
+               SUB     R2,R4,#4                ;And the y position
+               SWI     XOS_Plot                ;Move the cursor
+
+               MOV     R0,#rectfill+abs+fore   ;Plot the rectangle
+               SUB     R1,R5,R7                ;Sort out the overhang
+               ADD     R1,R1,#4                ;And add some overlap
+               SUB     R2,R4,R8                ;Set the y position
+               SWI     XOS_Plot                ;And plot the rectangle
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- rule_border ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == bottom edge of icon
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Fills the icon in, and plots a border around it, using the
+;              current foreground and background colours.
+
+               EXPORT  rule_border
+rule_border    ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+
+               ; --- Fill in the background ---
+               ;
+               ; We plot /within/ the border, to ensure that there's no
+               ; flicker.
+
+               MOV     R0,#move+abs            ;Move cursor absolute
+               ADD     R1,R3,R7                ;Move slightly inwards
+               ADD     R2,R4,R8                ;Move slightly upwards
+               SWI     XOS_Plot                ;Do the plotting
+
+               MOV     R0,#rectfill+abs+back   ;Plot rectangle in background
+               SUB     R1,R5,R7,LSL #1         ;Move inwards from right
+               SUB     R2,R6,R8,LSL #1         ;And downwards from top
+               SWI     XOS_Plot                ;Do the rectangle now
+
+               ; --- Plot the border around the edge ---
+
+               MOV     R0,#move+abs            ;Move cursor absolute
+               MOV     R1,R3                   ;Start on the left
+               MOV     R2,R4                   ;And at the bottom
+               SWI     XOS_Plot                ;Move the cursor
+
+               MOV     R0,#line+abs+fore       ;Draw line absolute
+               MOV     R1,R3                   ;Stay on the left
+               SUB     R2,R6,R8                ;Move to the top
+               SWI     XOS_Plot                ;Draw the line
+
+               MOV     R0,#line+abs+fore       ;Draw line absolute
+               SUB     R1,R5,R7                ;Move to the right
+               SUB     R2,R6,R8                ;Stay at the top
+               SWI     XOS_Plot                ;Draw the line
+
+               MOV     R0,#line+abs+fore       ;Draw line absolute
+               SUB     R1,R5,R7                ;Stay on the right
+               MOV     R2,R4                   ;Move to the bottom
+               SWI     XOS_Plot                ;Draw the line
+
+               MOV     R0,#line+abs+fore       ;Draw line absolute
+               MOV     R1,R3                   ;Move to the left
+               MOV     R2,R4                   ;Stay at the bottom
+               SWI     XOS_Plot                ;Draw the line
+
+               LDMFD   R13!,{PC}^              ;Return when done
+
+               LTORG
+
+;----- Plot codes -----------------------------------------------------------
+
+rel            EQU     0
+abs            EQU     4
+
+move           EQU     0
+line           EQU     0
+rectfill       EQU     96
+
+fore           EQU     1
+back           EQU     3
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/s/sculptrix b/StraySrc/Sculptrix/sculptrix/s/sculptrix
new file mode 100644 (file)
index 0000000..8c75677
--- /dev/null
@@ -0,0 +1,280 @@
+;
+; sculptrix.s
+;
+; Sculptrix module header and initialisation
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.bbox
+               GET     sh.config
+               GET     sh.plot
+               GET     sh.redraw
+               GET     sh.slab
+               GET     sh.vString
+               GET     sh.wSpace
+
+               GET     sh.messages
+
+               IMPORT  version
+
+;----- Module header --------------------------------------------------------
+
+               AREA    |!Module$$Code|,CODE,READONLY
+
+               DCD     0
+               DCD     sculpt__init
+               DCD     sculpt__final
+               DCD     sculpt__service
+               DCD     sculpt__name
+               DCD     version
+               DCD     sculpt__cmds
+               DCD     &4A2C0
+               DCD     sculpt__swis
+               DCD     sculpt__swiTbl
+               DCD     0
+
+sculpt__name   DCB     "Sculptrix",0
+
+;----- SWI name table -------------------------------------------------------
+
+sculpt__swiTbl DCB     "Sculptrix",0
+               DCB     "RedrawWindow",0
+               DCB     "DoSlab",0
+               DCB     "SlabIcon",0
+               DCB     "UnslabIcon",0
+               DCB     "BoundingBox",0
+               DCB     "PlotIcon",0
+               DCB     "PlotGroupBox",0
+               DCB     "SetSpriteArea",0
+               DCB     "UpdateIcon",0
+               DCB     "SlabColour",0
+               DCB     "SetConfig",0
+               DCB     "ReadConfig",0
+               DCB     0
+
+;----- *Command table -------------------------------------------------------
+
+sculpt__cmds   DCB     "Sculptrix_LoadConfig",0
+               DCD     config_load
+               DCB     1,0,1,0
+               DCD     synt_config
+               DCD     help_config
+
+               DCD     0
+
+;----- Main code ------------------------------------------------------------
+
+; --- sculpt__init ---
+;
+; On entry:    --
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Initialises the Sculptrix module.
+
+sculpt__init   ROUT
+
+               STMFD   R13!,{R14}              ;Save some registers
+
+               ; --- Allocate workspace ---
+
+               MOV     R0,#6                   ;Allocate some space please
+               LDR     R3,=sculpt_wSize        ;Get the workspace size
+               SWI     XOS_Module              ;Try to allocate the space
+               LDMVSFD R13!,{PC}               ;Abort if it failed
+               STR     R2,[R12,#0]             ;Store the workspace address
+               MOV     R12,R2                  ;Put pointer in R12
+
+               ; --- Initialise the workspace ---
+
+               BL      sculpt__vduVars         ;Read the VDU variables
+               MOV     R14,#1                  ;Use Wimp area by default
+               STR     R14,sculpt_sprArea      ;Store this as the area
+               MOV     R14,#0                  ;Clear some initial flags
+               STR     R14,sculpt_flags        ;Store these away
+
+               ; --- Initialise colour tables ---
+
+               ADR     R0,sculpt__colDefs      ;Point to the config block
+               BL      config_set              ;Set the configuration
+
+               LDMFD   R13!,{PC}^              ;Return when done
+
+sculpt__colDefs        DCD     0
+               DCB     4,0,4,0
+               DCB     2,0,2,0
+               DCB     12,14
+
+               LTORG
+
+; --- sculpt__final ---
+;
+; On entry:    --
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Clears up after Sculptrix.  We try to free the workspace,
+;              but return even if this failed, since it isn't worth screwing
+;              up the whole computer for the sake of <1K of memory.
+
+sculpt__final  ROUT
+
+               STMFD   R13!,{R14}              ;Save return address
+
+               ; --- Just workspace to free ---
+
+               MOV     R0,#7                   ;Free RMA block
+               LDR     R2,[R12,#0]             ;Load the address
+               SWI     XOS_Module              ;Try to do this
+               MOV     R14,#0                  ;Zero workspace address
+               STR     R14,[R12,#0]            ;Do this anyway
+
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- sculpt__service ---
+;
+; On entry:    R1 == service number
+;
+; On exit:     --
+;
+; Use:         Handles service calls to the Sculptrix module.
+
+sculpt__service        ROUT
+
+               CMP     R1,#&46                 ;Is it a mode change call?
+               MOVNES  PC,R14                  ;No -- ignore it then
+
+               LDR     R12,[R12,#0]            ;Load the workspace address
+               B       sculpt__vduVars         ;Set up the VDU variables
+
+               LTORG
+
+; --- sculpt__vduVars ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Reads the VDU variables into Sculptrix's cache buffer.
+
+sculpt__vduVars        ROUT
+
+               STMFD   R13!,{R0-R2,R14}        ;Save some registers
+
+               ; --- Read the pixel sizes ---
+
+               ADR     R0,sculpt__vduList      ;Point to request list
+               ADR     R1,sculpt_vduVars       ;Point to output buffer
+               SWI     XOS_ReadVduVariables    ;Read the variable values
+
+               LDMIA   R1,{R0,R1}              ;Load the values out
+
+               ; --- Now work out the mitring start ---
+
+               ORR     R2,R0,R1,LSL #2         ;Build a table index
+               ADR     R14,sculpt__mitres      ;Point to the table
+               LDRB    R2,[R14,R2]             ;Load the value I want
+
+               ; --- Convert to pixels ---
+
+               MOV     R14,#1                  ;We need this...
+               MOV     R0,R14,LSL R0           ;Convert log to pixels
+               MOV     R1,R14,LSL R1           ;For both of them, please
+               ADR     R14,sculpt_vduVars      ;Point to output buffer
+               STMIA   R14,{R0-R2}             ;Store the values away
+               LDMFD   R13!,{R0-R2,PC}^        ;Return when finished
+
+               ; --- Which VDU variables to get ---
+
+sculpt__vduList        DCD     4,5,-1                  ;Just x- and y-EIG factors
+
+               ; --- Table of mitring values ---
+
+sculpt__mitres DCB     1,2,0,0
+               DCB     2,2,0,0
+               DCB     2,2,4,0
+
+               LTORG
+
+; --- sculpt__swis ---
+;
+; On entry:    R0-R9 == arguments
+;              R11 == SWI number
+;
+; On exit:     R0-R9 == return values
+;
+; Use:         Processes SWI calls to Sculptrix.
+
+sculpt__swis   ROUT
+
+               LDR     R12,[R12,#0]            ;Load my workspace pointer
+               CMP     R11,#(%10-%00)/4        ;Is the SWI in range?
+               ADDCC   PC,PC,R11,LSL #2        ;Yes -- dispatch to handler
+               B       %10sculpt__swis         ;Otherwise report error
+
+00             B       redraw_window           ;Sculptrix_RedrawWindow
+               B       slab_doSlab             ;Sculptrix_DoSlab
+               B       slab_slab               ;Sculptrix_SlabIcon
+               B       slab_unslab             ;Sculptrix_UnslabIcon
+               B       bbox_calc               ;Sculptrix_BoundingBox
+               B       redraw_icon             ;Sculptrix_PlotIcon
+               B       redraw_group            ;Sculptrix_PlotGroupBox
+               B       sculpt__setArea         ;Sculptrix_SetSpriteArea
+               B       redraw_update           ;Sculptrix_UpdateIcon
+               B       slab_colour             ;Sculptrix_SlabColour
+               B       config_set              ;Sculptrix_SetConfig
+               B       config_read             ;Sculptrix_ReadConfig
+
+10             ADRL    R0,msg_errBadSwi        ;Point to the error message
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- sculpt__setArea ---
+;
+; On entry:    R0 == sprite area to select
+;
+; On exit:     --
+;
+; Use:         Sets the sprite area to use.
+
+sculpt__setArea        ROUT
+
+               STR     R0,sculpt_sprArea       ;Store the area address
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/s/slab b/StraySrc/Sculptrix/sculptrix/s/slab
new file mode 100644 (file)
index 0000000..d821f44
--- /dev/null
@@ -0,0 +1,278 @@
+;
+; slab.s
+;
+; Icon slabbing for Sculptrix
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.colours
+               GET     sh.plot
+               GET     sh.vString
+               GET     sh.wSpace
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- slab_doSlab ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;              R2 == new background colour for icon
+;
+; On exit:     R2 == old background colour, or -1
+;
+; Use:         Low-level slabbing operation.
+
+               EXPORT  slab_doSlab
+slab_doSlab    ROUT
+
+               STMFD   R13!,{R0-R5,R14}        ;Save some registers
+               MOV     R14,#-1                 ;Nothing achieved yet
+               STR     R14,[R13,#8]            ;Store as old colour
+
+               ; --- Read the icon information ---
+
+               SUB     R13,R13,#84             ;Enough for a redraw block
+               STMIA   R13,{R0,R1}             ;Store the window and icon
+               MOV     R1,R13                  ;Point to this block
+               SWI     XWimp_GetIconState      ;Read the icon information
+               BVS     %99slab_doSlab          ;If that failed, return
+
+               ADD     R1,R13,#8               ;Point to the icon data
+               BL      vString_read            ;Read the border information
+               BCC     %90slab_doSlab          ;No border -- return now
+               TST     R0,#vsFlag_slab         ;Is the border slabbable?
+               BEQ     %90slab_doSlab          ;Not slabbable -- return
+               BIC     R5,R0,#&FF              ;Clear to raw plinth
+
+               ; --- Swap the colours over ---
+
+               MOV     R1,R13                  ;Point to the full block
+               BL      colours_set             ;Set the background colour
+               STR     R2,[R13,#84+8]          ;Store this to return in R2
+
+               ; --- Now toggle the border ---
+
+               LDRB    R14,[R4,#0]             ;Load the invert character
+               EOR     R14,R14,#&20            ;Change its case
+               STRB    R14,[R4,#0]             ;Store the character back
+
+               ADD     R14,R13,#8              ;Point to the bounding box
+               LDMIA   R14,{R2-R4,R14}         ;Load these values out
+               SUB     R2,R2,#4                ;Expand to allow for border
+               SUB     R3,R3,#4
+               ADD     R4,R4,#4
+               ADD     R14,R14,#4
+               LDR     R0,[R13,#0]             ;Load the window handle
+               ADD     R1,R13,#40              ;Point to the update block
+               STMIA   R1,{R0,R2-R4,R14}       ;Store them back again
+
+               SWI     XWimp_UpdateWindow      ;Start the update operation
+               BVS     %99slab_doSlab          ;If that failed, return
+               CMP     R0,#0                   ;Is there anything to do?
+               BEQ     %90slab_doSlab          ;No -- do nothing then
+
+               ; --- Read the window origin position ---
+
+               LDR     R2,[R1,#4]              ;Load the x0 coordinate
+               ADD     R14,R1,#16              ;Find the others
+               LDMIA   R14,{R3,R4,R14}         ;Load them from the block
+               SUB     R2,R2,R4                ;Find the x origin
+               SUB     R3,R3,R14               ;And find the y origin
+
+               ; --- Do the update loop ---
+
+00             EOR     R0,R5,#vsFlag_invert    ;Get the border type word
+               ADD     R1,R13,#8               ;Point to the icon data
+               BL      plot_border             ;Go and plot the border
+               ADDVC   R1,R13,#40              ;Point to the update block
+               SWIVC   XWimp_GetRectangle      ;Get another rectangle
+               BVS     %99slab_doSlab          ;If that failed, return
+               CMP     R0,#0                   ;Is that all there is?
+               BNE     %b00                    ;No -- loop back then
+
+               ; --- Tidy up and return ---
+
+90slab_doSlab  ADD     R13,R13,#84             ;Restore the stack pointer
+               LDMFD   R13!,{R0-R5,R14}        ;Restore registers
+               BICS    PC,R14,#V_flag          ;And return without error
+
+99slab_doSlab  ADD     R13,R13,#84+4           ;Restore the stack pointer
+               LDMFD   R13!,{R1-R5,R14}        ;Restore registers except R0
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+; --- slab_slab ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;              R2 == pointer to slab descriptor block
+;
+; On exit:     --
+;
+; Use:         Slabs an icon in, and records information for unslabbing.
+
+               EXPORT  slab_slab
+slab_slab      ROUT
+
+               STMFD   R13!,{R0-R3,R14}        ;Save some registers
+
+               ; --- Fill in the descriptor block ---
+
+               MOV     R3,R2                   ;Remember this pointer
+               STMIA   R3,{R0,R1}              ;Store them away
+               SWI     XOS_ReadMonotonicTime   ;Read the time
+               STR     R0,[R3,#12]             ;Store it in the block
+
+               ; --- Do the slabness ---
+
+               LDR     R0,[R3,#0]              ;Load the window handle
+               LDR     R2,sculpt_slab          ;Get the slab colour
+               BL      slab_doSlab             ;Do the slabbing op
+               BVS     %99slab_slab
+
+               SUB     R13,R13,#20             ;Allow some space for block
+               MOV     R1,R13                  ;Point to the block
+               SWI     XWimp_GetPointerInfo    ;Fetch the mouse status
+               LDR     R14,[R13,#8]            ;Fetch the button state
+               ADD     R13,R13,#20             ;Restore the stack pointer
+               CMP     R14,#0                  ;Are any buttons pressed?
+               ORREQ   R2,R2,#&100             ;No -- set a flag then
+               STR     R2,[R3,#8]              ;Store in the descriptor
+
+               ; --- Clear the `immediate unslab' flag ---
+
+               LDR     R14,sculpt_flags        ;Load the flags word
+               BIC     R14,R14,#scFlag_unslab  ;Clear the flag
+               STR     R14,sculpt_flags        ;Store the flags back
+               LDMFD   R13!,{R0-R3,PC}^        ;Return when done
+
+99             ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R3,R14}        ;Restore other registers
+               ORRS    PC,R14,#V_flag          ;And return with V set
+
+               LTORG
+
+; --- slab_unslab ---
+;
+; On entry:    R2 == pointer to descriptor block
+;
+; On exit:     --
+;
+; Use:         Unslabs an icon which was slabbed.
+
+               EXPORT  slab_unslab
+slab_unslab    ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R4,R2                   ;Move this somewhere nice
+
+               ; --- Quick check to see if anything needs doing ---
+
+               LDR     R14,[R4,#8]             ;Load the colour word
+               CMP     R14,#-1                 ;Is this unset?
+               BEQ     %90slab_unslab          ;Yes -- return then
+
+               ; --- Do we do this quickly? ---
+
+               LDR     R14,sculpt_flags        ;Load the flags word
+               TST     R14,#scFlag_unslab      ;Have we recently unslabbed?
+               BNE     %50slab_unslab          ;Yes -- skip the delay
+               ORR     R14,R14,#scFlag_unslab  ;Set the flag now
+               STR     R14,sculpt_flags        ;Save the flags back
+
+               ; --- Work out how long to wait ---
+
+               SUB     R13,R13,#36             ;Make space for a block
+               LDR     R14,[R4,#0]             ;Load the window handle
+               STR     R14,[R13,#0]            ;Store in the block
+               MOV     R1,R13                  ;Point to my block
+               SWI     XWimp_GetWindowState    ;Read the window state
+               MOVVS   R14,#0                  ;If failed, assume deleted
+               LDRVC   R14,[R13,#32]           ;Else load the window flags
+               ADD     R13,R13,#36             ;Restore the stack pointer
+               TST     R14,#&00010000          ;Is the window open?
+               BEQ     %10slab_unslab          ;Yes -- wait for timer then
+
+               LDR     R14,[R4,#8]             ;Load the flags/colour word
+               TST     R14,#&100               ;Is the `no mouse' bit set?
+               BNE     %10slab_unslab          ;Yes -- wait for timer then
+
+               ; --- Check for the mouse then ---
+
+00             SWI     XOS_Mouse               ;Read the mouse position
+               CMP     R2,#0                   ;Are the buttons released?
+               BNE     %b00                    ;No -- skip round
+               B       %50slab_unslab          ;Now skip onwards for unslab
+
+               ; --- Check for the timer ---
+
+10slab_unslab  LDR     R1,[R4,#12]             ;Load the targt time
+               ADD     R1,R1,#10               ;Allow a tenth of a second
+00             SWI     XOS_ReadMonotonicTime   ;Read the current time
+               CMP     R0,R1                   ;Have we waited long enough?
+               BMI     %b00                    ;No -- loop back then
+
+               ; --- Now we can unslab the icon ---
+
+50slab_unslab  LDMIA   R4,{R0-R2}              ;Load the information out
+               AND     R2,R2,#&FF              ;Only use the colour bits
+               BL      slab_doSlab             ;Do the unslabbing
+
+90             LDMFD   R13!,{R0-R4,PC}^        ;Return to caller when done
+
+99             ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R4,R14}        ;Restore registers
+               ORRS    PC,R14,#V_flag          ;And return to caller
+
+               LTORG
+
+; --- slab_colour ---
+;
+; On entry:    --
+;
+; On exit:     R2 == slab colour
+;
+; Use:         Returns the current slabbing colour.
+
+               EXPORT  slab_colour
+slab_colour    ROUT
+
+               LDR     R2,sculpt_slab          ;Load the slabbing colour
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/s/utils b/StraySrc/Sculptrix/sculptrix/s/utils
new file mode 100644 (file)
index 0000000..688da57
--- /dev/null
@@ -0,0 +1,107 @@
+;
+; utils
+;
+; Various useful routines
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- utils_strWidth ---
+;
+; On entry:    R0 == pointer to a string
+;
+; On exit:     R0 == width of the string in OS units
+;
+; Use:         Returns the width of a string, as it would be displayed in
+;              an icon (i.e. taking into account things like the current
+;              desktop font etc.)  The width is exact, so if you want to
+;              e.g. draw a box round it, you'll have to add on a little
+;              clearance at each end.  8 OS units seems to be a good size
+;              for the clearance (so the total width you'd use is given by
+;              utils_strWidth(string)+16, because it has two ends).
+;
+;              [Stolen and bodged from sapphire/wimp.s by mdw]
+
+               EXPORT  utils_strWidth
+utils_strWidth ROUT
+
+               ; --- We need to find the string length anyway ---
+               ;
+               ; This length calculation is done inline to avoid a
+               ; dependency on string.  It's not very long, anyway, and
+               ; it *does* save a MOV R5,R0 :-)
+
+               STMFD   R13!,{R1-R6,R14}        ;Save a bunch of registers
+               MOV     R5,#0                   ;Length counter starts at 0
+               MOV     R6,R0                   ;Keep string pointer
+
+00             LDRB    R14,[R0,R5]             ;Get a byte from the string
+               CMP     R14,#' '                ;Is it a control char?
+               ADDCS   R5,R5,#1                ;Bump on *anyway* (see above)
+               BCS     %b00                    ;If more to go, loop back
+
+               ; --- Now try to find the current font handle ---
+
+               MOV     R0,#8                   ;Read Wimp font handle
+               SWI     XWimp_ReadSysInfo       ;Find out from WindowMangler
+               MOVVS   R0,#0                   ;If nothing, assume no font
+               CMP     R0,#0                   ;Is there there a real font?
+               BEQ     %10utils_strWidth       ;No -- skip ahead too
+
+               ; --- Now suss out the width of the string ---
+
+               SWI     Font_SetFont            ;Set up the desktop font
+               MOV     R1,#1000                ;A nice big round number
+               MOV     R2,R1                   ;And another nice big number
+               SWI     Font_Converttopoints    ;Font_StringWidth is weird
+               MOV     R3,R2                   ;Move coords to right regs
+               MOV     R2,R1                   ;That means both of them
+               MOV     R1,R6                   ;Retreive string pointer
+               MOV     R4,#-1                  ;Don't split the string
+               ADD     R5,R5,#1                ;Move this counter on one
+               SWI     Font_StringWidth        ;Find the width of the string
+               MOV     R1,R2                   ;Move coordinates back again
+               MOV     R2,R3                   ;Again, that means both
+               SWI     Font_ConverttoOS        ;Convert to OS units now
+               MOV     R0,R1                   ;Put the width in R0
+               LDMFD   R13!,{R1-R6,PC}^        ;Return to caller, then
+
+               ; --- Just normal system font ---
+
+10             MOV     R0,R5,LSL #4            ;Multiply by character width
+               LDMFD   R13!,{R1-R6,PC}^        ;Return to caller
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/s/vString b/StraySrc/Sculptrix/sculptrix/s/vString
new file mode 100644 (file)
index 0000000..0dc5e46
--- /dev/null
@@ -0,0 +1,389 @@
+;
+; vString.s
+;
+; Parses validation strings for Sculptrix
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.wSpace
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Module$$Code|,CODE,READONLY
+
+; --- vString_read ---
+;
+; On entry:    R1 == pointer to an icon block
+;
+; On exit:     CS if there's a border, and
+;                R0 == border info word
+;                R4 == pointer to `inverted' flag byte
+;              else CC and
+;                R0, R4 preserved
+;
+; Use:         Reads an icon's validation string, and extracts relevant
+;              information.  The border info word contains what sort of
+;              graphics we have to plot around the icon, and any special
+;              options thrown in.  A string (for group borders etc.) is
+;              copied into the misc buffer if one was found.
+;
+;              The syntax of a Sculptrix validation string is as follows:
+;
+;                `xb'<type>[<flags>][`,'<text>]
+;
+;              The <type> is a letter which determines what sort of border
+;              is to be drawn.  The <flags> modify the style of the border
+;              slightly.  Note that if the <type> is uppercase, then the
+;              border is inverted.  The <text> is only required for group
+;              boxes (type `g').  An unknown <type> causes the icon to be
+;              ignored.  Unknown <flags> are ignored.  If no text is
+;              specified, a null string is assumed by default.  Spaces
+;              are allowed in various sensible places.
+
+               EXPORT  vString_read
+vString_read   ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+
+               ; --- Find the validation string first ---
+
+               MOV     R2,#0                   ;First call, this is
+00             MOV     R0,#'x'                 ;Find the validation string
+               BL      vString_find            ;Try to find the string
+               BCC     %90vString_read         ;Can't find a Sculptrix cmd
+               LDRB    R14,[R2,#1]             ;Load the subcommand code
+
+             [ :LNOT::DEF:only_new_commands
+               SUB     R4,R14,#'0'             ;Convert to a digit
+               CMP     R4,#10                  ;Is this recognised?
+               BCC     %50vString_read         ;Yes -- deal with it
+             ]
+
+               ORR     R14,R14,#&20            ;Make the command lowercase
+
+             [ :LNOT::DEF:only_new_commands
+               CMP     R14,#'g'                ;Is it a group command?
+               BEQ     %60vString_read         ;Yes -- deal with it
+             ]
+
+               CMP     R14,#'s'                ;Is it a text+sprite?
+               BEQ     %70vString_read         ;Yes -- deal with that too
+
+               CMP     R14,#'b'                ;Is it the main `b' command?
+               BNE     %b00                    ;No -- loop back for more
+
+               ; --- Handle the new `xb' command ---
+
+               MOV     R14,#0                  ;Initially terminate string
+               STRB    R14,sculpt_misc         ;To avoid nasty problems
+               ADD     R2,R2,#2                ;Skip past the command chars
+
+00             LDRB    R3,[R2],#1              ;Load a byte from the string
+               CMP     R3,#&20                 ;Is it a space character?
+               BEQ     %b00                    ;Yes -- keep looking then
+               CMP     R3,#';'                 ;End of the command?
+               CMPNE   R3,#&1F                 ;Of of the whole string?
+               BLS     %90vString_read         ;End of string -- abort now
+
+               ORR     R0,R3,#&20              ;Make the char lowercase
+               ADR     R1,vString__cnvTbl      ;Point to the table
+               BL      vString__lookup         ;Look up letter in the table
+               BCC     %90vString_read         ;Not found -- give up then
+               MOV     R4,R0                   ;Get the command code
+
+               TST     R3,#&20                 ;Is the command uppercase?
+               EOREQ   R4,R4,#vsFlag_invert    ;Yes -- invert the border
+               SUB     R3,R2,#1                ;Remember this offset
+
+               ; --- Now read in the flags ---
+
+               ADR     R1,vString__flags       ;Point to the flags table
+
+00             LDRB    R14,[R2],#1             ;Load a byte from the string
+               CMP     R14,#&20                ;Is it a space character?
+               BEQ     %b00                    ;Yes -- keep looking then
+               CMP     R14,#';'                ;End of the command?
+               CMPNE   R14,#&1F                ;Of of the whole string?
+               BLS     %f05                    ;End of string -- return
+               CMP     R14,#','                ;Is it a comma?
+               BEQ     %f00                    ;Yes -- handle the text then
+
+               ORR     R0,R14,#&20             ;Make character lowercase
+               BL      vString__lookup         ;Do the lookup
+               EORCS   R4,R4,R0                ;And merge in the flag
+               B       %b00                    ;Keep going until done
+
+               ; --- Copy the text over and exit ---
+
+00             BL      vString__copy           ;Copy the text over, please
+               B       %80vString_read         ;Now return this to caller
+
+               ; --- Deal with an empty string ---
+
+05             AND     R14,R4,#&0000FF00       ;Extract the type code
+               CMP     R14,#vsCode_group       ;Is this a group box?
+               MOVEQ   R4,#vsBrd_ridge+vsFlag_fade+vsFlag_invert
+               LDREQ   R14,sculpt_flags        ;Load the flags word
+               TSTEQ   R14,#scFlag_acorn       ;Acorn style group box?
+               BICEQ   R4,R4,#vsFlag_invert    ;No -- don't invert it then
+               B       %80vString_read         ;Now return this to caller
+
+               ; --- Conversion tables ---
+
+vString__cnvTbl        DCD     'a',vsBrd_action + vsFlag_slab
+               DCD     'd',vsBrd_default + vsFlag_slab
+               DCD     'i',vsBrd_action + vsFlag_invert
+               DCD     'p',vsBrd_action + vsFlag_invert + vsFlag_fade
+               DCD     'r',vsBrd_ridge
+               DCD     'c',vsBrd_ridge + vsFlag_invert
+               DCD     'w',vsBrd_write
+               DCD     'o',vsBrd_offset
+               DCD     'g',vsCode_group
+               DCD     -1
+
+vString__flags DCD     'f',vsFlag_fade
+               DCD     'i',vsFlag_invert
+               DCD     -1
+
+               ; --- Handle old-style `x<digit>' command ---
+
+             [ :LNOT::DEF:only_new_commands
+
+50vString_read MOV     R3,R2                   ;Remember this position
+               ADR     R14,vString__oldTbl     ;Point to the table
+               LDR     R4,[R14,R4,LSL #2]      ;Load the appropriate word
+               CMP     R4,#-1                  ;Is there a zero there?
+               BEQ     %90vString_read         ;Yes -- give up then
+               LDRB    R14,[R3,#0]             ;Load the `X' character
+               TST     R14,#&20                ;Is it uppercase?
+               EOREQ   R4,R4,#vsFlag_invert    ;Yes -- invert the icon
+               B       %80vString_read         ;Now return this to caller
+
+vString__oldTbl        DCD     vsCode_simple + vsBrd_action + vsFlag_slab
+               DCD     vsCode_simple + vsBrd_ridge
+               DCD     vsCode_simple + vsBrd_default + vsFlag_slab
+               DCD     vsCode_simple + vsBrd_offset
+               DCD     vsCode_simple + vsBrd_action
+               DCD     -1                      ;Group box title -- withdrawn
+               DCD     -1                      ;Group box title -- withdrawn
+               DCD     vsCode_simple + vsBrd_write
+               DCD     vsCode_simple + vsBrd_action + vsFlag_fade
+               DCD     -1
+
+             ]
+
+               ; --- Handle old-style `xg' command ---
+
+             [ :LNOT::DEF:only_new_commands
+
+60vString_read ADD     R3,R2,#1                ;Point to the `G'
+               ADD     R2,R2,#3                ;Skip onto the text
+               MOV     R4,#vsCode_group        ;Get a group title word
+               BL      vString__copy           ;Copy the text over, please
+               B       %80vString_read         ;Now return this to caller
+
+             ]
+
+               ; --- Handle `xs' text+sprite command ---
+
+70vString_read ADD     R3,R2,#1                ;Point to the `S'
+               ADD     R2,R2,#2                ;Skip onto the text
+               MOV     R4,#vsCode_tns          ;Get the mystic word
+               BL      vString__copy           ;Copy the text over, please
+               B       %80vString_read         ;Now return this to caller
+
+               ; --- Return values to caller ---
+
+80vString_read STR     R4,[R13,#4*0]           ;Store the information word
+               STR     R3,[R13,#4*4]           ;And the invert flag address
+               LDMFD   R13!,{R0-R4,R14}        ;Restore registers
+               ORRS    PC,R14,#C_flag          ;And return with C set
+
+90vString_read LDMFD   R13!,{R0-R4,R14}        ;Restore registers
+               BICS    PC,R14,#C_flag          ;And return with C clear
+
+               LTORG
+
+; --- vString__copy ---
+;
+; On entry:    R0 == border type code
+;              R2 == pointer to tail of validation string
+;
+; On exit:     R2 moved on
+;
+; Use:         Copies the tail of the validation string into the misc
+;              buffer, transforming escape sequences correctly.
+
+vString__copy  ROUT
+
+               STMFD   R13!,{R0,R14}           ;Save some registers
+               ADR     R0,sculpt_misc          ;Point to the buffer
+
+00             LDRB    R14,[R2],#1             ;Load the next byte out
+               CMP     R14,#';'                ;Is this the end?
+               CMPNE   R14,#&1F                ;Check for end of string
+               BLS     %f00                    ;Yes -- skip onwards then
+
+               CMP     R14,#'\'                ;Is this an escape?
+               STRNEB  R14,[R0],#1             ;Nothing special -- store
+               BNE     %b00                    ;And loop back round
+
+               LDRB    R14,[R2],#1             ;Load the next byte out
+               CMP     R14,#&20                ;Check for end of string
+               STRCSB  R14,[R0],#1             ;Nothing special -- store
+               BCS     %b00                    ;And loop back round
+
+00             MOV     R14,#0                  ;Zero terminate the string
+               STRB    R14,[R0],#1             ;Store in the buffer
+               LDMFD   R13!,{R0,PC}^           ;Return when done
+
+               LTORG
+
+; --- vString__lookup ---
+;
+; On entry:    R0 == word to look for
+;              R1 == pointer to table
+;
+; On exit:     CS if found, and
+;                R0 == word from table
+;              else CC and
+;                R0 corrupted
+;
+; Use:         Looks a word in a table, and returns the corresponding other
+;              word.
+
+vString__lookup        ROUT
+
+               STMFD   R13!,{R1,R14}           ;Save some registers
+00             LDR     R14,[R1],#8             ;Load the next word
+               CMP     R14,#-1                 ;Is this the end?
+               CMPNE   R14,R0                  ;Do these match?
+               BNE     %b00                    ;Neither -- go back then
+               CMP     R14,R0                  ;Which one was it?
+               LDREQ   R0,[R1,#-4]             ;Match -- load previous word
+               LDMFD   R13!,{R1,R14}           ;Restore registers
+               ORREQS  PC,R14,#C_flag          ;Return C set if found
+               BICNES  PC,R14,#C_flag          ;Return C clear if not
+
+               LTORG
+
+; --- vString_find ---
+;
+; On entry:    R0 == character to find in block (not case-sensitive)
+;              R1 == pointer to icon block
+;              R2 == old pointer to search from, or 0
+;
+; On exit:     R0 == character forced to lower case
+;              CS if found, and
+;                R2 points to command string
+;              else CC and
+;                R2 corrupted
+;
+; Use:         Tries to find a validation string command in the given
+;              icon block.
+
+               EXPORT  vString_find
+vString_find   ROUT
+
+               BIC     R14,R14,#C_flag         ;Assume we won't find it
+               STMFD   R13!,{R3,R14}           ;Preserve for later use
+
+               ; --- Ensure the icon is text and indirected ---
+
+               LDR     R3,[R1,#16]             ;Get flags word
+               TST     R3,#1<<23               ;Is it deleted?
+               MOVEQ   R14,#&100               ;Can't put 101 in one instr
+               ORREQ   R14,R14,#&01            ;Check indirect and text
+               ANDEQ   R3,R3,R14               ;Mask the bits off
+               CMPEQ   R3,R14                  ;Were they both set?
+               LDMNEFD R13!,{R3,PC}^           ;No -- return huffily
+
+               ; --- Find the validation string ---
+
+               LDR     R3,[R1,#24]             ;Get pointer to valid string
+               CMP     R3,#-1                  ;Is it empty?
+               LDMEQFD R13!,{R3,PC}^           ;No -- return huffily
+
+               ; --- Start from the right index ---
+
+               ORR     R0,R0,#&20              ;Make valid char lower case
+               CMP     R2,#0                   ;Is it the start?
+               ADDNE   R2,R2,#1                ;No -- miss out one char
+               BNE     %30vString_find         ;And skip this command
+               MOV     R2,R3                   ;Start at the beginning
+
+               ; --- Check the first char of a validation string ---
+
+10vString_find LDRB    R14,[R2],#1             ;Get a byte from string
+               ORR     R3,R14,#&20             ;Make lower case
+               CMP     R3,R0                   ;Is it a match?
+               SUBEQ   R2,R2,#1                ;Point back to character
+               LDMEQFD R13!,{R3,R14}           ;And return
+               ORREQS  PC,R14,#C_flag          ;Set C on exit for this
+               MOV     R3,#0                   ;Not an excaped character
+
+               ; --- Skip ahead to the next validation string ---
+
+20vString_find CMP     R14,#' '                ;Is it a control char?
+               LDMCCFD R13!,{R3,PC}^           ;Yes -- return
+               CMP     R3,#1                   ;Are we escaping?
+               MOVEQ   R3,#0                   ;Yes -- done that now
+               BEQ     %30vString_find         ;So skip this bit
+               CMP     R14,#';'                ;Is it a semicolon?
+               BEQ     %10vString_find         ;Yes -- try a new command
+               CMP     R14,#'\'                ;Is it a backslash?
+               MOVEQ   R3,#1                   ;Yes -- escape next char
+30vString_find LDRB    R14,[R2],#1             ;Get another character
+               B       %20vString_find         ;And try again
+
+               LTORG
+
+;----- Border codes and flags -----------------------------------------------
+
+               ^       0
+vsCode_simple  #       &0100                   ;A simple border
+vsCode_group   #       &0100                   ;A group box border
+vsCode_tns     #       &0100                   ;Text+sprite icon
+
+               ^       0
+vsBrd_action   #       1                       ;Standard action button
+vsBrd_default  #       1                       ;Default action button
+vsBrd_ridge    #       1                       ;A ridge type border
+vsBrd_write    #       1                       ;A writable border
+vsBrd_offset   #       1                       ;Offset pressed-in border
+
+vsFlag_invert  EQU     (1<<31)                 ;Icon border is inverted
+vsFlag_fade    EQU     (1<<30)                 ;Icon border is faded
+vsFlag_slab    EQU     (1<<29)                 ;Icon may be slabbed
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/bbox b/StraySrc/Sculptrix/sculptrix/sh/bbox
new file mode 100644 (file)
index 0000000..4949d8d
--- /dev/null
@@ -0,0 +1,50 @@
+;
+; bbox.sh
+;
+; Bounding box calculations for Sculptrix borders
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  bbox_calc
+
+               [       :LNOT::DEF:bbox__dfn
+               GBLL    bbox__dfn
+
+; --- bbox_calc ---
+;
+; On entry:    R1 == pointer to icon block
+;
+; On exit:     R0 == 0 if there was no border, or nonzero otherwise
+;
+; Use:         Updates the block to represent the size of the border.
+
+               IMPORT  bbox_calc
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/border b/StraySrc/Sculptrix/sculptrix/sh/border
new file mode 100644 (file)
index 0000000..0b2d8c7
--- /dev/null
@@ -0,0 +1,283 @@
+;
+; border.sh
+;
+; Plots borders given an icon block and a definition of the border shape
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  border_plot
+
+               [       :LNOT::DEF:border__dfn
+               GBLL    border__dfn
+
+; --- border_plot ---
+;
+; On entry:    R0 == pointer to border defintion
+;              R1 == pointer to icon block
+;              R2,R3 == window origin position
+;              R4 == pointer to colour table
+;              R5 == group box title width (optional)
+;              R6 == group box title address (optional)
+;
+; On exit:     May return an error
+;
+; Use:         Plots a border using the border definition.
+
+               IMPORT  border_plot
+
+;----- Command codes --------------------------------------------------------
+;
+; We try to organise these in a way which makes it easy to decode.  The
+; bottom two bits end up as an immediate operand in most cases, allowing us
+; to select entries in the icon bounding box easily.
+
+               ^       -4
+
+               #       4
+bCmd_ret       EQU     {VAR}                   ;End border operation
+
+               #       4
+bCmd_ldix0     EQU     {VAR}+0                 ;Fetch X0 of the icon
+bCmd_ldiy0     EQU     {VAR}+1                 ;Fetch Y0 of the icon
+bCmd_ldix1     EQU     {VAR}+2                 ;Fetch X1 of the icon
+bCmd_ldiy1     EQU     {VAR}+3                 ;Fetch Y1 of the icon
+
+               #       4
+bCmd_ldx0      EQU     {VAR}+0                 ;Fetch last stored X0
+bCmd_ldy0      EQU     {VAR}+1                 ;Fetch last stored Y0
+bCmd_ldx1      EQU     {VAR}+2                 ;Fetch last stored X1
+bCmd_ldy1      EQU     {VAR}+3                 ;Fetch last stored Y1
+
+               #       4
+bCmd_ldhc      EQU     {VAR}+0                 ;Fetch horizontal centre
+bCmd_ldvc      EQU     {VAR}+1                 ;Fetch vertical centre
+
+               #       4
+bCmd_add       EQU     {VAR}+0                 ;Add next byte
+bCmd_sub       EQU     {VAR}+1                 ;Subtract next byte
+
+               #       4
+bCmd_stx0      EQU     {VAR}+0                 ;Store as the X0 parameter
+bCmd_sty0      EQU     {VAR}+1                 ;Store as the Y0 parameter
+bCmd_stx1      EQU     {VAR}+2                 ;Store as the X1 parameter
+bCmd_sty1      EQU     {VAR}+3                 ;Store as the Y1 parameter
+
+               #       4
+bCmd_dark      EQU     {VAR}+0                 ;Use the current `dark' col
+bCmd_light     EQU     {VAR}+1                 ;Use the current `light' col
+bCmd_raw       EQU     {VAR}+2                 ;Switch to uninverted colours
+
+               #       4
+bCmd_icon      EQU     {VAR}+0                 ;Set colours from icon
+bCmd_indCol    EQU     {VAR}+1                 ;Indirected colour
+bCmd_litCol    EQU     {VAR}+2                 ;Literal colour
+
+               #       4
+bCmd_plot      EQU     {VAR}+0                 ;Plot a rule (arg == branch)
+
+               #       4
+bCmd_skpt      EQU     {VAR}+0                 ;Skip past the `title'
+
+               #       4
+bCmd_group     EQU     {VAR}+0                 ;Plot a group box
+
+               #       4
+bCmd_jmp       EQU     {VAR}+0                 ;Jump to a routine
+bCmd_call      EQU     {VAR}+1                 ;Call subroutine
+
+;----- Macros ---------------------------------------------------------------
+
+               ; --- Return ---
+
+               MACRO
+$label         BRET
+$label         DCB     bCmd_ret
+               MEND
+
+               ; --- Load values ---
+
+               MACRO
+$label         BLDIX0
+$label         DCB     bCmd_ldix0
+               MEND
+
+               MACRO
+$label         BLDIY0
+$label         DCB     bCmd_ldiy0
+               MEND
+
+               MACRO
+$label         BLDIX1
+$label         DCB     bCmd_ldix1
+               MEND
+
+               MACRO
+$label         BLDIY1
+$label         DCB     bCmd_ldiy1
+               MEND
+
+               ; --- Load values ---
+
+               MACRO
+$label         BLDX0
+$label         DCB     bCmd_ldx0
+               MEND
+
+               MACRO
+$label         BLDY0
+$label         DCB     bCmd_ldy0
+               MEND
+
+               MACRO
+$label         BLDX1
+$label         DCB     bCmd_ldx1
+               MEND
+
+               MACRO
+$label         BLDY1
+$label         DCB     bCmd_ldy1
+               MEND
+
+               ; --- Centring ---
+
+               MACRO
+$label         LDHC
+$label         DCB     bCmd_ldhc
+               MEND
+
+               MACRO
+$label         BLDVC
+$label         DCB     bCmd_ldvc
+               MEND
+
+               ; --- Arithmetic ---
+
+               MACRO
+$label         BADD    $val
+$label         DCB     bCmd_add,$val
+               MEND
+
+               MACRO
+$label         BSUB    $val
+$label         DCB     bCmd_sub,$val
+               MEND
+
+               MACRO
+$label         BSKIPT
+$label         DCB     bCmd_skpt
+               MEND
+
+               ; --- Storing values ---
+
+               MACRO
+$label         BSTX0
+$label         DCB     bCmd_stx0
+               MEND
+
+               MACRO
+$label         BSTY0
+$label         DCB     bCmd_sty0
+               MEND
+
+               MACRO
+$label         BSTX1
+$label         DCB     bCmd_stx1
+               MEND
+
+               MACRO
+$label         BSTY1
+$label         DCB     bCmd_sty1
+               MEND
+
+               ; --- Colouring ---
+
+               MACRO
+$label         BLIGHT
+$label         DCB     bCmd_light
+               MEND
+
+               MACRO
+$label         BDARK
+$label         DCB     bCmd_dark
+               MEND
+
+               MACRO
+$label         BRAW
+$label         DCB     bCmd_raw
+               MEND
+
+               MACRO
+$label         BICON
+$label         DCB     bCmd_icon
+               MEND
+
+               MACRO
+$label         BINDCOL $colour
+$label         DCB     bCmd_indCol,:INDEX:$colour
+               MEND
+
+               MACRO
+$label         BLITCOL $colour
+$label         DCB     bCmd_litCol,$colour
+               MEND
+
+               ; --- Plotting ---
+
+               MACRO
+$label         BPLOT   $rule
+$label         DCB     bCmd_plot
+               ALIGN
+               B       $rule
+               MEND
+
+               MACRO
+$label         BGROUP  $flags
+$label         DCB     bCmd_group
+               ALIGN
+               DCD     $flags
+               MEND
+
+               ; --- Subroutines ---
+
+               MACRO
+$label         BJMP    $addr
+$label         DCB     bCmd_jmp
+               ALIGN
+               DCD     $addr-{PC}-4
+               MEND
+
+               MACRO
+$label         BCALL   $addr
+$label         DCB     bCmd_call
+               ALIGN
+               DCD     $addr-{PC}-4
+               MEND
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/colours b/StraySrc/Sculptrix/sculptrix/sh/colours
new file mode 100644 (file)
index 0000000..06bc664
--- /dev/null
@@ -0,0 +1,64 @@
+;
+; colours.sh
+;
+; Colour handling for Sculptrix
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  colours_read
+;  colours_set
+
+               [       :LNOT::DEF:colours__dfn
+               GBLL    colours__dfn
+
+; --- colours_read ---
+;
+; On entry:    R1 == pointer to icon block
+;
+; On exit:     R0 == foreground in bits 0-3, background in bits 4-7
+;              CS if colours in validation string, and
+;                R14 == address of colours in there, or 0
+;
+; Use:         Works out colours of an icon.
+
+               IMPORT  colours_read
+
+; --- colours_set ---
+;
+; On entry:    R1 == pointer to icon /state/ block
+;              R2 == new background colour
+;
+; On exit:     R2 == old background colour
+;
+; Use:         Changes the background colour of an icon.
+
+               IMPORT  colours_set
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/config b/StraySrc/Sculptrix/sculptrix/sh/config
new file mode 100644 (file)
index 0000000..0eafce7
--- /dev/null
@@ -0,0 +1,72 @@
+;
+; config.sh
+;
+; Configuration interface for Sculptrix
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  config_set
+;  config_read
+;  config_load
+
+               [       :LNOT::DEF:config__dfn
+               GBLL    config__dfn
+
+; --- config_set ---
+;
+; On entry:    R0 == pointer to config buffer
+;
+; On exit:     --
+;
+; Use:         Reads the config buffer into workspace.
+
+               IMPORT  config_set
+
+; --- config_read ---
+;
+; On entry:    R0 == pointer to a buffer
+;
+; On exit:     --
+;
+; Use:         Writes the config into a buffer
+
+               IMPORT  config_read
+
+; --- config_load ---
+;
+; On entry:    R0 == pointer to filename
+;
+; On exit:     --
+;
+; Use:         Loads a configuration file.
+
+               IMPORT  config_load
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/messages b/StraySrc/Sculptrix/sculptrix/sh/messages
new file mode 100644 (file)
index 0000000..4fb6d40
--- /dev/null
@@ -0,0 +1,17 @@
+;
+; Message symbols [generated by msgAOF]
+;
+
+               [       :LNOT::DEF:msg__dfn
+               GBLL    msg__dfn
+
+               IMPORT  msg_errBadSwi
+               IMPORT  msg_errBadOpcode
+               IMPORT  msg_errBadConfig
+               IMPORT  msg_errCfgBuff
+               IMPORT  help_config
+               IMPORT  synt_config
+
+               ]
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/plot b/StraySrc/Sculptrix/sculptrix/sh/plot
new file mode 100644 (file)
index 0000000..ffa73d0
--- /dev/null
@@ -0,0 +1,82 @@
+;
+; plot.sh
+;
+; Plots border types
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  plot_border
+;  plot_group
+;  plot_tnsBBox
+
+               [       :LNOT::DEF:plot__dfn
+               GBLL    plot__dfn
+
+; --- plot_border ---
+;
+; On entry:    R0 == pointer to border type
+;              R1 == pointer to icon block
+;              R2,R3 == window origin position
+;
+; On exit:     May return an error
+;
+; Use:         Plots the given border type.
+
+               IMPORT  plot_border
+
+; --- plot_group ---
+;
+; On entry:    R0 == pointer to border type
+;              R1 == pointer to icon block
+;              R2,R3 == window origin position
+;              R6 == pointer to group title
+;
+; On exit:     May return an error
+;
+; Use:         Plots a group box.
+
+               IMPORT  plot_group
+
+; --- plot_tnsBBox ---
+;
+; On entry:    R1 == pointer to an icon block
+;
+; On exit:     CS if sprite found, and
+;                R0-R3 == bounding box of icon
+;                R4 == icon flags word (modified)
+;              else CC and registers preserved
+;
+; Use:         Works out where the text of the icon ought to be.  (Actually
+;              the box returned is too wide, although this will probably
+;              be good enough for most purposes.)
+
+               IMPORT  plot_tnsBBox
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/redraw b/StraySrc/Sculptrix/sculptrix/sh/redraw
new file mode 100644 (file)
index 0000000..6bcf613
--- /dev/null
@@ -0,0 +1,88 @@
+;
+; redraw.sh
+;
+; Redrawing windows and icons
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  redraw_window
+;  redraw_icon
+;  redraw_group
+;  redraw_update
+
+               [       :LNOT::DEF:redraw__dfn
+               GBLL    redraw__dfn
+
+; --- redraw_window ---
+;
+; On entry:    R1 == pointer to redraw block
+;
+; On exit:     May return an error
+;
+; Use:         Redraws all the icons in a window.
+
+               IMPORT  redraw_window
+
+; --- redraw_icon ---
+;
+; On entry:    R0 == pointer to icon block
+;              R1 == pointer to redraw block
+;
+; On exit:     May return an error
+;
+; Use:         Redraws a single icon.
+
+               IMPORT  redraw_icon
+
+; --- redraw_group ---
+;
+; On entry:    R0 == pointer to icon block
+;              R1 == pointer to redraw block
+;              R2 == `border type' (ignored in Sculptrix 2.00)
+;              R3 == pointer to title string
+;
+; On exit:     --
+;
+; Use:         Plots a group box.
+
+               IMPORT  redraw_group
+
+; --- redraw_update ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;
+; On exit:     --
+;
+; Use:         Updates an icon.
+
+               IMPORT  redraw_update
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/rules b/StraySrc/Sculptrix/sculptrix/sh/rules
new file mode 100644 (file)
index 0000000..cfdfe84
--- /dev/null
@@ -0,0 +1,161 @@
+;
+; rules.sh
+;
+; Draws horizontal and vertical rules for Sculptrix borders
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  rule_left
+;  rule_right
+;  rule_top
+;  rule_bottom
+;  rule_pTop
+;  rule_pBottom
+;  rule_border
+
+               [       :LNOT::DEF:rules__dfn
+               GBLL    rules__dfn
+
+; --- rule_left ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == bottom y position
+;              R5 == unused
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a vertical rule in the current colour.
+
+               IMPORT  rule_left
+
+; --- rule_right ---
+;
+; On entry:    R3 == unused
+;              R4 == bottom y position
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a vertical rule in the current colour.
+
+               IMPORT  rule_right
+
+; --- rule_top ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == unused
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a horizontal rule in the current colour.
+
+               IMPORT  rule_top
+
+; --- rule_bottom ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == unused
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a horizontal rule in the current colour.
+
+               IMPORT  rule_bottom
+
+; --- rule_pTop ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == unused
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a horizontal rule in the current colour, without
+;              mitring.
+
+               IMPORT  rule_pTop
+
+; --- rule_pBottom ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == unused
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Plots a horizontal rule in the current colour, without
+;              mitring.
+
+               IMPORT  rule_pBottom
+
+; --- rule_border ---
+;
+; On entry:    R3 == left hand side of the icon
+;              R4 == bottom edge of icon
+;              R5 == right hand side of the icon
+;              R6 == top y position
+;              R7 == pixel width
+;              R8 == pixel height
+;              R9 == start position for mitring
+;
+; On exit:     R0-R6 corrupted
+;
+; Use:         Fills the icon in, and plots a border around it, using the
+;              current foreground and background colours.
+
+               IMPORT  rule_border
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/slab b/StraySrc/Sculptrix/sculptrix/sh/slab
new file mode 100644 (file)
index 0000000..6a588e4
--- /dev/null
@@ -0,0 +1,87 @@
+;
+; slab.sh
+;
+; Icon slabbing for Sculptrix
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  slab_doSlab
+;  slab_slab
+;  slab_unslab
+;  slab_colour
+
+               [       :LNOT::DEF:slab__dfn
+               GBLL    slab__dfn
+
+; --- slab_doSlab ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;              R2 == new background colour for icon
+;
+; On exit:     R2 == old background colour, or -1
+;
+; Use:         Low-level slabbing operation.
+
+               IMPORT  slab_doSlab
+
+; --- slab_slab ---
+;
+; On entry:    R0 == window handle
+;              R1 == icon handle
+;              R2 == pointer to slab descriptor block
+;
+; On exit:     --
+;
+; Use:         Slabs an icon in, and records information for unslabbing.
+
+               IMPORT  slab_slab
+
+; --- slab_unslab ---
+;
+; On entry:    R2 == pointer to descriptor block
+;
+; On exit:     --
+;
+; Use:         Unslabs an icon which was slabbed.
+
+               IMPORT  slab_unslab
+
+; --- slab_colour ---
+;
+; On entry:    --
+;
+; On exit:     R2 == slab colour
+;
+; Use:         Returns the current slabbing colour.
+
+               IMPORT  slab_colour
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/utils b/StraySrc/Sculptrix/sculptrix/sh/utils
new file mode 100644 (file)
index 0000000..441851f
--- /dev/null
@@ -0,0 +1,58 @@
+;
+; utilsh
+;
+; Various useful routines
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  utils_strWidth
+
+               [       :LNOT::DEF:utils__dfn
+               GBLL    utils__dfn
+
+; --- utils_strWidth ---
+;
+; On entry:    R0 == pointer to a string
+;
+; On exit:     R0 == width of the string in OS units
+;
+; Use:         Returns the width of a string, as it would be displayed in
+;              an icon (i.e. taking into account things like the current
+;              desktop font etc.)  The width is exact, so if you want to
+;              e.g. draw a box round it, you'll have to add on a little
+;              clearance at each end.  8 OS units seems to be a good size
+;              for the clearance (so the total width you'd use is given by
+;              utils_strWidth(string)+16, because it has two ends).
+;
+;              [Stolen and bodged from sapphire/wimp.s by mdw]
+
+               IMPORT  utils_strWidth
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/vString b/StraySrc/Sculptrix/sculptrix/sh/vString
new file mode 100644 (file)
index 0000000..8e98ed3
--- /dev/null
@@ -0,0 +1,107 @@
+;
+; vString.sh
+;
+; Parses validation strings for Sculptrix
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  vString_read
+;  vString_find
+
+               [       :LNOT::DEF:vString__dfn
+               GBLL    vString__dfn
+
+; --- vString_read ---
+;
+; On entry:    R1 == pointer to an icon block
+;
+; On exit:     CS if there's a border, and
+;                R0 == border info word
+;                R2 == pointer to `inverted' flag byte
+;              else CC and
+;                R0, R2 preserved
+;
+; Use:         Reads an icon's validation string, and extracts relevant
+;              information.  The border info word contains what sort of
+;              graphics we have to plot around the icon, and any special
+;              options thrown in.  A string (for group borders etc.) is
+;              copied into the misc buffer if one was found.
+;
+;              The syntax of a Sculptrix validation string is as follows:
+;
+;                `xb'<type>[<flags>][`,'<text>]
+;
+;              The <type> is a letter which determines what sort of border
+;              is to be drawn.  The <flags> modify the style of the border
+;              slightly.  Note that if the <type> is uppercase, then the
+;              border is inverted.  The <text> is only required for group
+;              boxes (type `g').  An unknown <type> causes the icon to be
+;              ignored.  Unknown <flags> are ignored.  If no text is
+;              specified, a null string is assumed by default.  Spaces
+;              are allowed in various sensible places.
+
+               IMPORT  vString_read
+
+; --- vString_find ---
+;
+; On entry:    R0 == character to find in block (not case-sensitive)
+;              R1 == pointer to icon block
+;              R2 == old pointer to search from, or 0
+;
+; On exit:     R0 == character forced to lower case
+;              CS if found, and
+;                R2 points to command string
+;              else CC and
+;                R2 corrupted
+;
+; Use:         Tries to find a validation string command in the given
+;              icon block.
+
+               IMPORT  vString_find
+
+;----- Border codes and flags -----------------------------------------------
+
+               ^       0
+vsCode_simple  #       &0100                   ;A simple border
+vsCode_group   #       &0100                   ;A group box border
+vsCode_tns     #       &0100                   ;Text+sprite icon
+
+               ^       0
+vsBrd_action   #       1                       ;Standard action button
+vsBrd_default  #       1                       ;Default action button
+vsBrd_ridge    #       1                       ;A ridge type border
+vsBrd_write    #       1                       ;A writable border
+vsBrd_offset   #       1                       ;Offset pressed-in border
+
+vsFlag_invert  EQU     (1<<31)                 ;Icon border is inverted
+vsFlag_fade    EQU     (1<<30)                 ;Icon border is faded
+vsFlag_slab    EQU     (1<<29)                 ;Icon may be slabbed
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Sculptrix/sculptrix/sh/wSpace b/StraySrc/Sculptrix/sculptrix/sh/wSpace
new file mode 100644 (file)
index 0000000..3c31255
--- /dev/null
@@ -0,0 +1,69 @@
+;
+; wSpace.sh
+;
+; Workspace layout for Sculptrix
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's Sculptrix.
+;
+; Sculptrix is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Sculptrix is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Sculptrix.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+               ^       0,R12
+sculpt_wStart  #       0
+
+               ; --- Useful flags ---
+
+sculpt_flags   #       4                       ;Some flags
+sculpt_sprArea #       4                       ;Sprite area for TNS sprites
+
+               ; --- Various colours ---
+
+sculpt_colours #       0                       ;Colour tables
+
+sculpt_defCol  #       4                       ;Normal colour table
+sculpt_groupCol        #       4                       ;Faded colour table
+sculpt_shadeCol        #       4                       ;Shaded colour table
+sculpt_shgrpCol        #       4                       ;Faded/shaded colour table
+
+sculpt_hilight #       1                       ;Highlight colour
+sculpt_slab    #       1                       ;Slabbing background
+               #       2                       ;Alignment padding
+
+               ; --- VDU variables ---
+
+sculpt_vduVars #       0                       ;Various VDU variables
+
+sculpt_dx      #       4                       ;Width of pixel in OS units
+sculpt_dy      #       4                       ;Height of pixel in OS units
+sculpt_start   #       4                       ;Initial mitring offset
+
+               ; --- Various buffers ---
+
+sculpt_small   #       16                      ;A small buffer
+sculpt_misc    #       256                     ;A handy buffer
+
+sculpt_wSize   EQU     {VAR}-sculpt_wStart
+
+
+scFlag_acorn   EQU     (1<<0)                  ;Use Acorn-style group box
+scFlag_unslab  EQU     (1<<31)                 ;We've just unslabbed an icon
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Utilities/Makefile,fe1 b/StraySrc/Utilities/Makefile,fe1
new file mode 100644 (file)
index 0000000..e837e0f
--- /dev/null
@@ -0,0 +1,311 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+PROGS = \
+       enumerate hour pathutil test \
+       each inst setdate setslot ssrclean submake \
+       chdrgen headergen \
+       buildstub fixlink msgaof resgen templaof
+
+CULIB = o.culib
+
+LIBS = $(CULIB) libs:aof.o.aof libs:o.astubs libs:o.swiv
+
+#----- Compiling things -----------------------------------------------------
+
+all: $(PROGS)
+
+# --- Assembler utilities ---
+
+ENUM_OBJ = o.enumerate
+ENUM_VER = 1.03
+enumerate: $(ENUM_OBJ)
+       $(SETDATE) o.ver-enum version="$(ENUM_VER) [$(DATE)] ($(CRIGHT))"
+       $(LD_UTIL) $(ENUM_OBJ) o.ver-enum
+       $(SET_UTIL)
+
+HOUR_OBJ = o.hour
+HOUR_VER = 1.00
+hour: $(HOUR_OBJ)
+       $(SETDATE) o.ver-hour version="$(HOUR_VER) [$(DATE)] ($(CRIGHT))"
+       $(LD_UTIL) $(HOUR_OBJ) o.ver-hour
+       $(SET_UTIL)
+
+PATH_OBJ = o.path_util o.pathutil
+PATH_VER = 1.10
+pathutil: $(PATH_OBJ)
+       $(SETDATE) o.ver-path version="$(PATH_VER) [$(DATE)] ($(CRIGHT))"
+       $(LD_UTIL) $(PATH_OBJ) o.ver-path
+       $(SET_UTIL)
+
+SLOT_OBJ = o.setslot
+SLOT_VER = 1.00
+setslot: $(SLOT_OBJ)
+       $(SETDATE) o.ver-slot version="$(SLOT_VER) [$(DATE)] ($(CRIGHT))"
+       $(LD_UTIL) $(SLOT_OBJ) o.ver-slot
+       $(SET_UTIL)
+
+TEST_OBJ = o.test
+TEST_VER = 1.00
+test: $(TEST_OBJ)
+       $(SETDATE) o.ver-test version="$(TEST_VER) [$(DATE)] ($(CRIGHT))"
+       $(LD_UTIL) $(TEST_OBJ) o.ver-test
+       $(SET_UTIL)
+
+# --- Various C programs ---
+
+EACH_OBJ = o.each $(LIBS)
+each: $(EACH_OBJ)
+       $(LD_APP) $(EACH_OBJ)
+       $(SQUEEZE)
+       $(SET_APP)
+
+INST_OBJ = o.inst $(LIBS)
+inst: $(INST_OBJ)
+       $(LD_APP) $(INST_OBJ)
+       $(SQUEEZE)
+       $(SET_APP)
+
+SDATE_OBJ = o.setdate $(LIBS)
+SDATE_VER = 1.00
+setdate: $(SDATE_OBJ)
+       $(SETDATE) o.ver-sdate _time="$(SDATE_VER) [$(DATE)] ($(CRIGHT))"
+       $(LD_APP) $(SDATE_OBJ) o.ver-sdate
+       $(SQUEEZE)
+       $(SET_APP)
+
+SSRC_OBJ = o.ssrclean $(LIBS)
+ssrclean: $(SSRC_OBJ)
+       $(LD_APP) $(SSRC_OBJ)
+       $(SQUEEZE)
+       $(SET_APP)
+
+SUBMAKE_OBJ = o.submake $(LIBS)
+submake: $(SUBMAKE_OBJ)
+       $(LD_APP) $(SUBMAKE_OBJ)
+       $(SQUEEZE)
+       $(SET_APP)
+
+# --- Sapphire header creation tools ---
+
+HGEN_OBJ = o.headergen $(LIBS)
+headergen: $(HGEN_OBJ)
+       $(LD_APP) $(HGEN_OBJ)
+       $(SQUEEZE)
+       $(SET_APP)
+
+CHGEN_OBJ = o.chdrgen $(LIBS)
+chdrgen: $(CHGEN_OBJ)
+       $(LD_APP) $(CHGEN_OBJ)
+       $(SQUEEZE)
+       $(SET_APP)
+
+# --- Basic tools ---
+
+buildstub: b.buildstub ex.buildstub
+       ccrunch -0 -xlibs:bas.exports -xex.buildstub b.buildstub buildstub
+
+fixlink: b.fixlink
+       ccrunch -0 b.fixlink fixlink
+
+msgaof: b.msgaof ex.msgaof
+       ccrunch -0 -xlibs:bas.exports -xex.msgaof b.msgaof msgaof
+
+resgen: b.resgen ex.resgen
+       ccrunch -0 -xlibs:bas.exports -xex.resgen b.resgen resgen
+
+templaof: b.templaof ex.templaof
+       ccrunch -0 -xlibs:bas.exports -xex.templaof b.templaof templaof
+
+# --- The common library ---
+
+LIBOBJS = o.alloc o.cmdr o.gf o.glob
+o.culib: $(LIBOBJS)
+       $(AR) -c $(CULIB) $(LIBOBJS)
+
+# --- Standard targets ---
+
+install: $(PROGS)
+       $(INSTALL) $(PROGS) <SSR$BinDir>
+       $(INSTALL) enumerate hour pathutil <SSR$DLLDir>
+
+clean:
+       -$(RM) o.* $(PROGS)
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
+setslot: s.setslot
+setslot: libs:header
+setslot: libs:swis
+setslot: libs:stream
+test: s.test
+test: libs:header
+test: libs:swis
+test: libs:stream
+o.enumerate: s.enumerate
+o.enumerate: libs:swis
+o.enumerate: libs:header
+o.hour: s.hour
+o.hour: libs:header
+o.hour: libs:swis
+o.hour: libs:stream
+o.path_util: s.path_util
+o.path_util: libs:header
+o.path_util: libs:swis
+o.path_util: sh.pathUtil
+o.pathutil: s.pathutil
+o.pathutil: libs:header
+o.pathutil: libs:swis
+o.test: s.test
+o.test: libs:header
+o.test: libs:swis
+o.test: libs:stream
+o.inst:        c.inst
+o.inst:        libs:h.swis
+o.inst:        libs:h.swiv
+o.inst:        c:h.kernel
+o.inst:        h.cmdr
+o.setdate:     c.setdate
+o.setdate:     libs:h.swis
+o.setdate:     c:h.kernel
+o.setdate:     libs:aof.h.aof
+o.setdate:     libs:aof.h.chunk
+o.setdate:     libs:h._time
+o.setslot: s.setslot
+o.setslot: libs:header
+o.setslot: libs:swis
+o.setslot: libs:stream
+o.ssrclean:    c.ssrclean
+o.ssrclean:    libs:h.swis
+o.ssrclean:    libs:h.swiv
+o.ssrclean:    c:h.kernel
+o.ssrclean:    h.cmdr
+o.chdrgen:     c.chdrgen
+o.chdrgen:     c:h.kernel
+o.alloc:       c.alloc
+o.alloc:       h.alloc
+o.cmdr:        c.cmdr
+o.cmdr:        libs:h.swis
+o.cmdr:        libs:h.swiv
+o.cmdr:        c:h.kernel
+o.cmdr:        h.alloc
+o.cmdr:        h.cmdr
+o.cmdr:        h.gf
+o.cmdr:        h.glob
+o.glob:        c.glob
+o.glob:        libs:h.swis
+o.glob:        libs:h.swiv
+o.glob:        c:h.kernel
+o.glob:        h.alloc
+o.glob:        h.gf
+o.glob:        h.glob
+o.submake:     c.submake
+o.submake:     libs:h.swis
+o.submake:     libs:h.swiv
+o.submake:     c:h.kernel
+o.submake:     h.alloc
+o.submake:     h.glob
+o.headergen:   c.headergen
+o.headergen:   c:h.kernel
+o.headergen:   libs:h.swis
+o.gf:  c.gf
+o.gf:  libs:h.swis
+o.gf:  libs:h.swiv
+o.gf:  c:h.kernel
+o.gf:  h.gf
+each:  c.each
+each:  libs:h.swis
+each:  libs:h.swiv
+each:  c:h.kernel
+each:  h.glob
+o.each:        c.each
+o.each:        c:h.kernel
+o.each:        libs:h.swis
+o.each:        libs:h.swiv
+o.each:        h.glob
diff --git a/StraySrc/Utilities/b/buildstub,ffb b/StraySrc/Utilities/b/buildstub,ffb
new file mode 100644 (file)
index 0000000..b0d9226
Binary files /dev/null and b/StraySrc/Utilities/b/buildstub,ffb differ
diff --git a/StraySrc/Utilities/b/fixlink,ffb b/StraySrc/Utilities/b/fixlink,ffb
new file mode 100644 (file)
index 0000000..df33d01
Binary files /dev/null and b/StraySrc/Utilities/b/fixlink,ffb differ
diff --git a/StraySrc/Utilities/b/msgaof,ffb b/StraySrc/Utilities/b/msgaof,ffb
new file mode 100644 (file)
index 0000000..75d7c7d
Binary files /dev/null and b/StraySrc/Utilities/b/msgaof,ffb differ
diff --git a/StraySrc/Utilities/b/resgen,ffb b/StraySrc/Utilities/b/resgen,ffb
new file mode 100644 (file)
index 0000000..68bb072
Binary files /dev/null and b/StraySrc/Utilities/b/resgen,ffb differ
diff --git a/StraySrc/Utilities/b/templaof,ffb b/StraySrc/Utilities/b/templaof,ffb
new file mode 100644 (file)
index 0000000..fc7f1fa
Binary files /dev/null and b/StraySrc/Utilities/b/templaof,ffb differ
diff --git a/StraySrc/Utilities/buildstub,ffb b/StraySrc/Utilities/buildstub,ffb
new file mode 100644 (file)
index 0000000..55731fe
Binary files /dev/null and b/StraySrc/Utilities/buildstub,ffb differ
diff --git a/StraySrc/Utilities/c/alloc b/StraySrc/Utilities/c/alloc
new file mode 100644 (file)
index 0000000..9a676bf
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * alloc.c
+ *
+ * Trivial veneers for allocating memory
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's core utilities (coreutils).
+ *
+ * Coreutils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Coreutils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with coreutils.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "alloc.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @xmalloc@ --- *
+ *
+ * Arguments:  @size_t sz@ = size of block to allocate
+ *
+ * Returns:    Pointer to newly allocated block.
+ *
+ * Use:                Returns a block of the requested size, or not at all.
+ */
+
+void *xmalloc(size_t sz)
+{
+  void *p = malloc(sz);
+  if (!p) {
+    fprintf(stderr, "inst: not enough memory\n");
+    exit(1);
+  }
+  return (p);
+}
+
+/* --- @xrealloc@ --- *
+ *
+ * Arguments:  @void *p@ = pointer to a block of memory
+ *             @size_t sz@ = size we want it to be
+ *
+ * Returns:    Pointer to resized block
+ *
+ * Use:                Resizes a block.  Returns the resized block, or not at all.
+ */
+
+void *xrealloc(void *p, size_t sz)
+{
+  p = realloc(p, sz);
+  if (!p) {
+    fprintf(stderr, "inst: not enough memory\n");
+    exit(1);
+  }
+  return (p);
+}
+
+/* --- @xstrdup@ --- *
+ *
+ * Arguments:  @const char *p@ = pointer to string to copy
+ *
+ * Returns:    Pointer to a copy of the string.
+ *
+ * Use:                Returns a copy of a string, or not at all.
+ */
+
+char *xstrdup(const char *p)
+{
+  size_t sz = strlen(p) + 1;
+  char *q = xmalloc(sz);
+  memcpy(q, p, sz);
+  return (q);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/StraySrc/Utilities/c/chdrgen b/StraySrc/Utilities/c/chdrgen
new file mode 100644 (file)
index 0000000..4ca37a6
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+ * chdrgen.c
+ *
+ * Generate csapph headers
+ *
+ * © 1995-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <time.h>
+
+
+#if defined(__riscos)
+  #include "kernel.h"
+  #define lasterr (_kernel_last_oserror()->errmess)
+#else
+  #define lasterr (strerror(errno))
+#endif
+
+static char buf[256];
+
+static int xtoi(const char *p)
+{
+  int base=10;
+  int flags=0;
+  int a=0;
+  unsigned t;
+  char ch;
+  int b10=0;
+
+  for (;;)
+  {
+    ch=*p++;
+    switch (ch)
+    {
+      case '&':
+      case '%':
+        if (flags & 0x3f) goto end;
+        if (ch=='&') base=16; else base=2;
+        flags|=(1<<5);
+        break;
+
+      case '_':
+        if ((flags & 0x30) || !(flags & (1<<2))) goto end;
+        base=b10;
+        flags=(flags & ~0xA) | (1<<5);
+        a=0;
+        break;
+
+      case '-':
+      case '+':
+        if (flags & 0x7f) goto end;
+        flags|=(1<<6);
+        if (ch=='-') flags|=(1<<7);
+        break;
+
+      default:
+        t=ch-'A';
+        if (t>=26) t=ch-'a';
+        if (t<26) flags|=(1<<0);
+        else
+        {
+          t=ch-'0';
+          if (t>=10) goto end;
+        }
+        if (t<10)
+        {
+          b10=(b10*10)+t;
+          flags|=(1<<2);
+        }
+        else
+          flags|=(1<<4);
+        if (!(flags&(1<<3)))
+        {
+          if (t<base)
+          {
+            a=(a*base)+t;
+            flags|=(1<<1);
+          }
+          else
+            flags|=(1<<3);
+        }
+        break;
+    }
+  }
+
+end:
+  if (flags & (1<<7)) a=-a;
+  return (a);
+}
+
+static void dogen(FILE *in,FILE *out,char *inn,char *outn)
+{
+  char *p,*q,*r,*s;
+  int ch;
+  time_t t;
+  unsigned int var = 0;
+  int macro=0;
+  int type=0;
+  int i;
+  char *footer="";
+  int flags=2;
+
+  time(&t);
+  strftime(buf,256,"%d %B %Y",localtime(&t));
+
+  p=outn; q=p;
+  while (*p)
+  {
+    if (*p=='.') q=p+1;
+    p++;
+  }
+
+  p=inn; r=p;
+  while (*p)
+  {
+    if (*p=='.') r=p+1;
+    p++;
+  }
+
+  fprintf(out,
+          "/*\n"
+          " * %s.h\n"
+          " *\n"
+          " * [Generated from %s, %s]\n"
+          " */\n"
+          "\n"
+          "#if !defined(__CC_NORCROFT) || !defined(__arm)\n"
+          "#  error You must use the Norcroft ARM Compiler for Sapphire "
+                                       "programs\n"
+          "endif\n"
+          "\n"
+          "#pragma include_only_once\n"
+          "#pragma force_top_level\n"
+          "\n"
+          "#ifndef __%s_h\n"
+          "#define __%s_h\n"
+          "\n"
+          "#ifndef __sapphire_h\n"
+          "#  include \"sapphire.h\"\n"
+          "#endif\n"
+          "\n",
+          q,r,buf,q,q);
+
+  do
+  {
+    p=buf;
+    while (ch=getc(in),ch!=EOF && ch!='\n')
+      *p++=ch;
+    *p++=0;
+    p=buf;
+    while (!isspace(*p) && *p)
+      p++;
+    s=p;
+    while (isspace(*p) && *p)
+      p++;
+    q=p;
+    while (!isspace(*q) && *q)
+      q++;
+    r=q;
+    while (isspace(*r) && *r)
+      r++;
+    if (*buf!=';') *q=*s=0;
+
+    if (!strcmp(p,"MACRO"))
+      macro=1;
+    else if (!strcmp(p,"MEND"))
+      macro=0;
+    else if (macro)
+      /* ... */;
+    else if (*buf==';')
+    {
+      if (flags & 2)
+        continue;
+      else if (type!=4)
+        { fputs(footer,out); type=4; footer=" */\n\n"; flags=0; }
+      else
+        flags=1;
+      switch (buf[1])
+      {
+        case '-':
+          fputs("/*",out);
+          i=3;
+          p=buf+1;
+          while (*p=='-') { putc(*p++,out); i++; }
+          while (*p!='-') { putc(*p++,out); i++; }
+          while (i<76) { putc('-',out); i++; }
+          ch=getc(in);
+          fputs(ch==';' ? "*\n" : "*/\n",out);
+          ungetc(ch,in);
+          if (ch!=';') footer="\n";
+          break;
+        case '+':
+          /* A BAS directive.  Yawn. */
+          type=0; footer="";
+          break;
+        case ' ':
+          if (buf[2]=='-')
+          {
+            fputs(flags & 1 ? " *" : "/*",out);
+            fputs(buf+1,out);
+            ch=getc(in);
+            fputs(ch==';' ? " *\n" : " */\n",out);
+            ungetc(ch,in);
+            if (ch!=';') footer="\n";
+            break;
+          }
+        default:
+          fputs(flags & 1 ? " *" : "/*",out);
+          fputs(buf+1,out);
+          putc('\n',out);
+          break;
+      }
+    }
+    else if (r==buf)
+    {
+      if (type!=0) { fputs(footer,out); type=0; footer=""; }
+      flags=0;
+    }
+    else if (!strcmp(p,"IMPORT"))
+    {
+      if (type!=1) { fputs(footer,out); type=1; footer="\n"; }
+      fprintf(out,"extern routine %s;\n",r);
+    }
+    else if (!strcmp(p,"EQU"))
+    {
+      if (type!=2) { fputs(footer,out); type=2; footer="\n"; }
+      fprintf(out,"#define %s (",buf);
+      i=0;
+      while (*r)
+      {
+        switch (*r)
+        {
+          case '&': while (i--) putc(' ',out); fputs("0x",out); i=0; break;
+          case ' ': case 9: i++; break;
+          case ';': goto end;
+          default:  while (i--) putc(' ',out); putc(*r,out); i=0; break;
+        }
+        r++;
+      }
+    end:
+      fputs(")\n",out);
+    }
+    else if (!strcmp(p,"^"))
+    {
+      var=xtoi(r);
+      type=0;
+    }
+    else if (!strcmp(p,"#"))
+    {
+      if (type!=3) { fputs(footer,out); type=3; footer="\n"; }
+      if (*buf) fprintf(out,"#define %s %i\n",buf,var);
+      var+=xtoi(r);
+    }
+  }
+  while (!feof(in));
+
+  if (type!=0) putc('\n',out);
+  fputs("#endif\n",out);
+}
+
+int main(int argc,char *argv[])
+{
+  FILE *in,*out;
+  if (argc!=3)
+  {
+    fprintf(stderr,"Usage: chdrgen <asm-header> <c-header>\n");
+    exit (1);
+  }
+  if (in=fopen(argv[1],"r"),!in) goto tidy_0;
+  if (out=fopen(argv[2],"w"),!out) goto tidy_1;
+  dogen(in,out,argv[1],argv[2]);
+  fclose(out);
+  fclose(in);
+  return (0);
+
+tidy_1:
+  fclose(in);
+tidy_0:
+  fprintf(stderr,"%s\n",lasterr);
+  exit(1);
+}
diff --git a/StraySrc/Utilities/c/cmdr b/StraySrc/Utilities/c/cmdr
new file mode 100644 (file)
index 0000000..6b55a4d
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * cmdr.c
+ *
+ * Perform expansions on the command line arguments
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's core utilities (coreutils).
+ *
+ * Coreutils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Coreutils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with coreutils.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "swis.h"
+#include "swiv.h"
+
+#include "alloc.h"
+#include "cmdr.h"
+#include "gf.h"
+#include "glob.h"
+
+/*----- Type definitions --------------------------------------------------*/
+
+typedef struct cmdr_ctx {
+  char **av;                           /* Pointer to @argv@ array */
+  size_t sz;                           /* Size currently allocated */
+  size_t i;                            /* Next available @argv@ index */
+} cmdr_ctx;
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @cmdr_add@ --- *
+ *
+ * Arguments:  @const char *p@ = pointer to an expanded item
+ *             @void *ctx@ = pointer to my context
+ *
+ * Returns:    ---
+ *
+ * Use:                Adds a globbed filename to the output buffer.
+ */
+
+static void cmdr_add(const char *p, void *ctx)
+{
+  cmdr_ctx *cx = ctx;
+
+  if (cx->i == cx->sz) {
+    cx->sz += 1024;
+    cx->av = xrealloc(cx->av, cx->sz * sizeof(cx->av[0]));
+  }
+  cx->av[cx->i++] = xstrdup(p);
+}
+
+/* --- @cmdreplace@ --- *
+ *
+ * Arguments:  @int *argc@ = pointer to argument count
+ *             @char ***argv@ = address of pointer to arg list
+ *
+ * Returns:    ---
+ *
+ * Use:                Mangles the argument list until it's nice.
+ */
+
+void cmdreplace(int *argc, char ***argv)
+{
+  cmdr_ctx cx;
+  char **iav = *argv;
+  int iac = 0;
+
+  /* --- Initialise the context --- */
+
+  cx.sz = 256;
+  cx.av = xmalloc(cx.sz * sizeof(cx.av[0]));
+  cx.i = 0;
+
+  /* --- Copy over @argv[0]@ because it's special --- */
+
+  cx.av[cx.i++] = iav[iac++];
+
+  /* --- Copy over everything else --- */
+
+  while (iav[iac]) {
+    if (glob(iav[iac], cmdr_add, &cx) == 0) {
+      if (cx.i == cx.sz) {
+        cx.sz += 1024;
+        cx.av = xrealloc(cx.av, cx.sz * sizeof(cx.av[0]));
+      }
+      cx.av[cx.i++] = iav[iac];
+    }
+    iac++;
+  }
+
+  /* --- Copy over the terminator --- */
+
+  if (cx.i == cx.sz) {
+    cx.sz += 1024;
+    cx.av = xrealloc(cx.av, cx.sz * sizeof(cx.av[0]));
+  }
+  cx.av[cx.i] = 0;
+
+  /* --- Return appropriate values to the caller --- */
+
+  *argc = cx.i;
+  *argv = cx.av;
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/StraySrc/Utilities/c/each b/StraySrc/Utilities/c/each
new file mode 100644 (file)
index 0000000..2dfdb29
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * each.c
+ *
+ * Run a command on each of a bunch of files
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "kernel.h"
+#include "swis.h"
+#include "swiv.h"
+
+#include "glob.h"
+
+/*----- Run commands ------------------------------------------------------*/
+
+typedef struct each_ctx {
+  int estat;
+  const char *skel;
+  size_t sksz;
+} each_ctx;
+
+/* --- @run@ --- *
+ *
+ * Arguments:   @const char *f@ = pointer to a filename
+ *              @void *ctx@ = pointer to a context block
+ *
+ * Returns:     ---
+ *
+ * Use:         Handles files.
+ */
+
+static void run(const char *f, void *ctx)
+{
+  each_ctx *ex = ctx;
+  char buf[1024];
+  int e;
+
+  _swi(OS_SubstituteArgs, _inr(0, 4),
+       f, buf, sizeof(buf), ex->skel, ex->sksz);
+  e = system(buf);
+  switch (e) {
+    case 0:
+      /* Nothing to do */;
+      break;
+    case -2:
+      fprintf(stderr, "each: couldn't run `%s': %s\n",
+              buf, _kernel_last_oserror()->errmess);
+    default:
+      ex->estat = e;
+      break;
+  }
+}
+
+/* --- @main@ --- *
+ *
+ * Arguments:  @int argc@ = number of arguments
+ *             @char *argv[]@ = list of arguments
+ *
+ * Returns:    Zero if all went well
+ *
+ * Use:                Installs files in the right places.  This is a bit of a
+ *             rip-off of unix `cp'.
+ */
+
+int main(int argc, char *argv[])
+{
+  each_ctx ex;
+  int i;
+
+  /* --- Make sure we have some arguments --- */
+
+  if (argc < 3) {
+    fprintf(stderr, "Usage: each COMMAND FILE...\n");
+    exit(1);
+  }
+
+  /* --- Go to work --- */
+
+  ex.skel = argv[1];
+  ex.sksz = strlen(ex.skel);
+  ex.estat = 0;
+
+  for (i = 2; i < argc; i++) {
+    if (glob(argv[i], run, &ex) == 0)
+      run(argv[i], &ex);
+  }
+
+  /* --- Done --- */
+
+  return (ex.estat);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/StraySrc/Utilities/c/gf b/StraySrc/Utilities/c/gf
new file mode 100644 (file)
index 0000000..7b4e06a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * gf.c
+ *
+ * Read directories in a buffered way
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's core utilities (coreutils).
+ *
+ * Coreutils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Coreutils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with coreutils.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "swis.h"
+#include "swiv.h"
+
+#include "gf.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @gf_init@ --- *
+ *
+ * Arguments:  @gf_ctx *g@ = pointer to a context buffer for me
+ *             @const char *pat@ = pointer to a (RISC OS) pattern string
+ *             @cost char *dir@ = pointer to name of parent directory
+ *
+ * Returns:    ---
+ *
+ * Use:                Initialise a wildcard match context ready for scanning.
+ */
+
+void gf_init(gf_ctx *g, const char *pat, const char *dir)
+{
+  g->ctx = 0;
+  g->pat = pat;
+  g->dir = dir;
+  g->nleft = 0;
+}
+
+/* --- @gf_next@ --- *
+ *
+ * Arguments:  @gf_ctx *g@ = pointer to my context
+ *
+ * Returns:    Pointer to a filename, or zero for end
+ *
+ * Use:                Returns the next matching file from the block.
+ */
+
+char *gf_next(gf_ctx *g)
+{
+  /* --- See if the buffer is empty --- */
+
+  while (!g->nleft) {
+
+    /* --- Check for end of the list --- */
+
+    if (g->ctx == -1)
+      return (0);
+
+    /* --- Fetch some more items from the list --- */
+
+    g->p = g->buf;
+    if (_swix(OS_GBPB, _inr(0, 6) | _out(3) | _out(4),
+              9, g->dir, g->buf, 1024, g->ctx, sizeof(g->buf), g->pat,
+              &g->nleft, &g->ctx))
+      return (0);
+  }
+
+  /* --- Dole out the next item from the list --- */
+
+  {
+    char *p = g->p;
+
+    while (*g->p)
+      g->p++;
+    g->p++;
+    g->nleft--;
+    return (p);
+  }
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/StraySrc/Utilities/c/glob b/StraySrc/Utilities/c/glob
new file mode 100644 (file)
index 0000000..70177db
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * glob.c
+ *
+ * Full file wildcard matching
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's core utilities (coreutils).
+ *
+ * Coreutils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Coreutils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with coreutils.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "swis.h"
+#include "swiv.h"
+
+#include "alloc.h"
+#include "gf.h"
+#include "glob.h"
+
+/*----- Type definitions --------------------------------------------------*/
+
+typedef struct glob_ctx {
+  char buf[1024];                      /* Pointer to output buffer */
+  void (*proc)(const char *, void *);  /* User procedure */
+  void *ctx;                           /* Context to pass the procedure */
+  int done;                            /* Number of matches found */
+} glob_ctx;
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- Wildcard syntax --- *
+ *
+ * The wildcards `*' and `#' do what they normally do: match zero-or-more
+ * and any-one characters respectively.  Additionally, a `.' where a
+ * filename is expected will search recursively down the directory
+ * structure.  Only globby matches with really existing things are counted;
+ * if a name contains nothing globbable then it matches nothing.  This is
+ * done for speed: I expect the client to use a name literally if it fails
+ * to match anything.  The syntax is a sort of blend between traditional
+ * RISC OS and kpathsea.
+ */
+
+/* --- Hack note --- *
+ *
+ * This will fail gloriously given something like `adfs::ak*ha.$.foo.*'.
+ * Do I look like I care?  This program has already taken five times longer
+ * than it should have done because I decided I wanted to do wildcarding.
+ */
+
+/* --- Forward reference --- */
+
+static void glob_do(glob_ctx *g, char *p, char *in);
+
+/* --- @glob_got@ --- *
+ *
+ * Arguments:  @glob_ctx *g@ = pointer to my context
+ *             @char *p@ = pointer to current position in buffer
+ *             @char *fn@ = filename to add
+ *             @char *in@ = rest of wildcard pattern to match
+ *
+ * Returns:    ---
+ *
+ * Use:                Handles a matched filename in the glob matcher.
+ */
+
+static void glob_got(glob_ctx *g, char *p, char *fn, char *in)
+{
+  size_t sz;
+
+  /* --- Build the filename --- */
+
+  if (p != g->buf)
+    *p++ = '.';
+  sz = strlen(fn);
+  memcpy(p, fn, sz + 1);
+  p += sz;
+
+  /* --- See if this is the final element --- */
+
+  if (!in) {
+    int ty;
+
+    if (_swix(OS_File, _inr(0, 1) | _out(0), 17, g->buf, &ty) || !ty)
+      return;
+    g->done++;
+    g->proc(g->buf, g->ctx);
+  } else
+    glob_do(g, p, in);
+}
+
+/* --- @glob_match@ --- *
+ *
+ * Arguments:  @const char *pat@ = pointer to pattern string
+ *             @const char *s@ = pointer to candidate string
+ *
+ * Returns:    Nonzero if pattern matches candidate.
+ *
+ * Use:                Tries to match globbily.  This is very simple stuff.
+ *             I may add character classes later if I feel really eager.
+ */
+
+static int glob_match(const char *pat, const char *s)
+{
+  for (;;) {
+    if (!*pat && !*s)
+      return (1);
+    else if (!*pat)
+      return (0);
+    else if (*pat == '*') {
+      do pat++; while (*pat == '*');
+      do {
+        if (glob_match(pat, s))
+          return (1);
+      } while (*s++);
+      return (0);
+    } else if (!*s)
+      return (0);
+    else if (*pat != '#' && tolower(*pat) != tolower(*s))
+      return (0);
+    else
+      pat++, s++;
+  }
+}
+
+/* --- @glob_do@ --- *
+ *
+ * Arguments:  @glob_ctx *g@ = pointer to my context
+ *             @char *p@ = pointer to current position in buffer
+ *             @char *in@ = rest of wildcard pattern to match
+ *
+ * Returns:    ---
+ *
+ * Use:                Main recursive glob matcher.
+ */
+
+static void glob_do(glob_ctx *g, char *p, char *in)
+{
+  char *q;
+  char *rec = 0;
+
+  /* --- Pick out the next component of the pathname --- */
+
+  if (*in == '.') {
+    do in++; while (*in == '.');
+    rec = in - 1;
+    if (!*in) in = "*";
+  }
+
+  q = strchr(in, '.');
+  if (q)
+    *q++ = 0;
+  else
+    q = 0;
+
+  /* --- See if this contains any wildcards --- */
+
+  if (rec) {
+    gf_ctx gx;
+    char *n;
+    char *qq = q ? q - 1 : 0;
+    for (gf_init(&gx, "*", g->buf); *p = 0, (n = gf_next(&gx)) != 0; ) {
+      if (qq) *qq = 0;
+      if (glob_match(in, n))
+        glob_got(g, p, n, q);
+      if (qq) *qq = '.';
+      glob_got(g, p, n, rec);
+    }
+  } else if (strpbrk(in, "*#")) {
+    gf_ctx gx;
+    char *n;
+    for (gf_init(&gx, in, g->buf); *p = 0, (n = gf_next(&gx)) != 0; )
+      glob_got(g, p, n, q);
+  } else
+    glob_got(g, p, in, q);
+}
+
+/* --- @glob@ --- *
+ *
+ * Arguments:  @const char *pat@ = pointer to pattern string to match
+ *             @void (*proc)(const char *, void *)@ = client function
+ *             @void *ctx@ = context pointer to pass function
+ *
+ * Returns:    Number of filenames matched.
+ *
+ * Use:                Does filename globbing.
+ */
+
+int glob(const char *pat, void (*proc)(const char *, void *), void *ctx)
+{
+  glob_ctx gx;
+  char *in;
+
+  if (!strpbrk(pat, "*#") && !strstr(pat, ".."))
+    return (0);
+
+  gx.proc = proc;
+  gx.ctx = ctx;
+  gx.done = 0;
+  in = xstrdup(pat);
+  glob_do(&gx, gx.buf, in);
+  free(in);
+  return (gx.done);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/StraySrc/Utilities/c/headerGen b/StraySrc/Utilities/c/headerGen
new file mode 100644 (file)
index 0000000..0757d15
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * headerGen.c
+ *
+ * Generate Sapphire headers automatically
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "kernel.h"
+#include "swis.h"
+
+static void swi(int s,_kernel_swi_regs *r)
+{
+  _kernel_oserror *e=_kernel_swi(s,r,r);
+  if (e)
+  {
+    fprintf(stderr,"Arrghh -- %s\n",e->errmess);
+    exit(1);
+  }
+}
+
+static char *getline(char **p,char *b)
+{
+  while (**p!=10)
+    *b++=*((*p)++);
+  *b=0;
+  (*p)++;
+  return (b);
+}
+
+static void headergen(char *buff,char *infile,char *outfile)
+{
+  FILE *fp;
+  char b[256];
+  char *p;
+  char *leaf=strrchr(infile,'.');
+
+  if (!leaf)
+    leaf=outfile;
+  else
+    leaf++;
+
+  if (fp=fopen(outfile,"w"),!fp)
+  {
+    fprintf(stderr,"Couldn't open output\n");
+    exit(1);
+  }
+
+  /* --- Do the header (this bit's a little fragile) --- */
+
+  getline(&buff,b);
+  fprintf(fp,"%s\n",b);
+
+  getline(&buff,b);
+  fprintf(fp,"%sh\n",b);
+
+  getline(&buff,b);
+  fprintf(fp,"%s\n",b);
+
+  p=getline(&buff,b);
+  if (p[-1]==')' && p[-5]=='(')
+    p[-6]=0;
+  fprintf(fp,"%s\n",b);
+
+  getline(&buff,b);
+  fprintf(fp,"%s\n",b);
+
+  getline(&buff,b);
+  fprintf(fp,"%s\n",b);
+
+  getline(&buff,b);
+  fprintf(fp,"%s\n",b);
+
+  getline(&buff,b);
+  fprintf(fp,"%s\n",b);
+
+  fprintf(fp,";----- Licensing note -------------------------------------------------------\n"
+             ";\n"
+             "; This file is part of Straylight's Sapphire library.\n"
+             ";\n"
+             "; Sapphire is free software; you can redistribute it and/or modify\n"
+             "; it under the terms of the GNU General Public License as published by\n"
+             "; the Free Software Foundation; either version 2, or (at your option)\n"
+             "; any later version.\n"
+             ";\n"
+             "; Sapphire is distributed in the hope that it will be useful,\n"
+             "; but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+             "; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
+             "; GNU General Public License for more details.\n"
+             ";\n"
+             "; You should have received a copy of the GNU General Public License\n"
+             "; along with Sapphire.  If not, write to the Free Software Foundation,\n"
+             "; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"
+             "\n"
+             ";----- Overview -------------------------------------------------------------\n"
+             ";\n"
+             "; Functions provided:\n"
+             ";\n");
+
+  /* --- Search for all EXPORTs and output them in the overview --- */
+
+  {
+    char *bb=buff;
+    do
+    {
+      getline(&bb,b);
+      if (!memcmp(b,"\t\tEXPORT",8))
+      {
+        p=b+8;
+        while (!isalnum(*p) && !(*p=='_'))
+          p++;
+        fprintf(fp,";  ");
+        while (isalnum(*p) || *p=='_')
+          fputc(*p++,fp);
+        fputc('\n',fp);
+      }
+    }
+    while (memcmp(b,"\t\tEND",5));
+  }
+  fputc('\n',fp);
+
+  fprintf(fp,"\t\t[\t:LNOT::DEF:%s__dfn\n"
+             "\t\tGBLL\t%s__dfn\n"
+             "\n",
+             leaf,leaf);
+
+  /* --- Now output the block comments etc. --- */
+
+  {
+    char *bb=buff;
+    char *ob=bb;
+    char *cm=0;
+    char *ocm=(char *)0x80000000;
+    do
+    {
+      getline(&bb,b);
+      if (*b==';' && !cm)
+      {
+        cm=ob;
+      }
+      else if (*b!=';' && cm)
+      {
+        ocm=cm;
+        cm=0;
+      }
+      if (!memcmp(b,"\t\tEXPORT",8))
+      {
+        for (p=ocm;p<ob;p++)
+          fputc(*p,fp);
+        fprintf(fp,"\t\tIMPORT\t%s\n\n",b+9);
+      }
+      ob=bb;
+    }
+    while (memcmp(b,"\t\tEND",5));
+  }
+
+  fprintf(fp,"\t\t]\n"
+             "\n"
+             ";----- That's all, folks ----------------------------------------------------\n"
+             "\n"
+             "\t\tEND\n");
+
+  fclose(fp);
+}
+
+int main(int argc,char *argv[])
+{
+  if (argc!=3)
+  {
+    fprintf(stderr,"Syntax: headerGen <input> <output>\n");
+    exit(1);
+  }
+
+  /* --- Load input file into mondo buffer --- */
+
+  {
+    _kernel_swi_regs r;
+    char *fb;
+    r.r[0]=17;
+    r.r[1]=(int)argv[1];
+    swi(OS_File,&r);
+    if (fb=malloc(r.r[4]),!fb)
+    {
+      fprintf(stderr,"No memory -- buy some more\n");
+      exit(1);
+    }
+    r.r[0]=16;
+    r.r[1]=(int)argv[1];
+    r.r[2]=(int)fb;
+    r.r[3]=0;
+    swi(OS_File,&r);
+    headergen(fb,argv[1],argv[2]);
+  }
+  return (0);
+}
diff --git a/StraySrc/Utilities/c/inst b/StraySrc/Utilities/c/inst
new file mode 100644 (file)
index 0000000..e5442a8
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * inst.c
+ *
+ * Copy files about an Acorn system
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "swis.h"
+#include "swiv.h"
+
+#include "cmdr.h"
+
+/*----- Install programs --------------------------------------------------*/
+
+static int exitstat = 0;               /* Exit status */
+
+/* -- @copy@ --- *
+ *
+ * Arguments:  @const char *s@ = pointer to source filename
+ *             @const char *d@ = pointer to destination filename
+ *
+ * Returns:    ---
+ *
+ * Use:                Copies a file.
+ */
+
+static void copy(const char *s, const char *d)
+{
+  _kernel_oserror *e;
+
+  e = _swix(OS_FSControl, _inr(0, 3), 26, s, d, 0x1002);
+  if (e) {
+    fprintf(stderr, "inst: error copying `%s' to `%s': %s\n",
+            s, d, e->errmess);
+    exitstat = 1;
+  }
+}
+
+/* --- @main@ --- *
+ *
+ * Arguments:  @int argc@ = number of arguments
+ *             @char *argv[]@ = list of arguments
+ *
+ * Returns:    Zero if all went well
+ *
+ * Use:                Installs files in the right places.  This is a bit of a
+ *             rip-off of unix `cp'.
+ */
+
+int main(int argc, char *argv[])
+{
+  const char *d;
+  int ty;
+
+  /* --- Expand wildcards in the arguments --- */
+
+  cmdreplace(&argc, &argv);
+
+  /* --- Report an error if there aren't enough arguments --- */
+
+  if (argc < 3) {
+    fprintf(stderr,
+            "Usage:\n"
+            "        inst SRCFILE DSTFILE\n"
+            "        inst SRCFILE [SRCFILE...] DSTDIR\n");
+    exit(1);
+  }
+
+  /* --- Sort out how to copy things --- */
+
+  d = argv[argc - 1];
+  ty = _swi(OS_File, _inr(0, 1) | _return(0), 17, d);
+
+  if (ty < 2 && argc > 3) {
+    fprintf(stderr,
+            "inst: too many files; destination is not a directory\n");
+    exit(1);
+  }
+
+  /* --- Do the copying --- */
+
+  if ((ty & 1 || ty == 0) && argc == 3)
+    copy(argv[1], argv[2]);
+  else {
+    char buf[1024];
+    size_t sz = strlen(d);
+    int i;
+
+    memcpy(buf, d, sz);
+    buf[sz] = '.';
+
+    for (i = 1; i < argc - 1; i++) {
+      char *p = strrchr(argv[i], '.');
+      if (p) p++; else p = argv[i];
+      strcpy(buf + sz + 1, p);
+      copy(argv[i], buf);
+    }
+  }
+
+  /* --- Done --- */
+
+  return (exitstat);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/StraySrc/Utilities/c/setdate b/StraySrc/Utilities/c/setdate
new file mode 100644 (file)
index 0000000..eaf8600
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * setdate.c
+ *
+ * Generate AOF file containing date strings
+ *
+ * © 1994-1998 Straylight
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's core utilities (coreutils).
+ *
+ * Coreutils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Coreutils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with coreutils.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "swis.h"
+#include "kernel.h"
+
+#include "aof/aof.h"
+#include "aof/chunk.h"
+
+#include "_time.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+static aof_file setdate_aof;
+
+static int cistrcmp(const char *s1,const char *s2)
+{
+  char c1;
+  char c2;
+  while (*s1 || *s2)
+  {
+    c1=tolower(*(s1++));
+    c2=tolower(*(s2++));
+    if (c1!=c2)
+      return (c1-c2);
+  }
+  return (0);
+}
+
+void aof_error(void)
+{
+  fprintf(stderr,"setdate: not enough memory.\n");
+  exit(1);
+}
+
+static void setdate_addSymbol(char *ident,char *format)
+{
+  _kernel_swi_regs r;
+  int osword[20];
+  char string[256];
+  char time[256];
+  char *p,*q,c;
+
+  /* --- Get the current date --- */
+
+  osword[0]=3;
+  _kernel_osword(14,osword);
+  r.r[0]=(int)osword;
+  r.r[1]=(int)time;
+  r.r[2]=256;
+  r.r[3]=(int)format;
+  if (_kernel_swi(OS_ConvertDateAndTime,&r,&r)!=0)
+  {
+    fprintf(stderr,"setdate: invalid date format.\n");
+    exit(1);
+  }
+
+  /* --- Translate our own magic control characters in the string --- */
+
+  p=time;
+  q=string;
+  while (*p)
+  {
+    switch (c=*p++)
+    {
+      case '\\':
+        switch (c=*p++)
+        {
+          case 't':
+            if (q-string<8)
+              *q++=9;
+            *q++=9;
+            break;
+          case '\\':
+            *q++='\\';
+            break;
+        }
+        break;
+      default:
+        *q++=c;
+        break;
+    }
+  }
+  *q=0;
+
+  /* --- Add the string to the AREA and give it a symbol --- */
+
+  aof_addsym(ident,
+             aof_string(string,setdate_aof.area),
+             0,
+             4,
+             &setdate_aof);
+}
+
+int main(int argc,char *argv[])
+{
+  int o;
+  int i;
+  char *p;
+  char *format;
+  FILE *fp;
+  char *pname;
+
+  aof_chunkinfo obj_area={0};
+  aof_chunkinfo obj_symt={0};
+  aof_chunkinfo obj_strt={0};
+  aof_chunkinfo reloc={0};
+  aof_chunkinfo obj_head={0};
+  aof_chunkinfo obj_idfn={0};
+
+  pname=strrchr(argv[0],'.');
+  if (!pname)
+    pname=argv[0];
+  else
+    pname++;
+
+  if (argc==1)
+  {
+    fprintf(stderr,
+            "Usage: %s <outfile> <identifier>[=<dateformat>]...\n",
+            pname);
+    exit(0);
+  }
+  else if (!cistrcmp(argv[1],"-help"))
+  {
+    fprintf(stderr,
+
+"%s version 1.00 [%s]\n"
+"\n"
+"  © 1994 Straylight\n"
+"\n"
+"Syntax: %s <outfile> <identifier>[=<dateformat>]...\n"
+"\n"
+"dateformat contains literal characters and format specifiers.  Format\n"
+"specifiers consist of a '%%' sign, an optional 'z' (indicating\n"
+"suppression of leading zero) and a two character format string, as\n"
+"follows:\n"
+"\n"
+"String  Value\n"
+"\n"
+"  cs    centiseconds\n"
+"  se    seconds\n"
+"  mi    minutes\n"
+"  12    12-hour style hours\n"
+"  24    14-hour style hours\n"
+"am/pm   'am' or 'pm' as appropriate\n"
+"  we    full weekday name\n"
+"  w3    abbreviated weekday name\n"
+"  wn    weekday number\n"
+"  dy    day of the month\n"
+"  st    suffix for day (e.g. 'st', 'nd', 'th' etc.)\n"
+"  mo    full month name\n"
+"  m3    abbreviated month name\n"
+"  mn    month number\n"
+"  ce    century number\n"
+"  yr    year number within century\n"
+"  wk    number of week in the year\n"
+"  dn    number of day in the year\n"
+"  tz    current time zone name\n"
+"  %%     insert a literal '%%' sign\n"
+"\n"
+"If no dateformat is specifed, a default of '%%zdy %%mo %%ce%%yr' is\n"
+"used.\n",
+
+            pname,
+            _time,
+            pname);
+    exit(0);
+  }
+
+  if (fp=fopen(argv[1],"wb"),!fp)
+  {
+    fprintf(stderr,"setdate: couldn't open output file.\n");
+    exit(1);
+  }
+
+  setdate_aof.area=&obj_area;
+  setdate_aof.symt=&obj_symt;
+  setdate_aof.strt=&obj_strt;
+  setdate_aof.reloc=&reloc;
+
+  /* --- Set up module identification --- */
+
+  aof_string("Straylight setdate utility 1.00",
+             &obj_idfn);
+  aof_align(obj_idfn);
+
+  /* --- Add in the AREA name --- */
+
+  aof_int(0,&obj_strt);
+  aof_string("SetDate$$Data",&obj_strt);
+
+  /* --- Create the date information in the AREA section --- */
+
+  for (i=2;i<argc;i++)
+  {
+    format="%zDY %MO %CE%YR";
+    for (p=argv[i];*p;p++)
+    {
+      if (*p=='=')
+      {
+        *p=0;
+        format=p+1;
+      }
+    }
+    setdate_addSymbol(argv[i],format);
+  }
+  aof_align(obj_area);
+
+  /* --- Build AOF header information --- */
+
+  aof_int((int)aof_RELOC,&obj_head);
+  aof_int(200,&obj_head);
+  aof_int(1,&obj_head);
+  aof_int(obj_symt.next/sizeof(aof_symbol),&obj_head);
+  aof_int(0,&obj_head);
+  aof_int(0,&obj_head);
+
+  aof_int(4,&obj_head);
+  aof_int(0x00002202,&obj_head);
+  aof_int(obj_area.next,&obj_head);
+  aof_int(reloc.next/8,&obj_head);
+  aof_int(0,&obj_head);
+
+  /* --- Add relocation stuff to AREA chunk --- */
+
+  aof_addBlock(reloc.p,reloc.next,&obj_area);
+
+  /* --- Complete string table by adding length word --- */
+
+  aof_fill(obj_strt.next,0,&obj_strt);
+  aof_align(obj_strt);
+
+  /* --- Write completed AOF file out to disk */
+
+  {
+    char _buf[sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry)];
+    chunk_header *h=(chunk_header *)&_buf;
+
+    h->hdr.id=chunk_MAGIC;
+    h->hdr.maxChunks=h->hdr.numChunks=5;
+
+    memcpy(h->table[0].chunkName,"OBJ_IDFN",8);
+    memcpy(h->table[1].chunkName,"OBJ_HEAD",8);
+    memcpy(h->table[2].chunkName,"OBJ_AREA",8);
+    memcpy(h->table[3].chunkName,"OBJ_SYMT",8);
+    memcpy(h->table[4].chunkName,"OBJ_STRT",8);
+
+    o=sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry);
+
+    h->table[0].offset=o;
+    h->table[0].size=obj_idfn.next;
+    o+=obj_idfn.next;
+
+    h->table[1].offset=o;
+    h->table[1].size=obj_head.next;
+    o+=obj_head.next;
+
+    h->table[2].offset=o;
+    h->table[2].size=obj_area.next;
+    o+=obj_area.next;
+
+    h->table[3].offset=o;
+    h->table[3].size=obj_symt.next;
+    o+=obj_symt.next;
+
+    h->table[4].offset=o;
+    h->table[4].size=obj_strt.next;
+    o+=obj_strt.next;
+
+    fwrite(h,sizeof(chunk_fixedHeader)+5*sizeof(chunk_tableEntry),1,fp);
+    fwrite(obj_idfn.p,obj_idfn.next,1,fp);
+    fwrite(obj_head.p,obj_head.next,1,fp);
+    fwrite(obj_area.p,obj_area.next,1,fp);
+    fwrite(obj_symt.p,obj_symt.next,1,fp);
+    fwrite(obj_strt.p,obj_strt.next,1,fp);
+    fclose(fp);
+
+    free(obj_idfn.p);
+    free(obj_area.p);
+    free(obj_strt.p);
+    free(obj_head.p);
+    free(obj_symt.p);
+  }
+}
diff --git a/StraySrc/Utilities/c/ssrclean b/StraySrc/Utilities/c/ssrclean
new file mode 100644 (file)
index 0000000..48ea5ea
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * ssrclean.c
+ *
+ * Delete lots of files (saves typing in Makefiles)
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "swis.h"
+#include "swiv.h"
+
+#include "cmdr.h"
+
+/*----- Install programs --------------------------------------------------*/
+
+static int exitstat = 0;               /* Exit status */
+
+/* -- @wipe@ --- *
+ *
+ * Arguments:  @const char *f@ = pointer to filename
+ *
+ * Returns:    ---
+ *
+ * Use:                Expunges a file.
+ */
+
+static void wipe(const char *f)
+{
+  _kernel_oserror *e;
+
+  e = _swix(OS_FSControl, _in(0) | _in(1) | _in(3), 27, f, 0);
+  if (e) {
+    fprintf(stderr, "ssrclean: error deleting `%s': %s\n",
+            f, e->errmess);
+    exitstat = 1;
+  }
+}
+
+/* --- @main@ --- *
+ *
+ * Arguments:  @int argc@ = number of arguments
+ *             @char *argv[]@ = list of arguments
+ *
+ * Returns:    Zero if all went well
+ *
+ * Use:                Deletes files.  This is an `rm' rip-off
+ */
+
+int main(int argc, char *argv[])
+{
+  int i;
+
+  /* --- Expand wildcards in the arguments --- */
+
+  cmdreplace(&argc, &argv);
+
+  /* --- Report an error if there aren't enough arguments --- */
+
+  if (argc < 2) {
+    fprintf(stderr, "Usage: ssrclean FILE [FILE...]\n");
+    exit(1);
+  }
+
+  /* --- Wipe things --- */
+
+  for (i = 1; i < argc; i++)
+    wipe(argv[i]);
+
+  /* --- Done --- */
+
+  return (exitstat);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/StraySrc/Utilities/c/submake b/StraySrc/Utilities/c/submake
new file mode 100644 (file)
index 0000000..1d8496d
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * submake.c
+ *
+ * Handle recursive makes
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "swis.h"
+#include "swiv.h"
+
+#include "alloc.h"
+#include "glob.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+typedef struct submk_ctx {
+  char **p;
+  size_t i;
+  size_t sz;
+} submk_ctx;
+
+static void submk_add(const char *p, void *ctx)
+{
+  int len = _swi(OS_FSControl, _inr(0, 5) | _return(5), 37, p, 0, 0, 0, 0);
+  char *q = xmalloc(1 - len);
+  submk_ctx *sx = ctx;
+
+  _swi(OS_FSControl, _inr(0, 5), 37, p, q, 0, 0, 1 - len);
+  if (sx->i == sx->sz) {
+    sx->sz += 256;
+    sx->p = xrealloc(sx->p, sx->sz * sizeof(sx->p[0]));
+  }
+  sx->p[sx->i++] = q;
+}
+
+static char *nstrcpy(char *d, const char *s)
+{
+  while ((*d++ = *s++) != 0)
+    ;
+  return (d - 1);
+}
+
+int main(int argc, char *argv[])
+{
+  char prefix[1024];
+  int is_prefix = 1;
+  char *tail;
+  submk_ctx sx;
+
+  /* --- Remember the original DDEUtils prefix --- */
+
+  {
+    int len;
+    if (_swix(OS_ReadVarVal, _inr(0, 4) | _out(2),
+              "Prefix$Dir", prefix, sizeof(prefix), 0, 0,
+              &len))
+      is_prefix = 0;
+    else
+      prefix[len] = 0;
+  }
+
+  /* --- Initialise the context --- */
+
+  sx.sz = 256;
+  sx.p = xmalloc(sx.sz * sizeof(sx.p[0]));
+  sx.i = 0;
+
+  /* --- Mangle the command line arguments --- */
+
+  {
+    int i;
+
+    /* --- Expand wildcarded makefile names --- */
+
+    for (i = 1; i < argc && strcmp(argv[i], "--"); i++) {
+      if (glob(argv[i], submk_add, &sx) == 0)
+        submk_add(argv[i], &sx);
+    }
+
+    /* --- Take the rest of the arguments --- *
+     *
+     * This is one of those times that C shows its Unix roots most
+     * irritatingly.  I've got to grab all the carefully separated
+     * arguments, and stick them all back together.
+     */
+
+    if (i >= argc)
+      tail = "";
+    else {
+      size_t sz = 0;
+      int j;
+      char *p;
+
+      i++;
+      for (j = i; j < argc; j++)
+        sz += strlen(argv[j]) + 1;
+      tail = xmalloc(sz + 1);
+      p = tail;
+      *p++ = ' ';
+      p = nstrcpy(p, argv[i++]);
+      for (j = i; j < argc; j++) {
+        *p++ = ' ';
+        p = nstrcpy(p, argv[j]);
+      }
+      *p = 0;
+    }
+  }
+
+  /* --- Now start work on making things --- */
+
+  {
+    int i, e;
+    char cmdbuf[1024];
+
+    if (is_prefix)
+      _swi(XDDEUtils_Prefix, _in(0), 0);
+    for (i = 0; i < sx.i; i++) {
+      sprintf(cmdbuf, "amu -desktop -f %s%s", sx.p[i], tail);
+      printf("submake: Making%s with `%s'\n", tail, sx.p[i]);
+      if ((e = system(cmdbuf)) != 0) {
+        printf("submake: Failed%s with `%s' [%i]\n", tail, sx.p[i], e);
+        exit(1);
+      }
+      printf("submake: Successfully made%s with `%s'\n", tail, sx.p[i]);
+    }
+  }
+
+  /* --- Restore the original prefix --- */
+
+  if (is_prefix)
+    _swi(XDDEUtils_Prefix, _in(0), prefix);
+
+  /* --- That's it: return --- */
+
+  return (0);
+}
diff --git a/StraySrc/Utilities/ex/buildstub b/StraySrc/Utilities/ex/buildstub
new file mode 100644 (file)
index 0000000..4b06904
--- /dev/null
@@ -0,0 +1,61 @@
+stubfn
+zero
+offDiff
+sapph_base
+sapph_limit
+bas_init
+bas_aofInit
+bas_aofSaveAs
+bas_aofSave
+pass
+import
+importAs
+importWeak
+importWeakAs
+export
+exportAs
+exportStrong
+exportStrongAs
+get
+bas_lib
+area
+reloc
+noReloc
+entry
+litStart
+litw
+lits
+litmagic
+litsz
+literr
+literal
+litAlign
+ltorg
+align
+reserve
+bin
+fSize
+ws_start
+ws_base
+ws
+ws_align
+ws_word
+ws_byte
+adrl
+adrccl
+addl
+addccl
+ldrl
+ldrccl
+ldrrl
+ldrrccl
+bas_a
+bas_b
+bas_c
+bas_d
+bas_e
+bas_f
+bas_g
+bas_h
+bas_i
+bas_j
diff --git a/StraySrc/Utilities/ex/msgaof b/StraySrc/Utilities/ex/msgaof
new file mode 100644 (file)
index 0000000..3a34cb7
--- /dev/null
@@ -0,0 +1,59 @@
+help
+syntax
+label
+bas_init
+bas_aofInit
+bas_aofSaveAs
+bas_aofSave
+pass
+import
+importAs
+importWeak
+importWeakAs
+export
+exportAs
+exportStrong
+exportStrongAs
+get
+bas_lib
+area
+reloc
+noReloc
+entry
+litStart
+litw
+lits
+litmagic
+litsz
+literr
+literal
+litAlign
+ltorg
+align
+reserve
+bin
+fSize
+ws_start
+ws_base
+ws
+ws_align
+ws_word
+ws_byte
+adrl
+adrccl
+addl
+addccl
+ldrl
+ldrccl
+ldrrl
+ldrrccl
+bas_a
+bas_b
+bas_c
+bas_d
+bas_e
+bas_f
+bas_g
+bas_h
+bas_i
+bas_j
diff --git a/StraySrc/Utilities/ex/resgen b/StraySrc/Utilities/ex/resgen
new file mode 100644 (file)
index 0000000..29c7bc5
--- /dev/null
@@ -0,0 +1,62 @@
+rsc_sprites
+rsc_msgBase
+rsc_msgLimit
+rsc_tplBase
+rsc_tplLimit
+assign
+bas_init
+bas_aofInit
+bas_aofSaveAs
+bas_aofSave
+pass
+import
+importAs
+importWeak
+importWeakAs
+export
+exportAs
+exportStrong
+exportStrongAs
+get
+bas_lib
+area
+reloc
+noReloc
+entry
+litStart
+litw
+lits
+litmagic
+litsz
+literr
+literal
+litAlign
+ltorg
+align
+reserve
+bin
+fSize
+ws_start
+ws_base
+ws
+ws_align
+ws_word
+ws_byte
+adrl
+adrccl
+addl
+addccl
+ldrl
+ldrccl
+ldrrl
+ldrrccl
+bas_a
+bas_b
+bas_c
+bas_d
+bas_e
+bas_f
+bas_g
+bas_h
+bas_i
+bas_j
diff --git a/StraySrc/Utilities/ex/templaof b/StraySrc/Utilities/ex/templaof
new file mode 100644 (file)
index 0000000..31ae7bd
--- /dev/null
@@ -0,0 +1,57 @@
+template
+bas_init
+bas_aofInit
+bas_aofSaveAs
+bas_aofSave
+pass
+import
+importAs
+importWeak
+importWeakAs
+export
+exportAs
+exportStrong
+exportStrongAs
+get
+bas_lib
+area
+reloc
+noReloc
+entry
+litStart
+litw
+lits
+litmagic
+litsz
+literr
+literal
+litAlign
+ltorg
+align
+reserve
+bin
+fSize
+ws_start
+ws_base
+ws
+ws_align
+ws_word
+ws_byte
+adrl
+adrccl
+addl
+addccl
+ldrl
+ldrccl
+ldrrl
+ldrrccl
+bas_a
+bas_b
+bas_c
+bas_d
+bas_e
+bas_f
+bas_g
+bas_h
+bas_i
+bas_j
diff --git a/StraySrc/Utilities/fixlink,ffb b/StraySrc/Utilities/fixlink,ffb
new file mode 100644 (file)
index 0000000..8c5d9fe
Binary files /dev/null and b/StraySrc/Utilities/fixlink,ffb differ
diff --git a/StraySrc/Utilities/h/alloc b/StraySrc/Utilities/h/alloc
new file mode 100644 (file)
index 0000000..ef0ab8e
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * alloc.h
+ *
+ * Trivial veneers for allocating memory
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's core utilities (coreutils).
+ *
+ * Coreutils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Coreutils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with coreutils.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef ALLOC_H
+#define ALLOC_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Required headers --------------------------------------------------*/
+
+#include <stddef.h>
+
+/*----- Functions ---------------------------------------------------------*/
+
+/* --- @xmalloc@ --- *
+ *
+ * Arguments:  @size_t sz@ = size of block to allocate
+ *
+ * Returns:    Pointer to newly allocated block.
+ *
+ * Use:                Returns a block of the requested size, or not at all.
+ */
+
+extern void *xmalloc(size_t /*sz*/);
+
+/* --- @xrealloc@ --- *
+ *
+ * Arguments:  @void *p@ = pointer to a block of memory
+ *             @size_t sz@ = size we want it to be
+ *
+ * Returns:    Pointer to resized block
+ *
+ * Use:                Resizes a block.  Returns the resized block, or not at all.
+ */
+
+extern void *xrealloc(void */*p*/, size_t /*sz*/);
+
+/* --- @xstrdup@ --- *
+ *
+ * Arguments:  @const char *p@ = pointer to string to copy
+ *
+ * Returns:    Pointer to a copy of the string.
+ *
+ * Use:                Returns a copy of a string, or not at all.
+ */
+
+extern char *xstrdup(const char */*p*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/StraySrc/Utilities/h/cmdr b/StraySrc/Utilities/h/cmdr
new file mode 100644 (file)
index 0000000..aca88fa
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * cmdr.h
+ *
+ * Perform expansions on the command line arguments
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's core utilities (coreutils).
+ *
+ * Coreutils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Coreutils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with coreutils.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CMDR_H
+#define CMDR_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Functions ---------------------------------------------------------*/
+
+/* --- @cmdreplace@ --- *
+ *
+ * Arguments:  @int *argc@ = pointer to argument count
+ *             @char ***argv@ = address of pointer to arg list
+ *
+ * Returns:    ---
+ *
+ * Use:                Mangles the argument list until it's nice.
+ */
+
+extern void cmdreplace(int */*argc*/, char ***/*argv*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/StraySrc/Utilities/h/gf b/StraySrc/Utilities/h/gf
new file mode 100644 (file)
index 0000000..614a4e6
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * gf.h
+ *
+ * Read directories in a buffered way
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's core utilities (coreutils).
+ *
+ * Coreutils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Coreutils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with coreutils.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GF_H
+#define GF_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Type definitions --------------------------------------------------*/
+
+/* --- Wildcard matcher context --- */
+
+typedef struct gf_ctx {
+  char buf[1024];                      /* Buffer for OS_HeebieJeebie */
+  int ctx;                             /* Context for OS_HeebieJeebie */
+  const char *dir;                     /* Pointer to directory to scan */
+  const char *pat;                     /* Pointer to pattern string */
+  int nleft;                           /* Number left in buffer */
+  char *p;                             /* Pointer into the buffer */
+} gf_ctx;
+
+/*----- Functions ---------------------------------------------------------*/
+
+/* --- @gf_init@ --- *
+ *
+ * Arguments:  @gf_ctx *g@ = pointer to a context buffer for me
+ *             @const char *pat@ = pointer to a (RISC OS) pattern string
+ *             @cost char *dir@ = pointer to name of parent directory
+ *
+ * Returns:    ---
+ *
+ * Use:                Initialise a wildcard match context ready for scanning.
+ */
+
+extern void gf_init(gf_ctx */*g*/, const char */*pat*/, const char */*dir*/);
+
+/* --- @gf_next@ --- *
+ *
+ * Arguments:  @gf_ctx *g@ = pointer to my context
+ *
+ * Returns:    Pointer to a filename, or zero for end
+ *
+ * Use:                Returns the next matching file from the block.
+ */
+
+extern char *gf_next(gf_ctx */*g*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/StraySrc/Utilities/h/glob b/StraySrc/Utilities/h/glob
new file mode 100644 (file)
index 0000000..1a54787
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * glob.c
+ *
+ * Full file wildcard matching
+ *
+ * © 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's core utilities (coreutils).
+ *
+ * Coreutils is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * Coreutils is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with coreutils.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GLOB_H
+#define GLOB_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Functions ---------------------------------------------------------*/
+
+/* --- @glob@ --- *
+ *
+ * Arguments:  @const char *pat@ = pointer to pattern string to match
+ *             @void (*proc)(const char *, void *)@ = client function
+ *             @void *ctx@ = context pointer to pass function
+ *
+ * Returns:    Number of filenames matched.
+ *
+ * Use:                Does filename globbing.
+ */
+
+extern int glob(const char */*pat*/,
+                void (*/*proc*/)(const char *, void *),
+                void */*ctx*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/StraySrc/Utilities/msgaof,ffb b/StraySrc/Utilities/msgaof,ffb
new file mode 100644 (file)
index 0000000..28a64af
Binary files /dev/null and b/StraySrc/Utilities/msgaof,ffb differ
diff --git a/StraySrc/Utilities/resgen,ffb b/StraySrc/Utilities/resgen,ffb
new file mode 100644 (file)
index 0000000..645b974
Binary files /dev/null and b/StraySrc/Utilities/resgen,ffb differ
diff --git a/StraySrc/Utilities/s/enumerate b/StraySrc/Utilities/s/enumerate
new file mode 100644 (file)
index 0000000..c2a1e39
--- /dev/null
@@ -0,0 +1,208 @@
+;
+; enumerate.s
+;
+; Run a command on lots of files (MDW)
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core utilities (coreutils).
+;
+; Coreutils is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Coreutils is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Coreutils.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard stuff -------------------------------------------------------
+
+               GET     libs:swis
+               GET     libs:header
+
+               IMPORT  version
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |!!!Util$$Header|,CODE,READONLY
+
+main           ROUT
+
+               ; --- Pass the command string to OS_ReadArgs ---
+
+               STMDB   R13!,{R14}              ;Keep my return address
+               ADR     R0,enum_commDef         ;Point to command definition
+               MOV     R2,R12                  ;Point to the output buffer
+               MOV     R3,#&100                ;Size of my buffer
+               SWI     XOS_ReadArgs            ;Parse up my command string
+               LDMVSIA R13!,{PC}               ;If it failed, quit now
+
+               ; --- Check validity of arguments ---
+
+               LDMIA   R12,{R10,R11}           ;Load info from the buffer
+
+               LDR     R14,[R12,#8]            ;Load the help flag
+               CMP     R14,#0                  ;Does he want help?
+               BNE     enum_showHelp           ;Yes -- display helpful text
+
+               CMP     R11,#0                  ;Is there a command to do?
+               BEQ     enum_noCommand          ;No -- complain about this
+               CMP     R10,#0                  ;Is there a directory?
+               ADREQ   R10,enum_currDir        ;No -- use current director
+
+               ADD     R14,R12,#12             ;Point to nofiles/nodirs
+               LDMIA   R14,{R8,R9}             ;Load these flags out
+               CMP     R8,#0                   ;Check for no files
+               CMPNE   R9,#0                   ;And for no directories
+               BNE     enum_trivial            ;If both set, it's easy!
+
+               ; --- Copy the command into a buffer ---
+
+               ADD     R0,R12,#&100            ;Point to second buffer
+
+00main         LDRB    R14,[R11],#1            ;Get a byte from the command
+               CMP     R14,#32                 ;Is this a nice character?
+               STRCSB  R14,[R0],#1             ;Store it in the buffer
+               BCS     %00main                 ;If more to do, loop round
+
+               MOV     R14,#' '                ;A space to put on the end
+               STRB    R14,[R0],#1             ;Stick it on the end
+               SUB     R11,R0,R12              ;Find length of this string
+               SUB     R11,R11,#&100
+
+               ; --- Copy the name after the command ---
+
+               ADD     R7,R12,#&300            ;Point to fourth buffer
+               MOV     R0,R10                  ;Point to pathname
+
+01main         LDRB    R14,[R0],#1             ;Get a dirname byte
+               CMP     R14,#32                 ;Is this the end yet?
+               STRCSB  R14,[R7],#1             ;Store it in the buffer
+               BCS     %01main                 ;If more to do, do more
+
+               MOV     R14,#'.'                ;Put a dot after the dirname
+               STRB    R14,[R7],#1             ;Store that on the end
+
+               ; --- Set up for main scanning loop ---
+
+               ADR     R6,enum_star            ;Find all names in the dir
+               MOV     R5,#&80                 ;Size of the buffer
+               MOV     R4,#0                   ;This is the first call
+
+               ; --- Read directory entries and do commands ---
+
+02main         MOV     R3,#1                   ;Read one entry at a time
+               ADD     R2,R12,#&200            ;Point to the buffer
+               MOV     R1,R10                  ;Point to the directory name
+               MOV     R0,#10                  ;Read files and information
+               SWI     XOS_GBPB                ;Get a directory entry
+               LDMVSIA R13!,{PC}               ;If it failed, return error
+               CMN     R4,#1                   ;Is that the end of it all?
+               LDMEQIA R13!,{PC}^              ;Yes -- return to caller
+
+               ; --- Find out if we process this entry ---
+
+               LDR     R0,[R2,#16]             ;Get the object type
+               CMP     R0,#1                   ;Is the object a file?
+               BNE     %03main                 ;No -- check for a directory
+               CMP     R8,#0                   ;Are we to process files?
+               BNE     %02main                 ;No -- ignore this entry
+               B       %04main                 ;Skip ahead to handle file
+
+03main         CMP     R9,#0                   ;Are we to process dirs?
+               BNE     %02                     ;No -- ignore this entry
+
+               ; --- Process the current entry ---
+
+04main         ADD     R0,R2,#20               ;Point to the actual name
+               MOV     R1,R7                   ;Point to the command head
+05main         LDRB    R14,[R0],#1             ;Get a byte from the name
+               STRB    R14,[R1],#1             ;Store it in the buffer
+               CMP     R14,#0                  ;Is that the end?
+               BNE     %05main                 ;No -- go round again
+
+               STMFD   R13!,{R4}               ;Save the current index
+               ADD     R0,R12,#&300            ;Point to full pathname
+               ADD     R1,R12,#&200            ;Use buffer three for output
+               MOV     R2,#&100                ;It's 256 bytes in size
+               ADD     R3,R12,#&100            ;Point to template string
+               MOV     R4,R11                  ;Get length of template
+               SWI     XOS_SubstituteArgs      ;Try and substitute things
+               LDMFD   R13!,{R4}               ;Reload the directory index
+               LDMVSIA R13!,{PC}               ;If it failed, return
+
+                MOV    R0,R1                   ;Point to output buffer
+               SWI     XOS_CLI                 ;Perform the command
+               BVC     %02main                 ;If it was OK continue
+
+               LDR     R14,[R12,#20]           ;Is the x flag on?
+               TEQ     R14,#0                  ;Don't corrupt the V flag
+               BNE     %02main                 ;Yes -- ignore the error
+               LDMFD   R13!,{PC}               ;Otherwise return to caller
+
+enum_commDef   DCB     "dir,"                  ;Offset 0
+               DCB     "cmd,"                  ;Offset 4
+
+               DCB     "help/S,"               ;Offset 8
+               DCB     "noFiles/S,"            ;Offset 12
+               DCB     "noDirs/S,"             ;Offset 16
+               DCB     "noErrors=x/S,"         ;Offset 20
+               DCB     0
+
+enum_currDir   DCB     "@",0
+
+enum_star      DCB     "*",0
+
+enum_showHelp  ADR     R0,enum_helpText        ;Point to the help text
+               MOV     R1,#0                   ;No didtionary, please
+               LDR     R2,=version             ;Find the version string
+               ADR     R14,main                ;Point to my base address
+               ADD     R2,R14,R2               ;Find the actual string
+               SWI     XOS_PrettyPrint         ;Display the string
+               LDMIA   R13!,{PC}^              ;And return to caller
+
+enum_helpText  DCB     "enumerate ",27,0,13
+               DCB     13
+               DCB     "Syntax: enumerate [<options>] [-dir <directory>] "
+               DCB     "-cmd <command>",13
+               DCB     13
+               DCB     "Executes <command> on each file/directory in "
+               DCB     "<directory>.  If no <directory> is specified, the "
+               DCB     "current directory is used.",13
+               DCB     13
+               DCB     "Options (which may be abbreviated) are:"
+               DCB     13
+               DCB     "-help",9,9,"Display this help text",13
+               DCB     "-noDirs",9,9,"Do not execute command on "
+               DCB     "directories",13
+               DCB     "-noFiles",9,"Do not execute command on files",13
+               DCB     "-noErrors",9,"Ignore errors from command",13
+               DCB     0
+
+enum_noCommand ADR     R0,enum_noCmdErr
+               LDMIA   R13!,{R14}
+               ORRS    PC,R14,#&10000000
+
+enum_trivial   ADR     R0,enum_easyErr
+               LDMIA   R13!,{R14}
+               ORRS    PC,R14,#&10000000
+
+enum_noCmdErr  DCD     1
+               DCB     "enumerate: No command specified.",0
+
+enum_easyErr   DCD     1
+               DCB     "enumerate: Nothing to do -- -nodirs and "
+               DCB     "-nofiles both set!",0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Utilities/s/hour b/StraySrc/Utilities/s/hour
new file mode 100644 (file)
index 0000000..e361793
--- /dev/null
@@ -0,0 +1,166 @@
+;
+; hour_util.s
+;
+; Fiddle with hourglass from command line
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core utilities (coreutils).
+;
+; Coreutils is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Coreutils is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Coreutils.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  version
+
+;----- Main code ------------------------------------------------------------
+
+               GBLA    count
+
+               AREA    |!!!Util$$Code|,CODE,READONLY
+
+main           ROUT
+
+               STMFD   R13!,{R14}              ;Save the return address
+               ADR     R0,hour__cmdDef         ;Point to command definition
+               MOV     R2,R12                  ;Point to a workspace buffer
+               MOV     R3,#256                 ;Size of the buffer
+               SWI     XOS_ReadArgs            ;Try to interpret the args
+               BVS     %90main                 ;If it failed, return
+
+               ; --- Handle the arguments ---
+
+               LDMIA   R12,{R0-R4}             ;Load values from block
+
+               CMP     R0,#0                   ;Does he want some help?
+               BNE     hour__help              ;Yes -- display help then
+
+               ; --- Make sure at most one is set ---
+
+               MOV     R14,#0                  ;Clear argument count
+               MOV     R0,#1                   ;Default is to turn on
+
+count          SETA    1
+               WHILE   count<5
+R$count                RN      $count
+               CMP     R$count,#0              ;Is the argument on?
+               ADDNE   R14,R14,#1              ;Yes -- bump the counter
+               MOVNE   R0,#count-1             ;And remember the argument
+count          SETA    count+1
+               WEND
+
+               CMP     R14,#2                  ;Is the count valid?
+               ADRCS   R0,hour__badArgs        ;No -- point to error
+               BCS     %90main                 ;And return to caller
+
+               ; --- Now do the necessaries ---
+               ;
+               ; The following should be two words long each -- this enables
+               ; most operations to be done inline with just a SWI and a
+               ; return.
+
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,PC,R0,LSL #3         ;Do what we must do
+               LDMFD   R13!,{PC}               ;Return to caller
+
+               ; --- Disable the hourglass ---
+
+               SWI     XHourglass_Off
+               MOV     PC,R14
+
+               ; --- Enable the hourglass ---
+
+               SWI     XHourglass_On
+               MOV     PC,R14
+
+               ; --- Trash hourglass totally ---
+
+               SWI     XHourglass_Smash
+               MOV     PC,R14
+
+               ; --- Turn on the percentage indicator ---
+               ;
+               ; To save space, this should be the last option.
+
+               LDRB    R0,[R4],#1              ;Load the expression type
+               CMP     R0,#0                   ;Is it numeric?
+               ADRNE   R0,hour__badType        ;No -- must be a bad type
+               ORRNES  PC,R14,#V_flag          ;So return the error
+               AND     R2,R4,#3                ;Get non-wordalignedness
+               BIC     R4,R4,#3                ;Word align the address
+               LDMIA   R4,{R0,R1}              ;Load two overlapping words
+               MOV     R2,R2,LSL #3            ;Convert bytes to bits
+               RSB     R3,R2,#32               ;And get reverse shift size
+               MOV     R0,R0,LSR R2            ;Get the bottom end right
+               ORR     R0,R0,R1,LSL R3         ;And move in the top end
+               SWI     XHourglass_Percentage   ;Set the percentage as reqd
+               MOV     PC,R14                  ;And return to caller
+
+90main         LDMFD   R13!,{R14}              ;Load the return address
+               ORRS    PC,R14,#V_flag          ;And return an error
+
+hour__cmdDef   DCB     "help/S,"               ;Offset 0  (R0)
+               DCB     "off/S,"                ;Offset 8  (R1)
+               DCB     "on/S,"                 ;Offset 4  (R2)
+               DCB     "smash/S,"              ;Offset 12 (R3)
+               DCB     "percent/K/E,"          ;Offset 16 (R4)
+               DCB     0
+
+hour__badArgs  DCD     1
+               DCB     "Syntax: hour [<command>]",0
+
+hour__badType  DCD     1
+               DCB     "Percentage must be a number",0
+
+hour__help     ADR     R0,hour__helpText       ;Point to the help text
+               MOV     R1,#0                   ;No dictionary please
+               LDR     R2,=version             ;Find the version string
+               ADR     R14,main                ;Find my base address
+               ADD     R2,R14,R2               ;Find the actual message
+               SWI     XOS_PrettyPrint         ;Print the message
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+hour__helpText DCB     "hour ",27,0,13
+               DCB     13
+               DCB     "Syntax: hour [<command>]",13
+               DCB     13
+               DCB     "Performs an Hourglass operation as specified by "
+               DCB     "<command>.  If no command is specified, the "
+               DCB     "Hourglass is turned on.",13
+               DCB     13
+               DCB     "Commands allowed are:",13
+               DCB     13
+               DCB     "-help",9,9,"Displays this help text",13
+               DCB     "-on",9,9,"Turns the Hourglass on",13
+               DCB     "-off",9,9,"Turns the Hourglass off",13
+               DCB     "-smash",9,9,"Forces the Hourglass off",13
+               DCB     "-percent",9,"Displays the given percentage",13
+               DCB     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Utilities/s/pathUtil b/StraySrc/Utilities/s/pathUtil
new file mode 100644 (file)
index 0000000..20c3a50
--- /dev/null
@@ -0,0 +1,282 @@
+;
+; pathUtil.s
+;
+; Messing about with path variables
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core utilities (coreutils).
+;
+; Coreutils is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Coreutils is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Coreutils.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |Asm$$Code|,CODE,READONLY
+
+; --- path_addDir ---
+;
+; On entry:    R0 == pointer to path variable name
+;              R1 == pointer to a directory string to add in
+;              R2 == flags:
+;                    bits 0-7 == variable type (2 == literal, 4 == macro)
+;                    bit 8    == create variable if doesn't exist
+;
+; On exit:     CS if path element added, CC otherwise
+;              May return an error
+;
+; Use:         Adds a directory to the given path variable.
+
+               EXPORT  path_addDir
+path_addDir    ROUT
+
+               BIC     R14,R14,#V_flag+C_flag  ;Assume everything is great
+               STMFD   R13!,{R0-R4,R14}        ;Save a load of registers
+               MOV     R4,R0                   ;Look after the variable name
+
+               ; --- Read the font path variable ---
+               ;
+               ; We must make sure we don't expand it when we do.
+
+               BL      path__readPath          ;Read the path variable
+               BVS     %90path_addDir          ;If it failed, return error
+               MOV     R0,R1                   ;Point to string to find
+               BL      path__findDir           ;Try to find the directory
+               LDMCSFD R13!,{R0-R4,PC}^        ;If it's in there, return
+
+               ; --- Add in the directory then ---
+
+               MOV     R1,R11                  ;Point to the string start
+               LDRB    R14,[R1,#0]             ;Load the first byte
+               CMP     R14,#0                  ;Is this a null string?
+               BEQ     %20path_addDir          ;Yes -- omit the comma then
+
+               ; --- Find the string end ---
+
+10path_addDir  LDRB    R14,[R1,#1]!            ;Load a new character out
+               CMP     R14,#0                  ;Is this the end yet?
+               BNE     %10path_addDir          ;No -- loop round again
+
+               MOV     R14,#','                ;Store a comma over the end
+               STRB    R14,[R1],#1             ;Store it at the end
+
+               ; --- Copy the new directory string on the end ---
+
+20path_addDir  LDRB    R14,[R0],#1             ;Load a source string byte
+               CMP     R14,#32                 ;Is this the string end?
+               STRCSB  R14,[R1],#1             ;Store it in the buffer
+               BCS     %20path_addDir          ;And look back round again
+
+               ; --- Now set the variable value and return ---
+
+               AND     R2,R2,#&FF              ;Get the variable type
+               CMP     R2,#4                   ;Are we setting a lit string?
+               MOVNE   R14,#0                  ;No -- null terminate then
+               STRNEB  R14,[R1],#1             ;Stick it on the end
+               MOV     R0,R4                   ;Point to path variable name
+               MOV     R4,R2                   ;Get variable type
+               SUB     R2,R1,R11               ;Get the string length out
+               MOV     R1,R11                  ;Point to the new path string
+               MOV     R3,#0                   ;No initial context here
+               SWI     XOS_SetVarVal           ;Set the variable value
+               BVS     %90path_addDir          ;Return an error if any
+
+               LDMFD   R13!,{R0-R4,R14}        ;Return to caller if OK
+               ORRS    PC,R14,#C_flag
+
+               ; --- Deal with any errors created ---
+
+90path_addDir  ADD     R13,R13,#4              ;Don't return stacked R0
+               LDMFD   R13!,{R1-R4,R14}        ;Restore caller's registers
+               ORRS    PC,R14,#V_flag          ;Return the error
+
+               LTORG
+
+; --- path__readPath ---
+;
+; On entry:    R0 == pointer to path variable name
+;              R2 == flags passed to addDir/removeDir
+;
+; On exit:     May return an error
+;
+; Use:         Reads the value of the path variable into the buffer
+;              pointed to by R11.
+
+path__readPath ROUT
+
+               BIC     R14,R14,#V_flag         ;Clear the error indicator
+               STMFD   R13!,{R0-R4,R14}        ;Save a load of registers
+               MOV     R1,R11                  ;Point to the scratch pad
+               MOV     R2,#256                 ;Say the buffer is 256 bytes
+               MOV     R3,#0                   ;No context space required
+               MOV     R4,#0                   ;Don't expand the string
+               SWI     XOS_ReadVarVal          ;Read the variable value
+               BVS     %90path__readPath       ;If it failed, handle error
+               MOV     R14,#0                  ;Store a zero byte on the end
+               STRB    R14,[R1,R2]             ;Terminate the path string
+               LDMFD   R13!,{R0-R4,PC}^        ;Return to caller now
+
+90             LDR     R14,[R13,#8]            ;Load the flags from stack
+               TST     R14,#&100               ;Is the `create' flag on?
+               MOVNE   R14,#0                  ;Yes -- get a zero byte
+               STRNEB  R14,[R11,#0]            ;Store in buffer
+               LDMNEFD R13!,{R0-R4,PC}^        ;And return to caller
+
+               ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R4,R14}        ;Restore all the others
+               ORRS    PC,R14,#V_flag          ;Return the error to caller
+
+               LTORG
+
+; --- path__findDir ---
+;
+; On entry:    R0 == pointer to string to search for
+;
+; On exit:     CS and R0 == pointer into path string if successful or
+;              CC and R0 preserved
+;
+; Use:         Tries to find a named directory within a font path string.
+
+path__findDir  ROUT
+
+               STMFD   R13!,{R1-R5,R14}        ;Save a load of registers
+               MOV     R1,R11                  ;Point to the path string
+               MOV     R3,R1                   ;Keep a pointer to this dir
+
+               ; --- Go through both strings ---
+
+00path__findDir        MOV     R2,R0                   ;Point to search pattern
+01path__findDir        LDRB    R4,[R1],#1              ;Load a char from the path
+               CMP     R4,#32                  ;Is it a space character?
+               BEQ     %01path__findDir        ;Yes -- ignore it then
+
+02path__findDir        LDRB    R5,[R2],#1              ;And one from the pattern
+               CMP     R5,#32                  ;Is this the end of the dir?
+               BCC     %10path__findDir        ;Yes -- deal with this
+
+               CMP     R4,#0                   ;Is it the end of the path?
+               BEQ     %07path__findDir        ;Yes -- deal with this
+
+               CMP     R4,R5                   ;Do the characters match?
+               LDREQB  R4,[R1],#1              ;Yes -- load next path char
+               BEQ     %02path__findDir        ;And go round again
+
+               ; --- Found a mismatch ---
+               ;
+               ; We have to find the next path element
+
+05path__findDir        CMP     R4,#','                 ;Is it a comma?
+               SUBEQ   R3,R1,#1                ;Yes -- point to it nicely
+               BEQ     %00path__findDir        ;And go round again
+               CMP     R4,#0                   ;Is it the string end?
+               LDRNEB  R4,[R1],#1              ;Load a char from the path
+               BNE     %05path__findDir        ;No -- continue the search
+07path__findDir        LDMFD   R13!,{R1-R5,R14}        ;Restore the registers
+               BICS    PC,R14,#C_flag          ;Return with carry clear
+
+               ; --- We reached the end of the directory ---
+
+10path__findDir        CMP     R4,#32                  ;Is it a space?
+               LDREQB  R4,[R1],#1              ;Load a char from the path
+               BEQ     %10path__findDir        ;Yes -- allow trailing space
+               CMP     R4,#','                 ;Is it a comma?
+               CMPNE   R4,#0                   ;Or the end of the whole lot?
+               BNE     %05path__findDir        ;No -- find the next one
+               MOV     R0,R3                   ;Point to the path entry strt
+               LDMFD   R13!,{R1-R5,R14}        ;Restore the registers
+               ORRS    PC,R14,#C_flag          ;And return a success
+
+               LTORG
+
+; --- path_removeDir ---
+;
+; On entry:    R0 == pointer to name of path variable
+;              R1 == pointer to a directory to remove
+;              R2 == flags:
+;                    bits 0-7 == variable type (2 == literal, 4 == macro)
+;                    bit 8    == create variable if doesn't exist
+;
+; On exit:     May return an error
+;
+; Use:         Removes an element from a given path variable.
+
+               EXPORT  path_removeDir
+path_removeDir ROUT
+
+               BIC     R14,R14,#V_flag+C_flag  ;Clear error indicator
+               STMFD   R13!,{R0-R4,R14}        ;Save a load of registers
+               MOV     R4,R0                   ;Look after variable name
+
+               BL      path__readPath          ;Read the actual path string
+               BVS     %90path_removeDir       ;If it failed, handle it
+               MOV     R0,R1                   ;Point to path element
+               BL      path__findDir           ;Find the particular entry
+               LDMCCFD R13!,{R0-R4,PC}^        ;Not there -- return
+
+               ; --- Now find the end of the entry ---
+
+               ADD     R1,R0,#1                ;Keep the start pointer
+10             LDRB    R14,[R1],#1             ;Load a byte from it
+               CMP     R14,#','                ;Is it the dir end?
+               CMPNE   R14,#0                  ;Or the end of the whole lot?
+               BNE     %10path_removeDir       ;No -- go round again then
+
+               ; --- Now remove this item from the list ---
+
+               CMP     R14,#','                ;Is this character a comma?
+               CMPEQ   R0,R11                  ;And is the dir at the start?
+               STRNEB  R14,[R0],#1             ;Neither -- store it here
+
+20             CMP     R14,#0                  ;Is this the string end?
+               BEQ     %50path_removeDir       ;Yes -- go and set the var
+               LDRB    R14,[R1],#1             ;Get a new char from the path
+               STRB    R14,[R0],#1             ;And store it nicely
+               B       %20path_removeDir       ;And go round for more
+
+               ; --- Right -- the string bashing's over ---
+
+50             AND     R1,R2,#&FF              ;Get the variable type
+               CMP     R1,#4                   ;Are we setting a lit string?
+               SUBEQ   R0,R0,#1                ;Yes -- don't include null
+
+               SUB     R2,R0,R11               ;Get the length in R2 nicely
+               MOV     R0,R4                   ;Point to the variable name
+               MOV     R4,R1                   ;Get the variable type
+               MOV     R1,R11                  ;Point to the string start
+               MOV     R3,#0                   ;Don't mess with wildcards
+               SWI     XOS_SetVarVal           ;Set the variable value
+               BVS     %90path_removeDir       ;If it failed, return error
+
+               LDMFD   R13!,{R0-R4,R14}        ;Return to caller
+               ORRS    PC,R14,#C_flag
+
+               ; --- Something went wrong ---
+
+90             ADD     R13,R13,#4              ;Don't restore R0 on exit
+               LDMFD   R13!,{R1-R4,R14}        ;Restore all the others
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Utilities/s/path_util b/StraySrc/Utilities/s/path_util
new file mode 100644 (file)
index 0000000..17623b3
--- /dev/null
@@ -0,0 +1,178 @@
+;
+; path_util.s
+;
+; A path manipulation utility
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core utilities (coreutils).
+;
+; Coreutils is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Coreutils is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Coreutils.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+;----- External dependencies ------------------------------------------------
+
+               GET     sh.pathUtil
+
+               IMPORT  version
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |!!!Utility$$Header|,CODE,READONLY
+
+; --- Main program ---
+;
+; Arguments:   [-add]|-remove[-path] <pathvar> [-dir] <element>
+;
+; Use:         Adds an element to a path, or removes one.
+
+main           ROUT
+
+               STMFD   R13!,{R14}              ;Keep the return address safe
+               ADR     R0,pu__commDef          ;Point to command syntax def
+               MOV     R2,R12                  ;Point to a workspace buffer
+               MOV     R3,#256                 ;Size of my buffer thingy
+               SWI     XOS_ReadArgs            ;Try to understand the string
+               BVS     %90main                 ;If it failed, return error
+
+               ; --- Make sure we got sensible arguments ---
+
+               LDMIA   R12,{R10,R11}           ;Load the two names
+
+               LDR     R14,[R12,#8]            ;Load the help flag value
+               CMP     R14,#0                  ;Is help specified?
+               BNE     pu__help                ;Yes -- give help then
+
+               LDR     R14,[R12,#24]           ;Load the fontinstall value
+               CMP     R14,#0                  ;Does he want to use it?
+               ADRNE   R10,pu__fontPath        ;Yes -- point to var name
+
+               CMP     R11,#0                  ;Is there no directory?
+               CMPNE   R10,#0                  ;Or no path variable?
+               BEQ     pu__noDir               ;None -- report an error
+
+               ; --- See if user wants GSTransing ---
+
+               MOV     R0,R11                  ;Point to the name string
+               LDR     R14,[R12,#20]           ;Load GSTrans flag out
+               CMP     R14,#0                  ;Does this want doing?
+               BEQ     %20main                 ;No -- skip onwards then
+               ADD     R1,R12,#512             ;Point to my GSTrans buffer
+               MOV     R2,#256                 ;Set the buffer size
+               ORR     R2,R2,#&E0000000        ;Set *all* the GSTrans flags
+               SWI     XOS_GSTrans             ;Translate it nicely
+               ADD     R0,R12,#512             ;Point to translated string
+
+               ; --- Do the main bit of processing ---
+
+20main         ADD     R11,R12,#256            ;Point to a spare buffer
+               MOV     R1,R0                   ;Point to directory in R1
+               MOV     R0,R10                  ;Point to path var in R0
+               MOV     R2,#2                   ;Path variables are macros
+               LDR     R14,[R12,#36]           ;Load the create flag
+               CMP     R14,#0                  ;Do we create the variable?
+               ORRNE   R2,R2,#&100             ;Yes -- set the bit then
+               LDR     R14,[R12,#16]           ;Load the remove flag
+               CMP     R14,#0                  ;Are we meant to remove it?
+               BLEQ    path_addDir             ;No -- then add it in
+               BLNE    path_removeDir          ;Yes -- remove it then
+               BVS     %90main                 ;If it failed, report error
+               BCC     %50main                 ;If nothing done, return
+
+               ; --- If we did fontPath things, update FontManager ---
+
+               LDR     R14,[R12,#24]           ;Load the fontinstall value
+               CMP     R14,#0                  ;Does he want to use it?
+               BEQ     %50main                 ;No -- do nothing then
+
+               SWI     XHourglass_On           ;This could take some time
+               ADR     R0,pu__finstall         ;Point to command thingy
+               SWI     XOS_CLI                 ;Try to update the font list
+               SWI     XHourglass_Off          ;And disable hourglass again
+
+               ; --- All done, all sweetness and light ---
+
+50main         LDMFD   R13!,{PC}^              ;Return to caller nicely
+
+pu__fontPath   DCB     "Font$Path",0
+pu__finstall   DCB     "FontInstall",0
+
+               ; --- Someone threw a spanner in the works ---
+
+90main         LDMFD   R13!,{R14}              ;Restore the link register
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               ; --- The command definition table ---
+
+pu__commDef    DCB     "path,"                 ;Offset 0     p
+               DCB     "dir,"                  ;Offset 4     d
+
+               DCB     "help/S,"               ;Offset 8     h
+               DCB     "add/S,"                ;Offset 12    a
+               DCB     "remove/S,"             ;Offset 16    r
+               DCB     "GS=GSTrans/S,"         ;Offset 20    g
+               DCB     "fInstall=fontPath/S,"  ;Offset 24    f
+               DCB     "create/S,"             ;Offset 28    c
+               DCB     0
+
+               ; --- Our arguments weren't done right ---
+
+pu__noDir      ADR     R0,pu__errNoDir         ;Point to the error message
+               B       %90main                 ;And report it as usual
+
+pu__errNoDir   DCD     1
+               DCB     "Syntax: PathUtil [<options>] "
+               DCB     "[-path] <pathvar> [-dir] <directory>",0
+
+               ; --- User wanted a helping hand ---
+
+pu__help       ADR     R0,pu__helpText         ;Point to the help text
+               MOV     R1,#0                   ;Don't use a dictionary
+               LDR     R2,=version             ;Point to version/cright
+               ADR     R14,main                ;Point to code base
+               ADD     R2,R14,R2               ;And point to the help text
+               SWI     XOS_PrettyPrint         ;Print it on the screen
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+pu__helpText   DCB     "PathUtil ",27,0,13
+               DCB     13
+               DCB     "Syntax: PathUtil [<options>] "
+               DCB     "[-path] <pathvar> [-dir] <directory>",13
+               DCB     13
+               DCB     "By default, adds a path element to the given path "
+               DCB     "variable.  If the element is already included, "
+               DCB     "PathUtil does nothing.",13
+               DCB     13
+               DCB     "Options (which may be abbreviated) are as "
+               DCB     "follows:",13
+               DCB     13
+               DCB     "-help",9,9,"Display this help text",13
+               DCB     "-add",9,9,"Add directory to path (default)",13
+               DCB     "-remove",9,9,"Remove directory from path",13
+               DCB     "-gsTrans",9,"Translate directory before adding",13
+               DCB     "-fontPath",9,"Use Font$Path as path variable",13
+               DCB     "-create",9,9,"Force creation of path variable",13
+               DCB     0
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Utilities/s/setSlot b/StraySrc/Utilities/s/setSlot
new file mode 100644 (file)
index 0000000..9b22ace
--- /dev/null
@@ -0,0 +1,355 @@
+;
+; setSlot.s
+;
+; Set up a WimpSlot
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core utilities (coreutils).
+;
+; Coreutils is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Coreutils is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Coreutils.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  version
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |!!!Util$$Code|,CODE,READONLY
+
+; --- main ---
+;
+; On entry:    R0 == pointer to command line
+;              R1 == pointer to command tail
+;              R12 == pointer to workspace
+;              R13 == pointer to stack
+;
+; On exit:     May return an error
+;
+; Use:         Sets up a wimpslot.
+
+main           ROUT
+
+               ; --- Find the command line ---
+
+               STR     R14,[R12,#0]            ;Store the link away
+               ADR     R0,ss__keys             ;Point to key tag definition
+               ADD     R2,R12,#256             ;Output into workspace
+               MOV     R3,#256                 ;Allow 256 bytes for this
+               SWI     XOS_ReadArgs            ;Read the arguments
+               BVS     ss__error               ;If it failed, return error
+
+               ; --- Now process the arguments ---
+
+               LDR     R0,[R12,#256+0]         ;Load the `-help' switch
+               CMP     R0,#0                   ;Is that set?
+               BNE     ss__help                ;Yes -- give some help then
+
+               LDR     R0,[R12,#256+4]         ;Load the base offset
+               CMP     R0,#0                   ;Is that defined?
+               ADREQ   R0,ss__usage            ;No -- point to error
+               BEQ     ss__error               ;And return an error
+               BL      ss__read                ;Read this number
+               MOV     R9,R0                   ;And look after the result
+
+               LDR     R0,[R12,#256+8]         ;Load the heap offset
+               CMP     R0,#0                   ;Is that defined?
+               BLNE    ss__read                ;Yes -- read the value
+               MOV     R10,R0                  ;And look after that too
+
+               LDR     R0,[R12,#256+12]        ;Load the flex offset
+               CMP     R0,#0                   ;Is that defined?
+               BLNE    ss__read                ;Yes -- read the value
+               ADD     R10,R10,R0              ;And bump on the heap size
+
+               LDR     R8,[R12,#256+16]        ;Load the application name
+               CMP     R8,#0                   ;Is that defined?
+               ADREQ   R8,ss__app              ;No -- use a default then
+
+               ; --- Read the memory limits imposed on me ---
+
+               MOV     R0,#14                  ;Read application space
+               MOV     R1,#0                   ;Don't provide new value
+               SWI     XOS_ChangeEnvironment   ;Read the value
+               MOV     R7,R1                   ;Look after that then
+               MOV     R0,#0                   ;Read the memory limit
+               MOV     R1,#0                   ;Don't provide new value
+               SWI     XOS_ChangeEnvironment   ;Read the value
+               MOV     R6,R1                   ;Look after that too
+               CMP     R6,R7                   ;Are these the same?
+               BCS     %f00                    ;We're OK -- skip onwards
+
+               ; --- We're running as a subprogram ---
+
+               SUB     R14,R6,#&8000           ;Find how much memory I have
+               CMP     R14,R9                  ;Is there enough for base?
+               BCC     ss__badSub              ;No -- complain then
+
+               MOV     R1,R7                   ;Extend the memory limit
+               SWI     XOS_ChangeEnvironment   ;Now I can extend the slot
+               MOV     R0,#-1                  ;I want to read the size
+               MOV     R1,#-1                  ;Leave next slot alone too
+               SWI     XWimp_SlotSize          ;Read the current slot size
+               MOV     R5,R0                   ;Remember this value
+               ADD     R0,R5,R10               ;Add on the heap size
+               MOV     R1,#-1                  ;Leave next slot alone still
+               SWI     XWimp_SlotSize          ;Try doing that then
+               SUB     R7,R0,R5                ;Find how much we added
+               MOV     R0,R5                   ;Restore to old value
+               MOV     R1,#-1                  ;Leave next slot alone too
+               SWI     XWimp_SlotSize          ;Try doing that then
+               MOV     R0,#0                   ;Now put the memorylimit back
+               MOV     R1,R6                   ;Get the old memory limit
+               SWI     XOS_ChangeEnvironment   ;Put that back now
+
+               CMP     R7,R10                  ;Did we get enough memory?
+               BCC     ss__noRoom              ;No -- complain bitterly
+               B       ss__end                 ;We finished OK then
+
+               ; --- We're in control here ---
+
+00             ADD     R6,R9,R10               ;Try to get it all
+               MOV     R0,R6                   ;Get this value
+               MOV     R1,#-1                  ;Don't change next slot
+               SWI     XWimp_SlotSize          ;Try doing that then
+               CMP     R0,R6                   ;Did we get enough?
+               BCC     ss__noRoom              ;No -- complain then
+               MOV     R0,R9                   ;Now set up base slot
+               MOV     R1,#-1                  ;Don't change next slot
+               SWI     XWimp_SlotSize          ;Try doing that then
+               B       ss__end                 ;And stop the program
+
+ss__keys       DCB     "help/S,"               ;0
+               DCB     "base,"                 ;4
+               DCB     "heap,"                 ;8
+               DCB     "flex,"                 ;12
+               DCB     "appName",0             ;16
+
+ss__usage      DCD     1
+               DCB     "Syntax: SetSlot -base <size>[K|M] "
+               DCB     "[-heap <size>[K|M]] [-flex <size>[K|M]] "
+               DCB     "[-appName <name>]",0
+
+ss__app                DCB     "Application",0
+
+               LTORG
+
+; --- ss__read ---
+;
+; On entry:    R0 == pointer to a string
+;
+; On exit:     R0 == numeric value read from string
+;
+; Use:         Reads a number represented by a string.  The number may be
+;              postfixed by `K' or `M' to indicate that it's shifted left by
+;              10 or 20 bits.  The resulting value is then aligned up to
+;              the next multiple of the machine's page size.  Scary.
+
+ss__read       ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+
+               ; --- Read the numeric value ---
+
+               MOV     R1,R0                   ;Point to the string
+               MOV     R0,#10                  ;By default it's base 10
+               SWI     XOS_ReadUnsigned        ;Read that value
+               BVS     ss__error               ;Handle a possible error
+               LDRB    R14,[R1],#1             ;Find the terminating char
+               ORR     R0,R14,#&20             ;Force it to lowercase
+               CMP     R0,#'m'                 ;Is value in megabytes?
+               MOVEQ   R2,R2,LSL #10           ;Yes -- shift it then
+               CMPNE   R0,#'k'                 ;Is value in kilobytes?
+               MOVEQ   R2,R2,LSL #10           ;Yes -- shift it then
+               LDREQB  R14,[R1],#1             ;And get another byte
+               CMP     R14,#&20                ;Make sure this is ctrl char
+               ADRCS   R0,ss__junk             ;No -- point to error
+               BCS     ss__error               ;And raise the error
+
+               ; --- Now align it to size ---
+
+               SWI     XOS_ReadMemMapInfo      ;Find out about memory map
+               BVS     ss__error               ;Handle a possible error
+               SUB     R14,R0,#1               ;Turn page size into bitmask
+               ADD     R0,R2,R14               ;And proceed to align
+               BIC     R0,R0,R14
+               LDMFD   R13!,{R1,R2,PC}^        ;Return to caller
+
+ss__junk       DCD     1
+               DCB     "Number not recognised",0
+
+               LTORG
+
+; --- ss__badSub ---
+;
+; On entry:    R9, R10 == memory requirements
+;
+; On exit:     --
+;
+; Use:         We didn't have enough memory to start as a subprogram, so
+;              we complain to the user.
+
+ss__badSub     ROUT
+
+               ADD     R1,R12,#512             ;Point to spare bit of memory
+               MOV     R14,#1                  ;Get an error number
+               STR     R14,[R1],#4             ;Store at the beginning
+               MOV     R0,R8                   ;Point to application name
+               BL      ss__strcpy              ;Copy that over
+               ADR     R0,ss__badSubErr        ;Point to the error
+               BL      ss__strcpy              ;Copy that too
+               MOV     R0,R9,LSR #10           ;Get the size in K
+               MOV     R2,#256                 ;And a bogus buffer size
+               SWI     XOS_ConvertInteger4     ;Write that out too
+               ADR     R0,ss__badSubEr2        ;Point to rest of the text
+               BL      ss__strcpy              ;Copy that over
+               ADD     R0,R12,#512             ;Point to base of error
+               B       ss__error               ;Complain now
+
+ss__badSubErr  DCB     " must have at least ",0
+ss__badSubEr2  DCB     "K left in application space to start up as a "
+               DCB     "subprogram",0
+
+               LTORG
+
+; --- ss__noRoom ---
+;
+; On entry:    R9, R10 == memory requirements
+;
+; On exit:     --
+;
+; Use:         We don't have enough memory for the heap or somesuch.
+
+ss__noRoom     ROUT
+
+               ADD     R1,R12,#512             ;Point to spare bit of memory
+               MOV     R14,#1                  ;Get an error number
+               STR     R14,[R1],#4             ;Store at the beginning
+               MOV     R0,R8                   ;Point to application name
+               BL      ss__strcpy              ;Copy that over
+               ADR     R0,ss__noRoomErr        ;Point to the error
+               BL      ss__strcpy              ;Copy that too
+               MOV     R0,R9,LSR #10           ;Get the size in K
+               ADD     R0,R0,R10,LSR #10       ;Add on the heap size
+               MOV     R2,#256                 ;And a bogus buffer size
+               SWI     XOS_ConvertInteger4     ;Write that out too
+               ADR     R0,ss__noRoomEr2        ;Point to rest of the text
+               BL      ss__strcpy              ;Copy that over
+               ADD     R0,R12,#512             ;Point to base of error
+               B       ss__error               ;Complain now
+
+ss__noRoomErr  DCB     " needs at least ",0
+ss__noRoomEr2  DCB     "K of memory available to start up",0
+
+               LTORG
+
+; --- ss__strcpy ---
+;
+; On entry:    R0 == pointer to source
+;              R1 == pointer to destination
+;
+; On exit:     R1 == pointer to terminating null
+;
+; Use:         Copies a string.
+
+ss__strcpy     ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+00             LDRB    R14,[R0],#1             ;Load a byte
+               CMP     R14,#&20                ;Is this the end?
+               MOVCC   R14,#0                  ;Yes -- null terminate then
+               STRB    R14,[R1],#1             ;Store it in the output
+               BCS     %b00                    ;Loop back if not done
+               SUB     R1,R1,#1                ;Point back at the null
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+               LTORG
+
+; --- ss__help ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Gives help about setSlot.
+
+ss__help       ROUT
+
+               ADR     R0,ss__helpText         ;Point to the help text
+               MOV     R1,#0                   ;Use system dictionary
+               LDR     R2,=version             ;Find the version string
+               ADR     R14,main                ;Find my base address
+               ADD     R2,R14,R2               ;And get the string address
+               SWI     XOS_PrettyPrint         ;Display the text
+               B       ss__end                 ;And return to caller
+
+ss__helpText   DCB     "SetSlot ",27,0,13
+               DCB     13
+               DCB     "Syntax: SetSlot -base <size>[K|M] "
+               DCB     "[-heap <size>[K|M]] [-flex <size>[K|M]] "
+               DCB     "[-appName <name>]",13
+               DCB     13
+               DCB     "Ensures that there is enough memory for an "
+               DCB     "application to start up.  The base size is the "
+               DCB     "amount of memory for the main image.  The heap "
+               DCB     "and flex sizes are added together to give the "
+               DCB     "required initial size for the shifting heap.",13
+               DCB     0
+
+               LTORG
+
+; --- ss__error ---
+;
+; On entry:    R0 == pointer to error
+;
+; On exit:     Doesn't
+;
+; Use:         Returns to the OS with an error.
+
+ss__error      ROUT
+
+               LDR     R14,[R12,#0]            ;Load the return address
+               ORRS    PC,R14,#V_flag          ;And return
+
+               LTORG
+
+; --- ss__end ---
+;
+; On entry:    --
+;
+; On exit:     Doesn't
+;
+; Use:         Returns to the OS successfully.
+
+ss__end                ROUT
+
+               LDR     R14,[R12,#0]            ;Load the return address
+               BICS    PC,R14,#V_flag          ;And return
+
+               LTORG
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Utilities/s/test b/StraySrc/Utilities/s/test
new file mode 100644 (file)
index 0000000..adc4897
--- /dev/null
@@ -0,0 +1,612 @@
+;
+; test.s
+;
+; Tests a condition
+;
+; © 1995-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core utilities (coreutils).
+;
+; Coreutils is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Coreutils is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Coreutils.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Standard header ------------------------------------------------------
+
+               GET     libs:header
+               GET     libs:swis
+
+               GET     libs:stream
+
+;----- External dependencies ------------------------------------------------
+
+               IMPORT  version
+
+;----- Main code ------------------------------------------------------------
+
+               AREA    |!!!Utility$$Code|,CODE,READONLY
+
+; --- main ---
+;
+; On entry:    R0 == pointer to command string
+;              R1 == pointer to command tail
+;
+; On exit:     May return an error
+;
+; Use:         Performs a test, and does things appropriately.
+
+main           ROUT
+
+               STR     R14,test_return         ;Save the return address
+
+               ; --- Read the command line arguments ---
+
+               ADR     R0,test_syntaxDef       ;Find the definitions
+               ADR     R2,test_args            ;Point to argument buffer
+               MOV     R3,#252                 ;Get the buffer size
+               SWI     XOS_ReadArgs            ;Read the arguments
+               BVS     test_error              ;If it failed, return now
+
+               ; --- Check for some easy cases ---
+
+               LDR     R14,tArg_help           ;Load the help switch
+               CMP     R14,#0                  ;Is it enabled?
+               BNE     test_help               ;Yes -- give some help then
+
+               ; --- Sort out the test ---
+
+               ADR     R0,tArg_file            ;Point to file arg
+               ADR     R1,tArg_exists          ;And to the limit
+               BL      test_which              ;Which one is set?
+               ADRCC   R0,test_noTest          ;None -- point to error
+               BCC     test_error              ;And complain then
+               MOV     R2,R0                   ;Look after this
+
+               ADR     R0,tArg_exists          ;Point to file qualifiers
+               ADR     R1,tArg_limit           ;And to the very end
+               BL      test_which              ;Which one is set?
+               CMP     R2,#0                   ;Is this a file?
+               CMPNE   R0,#-1                  ;No -- make sure no quals
+               ADRNE   R0,test_badQuals        ;If there are, find error
+               BNE     test_error              ;And complain
+               MOV     R10,R0                  ;Look after this
+
+               ; --- Dispatch the test ---
+
+               MOV     R14,PC                  ;Set up return address
+               ADD     PC,PC,R2,LSL #2         ;Dispatch
+               B       %f00                    ;And continue when done
+
+               B       test_file               ;Handle a file test
+               B       test_expr               ;Handle an expression test
+               B       test_key                ;Handle a key test
+               B       test_riscOs             ;Handle an OS version test
+               B       test_command            ;Handle a command test
+               B       test_true               ;Handle a true test
+               B       test_false              ;Handle a false test
+
+               ; --- Now handle the results ---
+
+00             LDR     R14,tArg_multiLine      ;Is this a multiline?
+               CMP     R14,#0                  ;Is the switch there?
+               BNE     %50main                 ;Yes -- handle that then
+               CMP     R0,#0                   ;Was the condition true?
+               LDRNE   R0,tArg_then            ;Yes -- find then clause
+               LDREQ   R0,tArg_else            ;No -- find else clause
+               CMP     R0,#0                   ;Is the clause defined?
+               SWINE   XOS_CLI                 ;Yes -- do it then
+               BVS     test_error              ;If it failed, die horribly
+               B       test_end                ;Otherwise end nicely
+
+               ; --- Deal with a multiline ---
+
+50             CMP     R0,#0                   ;Did the test succeed?
+               ADR     R0,test_uScore          ;Point to variable name
+               ADRNE   R1,test_vTrue           ;Yes -- use true value
+               ADREQ   R1,test_vFalse          ;No -- use false value
+               BL      test_setVar             ;Set that up
+
+               ADR     R0,test_else            ;Point to variable name
+               ADRNE   R1,test_eTrue           ;Yes -- use true value
+               ADREQ   R1,test_eFalse          ;No -- use false value
+               BL      test_setVar             ;Set that up
+
+               ADR     R0,test_endif           ;Point to variable name
+               ADR     R1,test_endVal          ;Point to value
+               BL      test_setVar             ;Set that up
+               B       test_end                ;And return when done
+
+test_uScore    DCB     "Alias$_",0
+test_vTrue     DCB     "%*0",0
+test_vFalse    DCB     "||",0
+test_else      DCB     "Alias$Else",0
+test_eTrue     DCB     "Set Alias$_ ||||",0
+test_eFalse    DCB     "Set Alias$_ %%*0",0
+test_endif     DCB     "Alias$EndIf",0
+test_endVal    DCB     "Unset Alias$_|mUnset Alias$Else|m"
+               DCB     "Unset Alias$EndIf",0
+
+test_noTest    DCD     1
+               DCB     "No condition to test",0
+
+test_badQuals  DCD     1
+               DCB     "File qualifier found, but not -file test",0
+               ALIGN
+
+test_syntaxDef DCB     "help/s,"
+
+               DCB     "then/k,"
+               DCB     "else/k,"
+               DCB     "multiline/s,"
+
+               DCB     "file/k,"
+               DCB     "expr/e/k,"
+               DCB     "key/e/k,"
+               DCB     "riscOs/k,"
+               DCB     "command/k,"
+               DCB     "true/s,"
+               DCB     "false/s,"
+
+               DCB     "exists/s,"
+               DCB     "isDir/s,"
+               DCB     "isFile/s,"
+               DCB     "isType/k",0
+
+               LTORG
+
+; --- test_which ---
+;
+; On entry:    R0 == pointer to base argument
+;              R1 == pointer to limit argument
+;
+; On exit:     CS if an argument matched, and
+;                R0 == index of argument chosen
+;              else CC and
+;                R0 == -1
+;
+; Use:         Works out which argument in a collection is actually chosen.
+;              an error is raised if more than one is chosen.
+
+test_which     ROUT
+
+               STMFD   R13!,{R1-R3,R14}        ;Save some registers
+               MOV     R2,R0                   ;Look after base pointer
+               MOV     R0,#-1                  ;Initially, we have no choice
+               MOV     R3,#-1                  ;Initialise a counter
+00             ADD     R3,R3,#1                ;Increment the counter
+               CMP     R2,R1                   ;Finished scanning?
+               BEQ     %10test_which           ;Yes -- deal with that
+               LDR     R14,[R2],#4             ;Load the argument
+               CMP     R14,#0                  ;Is this one enabled?
+               BEQ     %b00                    ;No -- ignore it then
+               CMP     R0,#-1                  ;Do we have a choice yet?
+               MOVEQ   R0,R3                   ;No -- we do now
+               BEQ     %b00                    ;So skip back again
+
+               ADR     R0,test_badRadio        ;Point to the error
+               B       test_error              ;And report it
+
+10test_which   CMP     R0,#-1                  ;Did we get an answer?
+               LDMFD   R13!,{R1-R3,R14}        ;Restore registers
+               ORRNES  PC,R14,#C_flag          ;Yes -- return C set
+               BICEQS  PC,R14,#C_flag          ;No -- return C clear
+
+test_badRadio  DCD     1
+               DCB     "Bad options",0
+
+               LTORG
+
+; --- test_help ---
+;
+; On entry:    --
+;
+; On exit:     Doesn't
+;
+; Use:         Gives the user some help.
+
+test_help      ROUT
+
+               ADR     R0,test_helpText        ;Point to the help text
+               MOV     R1,#0                   ;Use the system dictionary
+               LDR     R2,=version             ;Find the version string
+               ADRL    R14,main                ;Point to the utility base
+               ADD     R2,R14,R2               ;Relocate the pointer
+               SWI     XOS_PrettyPrint         ;Write the text out
+               B       test_end                ;And finish the program
+
+test_helpText  DCB     "test ",27,0,13
+               DCB     13
+               DCB     "Syntax: test <condition> <target>",13
+               DCB     13
+               DCB     "Tests a condition and then performs an operation "
+               DCB     "based on the result.  Possible targets are:",13
+               DCB     13
+               DCB     "[-then <command>] [-else <command>]",13
+               DCB     "-multiline",13
+               DCB     13
+               DCB     "-then ... -else ... works as expected.  "
+               DCB     "-multiline defines a collection of alias "
+               DCB     "commands, as follows:",13
+               DCB     13
+               DCB     "_",9,9,"prefix normal commands with this",13
+               DCB     "else",9,9,"toggles whether `_' executes commands",13
+               DCB     "endif",9,9,"undefines `_', `else' and `endif'",13
+               DCB     13
+               DCB     "Permitted tests are:",13
+               DCB     13
+               DCB     "-file <file> <qualifier>",13
+               DCB     "-expr <expression>",13
+               DCB     "-key <key number>",13
+               DCB     "-riscos <version number>",13
+               DCB     "-command <*command>",13
+               DCB     "-true | -false",13
+               DCB     13
+               DCB     "The file qualifiers test various things about a "
+               DCB     "file:",13
+               DCB     13
+               DCB     "-exists",9,9,"Ensure the file exists",13
+               DCB     "-isDir",9,9,"Ensure it's a directory",13
+               DCB     "-isFile",9,9,"Ensure it's a file",13
+               DCB     "-isType <type>",9,"Ensure it's a file of given "
+               DCB     "type",13
+               DCB     13
+               DCB     "Key numbers are given either as internal key "
+               DCB     "numbers (see sapphire:intKeys for bindings) or as "
+               DCB     "BASIC-style -ve INKEY numbers",13
+               DCB     13
+               DCB     "The -riscos test ensures that the current version "
+               DCB     "of the OS is the same or later than that given.",13
+               DCB     13
+               DCB     "The -command test runs a command and ensures that "
+               DCB     "it didn't return an error.  This may be useful "
+               DCB     "just to suppress the error.",13
+               DCB     0
+
+               LTORG
+
+; --- test_file ---
+;
+; On entry:    R10 == reason code
+;
+; On exit:     R0 == 0 if false, non-0 if true
+;              R1-R11 corrupted
+;
+; Use:         Performs a file operation and returns its truth.
+
+test_file      ROUT
+
+               ; --- Find the file information ---
+
+               MOV     R0,#17                  ;Read file information
+               LDR     R1,tArg_file            ;Get the filename
+               SWI     XOS_File                ;Try to get this information
+               MOVVS   R0,#0                   ;If failed, say not there
+               CMP     R10,#0                  ;Just checking existance?
+               CMPNE   R0,#0                   ;Or is the file not there?
+               MOVEQS  PC,R14                  ;Yes -- return now
+
+               CMP     R10,#-1                 ;Was one chosen?
+               ADDNE   PC,PC,R10,LSL #2        ;Yes -- dispatch it
+               MOVS    PC,R14                  ;No op -- assume existance
+
+               MOVS    PC,R14                  ;Dealt with this already
+               B       test_fDir               ;Check it's a directory
+               B       test_fFile              ;Check it's a file
+               B       test_fType              ;Check its type
+
+test_fDir      AND     R0,R0,#2                ;Leave only the dir bit
+               MOVS    PC,R14                  ;And return
+
+test_fFile     AND     R0,R0,#1                ;Leave only the file bit
+               MOVS    PC,R14                  ;And return
+
+test_fType     ANDS    R0,R0,#1                ;Test the file bit
+               MOVEQS  PC,R14                  ;If clear, skip on
+               MOV     R3,R2,LSL #12           ;Look after the filetype
+               MOV     R0,#31                  ;Convert filetype name
+               LDR     R1,tArg_isType          ;Find the type string
+               SWI     XOS_FSControl           ;Try to convert it
+               BVS     test_error              ;Fail if we couldn't
+               CMP     R2,R3,LSR #20           ;Compare the filetypes
+               MOVEQ   R0,#1                   ;If match, say true
+               MOVNE   R0,#0                   ;Otherwise say false
+               MOVS    PC,R14                  ;And return
+
+               LTORG
+
+; --- test_expr ---
+;
+; On entry:    --
+;
+; On exit:     R0 == 0 if false, non-0 if true
+;              R1-R11 corrupted
+;
+; Use:         Evaluates an expression and returns the result.
+
+test_expr      ROUT
+
+               LDR     R0,tArg_expr            ;Find the expression result
+               B       test_getValue           ;Read the value
+
+               LTORG
+
+; --- test_key ---
+;
+; On entry:    --
+;
+; On exit:     R0 == 0 if false, non-0 if true
+;              R1-R11 corrupted
+;
+; Use:         Tests a key on the keyboard.
+
+test_key       STMFD   R13!,{R14}              ;Save the link register
+               LDR     R0,tArg_key             ;Find the expression result
+               BL      test_getValue           ;Find the value
+               TST     R0,#&80000000           ;Is the result negative?
+               EOREQ   R0,R0,#&FF              ;No -- then do that then
+               MOV     R2,#&FF                 ;Scan for the key
+               AND     R1,R0,#&FF              ;Only have lowest byte
+               MOV     R0,#&81                 ;Get the OS_Byte code
+               SWI     XOS_Byte                ;Read the key pressedness
+               BVS     test_error              ;If it failed, return error
+               MOV     R0,R1                   ;Get the result
+               LDMFD   R13!,{PC}^              ;And return
+
+               LTORG
+
+; --- test_riscOs ---
+;
+; On entry:    --
+;
+; On exit:     R0 == 0 if false, and non-0 if true
+;              R1-R11 corrupted
+;
+; Use:         Returns the result of testing the OS version.
+
+test_riscOs    ROUT
+
+               STMFD   R13!,{R14}              ;Save a register
+               LDR     R0,tArg_riscOs          ;Find the version string
+               BL      test_getVersion         ;Translate it for me
+               MOV     R3,R0                   ;Look after this result
+
+               MOV     R0,#129                 ;Read the OS version
+               MOV     R1,#0                   ;Want the OS version
+               MOV     R2,#255                 ;Still want it, dammit
+               SWI     XOS_Byte                ;Try to read it then
+               BVS     test_error              ;If it failed, report error
+
+               ADR     R2,test_verTable        ;Point to version table
+               MOV     R0,#-1                  ;Start off with bad value
+00             LDMIA   R2!,{R4,R5}             ;Load the values out
+               CMP     R4,R1                   ;Does this version match?
+               MOVLE   R0,R5                   ;Yes -- use it then
+               BGT     %b00                    ;Otherwise loop back
+
+               CMP     R0,R3                   ;Compare with his version
+               MOVGE   R0,#1                   ;If later or same, return ok
+               MOVLT   R0,#0                   ;Otherwise return false
+               LDMFD   R13!,{PC}^              ;And return to caller
+
+test_verTable  DCD     &A5,350
+               DCD     &A4,310
+               DCD     &A3,300
+               DCD     &A2,201
+               DCD     &A1,200
+               DCD     &A0,120
+               DCD     0,0
+
+               LTORG
+
+; --- test_command ---
+;
+; On entry:    --
+;
+; On exit:     R0 == 0 if false, non-0 if true
+;
+; Use:         Runs a command, and returns true if the command didn't
+;              make an error.
+
+test_command   ROUT
+
+               LDR     R0,tArg_command         ;Load the command string
+               SWI     XOS_CLI                 ;Run the command
+               MOVVC   R0,#1                   ;If OK, return true
+               MOVVS   R0,#0                   ;Otherwise return false
+               MOVS    PC,R14                  ;And return to caller
+
+               LTORG
+
+; --- test_true and test_false ---
+;
+; On entry:    --
+;
+; On exit:     R0 == 0 if false, non-0 if true
+;              R1-R11 corrupted
+;
+; Use:         Return particular values.
+
+test_true      MOV     R0,#1                   ;Return true
+               MOVS    PC,R14                  ;And return
+
+test_false     MOV     R0,#0                   ;Return false
+               MOVS    PC,R14                  ;And return
+
+               LTORG
+
+; --- test_getValue ---
+;
+; On entry:    R0 == pointer to expression result
+;
+; On exit:     R0 == value read
+;
+; Use:         Reads the value of an expression from the OS_ReadArgs block.
+
+test_getValue  ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               LDRB    R14,[R0],#1             ;Load the first byte
+               CMP     R14,#0                  ;Is this an integer?
+               ADRNE   R0,test_notAnInt        ;No -- then find error
+               BNE     test_error              ;And complain
+               AND     R2,R0,#3                ;Find non-alignedness
+               BIC     R0,R0,#3                ;Round down a little
+               LDMIA   R0,{R0,R1}              ;Load the value out
+               MOV     R2,R2,LSL #3            ;Convert bits to bytes
+               RSB     R14,R2,#32              ;And find the other shift
+               MOV     R0,R0,LSR R2            ;Get the lower bits
+               ORR     R0,R0,R1,LSL R14        ;And the upper bits
+               LDMFD   R13!,{R1,R2,PC}^        ;And return to caller
+
+test_notAnInt  DCD     1
+               DCB     "Integer expected",0
+
+               LTORG
+
+; --- test_getVersion ---
+;
+; On entry:    R0 == pointer to version string
+;
+; On exit:     R0 == value of version number-
+;
+; Use:         Reads a version umber
+
+test_getVersion        ROUT
+
+               STMFD   R13!,{R1,R2,R14}        ;Save some registers
+               MOV     R2,#0                   ;Clear version accumulator
+
+00             LDRB    R1,[R0],#1              ;Load next byte from thing
+               SUB     R14,R1,#'0'             ;Convert digit to integer
+               CMP     R14,#10                 ;Is it in range?
+               ADDCC   R2,R2,R2,LSL #2         ;Yes -- accumulate
+               ADDCC   R2,R14,R2,LSL #1        ;Multiply by 10 and add
+               BCC     %b00                    ;And loop back round
+
+               ADD     R2,R2,R2,LSL #2         ;Multiply version by 100
+               ADD     R2,R2,R2,LSL #2
+               MOV     R2,R2,LSL #2
+
+               CMP     R1,#'.'                 ;Is the character a dot?
+               BNE     %f00                    ;No -- skip on then
+               LDRB    R1,[R0],#1              ;Load next byte from thing
+               SUB     R14,R1,#'0'             ;Convert digit to integer
+               CMP     R14,#10                 ;Is it in range?
+               ADDCC   R14,R14,R14,LSL #2      ;Yes -- accumulate
+               ADDCC   R2,R2,R14,LSL #1        ;Do it the other way round
+               LDRCCB  R1,[R0],#1              ;Load next byte from thing
+               SUB     R14,R1,#'0'             ;Convert digit to integer
+               CMP     R14,#10                 ;Is it in range?
+               ADDCC   R2,R2,R14               ;Yes -- add that on
+               LDRCCB  R1,[R0],#1              ;Load next byte from thing
+
+00             CMP     R1,#&20                 ;Is this the very end?
+               ADRCS   R0,test_badVer          ;Point to error message
+               BCS     test_error              ;And complain bitterly
+               MOV     R0,R2                   ;Get the version number
+               LDMFD   R13!,{R1,R2,PC}^        ;And return to caller
+
+test_badVer    DCD     1
+               DCB     "Bad version number",0
+
+               LTORG
+
+; --- test_setVar ---
+;
+; On entry:    R0 == variable name
+;              R1 == pointer to value
+;
+; On exit:     --
+;
+; Use:         Sets the variable given to the given value.
+
+test_setVar    ROUT
+
+               STMFD   R13!,{R0-R4,R14}        ;Save some registers
+               MOV     R2,R1                   ;Point to the value
+00             LDRB    R14,[R2],#1             ;Load the next byte
+               CMP     R14,#&20                ;Is this the end yet?
+               BCS     %b00                    ;No -- keep going
+               SUB     R2,R2,R1                ;Find the string length
+               SUB     R2,R2,#1                ;Don't count the terminator
+               MOV     R3,#0                   ;Start at the beginning
+               MOV     R4,#0                   ;Normal GS type variable
+               SWI     XOS_SetVarVal           ;Set the variable
+               BVS     test_error              ;If failed, abort
+               LDMFD   R13!,{R0-R4,PC}^        ;And return to caller
+
+               LTORG
+
+; --- test_end ---
+;
+; On entry:    --
+;
+; On exit:     --
+;
+; Use:         Returns to the operating system.
+
+test_end       ROUT
+
+               LDR     R14,test_return         ;Find the return address
+               BICS    PC,R14,#V_flag          ;And return with no error
+
+               LTORG
+
+; --- test_error ---
+;
+; On entry:    R0 == pointer to error block
+;
+; On exit:     --
+;
+; Use:         Reports an error to the operating system.
+
+test_error     ROUT
+
+               LDR     R14,test_return         ;Find the return address
+               ORRS    PC,R14,#V_flag          ;And return the error
+
+               LTORG
+
+;----- Workspace ------------------------------------------------------------
+
+               ^       0,R12
+test_wStart    #       0
+
+test_return    #       4                       ;Return address
+
+test_args      #       0                       ;Argument output buffer
+tArg_help      #       4                       ;Help switch
+tArg_then      #       4                       ;Then command
+tArg_else      #       4                       ;Else command
+tArg_multiLine #       4                       ;Multiline switch
+tArg_file      #       4                       ;File condition
+tArg_expr      #       4                       ;Expression condition
+tArg_key       #       4                       ;Key condition
+tArg_riscOs    #       4                       ;OS version condition
+tArg_command   #       4                       ;Run a *command
+tArg_true      #       4                       ;True condition
+tArg_false     #       4                       ;False condition
+tArg_exists    #       4                       ;Exists filetest
+tArg_isDir     #       4                       ;IsDir filetest
+tArg_isFile    #       4                       ;IsFile filetest
+tArg_isType    #       4                       ;IsType filetest
+tArg_limit     #       4                       ;End of the arguments
+
+test_buffer    EQU     test_wStart+256         ;Misc buffer for things
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Utilities/sh/pathUtil b/StraySrc/Utilities/sh/pathUtil
new file mode 100644 (file)
index 0000000..7e1f32f
--- /dev/null
@@ -0,0 +1,64 @@
+;
+; pathUtil.sh
+;
+; Messing about with path variables
+;
+; © 1994-1998 Straylight
+;
+
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's core utilities (coreutils).
+;
+; Coreutils is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; Coreutils is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with Coreutils.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+;----- Overview -------------------------------------------------------------
+;
+; Functions provided:
+;
+;  path_addDir
+;  path_removeDir
+
+               [       :LNOT::DEF:pathUtil__dfn
+               GBLL    pathUtil__dfn
+
+; --- path_addDir ---
+;
+; On entry:    R0 == pointer to path variable name
+;              R1 == pointer to a directory string to add in
+;
+; On exit:     CS if path element added, CC otherwise
+;              May return an error
+;
+; Use:         Adds a directory to the given path variable.
+
+               IMPORT  path_addDir
+
+; --- path_removeDir ---
+;
+; On entry:    R0 == pointer to name of path variable
+;              R1 == pointer to a directory to remove
+;
+; On exit:     May return an error
+;
+; Use:         Removes an element from a given path variable.
+
+               IMPORT  path_removeDir
+
+               ]
+
+;----- That's all, folks ----------------------------------------------------
+
+               END
diff --git a/StraySrc/Utilities/templaof,ffb b/StraySrc/Utilities/templaof,ffb
new file mode 100644 (file)
index 0000000..3a1c50a
Binary files /dev/null and b/StraySrc/Utilities/templaof,ffb differ
diff --git a/StraySrc/dist/Core b/StraySrc/dist/Core
new file mode 100644 (file)
index 0000000..dccf9ae
--- /dev/null
@@ -0,0 +1,208 @@
+StraySrc.!DLLs
+StraySrc.!DLLs.enumerate
+StraySrc.!DLLs.hour
+StraySrc.!DLLs.pathutil
+StraySrc.bin
+StraySrc.bin.buildstub
+StraySrc.bin.chdrgen
+StraySrc.bin.each
+StraySrc.bin.enumerate
+StraySrc.bin.fixlink
+StraySrc.bin.headergen
+StraySrc.bin.hour
+StraySrc.bin.inst
+StraySrc.bin.msgaof
+StraySrc.bin.pathutil
+StraySrc.bin.resgen
+StraySrc.bin.setdate
+StraySrc.bin.setslot
+StraySrc.bin.ssrclean
+StraySrc.bin.submake
+StraySrc.bin.templaof
+StraySrc.bin.test
+StraySrc.COPYING
+StraySrc.dist
+StraySrc.dist.Core
+StraySrc.dist.makedist
+StraySrc.Libraries
+StraySrc.Libraries.BAS
+StraySrc.Libraries.BAS.bas
+StraySrc.Libraries.BAS.exports
+StraySrc.Libraries.BAS.Makefile
+StraySrc.Libraries.BAS.src
+StraySrc.Libraries.BAS.src.b
+StraySrc.Libraries.BAS.src.b.bas
+StraySrc.Libraries.BAS.src.bc
+StraySrc.Libraries.BAS.src.bc.bas
+StraySrc.Libraries.BAS.src.Makefile
+StraySrc.Libraries.BAS.src.o
+StraySrc.Libraries.BAS.src.README
+StraySrc.Libraries.BAS.src.rsc
+StraySrc.Libraries.BAS.src.rsc.messages
+StraySrc.Libraries.BAS.src.s
+StraySrc.Libraries.BAS.src.s.aofGen
+StraySrc.Libraries.BAS.src.s.bas
+StraySrc.Libraries.BAS.src.s.basTalk
+StraySrc.Libraries.BAS.src.s.fastMove
+StraySrc.Libraries.BAS.src.s.flex
+StraySrc.Libraries.BAS.src.s.get
+StraySrc.Libraries.BAS.src.s.insert
+StraySrc.Libraries.BAS.src.s.lit
+StraySrc.Libraries.BAS.src.s.string
+StraySrc.Libraries.BAS.src.s.vars
+StraySrc.Libraries.BAS.src.scripts
+StraySrc.Libraries.BAS.src.scripts.crunchit
+StraySrc.Libraries.BAS.src.scripts.execit
+StraySrc.Libraries.BAS.src.scripts.exports
+StraySrc.Libraries.BAS.src.scripts.preproc
+StraySrc.Libraries.BAS.src.sh
+StraySrc.Libraries.BAS.src.sh.aofGen
+StraySrc.Libraries.BAS.src.sh.bas
+StraySrc.Libraries.BAS.src.sh.basicEnv
+StraySrc.Libraries.BAS.src.sh.basTalk
+StraySrc.Libraries.BAS.src.sh.fastMove
+StraySrc.Libraries.BAS.src.sh.flex
+StraySrc.Libraries.BAS.src.sh.get
+StraySrc.Libraries.BAS.src.sh.insert
+StraySrc.Libraries.BAS.src.sh.lit
+StraySrc.Libraries.BAS.src.sh.messages
+StraySrc.Libraries.BAS.src.sh.string
+StraySrc.Libraries.BAS.src.sh.vars
+StraySrc.Libraries.BAS.src.sh.workspace
+StraySrc.Libraries.BAS.src.work
+StraySrc.Libraries.Core
+StraySrc.Libraries.Core.AOF
+StraySrc.Libraries.Core.AOF.c
+StraySrc.Libraries.Core.AOF.c.aof
+StraySrc.Libraries.Core.AOF.h
+StraySrc.Libraries.Core.AOF.h.alf
+StraySrc.Libraries.Core.AOF.h.aof
+StraySrc.Libraries.Core.AOF.h.chunk
+StraySrc.Libraries.Core.AOF.Makefile
+StraySrc.Libraries.Core.AOF.o
+StraySrc.Libraries.Core.AOF.o.aof
+StraySrc.Libraries.Core.AOF.README
+StraySrc.Libraries.Core.dump
+StraySrc.Libraries.Core.EmbTemp
+StraySrc.Libraries.Core.EmbTemp.Makefile
+StraySrc.Libraries.Core.EmbTemp.o
+StraySrc.Libraries.Core.EmbTemp.o.embTemp
+StraySrc.Libraries.Core.EmbTemp.README
+StraySrc.Libraries.Core.EmbTemp.s
+StraySrc.Libraries.Core.EmbTemp.s.embTemp
+StraySrc.Libraries.Core.EmbTemp.sh
+StraySrc.Libraries.Core.EmbTemp.sh.embTemp
+StraySrc.Libraries.Core.h
+StraySrc.Libraries.Core.h.swis
+StraySrc.Libraries.Core.h.swiv
+StraySrc.Libraries.Core.h._time
+StraySrc.Libraries.Core.header
+StraySrc.Libraries.Core.Makefile
+StraySrc.Libraries.Core.o
+StraySrc.Libraries.Core.o.asstubs
+StraySrc.Libraries.Core.o.astubs
+StraySrc.Libraries.Core.o.dstubs
+StraySrc.Libraries.Core.o.msstubs
+StraySrc.Libraries.Core.o.mstubs
+StraySrc.Libraries.Core.o.rdump
+StraySrc.Libraries.Core.o.swiv
+StraySrc.Libraries.Core.s
+StraySrc.Libraries.Core.s.fastMove
+StraySrc.Libraries.Core.s.flex
+StraySrc.Libraries.Core.s.heap
+StraySrc.Libraries.Core.s.oxswi
+StraySrc.Libraries.Core.s.rdump
+StraySrc.Libraries.Core.s.swihack
+StraySrc.Libraries.Core.s.swiv
+StraySrc.Libraries.Core.s.xapp
+StraySrc.Libraries.Core.s.xcommon
+StraySrc.Libraries.Core.s.xdata
+StraySrc.Libraries.Core.s.xdll
+StraySrc.Libraries.Core.s.xentry
+StraySrc.Libraries.Core.s.xentry_swi
+StraySrc.Libraries.Core.s.xmodule
+StraySrc.Libraries.Core.s.xsmall
+StraySrc.Libraries.Core.s.xsmall_swi
+StraySrc.Libraries.Core.s.xswi
+StraySrc.Libraries.Core.sh
+StraySrc.Libraries.Core.sh.fastMove
+StraySrc.Libraries.Core.sh.flex
+StraySrc.Libraries.Core.sh.flexws
+StraySrc.Libraries.Core.sh.heapws
+StraySrc.Libraries.Core.stream
+StraySrc.Libraries.Core.swis
+StraySrc.Libraries.Core.TearSupt
+StraySrc.Libraries.Core.TearSupt.bs
+StraySrc.Libraries.Core.TearSupt.bs.tearSupt
+StraySrc.Libraries.Core.TearSupt.h
+StraySrc.Libraries.Core.TearSupt.h.tearSupt
+StraySrc.Libraries.Core.TearSupt.Makefile
+StraySrc.Libraries.Core.TearSupt.o
+StraySrc.Libraries.Core.TearSupt.o.tearSupt
+StraySrc.Libraries.Core.TearSupt.README
+StraySrc.Libraries.Core.TearSupt.s
+StraySrc.Libraries.Core.TearSupt.s.tt
+StraySrc.Libraries.Core.TearSupt.sh
+StraySrc.Libraries.Core.TearSupt.sh.tearSupt
+StraySrc.Libraries.Core.TearSupt.UnLoad
+StraySrc.Libraries.Makefile
+StraySrc.Makefile
+StraySrc.Modules
+StraySrc.ssr-init
+StraySrc.Utilities
+StraySrc.Utilities.b
+StraySrc.Utilities.b.buildstub
+StraySrc.Utilities.b.fixlink
+StraySrc.Utilities.b.msgaof
+StraySrc.Utilities.b.resgen
+StraySrc.Utilities.b.templaof
+StraySrc.Utilities.buildstub
+StraySrc.Utilities.c
+StraySrc.Utilities.c.alloc
+StraySrc.Utilities.c.chdrgen
+StraySrc.Utilities.c.cmdr
+StraySrc.Utilities.c.each
+StraySrc.Utilities.c.gf
+StraySrc.Utilities.c.glob
+StraySrc.Utilities.c.headerGen
+StraySrc.Utilities.c.inst
+StraySrc.Utilities.c.setdate
+StraySrc.Utilities.c.ssrclean
+StraySrc.Utilities.c.submake
+StraySrc.Utilities.chdrgen
+StraySrc.Utilities.each
+StraySrc.Utilities.enumerate
+StraySrc.Utilities.ex
+StraySrc.Utilities.ex.buildstub
+StraySrc.Utilities.ex.msgaof
+StraySrc.Utilities.ex.resgen
+StraySrc.Utilities.ex.templaof
+StraySrc.Utilities.fixlink
+StraySrc.Utilities.h
+StraySrc.Utilities.h.alloc
+StraySrc.Utilities.h.cmdr
+StraySrc.Utilities.h.gf
+StraySrc.Utilities.h.glob
+StraySrc.Utilities.headergen
+StraySrc.Utilities.hour
+StraySrc.Utilities.inst
+StraySrc.Utilities.Makefile
+StraySrc.Utilities.msgaof
+StraySrc.Utilities.o
+StraySrc.Utilities.pathutil
+StraySrc.Utilities.resgen
+StraySrc.Utilities.s
+StraySrc.Utilities.s.enumerate
+StraySrc.Utilities.s.hour
+StraySrc.Utilities.s.pathUtil
+StraySrc.Utilities.s.path_util
+StraySrc.Utilities.s.setSlot
+StraySrc.Utilities.s.test
+StraySrc.Utilities.setdate
+StraySrc.Utilities.setslot
+StraySrc.Utilities.sh
+StraySrc.Utilities.sh.pathUtil
+StraySrc.Utilities.ssrclean
+StraySrc.Utilities.submake
+StraySrc.Utilities.templaof
+StraySrc.Utilities.test
diff --git a/StraySrc/dist/Dynamite b/StraySrc/dist/Dynamite
new file mode 100644 (file)
index 0000000..851183a
--- /dev/null
@@ -0,0 +1,34 @@
+StraySrc.COPYING
+StraySrc.dist.Dynamite
+StraySrc.Dynamite
+StraySrc.Dynamite.apcs
+StraySrc.Dynamite.apcs.h
+StraySrc.Dynamite.apcs.h.dynamite
+StraySrc.Dynamite.apcs.Makefile
+StraySrc.Dynamite.apcs.o
+StraySrc.Dynamite.apcs.s
+StraySrc.Dynamite.apcs.s.dyn_apcs
+StraySrc.Dynamite.dynamite
+StraySrc.Dynamite.dynamite.Dynamite
+StraySrc.Dynamite.dynamite.Makefile
+StraySrc.Dynamite.dynamite.o
+StraySrc.Dynamite.dynamite.rsc
+StraySrc.Dynamite.dynamite.rsc.messages
+StraySrc.Dynamite.dynamite.s
+StraySrc.Dynamite.dynamite.s.dynamite
+StraySrc.Dynamite.dynamite.s.dynAnchor
+StraySrc.Dynamite.dynamite.s.dynArea
+StraySrc.Dynamite.dynamite.s.dynHeap
+StraySrc.Dynamite.dynamite.s.dynTask
+StraySrc.Dynamite.dynamite.s.fastMove
+StraySrc.Dynamite.dynamite.sh
+StraySrc.Dynamite.dynamite.sh.dynAnchor
+StraySrc.Dynamite.dynamite.sh.dynArea
+StraySrc.Dynamite.dynamite.sh.dynHeap
+StraySrc.Dynamite.dynamite.sh.dynTask
+StraySrc.Dynamite.dynamite.sh.messages
+StraySrc.Dynamite.dynamite.sh.wSpace
+StraySrc.Dynamite.Makefile
+StraySrc.Makefile
+StraySrc.Modules
+StraySrc.Modules.Dynamite
diff --git a/StraySrc/dist/Hammer b/StraySrc/dist/Hammer
new file mode 100644 (file)
index 0000000..eeea31b
--- /dev/null
@@ -0,0 +1,20 @@
+StraySrc.COPYING
+StraySrc.dist.Hammer
+StraySrc.Hammer
+StraySrc.Hammer.Makefile
+StraySrc.Hammer.o
+StraySrc.Hammer.s
+StraySrc.Hammer.s.armEmul
+StraySrc.Hammer.s.asm
+StraySrc.Hammer.s.brkpt
+StraySrc.Hammer.s.diss
+StraySrc.Hammer.s.driver
+StraySrc.Hammer.s.hammer
+StraySrc.Hammer.sh
+StraySrc.Hammer.sh.armEmul
+StraySrc.Hammer.sh.asm
+StraySrc.Hammer.sh.brkpt
+StraySrc.Hammer.sh.diss
+StraySrc.Hammer.sh.driver
+StraySrc.Hammer.sh.hammer
+StraySrc.Makefile
diff --git a/StraySrc/dist/MiscToys b/StraySrc/dist/MiscToys
new file mode 100644 (file)
index 0000000..7c3effc
--- /dev/null
@@ -0,0 +1,28 @@
+StraySrc.COPYING
+StraySrc.Makefile
+StraySrc.MiscToys
+StraySrc.MiscToys.CheckSD
+StraySrc.MiscToys.CheckSD.checksd
+StraySrc.MiscToys.CheckSD.Makefile
+StraySrc.MiscToys.CheckSD.o
+StraySrc.MiscToys.CheckSD.README
+StraySrc.MiscToys.CheckSD.rsc
+StraySrc.MiscToys.CheckSD.rsc.Templates
+StraySrc.MiscToys.CheckSD.s
+StraySrc.MiscToys.CheckSD.s.CheckSD
+StraySrc.MiscToys.CurrDir
+StraySrc.MiscToys.CurrDir.currDir
+StraySrc.MiscToys.CurrDir.Makefile
+StraySrc.MiscToys.CurrDir.o
+StraySrc.MiscToys.CurrDir.README
+StraySrc.MiscToys.CurrDir.s
+StraySrc.MiscToys.CurrDir.s.currDir
+StraySrc.MiscToys.Makefile
+StraySrc.MiscToys.PlainError
+StraySrc.MiscToys.PlainError.b
+StraySrc.MiscToys.PlainError.b.plainError
+StraySrc.MiscToys.PlainError.Makefile
+StraySrc.MiscToys.PlainError.PlainError
+StraySrc.MiscToys.PlainError.ReadMe
+StraySrc.Modules
+StraySrc.Modules.PlainError
diff --git a/StraySrc/dist/Quartz b/StraySrc/dist/Quartz
new file mode 100644 (file)
index 0000000..5ffa338
--- /dev/null
@@ -0,0 +1,19 @@
+StraySrc.COPYING
+StraySrc.dist.Quartz
+StraySrc.Libraries
+StraySrc.Libraries.Makefile
+StraySrc.Libraries.Quartz
+StraySrc.Libraries.Quartz.Makefile
+StraySrc.Libraries.Quartz.o
+StraySrc.Libraries.Quartz.o.quartz
+StraySrc.Libraries.Quartz.s
+StraySrc.Libraries.Quartz.s.fastMove
+StraySrc.Libraries.Quartz.s.kernel
+StraySrc.Libraries.Quartz.s.screen
+StraySrc.Libraries.Quartz.s.string
+StraySrc.Libraries.Quartz.sh
+StraySrc.Libraries.Quartz.sh.fastMove
+StraySrc.Libraries.Quartz.sh.quartz
+StraySrc.Libraries.Quartz.sh.screen
+StraySrc.Libraries.Quartz.sh.string
+StraySrc.Makefile
diff --git a/StraySrc/dist/SDLS b/StraySrc/dist/SDLS
new file mode 100644 (file)
index 0000000..0e14453
--- /dev/null
@@ -0,0 +1,107 @@
+StraySrc.!DLLs
+StraySrc.!DLLs.!Boot
+StraySrc.!DLLs.!Run
+StraySrc.!DLLs.!Sprites
+StraySrc.!DLLs.!Sprites22
+StraySrc.!DLLs.DLLManager
+StraySrc.bin
+StraySrc.bin.cdll
+StraySrc.bin.dissect
+StraySrc.bin.dllmdump
+StraySrc.COPYING
+StraySrc.dist.SDLS
+StraySrc.Libraries
+StraySrc.Libraries.DLLLib
+StraySrc.Libraries.DLLLib.h
+StraySrc.Libraries.DLLLib.h.ctype
+StraySrc.Libraries.DLLLib.h.dll
+StraySrc.Libraries.DLLLib.h.errno
+StraySrc.Libraries.DLLLib.h.math
+StraySrc.Libraries.DLLLib.h.stdio
+StraySrc.Libraries.DLLLib.h.swiv
+StraySrc.Libraries.DLLLib.Makefile
+StraySrc.Libraries.DLLLib.o
+StraySrc.Libraries.DLLLib.o.dlllib
+StraySrc.Libraries.DLLLib.s
+StraySrc.Libraries.DLLLib.s.appEntry
+StraySrc.Libraries.DLLLib.s.clib
+StraySrc.Libraries.DLLLib.s.dpoll
+StraySrc.Libraries.DLLLib.s.dsetjmp
+StraySrc.Libraries.DLLLib.s.extEntry
+StraySrc.Libraries.DLLLib.s.findAll
+StraySrc.Libraries.DLLLib.s.iface
+StraySrc.Libraries.DLLLib.s.loadLocal
+StraySrc.Libraries.DLLLib.s.oscli
+StraySrc.Libraries.DLLLib.s.wSpace
+StraySrc.Libraries.DLLLib.sh
+StraySrc.Libraries.DLLLib.sh.dllswis
+StraySrc.Libraries.Makefile
+StraySrc.SDLS
+StraySrc.SDLS.!DLLMerge
+StraySrc.SDLS.!DLLMerge.!Help
+StraySrc.SDLS.!DLLMerge.!Run
+StraySrc.SDLS.!DLLMerge.!RunImage
+StraySrc.SDLS.!DLLMerge.!Sprites
+StraySrc.SDLS.!DLLMerge.Makefile
+StraySrc.SDLS.!DLLMerge.o
+StraySrc.SDLS.!DLLMerge.rsc
+StraySrc.SDLS.!DLLMerge.rsc.messages
+StraySrc.SDLS.!DLLMerge.rsc.templates
+StraySrc.SDLS.!DLLMerge.s
+StraySrc.SDLS.!DLLMerge.s.dllmerge
+StraySrc.SDLS.!DLLMerge.Sculptrix
+StraySrc.SDLS.!DLLMerge.sh
+StraySrc.SDLS.!DLLMerge.sh.messages
+StraySrc.SDLS.!DLLMerge.sh.templates
+StraySrc.SDLS.cdll
+StraySrc.SDLS.cdll.c
+StraySrc.SDLS.cdll.c.binding
+StraySrc.SDLS.cdll.c.cstub
+StraySrc.SDLS.cdll.c.decode
+StraySrc.SDLS.cdll.c.dissect
+StraySrc.SDLS.cdll.c.dllbinder
+StraySrc.SDLS.cdll.c.error
+StraySrc.SDLS.cdll.c.extentry
+StraySrc.SDLS.cdll.c.hashtable
+StraySrc.SDLS.cdll.c.readdef
+StraySrc.SDLS.cdll.cdll
+StraySrc.SDLS.cdll.dissect
+StraySrc.SDLS.cdll.h
+StraySrc.SDLS.cdll.h.binding
+StraySrc.SDLS.cdll.h.crc32
+StraySrc.SDLS.cdll.h.cstub
+StraySrc.SDLS.cdll.h.decode
+StraySrc.SDLS.cdll.h.error
+StraySrc.SDLS.cdll.h.extentry
+StraySrc.SDLS.cdll.h.hashtable
+StraySrc.SDLS.cdll.h.readdef
+StraySrc.SDLS.cdll.Makefile
+StraySrc.SDLS.cdll.o
+StraySrc.SDLS.cdll.ordinal
+StraySrc.SDLS.cdll.s
+StraySrc.SDLS.cdll.s.crc32
+StraySrc.SDLS.DLLManager
+StraySrc.SDLS.DLLManager.DLLManager
+StraySrc.SDLS.DLLManager.dllmdump
+StraySrc.SDLS.DLLManager.Makefile
+StraySrc.SDLS.DLLManager.o
+StraySrc.SDLS.DLLManager.rsc
+StraySrc.SDLS.DLLManager.rsc.messages
+StraySrc.SDLS.DLLManager.s
+StraySrc.SDLS.DLLManager.s.app
+StraySrc.SDLS.DLLManager.s.dheader
+StraySrc.SDLS.DLLManager.s.dll
+StraySrc.SDLS.DLLManager.s.dllmdump
+StraySrc.SDLS.DLLManager.s.misc
+StraySrc.SDLS.DLLManager.s.suballoc
+StraySrc.SDLS.DLLManager.sh
+StraySrc.SDLS.DLLManager.sh.app
+StraySrc.SDLS.DLLManager.sh.appblock
+StraySrc.SDLS.DLLManager.sh.dll
+StraySrc.SDLS.DLLManager.sh.dllblock
+StraySrc.SDLS.DLLManager.sh.linkblock
+StraySrc.SDLS.DLLManager.sh.messages
+StraySrc.SDLS.DLLManager.sh.misc
+StraySrc.SDLS.DLLManager.sh.suballoc
+StraySrc.SDLS.DLLManager.sh.wSpace
+StraySrc.SDLS.Makefile
diff --git a/StraySrc/dist/Sapphire b/StraySrc/dist/Sapphire
new file mode 100644 (file)
index 0000000..0ae5859
--- /dev/null
@@ -0,0 +1,416 @@
+StraySrc.!DLLs
+StraySrc.!DLLs.Straylight
+StraySrc.!DLLs.Straylight.Sapphire
+StraySrc.!DLLs.Straylight.Sapphire.Core
+StraySrc.!DLLs.Straylight.Sapphire.CSapph
+StraySrc.!DLLs.Straylight.Sapphire.List
+StraySrc.!DLLs.Straylight.Sapphire.Resources
+StraySrc.!DLLs.Straylight.Sapphire.Tearoff
+StraySrc.!DLLs.Straylight.Sapphire.Thread
+StraySrc.COPYING
+StraySrc.dist
+StraySrc.dist.Sapphire
+StraySrc.Libraries
+StraySrc.Libraries.Makefile
+StraySrc.Libraries.Sapphire
+StraySrc.Libraries.Sapphire.bs
+StraySrc.Libraries.Sapphire.bs.fixedPt
+StraySrc.Libraries.Sapphire.bsh
+StraySrc.Libraries.Sapphire.bsh.banner
+StraySrc.Libraries.Sapphire.bsh.dbx
+StraySrc.Libraries.Sapphire.bsh.flex
+StraySrc.Libraries.Sapphire.bsh.libOpts
+StraySrc.Libraries.Sapphire.bsh.menuDefs
+StraySrc.Libraries.Sapphire.bsh.options
+StraySrc.Libraries.Sapphire.bsh.stdDbox
+StraySrc.Libraries.Sapphire.choices
+StraySrc.Libraries.Sapphire.choices.o
+StraySrc.Libraries.Sapphire.choices.s
+StraySrc.Libraries.Sapphire.choices.s.choices
+StraySrc.Libraries.Sapphire.choices.s.options
+StraySrc.Libraries.Sapphire.choices.s.prefs
+StraySrc.Libraries.Sapphire.colSelect
+StraySrc.Libraries.Sapphire.colSelect.s
+StraySrc.Libraries.Sapphire.csapph
+StraySrc.Libraries.Sapphire.csapph.h
+StraySrc.Libraries.Sapphire.csapph.h.akbd
+StraySrc.Libraries.Sapphire.csapph.h.alloc
+StraySrc.Libraries.Sapphire.csapph.h.banner
+StraySrc.Libraries.Sapphire.csapph.h.buttons
+StraySrc.Libraries.Sapphire.csapph.h.choices
+StraySrc.Libraries.Sapphire.csapph.h.choices.choices
+StraySrc.Libraries.Sapphire.csapph.h.choices.options
+StraySrc.Libraries.Sapphire.csapph.h.choices.prefs
+StraySrc.Libraries.Sapphire.csapph.h.chunk
+StraySrc.Libraries.Sapphire.csapph.h.cmdLine
+StraySrc.Libraries.Sapphire.csapph.h.colourBox
+StraySrc.Libraries.Sapphire.csapph.h.colSelect
+StraySrc.Libraries.Sapphire.csapph.h.coRoutine
+StraySrc.Libraries.Sapphire.csapph.h.dbox
+StraySrc.Libraries.Sapphire.csapph.h.dbx
+StraySrc.Libraries.Sapphire.csapph.h.dbx.arrow
+StraySrc.Libraries.Sapphire.csapph.h.dbx.colourPot
+StraySrc.Libraries.Sapphire.csapph.h.dbx.dbx
+StraySrc.Libraries.Sapphire.csapph.h.dbx.fileIcon
+StraySrc.Libraries.Sapphire.csapph.h.dbx.numWrite
+StraySrc.Libraries.Sapphire.csapph.h.dbx.slider
+StraySrc.Libraries.Sapphire.csapph.h.dbx.stringSet
+StraySrc.Libraries.Sapphire.csapph.h.defHandler
+StraySrc.Libraries.Sapphire.csapph.h.divide
+StraySrc.Libraries.Sapphire.csapph.h.drag
+StraySrc.Libraries.Sapphire.csapph.h.draw
+StraySrc.Libraries.Sapphire.csapph.h.dynPtr
+StraySrc.Libraries.Sapphire.csapph.h.errorBox
+StraySrc.Libraries.Sapphire.csapph.h.event
+StraySrc.Libraries.Sapphire.csapph.h.except
+StraySrc.Libraries.Sapphire.csapph.h.fastMove
+StraySrc.Libraries.Sapphire.csapph.h.fixedPt
+StraySrc.Libraries.Sapphire.csapph.h.flex
+StraySrc.Libraries.Sapphire.csapph.h.fontmenu
+StraySrc.Libraries.Sapphire.csapph.h.gallery
+StraySrc.Libraries.Sapphire.csapph.h.heap
+StraySrc.Libraries.Sapphire.csapph.h.help
+StraySrc.Libraries.Sapphire.csapph.h.hour
+StraySrc.Libraries.Sapphire.csapph.h.ibicon
+StraySrc.Libraries.Sapphire.csapph.h.idle
+StraySrc.Libraries.Sapphire.csapph.h.intKeys
+StraySrc.Libraries.Sapphire.csapph.h.keyMap
+StraySrc.Libraries.Sapphire.csapph.h.keyString
+StraySrc.Libraries.Sapphire.csapph.h.libOpts
+StraySrc.Libraries.Sapphire.csapph.h.listbox
+StraySrc.Libraries.Sapphire.csapph.h.llistMan
+StraySrc.Libraries.Sapphire.csapph.h.mbox
+StraySrc.Libraries.Sapphire.csapph.h.mem
+StraySrc.Libraries.Sapphire.csapph.h.menu
+StraySrc.Libraries.Sapphire.csapph.h.menuDefs
+StraySrc.Libraries.Sapphire.csapph.h.msgs
+StraySrc.Libraries.Sapphire.csapph.h.nopoll
+StraySrc.Libraries.Sapphire.csapph.h.note
+StraySrc.Libraries.Sapphire.csapph.h.pane
+StraySrc.Libraries.Sapphire.csapph.h.progInfo
+StraySrc.Libraries.Sapphire.csapph.h.ptr
+StraySrc.Libraries.Sapphire.csapph.h.rand
+StraySrc.Libraries.Sapphire.csapph.h.repeater
+StraySrc.Libraries.Sapphire.csapph.h.report
+StraySrc.Libraries.Sapphire.csapph.h.res
+StraySrc.Libraries.Sapphire.csapph.h.resources
+StraySrc.Libraries.Sapphire.csapph.h.resspr
+StraySrc.Libraries.Sapphire.csapph.h.roVersion
+StraySrc.Libraries.Sapphire.csapph.h.sapphire
+StraySrc.Libraries.Sapphire.csapph.h.saveWarn
+StraySrc.Libraries.Sapphire.csapph.h.screen
+StraySrc.Libraries.Sapphire.csapph.h.seh
+StraySrc.Libraries.Sapphire.csapph.h.sprite
+StraySrc.Libraries.Sapphire.csapph.h.sqrt
+StraySrc.Libraries.Sapphire.csapph.h.string
+StraySrc.Libraries.Sapphire.csapph.h.subAlloc
+StraySrc.Libraries.Sapphire.csapph.h.template
+StraySrc.Libraries.Sapphire.csapph.h.thread
+StraySrc.Libraries.Sapphire.csapph.h.tms
+StraySrc.Libraries.Sapphire.csapph.h.transWin
+StraySrc.Libraries.Sapphire.csapph.h.tspr
+StraySrc.Libraries.Sapphire.csapph.h.viewer
+StraySrc.Libraries.Sapphire.csapph.h.warning
+StraySrc.Libraries.Sapphire.csapph.h.wimp
+StraySrc.Libraries.Sapphire.csapph.h.win
+StraySrc.Libraries.Sapphire.csapph.h.winUtils
+StraySrc.Libraries.Sapphire.csapph.h.writable
+StraySrc.Libraries.Sapphire.csapph.h.xfer
+StraySrc.Libraries.Sapphire.csapph.h.xfer.load
+StraySrc.Libraries.Sapphire.csapph.h.xfer.save
+StraySrc.Libraries.Sapphire.csapph.h.xfer.saveAs
+StraySrc.Libraries.Sapphire.csapph.h.xfer.xload
+StraySrc.Libraries.Sapphire.csapph.h.xfer.xsave
+StraySrc.Libraries.Sapphire.csapph.o
+StraySrc.Libraries.Sapphire.csapph.s
+StraySrc.Libraries.Sapphire.csapph.s.cmath
+StraySrc.Libraries.Sapphire.csapph.s.crout
+StraySrc.Libraries.Sapphire.csapph.s.crts
+StraySrc.Libraries.Sapphire.csapph.s.csapph
+StraySrc.Libraries.Sapphire.csapph.s.csetjmp
+StraySrc.Libraries.Sapphire.csapph.s.cstart
+StraySrc.Libraries.Sapphire.csapph.s.ctype
+StraySrc.Libraries.Sapphire.dbx
+StraySrc.Libraries.Sapphire.dbx.o
+StraySrc.Libraries.Sapphire.dbx.s
+StraySrc.Libraries.Sapphire.dbx.s.arrow
+StraySrc.Libraries.Sapphire.dbx.s.colourPot
+StraySrc.Libraries.Sapphire.dbx.s.dbx
+StraySrc.Libraries.Sapphire.dbx.s.fileIcon
+StraySrc.Libraries.Sapphire.dbx.s.numWrite
+StraySrc.Libraries.Sapphire.dbx.s.slider
+StraySrc.Libraries.Sapphire.dbx.s.stringSet
+StraySrc.Libraries.Sapphire.dc
+StraySrc.Libraries.Sapphire.def
+StraySrc.Libraries.Sapphire.def.core
+StraySrc.Libraries.Sapphire.def.csapph
+StraySrc.Libraries.Sapphire.def.list
+StraySrc.Libraries.Sapphire.def.resources
+StraySrc.Libraries.Sapphire.def.tearoff
+StraySrc.Libraries.Sapphire.def.thread
+StraySrc.Libraries.Sapphire.dh
+StraySrc.Libraries.Sapphire.dl
+StraySrc.Libraries.Sapphire.dll
+StraySrc.Libraries.Sapphire.dll.core
+StraySrc.Libraries.Sapphire.dll.csapph
+StraySrc.Libraries.Sapphire.dll.list
+StraySrc.Libraries.Sapphire.dll.resources
+StraySrc.Libraries.Sapphire.dll.tearoff
+StraySrc.Libraries.Sapphire.dll.thread
+StraySrc.Libraries.Sapphire.ds
+StraySrc.Libraries.Sapphire.ds.core
+StraySrc.Libraries.Sapphire.ds.csapph
+StraySrc.Libraries.Sapphire.ds.list
+StraySrc.Libraries.Sapphire.ds.resources
+StraySrc.Libraries.Sapphire.ds.tearoff
+StraySrc.Libraries.Sapphire.ds.thread
+StraySrc.Libraries.Sapphire.lib
+StraySrc.Libraries.Sapphire.lib.csapph
+StraySrc.Libraries.Sapphire.lib.sapphdll
+StraySrc.Libraries.Sapphire.lib.sapphire
+StraySrc.Libraries.Sapphire.Makefile
+StraySrc.Libraries.Sapphire.Modules
+StraySrc.Libraries.Sapphire.Modules.Constrain
+StraySrc.Libraries.Sapphire.Modules.Docs
+StraySrc.Libraries.Sapphire.Modules.Docs.Sprinkle
+StraySrc.Libraries.Sapphire.Modules.Makefile
+StraySrc.Libraries.Sapphire.Modules.o
+StraySrc.Libraries.Sapphire.Modules.s
+StraySrc.Libraries.Sapphire.Modules.s.constrain
+StraySrc.Libraries.Sapphire.Modules.s.sprinkle
+StraySrc.Libraries.Sapphire.Modules.Sprinkle
+StraySrc.Libraries.Sapphire.o
+StraySrc.Libraries.Sapphire.README
+StraySrc.Libraries.Sapphire.rsc
+StraySrc.Libraries.Sapphire.rsc.ColourSel
+StraySrc.Libraries.Sapphire.rsc.Messages
+StraySrc.Libraries.Sapphire.rsc.Sprites
+StraySrc.Libraries.Sapphire.rsc.Templates
+StraySrc.Libraries.Sapphire.s
+StraySrc.Libraries.Sapphire.s.akbd
+StraySrc.Libraries.Sapphire.s.alloc
+StraySrc.Libraries.Sapphire.s.banner
+StraySrc.Libraries.Sapphire.s.bnrStub
+StraySrc.Libraries.Sapphire.s.buttons
+StraySrc.Libraries.Sapphire.s.chunk
+StraySrc.Libraries.Sapphire.s.cmdLine
+StraySrc.Libraries.Sapphire.s.colourBox
+StraySrc.Libraries.Sapphire.s.coRoutine
+StraySrc.Libraries.Sapphire.s.dBanner
+StraySrc.Libraries.Sapphire.s.dbox
+StraySrc.Libraries.Sapphire.s.defHandler
+StraySrc.Libraries.Sapphire.s.divide
+StraySrc.Libraries.Sapphire.s.dKernel
+StraySrc.Libraries.Sapphire.s.drag
+StraySrc.Libraries.Sapphire.s.draw
+StraySrc.Libraries.Sapphire.s.dynPtr
+StraySrc.Libraries.Sapphire.s.errorBox
+StraySrc.Libraries.Sapphire.s.event
+StraySrc.Libraries.Sapphire.s.except
+StraySrc.Libraries.Sapphire.s.fastMove
+StraySrc.Libraries.Sapphire.s.flex
+StraySrc.Libraries.Sapphire.s.fontMenu
+StraySrc.Libraries.Sapphire.s.gallery
+StraySrc.Libraries.Sapphire.s.heap
+StraySrc.Libraries.Sapphire.s.help
+StraySrc.Libraries.Sapphire.s.hour
+StraySrc.Libraries.Sapphire.s.ibicon
+StraySrc.Libraries.Sapphire.s.idle
+StraySrc.Libraries.Sapphire.s.kernel
+StraySrc.Libraries.Sapphire.s.keyString
+StraySrc.Libraries.Sapphire.s.libOpts
+StraySrc.Libraries.Sapphire.s.listbox
+StraySrc.Libraries.Sapphire.s.llistMan
+StraySrc.Libraries.Sapphire.s.llistStub
+StraySrc.Libraries.Sapphire.s.mbox
+StraySrc.Libraries.Sapphire.s.mem
+StraySrc.Libraries.Sapphire.s.menu
+StraySrc.Libraries.Sapphire.s.msgs
+StraySrc.Libraries.Sapphire.s.nopoll
+StraySrc.Libraries.Sapphire.s.note
+StraySrc.Libraries.Sapphire.s.pane
+StraySrc.Libraries.Sapphire.s.progInfo
+StraySrc.Libraries.Sapphire.s.ptr
+StraySrc.Libraries.Sapphire.s.rand
+StraySrc.Libraries.Sapphire.s.repeater
+StraySrc.Libraries.Sapphire.s.report
+StraySrc.Libraries.Sapphire.s.res
+StraySrc.Libraries.Sapphire.s.resources
+StraySrc.Libraries.Sapphire.s.resspr
+StraySrc.Libraries.Sapphire.s.roVersion
+StraySrc.Libraries.Sapphire.s.sapphRes
+StraySrc.Libraries.Sapphire.s.saveWarn
+StraySrc.Libraries.Sapphire.s.screen
+StraySrc.Libraries.Sapphire.s.seh
+StraySrc.Libraries.Sapphire.s.sprite
+StraySrc.Libraries.Sapphire.s.sqrt
+StraySrc.Libraries.Sapphire.s.string
+StraySrc.Libraries.Sapphire.s.stub
+StraySrc.Libraries.Sapphire.s.subAlloc
+StraySrc.Libraries.Sapphire.s.template
+StraySrc.Libraries.Sapphire.s.thread
+StraySrc.Libraries.Sapphire.s.transWin
+StraySrc.Libraries.Sapphire.s.tspr
+StraySrc.Libraries.Sapphire.s.viewer
+StraySrc.Libraries.Sapphire.s.warning
+StraySrc.Libraries.Sapphire.s.wimp
+StraySrc.Libraries.Sapphire.s.win
+StraySrc.Libraries.Sapphire.s.winUtils
+StraySrc.Libraries.Sapphire.s.writable
+StraySrc.Libraries.Sapphire.sh
+StraySrc.Libraries.Sapphire.sh.akbd
+StraySrc.Libraries.Sapphire.sh.alloc
+StraySrc.Libraries.Sapphire.sh.banner
+StraySrc.Libraries.Sapphire.sh.buttons
+StraySrc.Libraries.Sapphire.sh.choices
+StraySrc.Libraries.Sapphire.sh.choices.choices
+StraySrc.Libraries.Sapphire.sh.choices.options
+StraySrc.Libraries.Sapphire.sh.choices.prefs
+StraySrc.Libraries.Sapphire.sh.chunk
+StraySrc.Libraries.Sapphire.sh.cmdLine
+StraySrc.Libraries.Sapphire.sh.colourBox
+StraySrc.Libraries.Sapphire.sh.colSelect
+StraySrc.Libraries.Sapphire.sh.coRoutine
+StraySrc.Libraries.Sapphire.sh.dbox
+StraySrc.Libraries.Sapphire.sh.dbx
+StraySrc.Libraries.Sapphire.sh.dbx.arrow
+StraySrc.Libraries.Sapphire.sh.dbx.colourPot
+StraySrc.Libraries.Sapphire.sh.dbx.dbx
+StraySrc.Libraries.Sapphire.sh.dbx.fileIcon
+StraySrc.Libraries.Sapphire.sh.dbx.numWrite
+StraySrc.Libraries.Sapphire.sh.dbx.slider
+StraySrc.Libraries.Sapphire.sh.dbx.stringSet
+StraySrc.Libraries.Sapphire.sh.dbx._dbxMacs
+StraySrc.Libraries.Sapphire.sh.defHandler
+StraySrc.Libraries.Sapphire.sh.divide
+StraySrc.Libraries.Sapphire.sh.drag
+StraySrc.Libraries.Sapphire.sh.draw
+StraySrc.Libraries.Sapphire.sh.dynPtr
+StraySrc.Libraries.Sapphire.sh.errorBox
+StraySrc.Libraries.Sapphire.sh.event
+StraySrc.Libraries.Sapphire.sh.except
+StraySrc.Libraries.Sapphire.sh.fastMove
+StraySrc.Libraries.Sapphire.sh.fixedPt
+StraySrc.Libraries.Sapphire.sh.flex
+StraySrc.Libraries.Sapphire.sh.fontmenu
+StraySrc.Libraries.Sapphire.sh.gallery
+StraySrc.Libraries.Sapphire.sh.heap
+StraySrc.Libraries.Sapphire.sh.help
+StraySrc.Libraries.Sapphire.sh.hour
+StraySrc.Libraries.Sapphire.sh.ibicon
+StraySrc.Libraries.Sapphire.sh.idle
+StraySrc.Libraries.Sapphire.sh.intKeys
+StraySrc.Libraries.Sapphire.sh.keyMap
+StraySrc.Libraries.Sapphire.sh.keyString
+StraySrc.Libraries.Sapphire.sh.libOpts
+StraySrc.Libraries.Sapphire.sh.listbox
+StraySrc.Libraries.Sapphire.sh.llistMan
+StraySrc.Libraries.Sapphire.sh.mbox
+StraySrc.Libraries.Sapphire.sh.mem
+StraySrc.Libraries.Sapphire.sh.menu
+StraySrc.Libraries.Sapphire.sh.menuDefs
+StraySrc.Libraries.Sapphire.sh.msgs
+StraySrc.Libraries.Sapphire.sh.nopoll
+StraySrc.Libraries.Sapphire.sh.note
+StraySrc.Libraries.Sapphire.sh.pane
+StraySrc.Libraries.Sapphire.sh.progInfo
+StraySrc.Libraries.Sapphire.sh.ptr
+StraySrc.Libraries.Sapphire.sh.rand
+StraySrc.Libraries.Sapphire.sh.repeater
+StraySrc.Libraries.Sapphire.sh.report
+StraySrc.Libraries.Sapphire.sh.res
+StraySrc.Libraries.Sapphire.sh.resources
+StraySrc.Libraries.Sapphire.sh.resspr
+StraySrc.Libraries.Sapphire.sh.roVersion
+StraySrc.Libraries.Sapphire.sh.sapphire
+StraySrc.Libraries.Sapphire.sh.saveWarn
+StraySrc.Libraries.Sapphire.sh.screen
+StraySrc.Libraries.Sapphire.sh.seh
+StraySrc.Libraries.Sapphire.sh.sprite
+StraySrc.Libraries.Sapphire.sh.sqrt
+StraySrc.Libraries.Sapphire.sh.string
+StraySrc.Libraries.Sapphire.sh.subAlloc
+StraySrc.Libraries.Sapphire.sh.template
+StraySrc.Libraries.Sapphire.sh.thread
+StraySrc.Libraries.Sapphire.sh.tms
+StraySrc.Libraries.Sapphire.sh.transWin
+StraySrc.Libraries.Sapphire.sh.tspr
+StraySrc.Libraries.Sapphire.sh.viewer
+StraySrc.Libraries.Sapphire.sh.warning
+StraySrc.Libraries.Sapphire.sh.wimp
+StraySrc.Libraries.Sapphire.sh.win
+StraySrc.Libraries.Sapphire.sh.winUtils
+StraySrc.Libraries.Sapphire.sh.writable
+StraySrc.Libraries.Sapphire.sh.xfer
+StraySrc.Libraries.Sapphire.sh.xfer.load
+StraySrc.Libraries.Sapphire.sh.xfer.save
+StraySrc.Libraries.Sapphire.sh.xfer.saveAs
+StraySrc.Libraries.Sapphire.sh.xfer.xload
+StraySrc.Libraries.Sapphire.sh.xfer.xsave
+StraySrc.Libraries.Sapphire.sh._tms
+StraySrc.Libraries.Sapphire.sh._tms.tmsCreate
+StraySrc.Libraries.Sapphire.sh._tms.tmsGlobal
+StraySrc.Libraries.Sapphire.sh._tms.tmsGlue
+StraySrc.Libraries.Sapphire.sh._tms.tmsMain
+StraySrc.Libraries.Sapphire.stub
+StraySrc.Libraries.Sapphire.tms
+StraySrc.Libraries.Sapphire.tms.o
+StraySrc.Libraries.Sapphire.tms.s
+StraySrc.Libraries.Sapphire.tms.s.tmsCreate
+StraySrc.Libraries.Sapphire.tms.s.tmsGlue
+StraySrc.Libraries.Sapphire.tms.s.tmsMain
+StraySrc.Libraries.Sapphire.xfer
+StraySrc.Libraries.Sapphire.xfer.o
+StraySrc.Libraries.Sapphire.xfer.s
+StraySrc.Libraries.Sapphire.xfer.s.load
+StraySrc.Libraries.Sapphire.xfer.s.save
+StraySrc.Libraries.Sapphire.xfer.s.saveAs
+StraySrc.Libraries.Sapphire.xfer.s.xload
+StraySrc.Libraries.Sapphire.xfer.s.xsave
+StraySrc.Makefile
+StraySrc.Modules
+StraySrc.Modules.Constrain
+StraySrc.Modules.Sprinkle
+StraySrc.SapphToys
+StraySrc.SapphToys.!CApp
+StraySrc.SapphToys.!CApp.!Run
+StraySrc.SapphToys.!CApp.!RunImage
+StraySrc.SapphToys.!CApp.c
+StraySrc.SapphToys.!CApp.c.capp
+StraySrc.SapphToys.!CApp.Makefile
+StraySrc.SapphToys.!CApp.o
+StraySrc.SapphToys.!CApp.UK
+StraySrc.SapphToys.!DrawX
+StraySrc.SapphToys.!DrawX.!Boot
+StraySrc.SapphToys.!DrawX.!Help
+StraySrc.SapphToys.!DrawX.!Run
+StraySrc.SapphToys.!DrawX.!RunImage
+StraySrc.SapphToys.!DrawX.!Sprites
+StraySrc.SapphToys.!DrawX.Choices
+StraySrc.SapphToys.!DrawX.Makefile
+StraySrc.SapphToys.!DrawX.Modules
+StraySrc.SapphToys.!DrawX.Modules.Sculptrix
+StraySrc.SapphToys.!DrawX.Modules.Sprinkle
+StraySrc.SapphToys.!DrawX.o
+StraySrc.SapphToys.!DrawX.Resources
+StraySrc.SapphToys.!DrawX.Resources.Messages
+StraySrc.SapphToys.!DrawX.Resources.Sprites
+StraySrc.SapphToys.!DrawX.Resources.Templates
+StraySrc.SapphToys.!DrawX.s
+StraySrc.SapphToys.!DrawX.s.drawX
+StraySrc.SapphToys.!DrawX.setSlot
+StraySrc.SapphToys.!SWIlist
+StraySrc.SapphToys.!SWIlist.!Help
+StraySrc.SapphToys.!SWIlist.!Run
+StraySrc.SapphToys.!SWIlist.!RunImage
+StraySrc.SapphToys.!SWIlist.!Sprites
+StraySrc.SapphToys.!SWIlist.bs
+StraySrc.SapphToys.!SWIlist.bs.swiList
+StraySrc.SapphToys.!SWIlist.Format
+StraySrc.SapphToys.!SWIlist.Makefile
+StraySrc.SapphToys.!SWIlist.o
+StraySrc.SapphToys.!SWIlist.Sculptrix
+StraySrc.SapphToys.!SWIlist.setSlot
+StraySrc.SapphToys.!SWIlist.SWIDump
+StraySrc.SapphToys.!SWIlist.UK
+StraySrc.SapphToys.Makefile
diff --git a/StraySrc/dist/Sculptrix b/StraySrc/dist/Sculptrix
new file mode 100644 (file)
index 0000000..6c38658
--- /dev/null
@@ -0,0 +1,77 @@
+StraySrc.COPYING
+StraySrc.dist.Sculptrix
+StraySrc.Makefile
+StraySrc.Modules.Sculptrix
+StraySrc.Sculptrix
+StraySrc.Sculptrix.!SConfig
+StraySrc.Sculptrix.!SConfig.!Run
+StraySrc.Sculptrix.!SConfig.loadConfig
+StraySrc.Sculptrix.!SConfig.Makefile
+StraySrc.Sculptrix.!SConfig.o
+StraySrc.Sculptrix.!SConfig.s
+StraySrc.Sculptrix.!SConfig.s.loadConfig
+StraySrc.Sculptrix.!SConfig.SConfig
+StraySrc.Sculptrix.!SConfig.Sculptrix
+StraySrc.Sculptrix.!Setrix
+StraySrc.Sculptrix.!Setrix.!Help
+StraySrc.Sculptrix.!Setrix.!Run
+StraySrc.Sculptrix.!Setrix.!RunImage
+StraySrc.Sculptrix.!Setrix.!Sprites
+StraySrc.Sculptrix.!Setrix.Makefile
+StraySrc.Sculptrix.!Setrix.Modules
+StraySrc.Sculptrix.!Setrix.Modules.Sculptrix
+StraySrc.Sculptrix.!Setrix.o
+StraySrc.Sculptrix.!Setrix.Resources
+StraySrc.Sculptrix.!Setrix.Resources.Messages
+StraySrc.Sculptrix.!Setrix.Resources.Sprites
+StraySrc.Sculptrix.!Setrix.Resources.Templates
+StraySrc.Sculptrix.!Setrix.s
+StraySrc.Sculptrix.!Setrix.s.setrix
+StraySrc.Sculptrix.!Setrix.setSlot
+StraySrc.Sculptrix.apcs
+StraySrc.Sculptrix.apcs.h
+StraySrc.Sculptrix.apcs.h.sculptrix
+StraySrc.Sculptrix.apcs.Makefile
+StraySrc.Sculptrix.apcs.o
+StraySrc.Sculptrix.apcs.o.sculptrix
+StraySrc.Sculptrix.apcs.s
+StraySrc.Sculptrix.apcs.s.scp_apcs
+StraySrc.Sculptrix.Changes
+StraySrc.Sculptrix.Makefile
+StraySrc.Sculptrix.NewVersion
+StraySrc.Sculptrix.old-vsn
+StraySrc.Sculptrix.old-vsn.README
+StraySrc.Sculptrix.old-vsn.s
+StraySrc.Sculptrix.old-vsn.s.sculptrix
+StraySrc.Sculptrix.README
+StraySrc.Sculptrix.sculptrix
+StraySrc.Sculptrix.sculptrix.Makefile
+StraySrc.Sculptrix.sculptrix.o
+StraySrc.Sculptrix.sculptrix.rsc
+StraySrc.Sculptrix.sculptrix.rsc.messages
+StraySrc.Sculptrix.sculptrix.s
+StraySrc.Sculptrix.sculptrix.s.bbox
+StraySrc.Sculptrix.sculptrix.s.border
+StraySrc.Sculptrix.sculptrix.s.colours
+StraySrc.Sculptrix.sculptrix.s.config
+StraySrc.Sculptrix.sculptrix.s.plot
+StraySrc.Sculptrix.sculptrix.s.redraw
+StraySrc.Sculptrix.sculptrix.s.rules
+StraySrc.Sculptrix.sculptrix.s.sculptrix
+StraySrc.Sculptrix.sculptrix.s.slab
+StraySrc.Sculptrix.sculptrix.s.utils
+StraySrc.Sculptrix.sculptrix.s.vString
+StraySrc.Sculptrix.sculptrix.Sculptrix
+StraySrc.Sculptrix.sculptrix.sh
+StraySrc.Sculptrix.sculptrix.sh.bbox
+StraySrc.Sculptrix.sculptrix.sh.border
+StraySrc.Sculptrix.sculptrix.sh.colours
+StraySrc.Sculptrix.sculptrix.sh.config
+StraySrc.Sculptrix.sculptrix.sh.messages
+StraySrc.Sculptrix.sculptrix.sh.plot
+StraySrc.Sculptrix.sculptrix.sh.redraw
+StraySrc.Sculptrix.sculptrix.sh.rules
+StraySrc.Sculptrix.sculptrix.sh.slab
+StraySrc.Sculptrix.sculptrix.sh.utils
+StraySrc.Sculptrix.sculptrix.sh.vString
+StraySrc.Sculptrix.sculptrix.sh.wSpace
diff --git a/StraySrc/dist/dist b/StraySrc/dist/dist
new file mode 100644 (file)
index 0000000..7e89f0b
--- /dev/null
@@ -0,0 +1,1069 @@
+StraySrc.!DLLs
+StraySrc.!DLLs.!Boot
+StraySrc.!DLLs.!Run
+StraySrc.!DLLs.!Sprites
+StraySrc.!DLLs.!Sprites22
+StraySrc.!DLLs.DLLManager
+StraySrc.!DLLs.enumerate
+StraySrc.!DLLs.hour
+StraySrc.!DLLs.pathutil
+StraySrc.!DLLs.Straylight
+StraySrc.!DLLs.Straylight.Sapphire
+StraySrc.!DLLs.Straylight.Sapphire.Core
+StraySrc.!DLLs.Straylight.Sapphire.CSapph
+StraySrc.!DLLs.Straylight.Sapphire.List
+StraySrc.!DLLs.Straylight.Sapphire.Tearoff
+StraySrc.!DLLs.Straylight.Sapphire.Thread
+StraySrc.!DLLs.Straylight.Steel
+StraySrc.bin
+StraySrc.bin.buildstub
+StraySrc.bin.cdll
+StraySrc.bin.chdrgen
+StraySrc.bin.checksd
+StraySrc.bin.currDir
+StraySrc.bin.dissect
+StraySrc.bin.dllmdump
+StraySrc.bin.each
+StraySrc.bin.enumerate
+StraySrc.bin.fixlink
+StraySrc.bin.headergen
+StraySrc.bin.hour
+StraySrc.bin.inst
+StraySrc.bin.msgaof
+StraySrc.bin.pathutil
+StraySrc.bin.resgen
+StraySrc.bin.setdate
+StraySrc.bin.setslot
+StraySrc.bin.ssrclean
+StraySrc.bin.submake
+StraySrc.bin.templaof
+StraySrc.bin.test
+StraySrc.BuildTools
+StraySrc.COPYING
+StraySrc.dist
+StraySrc.dist.Core
+StraySrc.dist.Dynamite
+StraySrc.dist.Glass
+StraySrc.dist.MiscToys
+StraySrc.dist.Sapphire
+StraySrc.dist.SDLS
+StraySrc.dist.Steel
+StraySrc.Dynamite
+StraySrc.Dynamite.apcs
+StraySrc.Dynamite.apcs.h
+StraySrc.Dynamite.apcs.h.dynamite
+StraySrc.Dynamite.apcs.Makefile
+StraySrc.Dynamite.apcs.o
+StraySrc.Dynamite.apcs.s
+StraySrc.Dynamite.apcs.s.dyn_apcs
+StraySrc.Dynamite.dynamite
+StraySrc.Dynamite.dynamite.Dynamite
+StraySrc.Dynamite.dynamite.Makefile
+StraySrc.Dynamite.dynamite.o
+StraySrc.Dynamite.dynamite.rsc
+StraySrc.Dynamite.dynamite.rsc.messages
+StraySrc.Dynamite.dynamite.s
+StraySrc.Dynamite.dynamite.s.dynamite
+StraySrc.Dynamite.dynamite.s.dynAnchor
+StraySrc.Dynamite.dynamite.s.dynArea
+StraySrc.Dynamite.dynamite.s.dynHeap
+StraySrc.Dynamite.dynamite.s.dynTask
+StraySrc.Dynamite.dynamite.s.fastMove
+StraySrc.Dynamite.dynamite.sh
+StraySrc.Dynamite.dynamite.sh.dynAnchor
+StraySrc.Dynamite.dynamite.sh.dynArea
+StraySrc.Dynamite.dynamite.sh.dynHeap
+StraySrc.Dynamite.dynamite.sh.dynTask
+StraySrc.Dynamite.dynamite.sh.messages
+StraySrc.Dynamite.dynamite.sh.wSpace
+StraySrc.Dynamite.Makefile
+StraySrc.Glass
+StraySrc.Glass.!Glass
+StraySrc.Glass.!Glass.!Boot
+StraySrc.Glass.!Glass.!Help
+StraySrc.Glass.!Glass.!Run
+StraySrc.Glass.!Glass.!RunImage
+StraySrc.Glass.!Glass.!Sprites
+StraySrc.Glass.!Glass.c
+StraySrc.Glass.!Glass.c.align
+StraySrc.Glass.!Glass.c.colSelect
+StraySrc.Glass.!Glass.c.editIcon
+StraySrc.Glass.!Glass.c.editWin
+StraySrc.Glass.!Glass.c.glass
+StraySrc.Glass.!Glass.c.gPrefs
+StraySrc.Glass.!Glass.c.gSprite
+StraySrc.Glass.!Glass.c.iconData
+StraySrc.Glass.!Glass.c.indir
+StraySrc.Glass.!Glass.c.intMsgs
+StraySrc.Glass.!Glass.c.tearEdit
+StraySrc.Glass.!Glass.c.tfile
+StraySrc.Glass.!Glass.c.toolbox
+StraySrc.Glass.!Glass.c.wDragging
+StraySrc.Glass.!Glass.c.wGrab
+StraySrc.Glass.!Glass.c.wGraph
+StraySrc.Glass.!Glass.c.wIcons
+StraySrc.Glass.!Glass.c.window
+StraySrc.Glass.!Glass.c.wMenus
+StraySrc.Glass.!Glass.c.wMousePtr
+StraySrc.Glass.!Glass.c.wPalette
+StraySrc.Glass.!Glass.c.wRedraw
+StraySrc.Glass.!Glass.c.wSelect
+StraySrc.Glass.!Glass.c.wToolbars
+StraySrc.Glass.!Glass.c.wWindows
+StraySrc.Glass.!Glass.c.wWinEvent
+StraySrc.Glass.!Glass.Choices
+StraySrc.Glass.!Glass.Defaults
+StraySrc.Glass.!Glass.Defaults.Templates
+StraySrc.Glass.!Glass.h
+StraySrc.Glass.!Glass.h.align
+StraySrc.Glass.!Glass.h.colSelect
+StraySrc.Glass.!Glass.h.editIcon
+StraySrc.Glass.!Glass.h.editWin
+StraySrc.Glass.!Glass.h.gIcons
+StraySrc.Glass.!Glass.h.glass
+StraySrc.Glass.!Glass.h.gMenus
+StraySrc.Glass.!Glass.h.gPrefs
+StraySrc.Glass.!Glass.h.gSprite
+StraySrc.Glass.!Glass.h.gStruct
+StraySrc.Glass.!Glass.h.iconData
+StraySrc.Glass.!Glass.h.indir
+StraySrc.Glass.!Glass.h.intMsgs
+StraySrc.Glass.!Glass.h.tearEdit
+StraySrc.Glass.!Glass.h.tfile
+StraySrc.Glass.!Glass.h.toolbox
+StraySrc.Glass.!Glass.h.window
+StraySrc.Glass.!Glass.h._window
+StraySrc.Glass.!Glass.Makefile
+StraySrc.Glass.!Glass.Modules
+StraySrc.Glass.!Glass.Modules.Interface
+StraySrc.Glass.!Glass.Modules.Sculptrix
+StraySrc.Glass.!Glass.Modules.WimpExt
+StraySrc.Glass.!Glass.o
+StraySrc.Glass.!Glass.Resources
+StraySrc.Glass.!Glass.Resources.LoadSpr
+StraySrc.Glass.!Glass.Resources.LoadTpl
+StraySrc.Glass.!Glass.Resources.Messages
+StraySrc.Glass.!Glass.Resources.Sprites
+StraySrc.Glass.!Glass.Resources.Templates
+StraySrc.Glass.!Glass.s
+StraySrc.Glass.!Glass.s.toolSupprt
+StraySrc.Glass.!Glass.setSlot
+StraySrc.Glass.!Glass.test
+StraySrc.gplnote
+StraySrc.gplnote.asm
+StraySrc.gplnote.basic
+StraySrc.gplnote.c
+StraySrc.gplnote.Makefile
+StraySrc.Libraries
+StraySrc.Libraries.BAS
+StraySrc.Libraries.BAS.bas
+StraySrc.Libraries.BAS.exports
+StraySrc.Libraries.BAS.Makefile
+StraySrc.Libraries.BAS.src
+StraySrc.Libraries.BAS.src.b
+StraySrc.Libraries.BAS.src.b.bas
+StraySrc.Libraries.BAS.src.bc
+StraySrc.Libraries.BAS.src.bc.bas
+StraySrc.Libraries.BAS.src.Makefile
+StraySrc.Libraries.BAS.src.o
+StraySrc.Libraries.BAS.src.README
+StraySrc.Libraries.BAS.src.rsc
+StraySrc.Libraries.BAS.src.rsc.messages
+StraySrc.Libraries.BAS.src.s
+StraySrc.Libraries.BAS.src.s.aofGen
+StraySrc.Libraries.BAS.src.s.bas
+StraySrc.Libraries.BAS.src.s.basTalk
+StraySrc.Libraries.BAS.src.s.fastMove
+StraySrc.Libraries.BAS.src.s.flex
+StraySrc.Libraries.BAS.src.s.get
+StraySrc.Libraries.BAS.src.s.insert
+StraySrc.Libraries.BAS.src.s.lit
+StraySrc.Libraries.BAS.src.s.string
+StraySrc.Libraries.BAS.src.s.vars
+StraySrc.Libraries.BAS.src.scripts
+StraySrc.Libraries.BAS.src.scripts.crunchit
+StraySrc.Libraries.BAS.src.scripts.execit
+StraySrc.Libraries.BAS.src.scripts.exports
+StraySrc.Libraries.BAS.src.scripts.preproc
+StraySrc.Libraries.BAS.src.sh
+StraySrc.Libraries.BAS.src.sh.aofGen
+StraySrc.Libraries.BAS.src.sh.bas
+StraySrc.Libraries.BAS.src.sh.basicEnv
+StraySrc.Libraries.BAS.src.sh.basTalk
+StraySrc.Libraries.BAS.src.sh.fastMove
+StraySrc.Libraries.BAS.src.sh.flex
+StraySrc.Libraries.BAS.src.sh.get
+StraySrc.Libraries.BAS.src.sh.insert
+StraySrc.Libraries.BAS.src.sh.lit
+StraySrc.Libraries.BAS.src.sh.messages
+StraySrc.Libraries.BAS.src.sh.string
+StraySrc.Libraries.BAS.src.sh.vars
+StraySrc.Libraries.BAS.src.sh.workspace
+StraySrc.Libraries.BAS.src.work
+StraySrc.Libraries.Core
+StraySrc.Libraries.Core.AOF
+StraySrc.Libraries.Core.AOF.c
+StraySrc.Libraries.Core.AOF.c.aof
+StraySrc.Libraries.Core.AOF.h
+StraySrc.Libraries.Core.AOF.h.alf
+StraySrc.Libraries.Core.AOF.h.aof
+StraySrc.Libraries.Core.AOF.h.chunk
+StraySrc.Libraries.Core.AOF.Makefile
+StraySrc.Libraries.Core.AOF.o
+StraySrc.Libraries.Core.AOF.o.aof
+StraySrc.Libraries.Core.AOF.README
+StraySrc.Libraries.Core.dump
+StraySrc.Libraries.Core.EmbTemp
+StraySrc.Libraries.Core.EmbTemp.Makefile
+StraySrc.Libraries.Core.EmbTemp.o
+StraySrc.Libraries.Core.EmbTemp.o.embTemp
+StraySrc.Libraries.Core.EmbTemp.README
+StraySrc.Libraries.Core.EmbTemp.s
+StraySrc.Libraries.Core.EmbTemp.s.embTemp
+StraySrc.Libraries.Core.EmbTemp.sh
+StraySrc.Libraries.Core.EmbTemp.sh.embTemp
+StraySrc.Libraries.Core.h
+StraySrc.Libraries.Core.h.swis
+StraySrc.Libraries.Core.h.swiv
+StraySrc.Libraries.Core.h._time
+StraySrc.Libraries.Core.header
+StraySrc.Libraries.Core.Makefile
+StraySrc.Libraries.Core.o
+StraySrc.Libraries.Core.o.asstubs
+StraySrc.Libraries.Core.o.astubs
+StraySrc.Libraries.Core.o.dstubs
+StraySrc.Libraries.Core.o.msstubs
+StraySrc.Libraries.Core.o.mstubs
+StraySrc.Libraries.Core.o.rdump
+StraySrc.Libraries.Core.o.swiv
+StraySrc.Libraries.Core.s
+StraySrc.Libraries.Core.s.fastMove
+StraySrc.Libraries.Core.s.flex
+StraySrc.Libraries.Core.s.heap
+StraySrc.Libraries.Core.s.oxswi
+StraySrc.Libraries.Core.s.rdump
+StraySrc.Libraries.Core.s.swihack
+StraySrc.Libraries.Core.s.swiv
+StraySrc.Libraries.Core.s.xapp
+StraySrc.Libraries.Core.s.xcommon
+StraySrc.Libraries.Core.s.xdata
+StraySrc.Libraries.Core.s.xdll
+StraySrc.Libraries.Core.s.xentry
+StraySrc.Libraries.Core.s.xentry_swi
+StraySrc.Libraries.Core.s.xmodule
+StraySrc.Libraries.Core.s.xsmall
+StraySrc.Libraries.Core.s.xsmall_swi
+StraySrc.Libraries.Core.s.xswi
+StraySrc.Libraries.Core.sh
+StraySrc.Libraries.Core.sh.fastMove
+StraySrc.Libraries.Core.sh.flex
+StraySrc.Libraries.Core.sh.flexws
+StraySrc.Libraries.Core.sh.heapws
+StraySrc.Libraries.Core.stream
+StraySrc.Libraries.Core.swis
+StraySrc.Libraries.Core.TearSupt
+StraySrc.Libraries.Core.TearSupt.bs
+StraySrc.Libraries.Core.TearSupt.bs.tearSupt
+StraySrc.Libraries.Core.TearSupt.h
+StraySrc.Libraries.Core.TearSupt.h.tearSupt
+StraySrc.Libraries.Core.TearSupt.Makefile
+StraySrc.Libraries.Core.TearSupt.o
+StraySrc.Libraries.Core.TearSupt.o.tearSupt
+StraySrc.Libraries.Core.TearSupt.README
+StraySrc.Libraries.Core.TearSupt.s
+StraySrc.Libraries.Core.TearSupt.s.tt
+StraySrc.Libraries.Core.TearSupt.sh
+StraySrc.Libraries.Core.TearSupt.sh.tearSupt
+StraySrc.Libraries.Core.TearSupt.UnLoad
+StraySrc.Libraries.DLLLib
+StraySrc.Libraries.DLLLib.h
+StraySrc.Libraries.DLLLib.h.ctype
+StraySrc.Libraries.DLLLib.h.dll
+StraySrc.Libraries.DLLLib.h.errno
+StraySrc.Libraries.DLLLib.h.math
+StraySrc.Libraries.DLLLib.h.stdio
+StraySrc.Libraries.DLLLib.h.swiv
+StraySrc.Libraries.DLLLib.Makefile
+StraySrc.Libraries.DLLLib.o
+StraySrc.Libraries.DLLLib.o.dlllib
+StraySrc.Libraries.DLLLib.s
+StraySrc.Libraries.DLLLib.s.appEntry
+StraySrc.Libraries.DLLLib.s.clib
+StraySrc.Libraries.DLLLib.s.dpoll
+StraySrc.Libraries.DLLLib.s.dsetjmp
+StraySrc.Libraries.DLLLib.s.extEntry
+StraySrc.Libraries.DLLLib.s.findAll
+StraySrc.Libraries.DLLLib.s.iface
+StraySrc.Libraries.DLLLib.s.loadLocal
+StraySrc.Libraries.DLLLib.s.oscli
+StraySrc.Libraries.DLLLib.s.wSpace
+StraySrc.Libraries.DLLLib.sh
+StraySrc.Libraries.DLLLib.sh.dllswis
+StraySrc.Libraries.Makefile
+StraySrc.Libraries.Sapphire
+StraySrc.Libraries.Sapphire.bs
+StraySrc.Libraries.Sapphire.bs.fixedPt
+StraySrc.Libraries.Sapphire.bsh
+StraySrc.Libraries.Sapphire.bsh.banner
+StraySrc.Libraries.Sapphire.bsh.dbx
+StraySrc.Libraries.Sapphire.bsh.flex
+StraySrc.Libraries.Sapphire.bsh.libOpts
+StraySrc.Libraries.Sapphire.bsh.menuDefs
+StraySrc.Libraries.Sapphire.bsh.options
+StraySrc.Libraries.Sapphire.bsh.stdDbox
+StraySrc.Libraries.Sapphire.choices
+StraySrc.Libraries.Sapphire.choices.o
+StraySrc.Libraries.Sapphire.choices.s
+StraySrc.Libraries.Sapphire.choices.s.choices
+StraySrc.Libraries.Sapphire.choices.s.options
+StraySrc.Libraries.Sapphire.choices.s.prefs
+StraySrc.Libraries.Sapphire.colSelect
+StraySrc.Libraries.Sapphire.colSelect.s
+StraySrc.Libraries.Sapphire.csapph
+StraySrc.Libraries.Sapphire.csapph.h
+StraySrc.Libraries.Sapphire.csapph.h.akbd
+StraySrc.Libraries.Sapphire.csapph.h.alloc
+StraySrc.Libraries.Sapphire.csapph.h.banner
+StraySrc.Libraries.Sapphire.csapph.h.buttons
+StraySrc.Libraries.Sapphire.csapph.h.choices
+StraySrc.Libraries.Sapphire.csapph.h.choices.choices
+StraySrc.Libraries.Sapphire.csapph.h.choices.options
+StraySrc.Libraries.Sapphire.csapph.h.choices.prefs
+StraySrc.Libraries.Sapphire.csapph.h.chunk
+StraySrc.Libraries.Sapphire.csapph.h.cmdLine
+StraySrc.Libraries.Sapphire.csapph.h.colourBox
+StraySrc.Libraries.Sapphire.csapph.h.colSelect
+StraySrc.Libraries.Sapphire.csapph.h.coRoutine
+StraySrc.Libraries.Sapphire.csapph.h.dbox
+StraySrc.Libraries.Sapphire.csapph.h.dbx
+StraySrc.Libraries.Sapphire.csapph.h.dbx.arrow
+StraySrc.Libraries.Sapphire.csapph.h.dbx.colourPot
+StraySrc.Libraries.Sapphire.csapph.h.dbx.dbx
+StraySrc.Libraries.Sapphire.csapph.h.dbx.fileIcon
+StraySrc.Libraries.Sapphire.csapph.h.dbx.numWrite
+StraySrc.Libraries.Sapphire.csapph.h.dbx.slider
+StraySrc.Libraries.Sapphire.csapph.h.dbx.stringSet
+StraySrc.Libraries.Sapphire.csapph.h.defHandler
+StraySrc.Libraries.Sapphire.csapph.h.divide
+StraySrc.Libraries.Sapphire.csapph.h.drag
+StraySrc.Libraries.Sapphire.csapph.h.draw
+StraySrc.Libraries.Sapphire.csapph.h.dynPtr
+StraySrc.Libraries.Sapphire.csapph.h.errorBox
+StraySrc.Libraries.Sapphire.csapph.h.event
+StraySrc.Libraries.Sapphire.csapph.h.except
+StraySrc.Libraries.Sapphire.csapph.h.fastMove
+StraySrc.Libraries.Sapphire.csapph.h.fixedPt
+StraySrc.Libraries.Sapphire.csapph.h.flex
+StraySrc.Libraries.Sapphire.csapph.h.fontmenu
+StraySrc.Libraries.Sapphire.csapph.h.gallery
+StraySrc.Libraries.Sapphire.csapph.h.heap
+StraySrc.Libraries.Sapphire.csapph.h.help
+StraySrc.Libraries.Sapphire.csapph.h.hour
+StraySrc.Libraries.Sapphire.csapph.h.ibicon
+StraySrc.Libraries.Sapphire.csapph.h.idle
+StraySrc.Libraries.Sapphire.csapph.h.intKeys
+StraySrc.Libraries.Sapphire.csapph.h.keyMap
+StraySrc.Libraries.Sapphire.csapph.h.keyString
+StraySrc.Libraries.Sapphire.csapph.h.libOpts
+StraySrc.Libraries.Sapphire.csapph.h.listbox
+StraySrc.Libraries.Sapphire.csapph.h.llistMan
+StraySrc.Libraries.Sapphire.csapph.h.mbox
+StraySrc.Libraries.Sapphire.csapph.h.mem
+StraySrc.Libraries.Sapphire.csapph.h.menu
+StraySrc.Libraries.Sapphire.csapph.h.menuDefs
+StraySrc.Libraries.Sapphire.csapph.h.msgs
+StraySrc.Libraries.Sapphire.csapph.h.nopoll
+StraySrc.Libraries.Sapphire.csapph.h.note
+StraySrc.Libraries.Sapphire.csapph.h.pane
+StraySrc.Libraries.Sapphire.csapph.h.progInfo
+StraySrc.Libraries.Sapphire.csapph.h.ptr
+StraySrc.Libraries.Sapphire.csapph.h.rand
+StraySrc.Libraries.Sapphire.csapph.h.repeater
+StraySrc.Libraries.Sapphire.csapph.h.report
+StraySrc.Libraries.Sapphire.csapph.h.res
+StraySrc.Libraries.Sapphire.csapph.h.resources
+StraySrc.Libraries.Sapphire.csapph.h.resspr
+StraySrc.Libraries.Sapphire.csapph.h.roVersion
+StraySrc.Libraries.Sapphire.csapph.h.sapphire
+StraySrc.Libraries.Sapphire.csapph.h.saveWarn
+StraySrc.Libraries.Sapphire.csapph.h.screen
+StraySrc.Libraries.Sapphire.csapph.h.seh
+StraySrc.Libraries.Sapphire.csapph.h.sprite
+StraySrc.Libraries.Sapphire.csapph.h.sqrt
+StraySrc.Libraries.Sapphire.csapph.h.string
+StraySrc.Libraries.Sapphire.csapph.h.subAlloc
+StraySrc.Libraries.Sapphire.csapph.h.template
+StraySrc.Libraries.Sapphire.csapph.h.thread
+StraySrc.Libraries.Sapphire.csapph.h.tms
+StraySrc.Libraries.Sapphire.csapph.h.transWin
+StraySrc.Libraries.Sapphire.csapph.h.tspr
+StraySrc.Libraries.Sapphire.csapph.h.viewer
+StraySrc.Libraries.Sapphire.csapph.h.warning
+StraySrc.Libraries.Sapphire.csapph.h.wimp
+StraySrc.Libraries.Sapphire.csapph.h.win
+StraySrc.Libraries.Sapphire.csapph.h.winUtils
+StraySrc.Libraries.Sapphire.csapph.h.writable
+StraySrc.Libraries.Sapphire.csapph.h.xfer
+StraySrc.Libraries.Sapphire.csapph.h.xfer.load
+StraySrc.Libraries.Sapphire.csapph.h.xfer.save
+StraySrc.Libraries.Sapphire.csapph.h.xfer.saveAs
+StraySrc.Libraries.Sapphire.csapph.h.xfer.xload
+StraySrc.Libraries.Sapphire.csapph.h.xfer.xsave
+StraySrc.Libraries.Sapphire.csapph.o
+StraySrc.Libraries.Sapphire.csapph.s
+StraySrc.Libraries.Sapphire.csapph.s.cmath
+StraySrc.Libraries.Sapphire.csapph.s.crout
+StraySrc.Libraries.Sapphire.csapph.s.crts
+StraySrc.Libraries.Sapphire.csapph.s.csapph
+StraySrc.Libraries.Sapphire.csapph.s.csetjmp
+StraySrc.Libraries.Sapphire.csapph.s.cstart
+StraySrc.Libraries.Sapphire.csapph.s.ctype
+StraySrc.Libraries.Sapphire.dbx
+StraySrc.Libraries.Sapphire.dbx.o
+StraySrc.Libraries.Sapphire.dbx.s
+StraySrc.Libraries.Sapphire.dbx.s.arrow
+StraySrc.Libraries.Sapphire.dbx.s.colourPot
+StraySrc.Libraries.Sapphire.dbx.s.dbx
+StraySrc.Libraries.Sapphire.dbx.s.fileIcon
+StraySrc.Libraries.Sapphire.dbx.s.numWrite
+StraySrc.Libraries.Sapphire.dbx.s.slider
+StraySrc.Libraries.Sapphire.dbx.s.stringSet
+StraySrc.Libraries.Sapphire.dc
+StraySrc.Libraries.Sapphire.def
+StraySrc.Libraries.Sapphire.def.core
+StraySrc.Libraries.Sapphire.def.csapph
+StraySrc.Libraries.Sapphire.def.list
+StraySrc.Libraries.Sapphire.def.resources
+StraySrc.Libraries.Sapphire.def.tearoff
+StraySrc.Libraries.Sapphire.def.thread
+StraySrc.Libraries.Sapphire.dh
+StraySrc.Libraries.Sapphire.dl
+StraySrc.Libraries.Sapphire.dll
+StraySrc.Libraries.Sapphire.dll.core
+StraySrc.Libraries.Sapphire.dll.csapph
+StraySrc.Libraries.Sapphire.dll.list
+StraySrc.Libraries.Sapphire.dll.resources
+StraySrc.Libraries.Sapphire.dll.tearoff
+StraySrc.Libraries.Sapphire.dll.thread
+StraySrc.Libraries.Sapphire.ds
+StraySrc.Libraries.Sapphire.ds.core
+StraySrc.Libraries.Sapphire.ds.csapph
+StraySrc.Libraries.Sapphire.ds.list
+StraySrc.Libraries.Sapphire.ds.resources
+StraySrc.Libraries.Sapphire.ds.tearoff
+StraySrc.Libraries.Sapphire.ds.thread
+StraySrc.Libraries.Sapphire.lib
+StraySrc.Libraries.Sapphire.lib.csapph
+StraySrc.Libraries.Sapphire.lib.sapphdll
+StraySrc.Libraries.Sapphire.lib.sapphire
+StraySrc.Libraries.Sapphire.Makefile
+StraySrc.Libraries.Sapphire.Modules
+StraySrc.Libraries.Sapphire.Modules.Constrain
+StraySrc.Libraries.Sapphire.Modules.Docs
+StraySrc.Libraries.Sapphire.Modules.Docs.Sprinkle
+StraySrc.Libraries.Sapphire.Modules.Makefile
+StraySrc.Libraries.Sapphire.Modules.o
+StraySrc.Libraries.Sapphire.Modules.o.constrain
+StraySrc.Libraries.Sapphire.Modules.o.conVersion
+StraySrc.Libraries.Sapphire.Modules.o.sprinkle
+StraySrc.Libraries.Sapphire.Modules.o.sprVersion
+StraySrc.Libraries.Sapphire.Modules.s
+StraySrc.Libraries.Sapphire.Modules.s.constrain
+StraySrc.Libraries.Sapphire.Modules.s.sprinkle
+StraySrc.Libraries.Sapphire.Modules.Sprinkle
+StraySrc.Libraries.Sapphire.o
+StraySrc.Libraries.Sapphire.README
+StraySrc.Libraries.Sapphire.rsc
+StraySrc.Libraries.Sapphire.rsc.ColourSel
+StraySrc.Libraries.Sapphire.rsc.Messages
+StraySrc.Libraries.Sapphire.rsc.Sprites
+StraySrc.Libraries.Sapphire.rsc.Templates
+StraySrc.Libraries.Sapphire.s
+StraySrc.Libraries.Sapphire.s.akbd
+StraySrc.Libraries.Sapphire.s.alloc
+StraySrc.Libraries.Sapphire.s.banner
+StraySrc.Libraries.Sapphire.s.bnrStub
+StraySrc.Libraries.Sapphire.s.buttons
+StraySrc.Libraries.Sapphire.s.chunk
+StraySrc.Libraries.Sapphire.s.cmdLine
+StraySrc.Libraries.Sapphire.s.colourBox
+StraySrc.Libraries.Sapphire.s.coRoutine
+StraySrc.Libraries.Sapphire.s.dBanner
+StraySrc.Libraries.Sapphire.s.dbox
+StraySrc.Libraries.Sapphire.s.defHandler
+StraySrc.Libraries.Sapphire.s.divide
+StraySrc.Libraries.Sapphire.s.dKernel
+StraySrc.Libraries.Sapphire.s.drag
+StraySrc.Libraries.Sapphire.s.draw
+StraySrc.Libraries.Sapphire.s.dynPtr
+StraySrc.Libraries.Sapphire.s.errorBox
+StraySrc.Libraries.Sapphire.s.event
+StraySrc.Libraries.Sapphire.s.except
+StraySrc.Libraries.Sapphire.s.fastMove
+StraySrc.Libraries.Sapphire.s.flex
+StraySrc.Libraries.Sapphire.s.fontMenu
+StraySrc.Libraries.Sapphire.s.gallery
+StraySrc.Libraries.Sapphire.s.heap
+StraySrc.Libraries.Sapphire.s.help
+StraySrc.Libraries.Sapphire.s.hour
+StraySrc.Libraries.Sapphire.s.ibicon
+StraySrc.Libraries.Sapphire.s.idle
+StraySrc.Libraries.Sapphire.s.kernel
+StraySrc.Libraries.Sapphire.s.keyString
+StraySrc.Libraries.Sapphire.s.libOpts
+StraySrc.Libraries.Sapphire.s.listbox
+StraySrc.Libraries.Sapphire.s.llistMan
+StraySrc.Libraries.Sapphire.s.llistStub
+StraySrc.Libraries.Sapphire.s.mbox
+StraySrc.Libraries.Sapphire.s.mem
+StraySrc.Libraries.Sapphire.s.menu
+StraySrc.Libraries.Sapphire.s.msgs
+StraySrc.Libraries.Sapphire.s.nopoll
+StraySrc.Libraries.Sapphire.s.note
+StraySrc.Libraries.Sapphire.s.pane
+StraySrc.Libraries.Sapphire.s.progInfo
+StraySrc.Libraries.Sapphire.s.ptr
+StraySrc.Libraries.Sapphire.s.rand
+StraySrc.Libraries.Sapphire.s.repeater
+StraySrc.Libraries.Sapphire.s.report
+StraySrc.Libraries.Sapphire.s.res
+StraySrc.Libraries.Sapphire.s.resources
+StraySrc.Libraries.Sapphire.s.resspr
+StraySrc.Libraries.Sapphire.s.roVersion
+StraySrc.Libraries.Sapphire.s.sapphRes
+StraySrc.Libraries.Sapphire.s.saveWarn
+StraySrc.Libraries.Sapphire.s.screen
+StraySrc.Libraries.Sapphire.s.seh
+StraySrc.Libraries.Sapphire.s.sprite
+StraySrc.Libraries.Sapphire.s.sqrt
+StraySrc.Libraries.Sapphire.s.string
+StraySrc.Libraries.Sapphire.s.stub
+StraySrc.Libraries.Sapphire.s.subAlloc
+StraySrc.Libraries.Sapphire.s.template
+StraySrc.Libraries.Sapphire.s.thread
+StraySrc.Libraries.Sapphire.s.transWin
+StraySrc.Libraries.Sapphire.s.tspr
+StraySrc.Libraries.Sapphire.s.viewer
+StraySrc.Libraries.Sapphire.s.warning
+StraySrc.Libraries.Sapphire.s.wimp
+StraySrc.Libraries.Sapphire.s.win
+StraySrc.Libraries.Sapphire.s.winUtils
+StraySrc.Libraries.Sapphire.s.writable
+StraySrc.Libraries.Sapphire.sh
+StraySrc.Libraries.Sapphire.sh.akbd
+StraySrc.Libraries.Sapphire.sh.alloc
+StraySrc.Libraries.Sapphire.sh.banner
+StraySrc.Libraries.Sapphire.sh.buttons
+StraySrc.Libraries.Sapphire.sh.choices
+StraySrc.Libraries.Sapphire.sh.choices.choices
+StraySrc.Libraries.Sapphire.sh.choices.options
+StraySrc.Libraries.Sapphire.sh.choices.prefs
+StraySrc.Libraries.Sapphire.sh.chunk
+StraySrc.Libraries.Sapphire.sh.cmdLine
+StraySrc.Libraries.Sapphire.sh.colourBox
+StraySrc.Libraries.Sapphire.sh.colSelect
+StraySrc.Libraries.Sapphire.sh.coRoutine
+StraySrc.Libraries.Sapphire.sh.dbox
+StraySrc.Libraries.Sapphire.sh.dbx
+StraySrc.Libraries.Sapphire.sh.dbx.arrow
+StraySrc.Libraries.Sapphire.sh.dbx.colourPot
+StraySrc.Libraries.Sapphire.sh.dbx.dbx
+StraySrc.Libraries.Sapphire.sh.dbx.fileIcon
+StraySrc.Libraries.Sapphire.sh.dbx.numWrite
+StraySrc.Libraries.Sapphire.sh.dbx.slider
+StraySrc.Libraries.Sapphire.sh.dbx.stringSet
+StraySrc.Libraries.Sapphire.sh.dbx._dbxMacs
+StraySrc.Libraries.Sapphire.sh.defHandler
+StraySrc.Libraries.Sapphire.sh.divide
+StraySrc.Libraries.Sapphire.sh.drag
+StraySrc.Libraries.Sapphire.sh.draw
+StraySrc.Libraries.Sapphire.sh.dynPtr
+StraySrc.Libraries.Sapphire.sh.errorBox
+StraySrc.Libraries.Sapphire.sh.event
+StraySrc.Libraries.Sapphire.sh.except
+StraySrc.Libraries.Sapphire.sh.fastMove
+StraySrc.Libraries.Sapphire.sh.fixedPt
+StraySrc.Libraries.Sapphire.sh.flex
+StraySrc.Libraries.Sapphire.sh.fontmenu
+StraySrc.Libraries.Sapphire.sh.gallery
+StraySrc.Libraries.Sapphire.sh.heap
+StraySrc.Libraries.Sapphire.sh.help
+StraySrc.Libraries.Sapphire.sh.hour
+StraySrc.Libraries.Sapphire.sh.ibicon
+StraySrc.Libraries.Sapphire.sh.idle
+StraySrc.Libraries.Sapphire.sh.intKeys
+StraySrc.Libraries.Sapphire.sh.keyMap
+StraySrc.Libraries.Sapphire.sh.keyString
+StraySrc.Libraries.Sapphire.sh.libOpts
+StraySrc.Libraries.Sapphire.sh.listbox
+StraySrc.Libraries.Sapphire.sh.llistMan
+StraySrc.Libraries.Sapphire.sh.mbox
+StraySrc.Libraries.Sapphire.sh.mem
+StraySrc.Libraries.Sapphire.sh.menu
+StraySrc.Libraries.Sapphire.sh.menuDefs
+StraySrc.Libraries.Sapphire.sh.msgs
+StraySrc.Libraries.Sapphire.sh.nopoll
+StraySrc.Libraries.Sapphire.sh.note
+StraySrc.Libraries.Sapphire.sh.pane
+StraySrc.Libraries.Sapphire.sh.progInfo
+StraySrc.Libraries.Sapphire.sh.ptr
+StraySrc.Libraries.Sapphire.sh.rand
+StraySrc.Libraries.Sapphire.sh.repeater
+StraySrc.Libraries.Sapphire.sh.report
+StraySrc.Libraries.Sapphire.sh.res
+StraySrc.Libraries.Sapphire.sh.resources
+StraySrc.Libraries.Sapphire.sh.resspr
+StraySrc.Libraries.Sapphire.sh.roVersion
+StraySrc.Libraries.Sapphire.sh.sapphire
+StraySrc.Libraries.Sapphire.sh.saveWarn
+StraySrc.Libraries.Sapphire.sh.screen
+StraySrc.Libraries.Sapphire.sh.seh
+StraySrc.Libraries.Sapphire.sh.sprite
+StraySrc.Libraries.Sapphire.sh.sqrt
+StraySrc.Libraries.Sapphire.sh.string
+StraySrc.Libraries.Sapphire.sh.subAlloc
+StraySrc.Libraries.Sapphire.sh.template
+StraySrc.Libraries.Sapphire.sh.thread
+StraySrc.Libraries.Sapphire.sh.tms
+StraySrc.Libraries.Sapphire.sh.transWin
+StraySrc.Libraries.Sapphire.sh.tspr
+StraySrc.Libraries.Sapphire.sh.viewer
+StraySrc.Libraries.Sapphire.sh.warning
+StraySrc.Libraries.Sapphire.sh.wimp
+StraySrc.Libraries.Sapphire.sh.win
+StraySrc.Libraries.Sapphire.sh.winUtils
+StraySrc.Libraries.Sapphire.sh.writable
+StraySrc.Libraries.Sapphire.sh.xfer
+StraySrc.Libraries.Sapphire.sh.xfer.load
+StraySrc.Libraries.Sapphire.sh.xfer.save
+StraySrc.Libraries.Sapphire.sh.xfer.saveAs
+StraySrc.Libraries.Sapphire.sh.xfer.xload
+StraySrc.Libraries.Sapphire.sh.xfer.xsave
+StraySrc.Libraries.Sapphire.sh._tms
+StraySrc.Libraries.Sapphire.sh._tms.tmsCreate
+StraySrc.Libraries.Sapphire.sh._tms.tmsGlobal
+StraySrc.Libraries.Sapphire.sh._tms.tmsGlue
+StraySrc.Libraries.Sapphire.sh._tms.tmsMain
+StraySrc.Libraries.Sapphire.stub
+StraySrc.Libraries.Sapphire.tms
+StraySrc.Libraries.Sapphire.tms.o
+StraySrc.Libraries.Sapphire.tms.s
+StraySrc.Libraries.Sapphire.tms.s.tmsCreate
+StraySrc.Libraries.Sapphire.tms.s.tmsGlue
+StraySrc.Libraries.Sapphire.tms.s.tmsMain
+StraySrc.Libraries.Sapphire.xfer
+StraySrc.Libraries.Sapphire.xfer.o
+StraySrc.Libraries.Sapphire.xfer.s
+StraySrc.Libraries.Sapphire.xfer.s.load
+StraySrc.Libraries.Sapphire.xfer.s.save
+StraySrc.Libraries.Sapphire.xfer.s.saveAs
+StraySrc.Libraries.Sapphire.xfer.s.xload
+StraySrc.Libraries.Sapphire.xfer.s.xsave
+StraySrc.Libraries.Steel
+StraySrc.Libraries.Steel.c
+StraySrc.Libraries.Steel.c.akbd
+StraySrc.Libraries.Steel.c.alarm
+StraySrc.Libraries.Steel.c.baricon
+StraySrc.Libraries.Steel.c.blinkC
+StraySrc.Libraries.Steel.c.buffer
+StraySrc.Libraries.Steel.c.buttons
+StraySrc.Libraries.Steel.c.caretptr
+StraySrc.Libraries.Steel.c.choices
+StraySrc.Libraries.Steel.c.crc
+StraySrc.Libraries.Steel.c.creator
+StraySrc.Libraries.Steel.c.dbox
+StraySrc.Libraries.Steel.c.event
+StraySrc.Libraries.Steel.c.exception
+StraySrc.Libraries.Steel.c.fileicon
+StraySrc.Libraries.Steel.c.font
+StraySrc.Libraries.Steel.c.fontMenu
+StraySrc.Libraries.Steel.c.help
+StraySrc.Libraries.Steel.c.ibicon
+StraySrc.Libraries.Steel.c.interface
+StraySrc.Libraries.Steel.c.keyString
+StraySrc.Libraries.Steel.c.listbox
+StraySrc.Libraries.Steel.c.mem
+StraySrc.Libraries.Steel.c.menu
+StraySrc.Libraries.Steel.c.msgs
+StraySrc.Libraries.Steel.c.nopoll
+StraySrc.Libraries.Steel.c.pane
+StraySrc.Libraries.Steel.c.pointer
+StraySrc.Libraries.Steel.c.prefs
+StraySrc.Libraries.Steel.c.print
+StraySrc.Libraries.Steel.c.res
+StraySrc.Libraries.Steel.c.resspr
+StraySrc.Libraries.Steel.c.saveas
+StraySrc.Libraries.Steel.c.scroller
+StraySrc.Libraries.Steel.c.sprite
+StraySrc.Libraries.Steel.c.stddbox
+StraySrc.Libraries.Steel.c.tcol
+StraySrc.Libraries.Steel.c.tearoff
+StraySrc.Libraries.Steel.c.template
+StraySrc.Libraries.Steel.c.utils
+StraySrc.Libraries.Steel.c.viewer
+StraySrc.Libraries.Steel.c.visdelay
+StraySrc.Libraries.Steel.c.vsscanf
+StraySrc.Libraries.Steel.c.werr
+StraySrc.Libraries.Steel.c.wimpt
+StraySrc.Libraries.Steel.c.win
+StraySrc.Libraries.Steel.c.xferrecv
+StraySrc.Libraries.Steel.c.xfersend
+StraySrc.Libraries.Steel.c.xproginfo
+StraySrc.Libraries.Steel.def
+StraySrc.Libraries.Steel.def.steel
+StraySrc.Libraries.Steel.dh
+StraySrc.Libraries.Steel.dll
+StraySrc.Libraries.Steel.dll.Steel
+StraySrc.Libraries.Steel.do
+StraySrc.Libraries.Steel.ds
+StraySrc.Libraries.Steel.h
+StraySrc.Libraries.Steel.h.akbd
+StraySrc.Libraries.Steel.h.alarm
+StraySrc.Libraries.Steel.h.baricon
+StraySrc.Libraries.Steel.h.bbc
+StraySrc.Libraries.Steel.h.blinkC
+StraySrc.Libraries.Steel.h.buffer
+StraySrc.Libraries.Steel.h.buttons
+StraySrc.Libraries.Steel.h.calltrace
+StraySrc.Libraries.Steel.h.caretptr
+StraySrc.Libraries.Steel.h.choices
+StraySrc.Libraries.Steel.h.colourtran
+StraySrc.Libraries.Steel.h.coords
+StraySrc.Libraries.Steel.h.crc
+StraySrc.Libraries.Steel.h.crc32
+StraySrc.Libraries.Steel.h.dbox
+StraySrc.Libraries.Steel.h.event
+StraySrc.Libraries.Steel.h.exception
+StraySrc.Libraries.Steel.h.fileicon
+StraySrc.Libraries.Steel.h.flex
+StraySrc.Libraries.Steel.h.font
+StraySrc.Libraries.Steel.h.fontMenu
+StraySrc.Libraries.Steel.h.heap
+StraySrc.Libraries.Steel.h.help
+StraySrc.Libraries.Steel.h.ibicon
+StraySrc.Libraries.Steel.h.interface
+StraySrc.Libraries.Steel.h.keyString
+StraySrc.Libraries.Steel.h.listbox
+StraySrc.Libraries.Steel.h.mem
+StraySrc.Libraries.Steel.h.menu
+StraySrc.Libraries.Steel.h.menuExt
+StraySrc.Libraries.Steel.h.msgs
+StraySrc.Libraries.Steel.h.nopoll
+StraySrc.Libraries.Steel.h.os
+StraySrc.Libraries.Steel.h.pane
+StraySrc.Libraries.Steel.h.pointer
+StraySrc.Libraries.Steel.h.prefs
+StraySrc.Libraries.Steel.h.res
+StraySrc.Libraries.Steel.h.resspr
+StraySrc.Libraries.Steel.h.saveas
+StraySrc.Libraries.Steel.h.scroller
+StraySrc.Libraries.Steel.h.sculptrix
+StraySrc.Libraries.Steel.h.sprite
+StraySrc.Libraries.Steel.h.stddbox
+StraySrc.Libraries.Steel.h.steel
+StraySrc.Libraries.Steel.h.tcol
+StraySrc.Libraries.Steel.h.tearoff
+StraySrc.Libraries.Steel.h.template
+StraySrc.Libraries.Steel.h.utils
+StraySrc.Libraries.Steel.h.viewer
+StraySrc.Libraries.Steel.h.visdelay
+StraySrc.Libraries.Steel.h.vsscanf
+StraySrc.Libraries.Steel.h.werr
+StraySrc.Libraries.Steel.h.wimp
+StraySrc.Libraries.Steel.h.wimpext
+StraySrc.Libraries.Steel.h.wimpstruct
+StraySrc.Libraries.Steel.h.wimpt
+StraySrc.Libraries.Steel.h.win
+StraySrc.Libraries.Steel.h.xferrecv
+StraySrc.Libraries.Steel.h.xfersend
+StraySrc.Libraries.Steel.h.xproginfo
+StraySrc.Libraries.Steel.h.xtearoff
+StraySrc.Libraries.Steel.lib
+StraySrc.Libraries.Steel.lib.steel
+StraySrc.Libraries.Steel.lib.steeldll
+StraySrc.Libraries.Steel.Makefile
+StraySrc.Libraries.Steel.Messages
+StraySrc.Libraries.Steel.o
+StraySrc.Libraries.Steel.s
+StraySrc.Libraries.Steel.s.bbc
+StraySrc.Libraries.Steel.s.calltrace
+StraySrc.Libraries.Steel.s.colourtran
+StraySrc.Libraries.Steel.s.coords
+StraySrc.Libraries.Steel.s.crc32
+StraySrc.Libraries.Steel.s.fastMove
+StraySrc.Libraries.Steel.s.flex_dll
+StraySrc.Libraries.Steel.s.flex_stat
+StraySrc.Libraries.Steel.s.heap_dll
+StraySrc.Libraries.Steel.s.heap_stat
+StraySrc.Libraries.Steel.s.os
+StraySrc.Libraries.Steel.s.sculptrix
+StraySrc.Libraries.Steel.s.wimpExt
+StraySrc.Libraries.Steel.s.wimp_dll
+StraySrc.Libraries.Steel.s.wimp_main
+StraySrc.Libraries.Steel.s.wimp_stat
+StraySrc.Makefile
+StraySrc.MiscToys
+StraySrc.MiscToys.CheckSD
+StraySrc.MiscToys.CheckSD.checksd
+StraySrc.MiscToys.CheckSD.Makefile
+StraySrc.MiscToys.CheckSD.o
+StraySrc.MiscToys.CheckSD.README
+StraySrc.MiscToys.CheckSD.rsc
+StraySrc.MiscToys.CheckSD.rsc.Templates
+StraySrc.MiscToys.CheckSD.s
+StraySrc.MiscToys.CheckSD.s.CheckSD
+StraySrc.MiscToys.CurrDir
+StraySrc.MiscToys.CurrDir.currDir
+StraySrc.MiscToys.CurrDir.Makefile
+StraySrc.MiscToys.CurrDir.o
+StraySrc.MiscToys.CurrDir.README
+StraySrc.MiscToys.CurrDir.s
+StraySrc.MiscToys.CurrDir.currDir
+StraySrc.MiscToys.Makefile
+StraySrc.MiscToys.PlainError
+StraySrc.MiscToys.PlainError.b
+StraySrc.MiscToys.PlainError.b.plainError
+StraySrc.MiscToys.PlainError.Makefile
+StraySrc.MiscToys.PlainError.PlainError
+StraySrc.MiscToys.PlainError.ReadMe
+StraySrc.Modules
+StraySrc.Modules.Constrain
+StraySrc.Modules.PlainError
+StraySrc.Modules.Sculptrix
+StraySrc.Modules.Sprinkle
+StraySrc.READsteel
+StraySrc.SapphDoc
+StraySrc.SapphToys
+StraySrc.SapphToys.!DrawX
+StraySrc.SapphToys.!DrawX.!Boot
+StraySrc.SapphToys.!DrawX.!Help
+StraySrc.SapphToys.!DrawX.!Run
+StraySrc.SapphToys.!DrawX.!RunImage
+StraySrc.SapphToys.!DrawX.!Sprites
+StraySrc.SapphToys.!DrawX.Choices
+StraySrc.SapphToys.!DrawX.Makefile
+StraySrc.SapphToys.!DrawX.Modules
+StraySrc.SapphToys.!DrawX.Modules.Sculptrix
+StraySrc.SapphToys.!DrawX.Modules.Sprinkle
+StraySrc.SapphToys.!DrawX.o
+StraySrc.SapphToys.!DrawX.Resources
+StraySrc.SapphToys.!DrawX.Resources.Messages
+StraySrc.SapphToys.!DrawX.Resources.Sprites
+StraySrc.SapphToys.!DrawX.Resources.Templates
+StraySrc.SapphToys.!DrawX.s
+StraySrc.SapphToys.!DrawX.s.drawX
+StraySrc.SapphToys.!DrawX.setSlot
+StraySrc.SapphToys.!SWIlist
+StraySrc.SapphToys.!SWIlist.!Help
+StraySrc.SapphToys.!SWIlist.!Run
+StraySrc.SapphToys.!SWIlist.!RunImage
+StraySrc.SapphToys.!SWIlist.!Sprites
+StraySrc.SapphToys.!SWIlist.bs
+StraySrc.SapphToys.!SWIlist.bs.swiList
+StraySrc.SapphToys.!SWIlist.Format
+StraySrc.SapphToys.!SWIlist.Makefile
+StraySrc.SapphToys.!SWIlist.o
+StraySrc.SapphToys.!SWIlist.Sculptrix
+StraySrc.SapphToys.!SWIlist.setSlot
+StraySrc.SapphToys.!SWIlist.SWIDump
+StraySrc.SapphToys.!SWIlist.UK
+StraySrc.Sculptrix
+StraySrc.Sculptrix.!SConfig
+StraySrc.Sculptrix.!SConfig.!Run
+StraySrc.Sculptrix.!SConfig.loadConfig
+StraySrc.Sculptrix.!SConfig.Makefile
+StraySrc.Sculptrix.!SConfig.o
+StraySrc.Sculptrix.!SConfig.s
+StraySrc.Sculptrix.!SConfig.s.loadConfig
+StraySrc.Sculptrix.!SConfig.SConfig
+StraySrc.Sculptrix.!SConfig.Sculptrix
+StraySrc.Sculptrix.!Setrix
+StraySrc.Sculptrix.!Setrix.!Help
+StraySrc.Sculptrix.!Setrix.!Run
+StraySrc.Sculptrix.!Setrix.!RunImage
+StraySrc.Sculptrix.!Setrix.!Sprites
+StraySrc.Sculptrix.!Setrix.Makefile
+StraySrc.Sculptrix.!Setrix.Modules
+StraySrc.Sculptrix.!Setrix.Modules.Sculptrix
+StraySrc.Sculptrix.!Setrix.o
+StraySrc.Sculptrix.!Setrix.Resources
+StraySrc.Sculptrix.!Setrix.Resources.Messages
+StraySrc.Sculptrix.!Setrix.Resources.Sprites
+StraySrc.Sculptrix.!Setrix.Resources.Templates
+StraySrc.Sculptrix.!Setrix.s
+StraySrc.Sculptrix.!Setrix.s.setrix
+StraySrc.Sculptrix.!Setrix.setSlot
+StraySrc.Sculptrix.apcs
+StraySrc.Sculptrix.apcs.h
+StraySrc.Sculptrix.apcs.h.sculptrix
+StraySrc.Sculptrix.apcs.Makefile
+StraySrc.Sculptrix.apcs.o
+StraySrc.Sculptrix.apcs.o.sculptrix
+StraySrc.Sculptrix.apcs.s
+StraySrc.Sculptrix.apcs.s.scp_apcs
+StraySrc.Sculptrix.Changes
+StraySrc.Sculptrix.Makefile
+StraySrc.Sculptrix.NewVersion
+StraySrc.Sculptrix.old-vsn
+StraySrc.Sculptrix.old-vsn.README
+StraySrc.Sculptrix.old-vsn.s
+StraySrc.Sculptrix.old-vsn.s.sculptrix
+StraySrc.Sculptrix.README
+StraySrc.Sculptrix.sculptrix
+StraySrc.Sculptrix.sculptrix.Makefile
+StraySrc.Sculptrix.sculptrix.o
+StraySrc.Sculptrix.sculptrix.rsc
+StraySrc.Sculptrix.sculptrix.rsc.messages
+StraySrc.Sculptrix.sculptrix.s
+StraySrc.Sculptrix.sculptrix.s.bbox
+StraySrc.Sculptrix.sculptrix.s.border
+StraySrc.Sculptrix.sculptrix.s.colours
+StraySrc.Sculptrix.sculptrix.s.config
+StraySrc.Sculptrix.sculptrix.s.plot
+StraySrc.Sculptrix.sculptrix.s.redraw
+StraySrc.Sculptrix.sculptrix.s.rules
+StraySrc.Sculptrix.sculptrix.s.sculptrix
+StraySrc.Sculptrix.sculptrix.s.slab
+StraySrc.Sculptrix.sculptrix.s.utils
+StraySrc.Sculptrix.sculptrix.s.vString
+StraySrc.Sculptrix.sculptrix.Sculptrix
+StraySrc.Sculptrix.sculptrix.sh
+StraySrc.Sculptrix.sculptrix.sh.bbox
+StraySrc.Sculptrix.sculptrix.sh.border
+StraySrc.Sculptrix.sculptrix.sh.colours
+StraySrc.Sculptrix.sculptrix.sh.config
+StraySrc.Sculptrix.sculptrix.sh.messages
+StraySrc.Sculptrix.sculptrix.sh.plot
+StraySrc.Sculptrix.sculptrix.sh.redraw
+StraySrc.Sculptrix.sculptrix.sh.rules
+StraySrc.Sculptrix.sculptrix.sh.slab
+StraySrc.Sculptrix.sculptrix.sh.utils
+StraySrc.Sculptrix.sculptrix.sh.vString
+StraySrc.Sculptrix.sculptrix.sh.wSpace
+StraySrc.SDLS
+StraySrc.SDLS.!DLLMerge
+StraySrc.SDLS.!DLLMerge.!Help
+StraySrc.SDLS.!DLLMerge.!Run
+StraySrc.SDLS.!DLLMerge.!RunImage
+StraySrc.SDLS.!DLLMerge.!Sprites
+StraySrc.SDLS.!DLLMerge.Makefile
+StraySrc.SDLS.!DLLMerge.o
+StraySrc.SDLS.!DLLMerge.rsc
+StraySrc.SDLS.!DLLMerge.rsc.messages
+StraySrc.SDLS.!DLLMerge.rsc.templates
+StraySrc.SDLS.!DLLMerge.s
+StraySrc.SDLS.!DLLMerge.s.dllmerge
+StraySrc.SDLS.!DLLMerge.Sculptrix
+StraySrc.SDLS.!DLLMerge.sh
+StraySrc.SDLS.!DLLMerge.sh.messages
+StraySrc.SDLS.!DLLMerge.sh.templates
+StraySrc.SDLS.cdll
+StraySrc.SDLS.cdll.c
+StraySrc.SDLS.cdll.c.binding
+StraySrc.SDLS.cdll.c.cstub
+StraySrc.SDLS.cdll.c.decode
+StraySrc.SDLS.cdll.c.dissect
+StraySrc.SDLS.cdll.c.dllbinder
+StraySrc.SDLS.cdll.c.error
+StraySrc.SDLS.cdll.c.extentry
+StraySrc.SDLS.cdll.c.hashtable
+StraySrc.SDLS.cdll.c.readdef
+StraySrc.SDLS.cdll.cdll
+StraySrc.SDLS.cdll.dissect
+StraySrc.SDLS.cdll.h
+StraySrc.SDLS.cdll.h.binding
+StraySrc.SDLS.cdll.h.crc32
+StraySrc.SDLS.cdll.h.cstub
+StraySrc.SDLS.cdll.h.decode
+StraySrc.SDLS.cdll.h.error
+StraySrc.SDLS.cdll.h.extentry
+StraySrc.SDLS.cdll.h.hashtable
+StraySrc.SDLS.cdll.h.readdef
+StraySrc.SDLS.cdll.Makefile
+StraySrc.SDLS.cdll.o
+StraySrc.SDLS.cdll.ordinal
+StraySrc.SDLS.cdll.s
+StraySrc.SDLS.cdll.s.crc32
+StraySrc.SDLS.DLLManager
+StraySrc.SDLS.DLLManager.DLLManager
+StraySrc.SDLS.DLLManager.dllmdump
+StraySrc.SDLS.DLLManager.Makefile
+StraySrc.SDLS.DLLManager.o
+StraySrc.SDLS.DLLManager.rsc
+StraySrc.SDLS.DLLManager.rsc.messages
+StraySrc.SDLS.DLLManager.s
+StraySrc.SDLS.DLLManager.s.app
+StraySrc.SDLS.DLLManager.s.dheader
+StraySrc.SDLS.DLLManager.s.dll
+StraySrc.SDLS.DLLManager.s.dllmdump
+StraySrc.SDLS.DLLManager.s.misc
+StraySrc.SDLS.DLLManager.s.suballoc
+StraySrc.SDLS.DLLManager.sh
+StraySrc.SDLS.DLLManager.sh.app
+StraySrc.SDLS.DLLManager.sh.appblock
+StraySrc.SDLS.DLLManager.sh.dll
+StraySrc.SDLS.DLLManager.sh.dllblock
+StraySrc.SDLS.DLLManager.sh.linkblock
+StraySrc.SDLS.DLLManager.sh.messages
+StraySrc.SDLS.DLLManager.sh.misc
+StraySrc.SDLS.DLLManager.sh.suballoc
+StraySrc.SDLS.DLLManager.sh.wSpace
+StraySrc.SDLS.Makefile
+StraySrc.ssr-init
+StraySrc.Utilities
+StraySrc.Utilities.b
+StraySrc.Utilities.b.buildstub
+StraySrc.Utilities.b.fixlink
+StraySrc.Utilities.b.msgaof
+StraySrc.Utilities.b.resgen
+StraySrc.Utilities.b.templaof
+StraySrc.Utilities.buildstub
+StraySrc.Utilities.c
+StraySrc.Utilities.c.alloc
+StraySrc.Utilities.c.chdrgen
+StraySrc.Utilities.c.cmdr
+StraySrc.Utilities.c.each
+StraySrc.Utilities.c.gf
+StraySrc.Utilities.c.glob
+StraySrc.Utilities.c.headerGen
+StraySrc.Utilities.c.inst
+StraySrc.Utilities.c.setdate
+StraySrc.Utilities.c.ssrclean
+StraySrc.Utilities.c.submake
+StraySrc.Utilities.chdrgen
+StraySrc.Utilities.each
+StraySrc.Utilities.enumerate
+StraySrc.Utilities.ex
+StraySrc.Utilities.ex.buildstub
+StraySrc.Utilities.ex.msgaof
+StraySrc.Utilities.ex.resgen
+StraySrc.Utilities.ex.templaof
+StraySrc.Utilities.fixlink
+StraySrc.Utilities.h
+StraySrc.Utilities.h.alloc
+StraySrc.Utilities.h.cmdr
+StraySrc.Utilities.h.gf
+StraySrc.Utilities.h.glob
+StraySrc.Utilities.headergen
+StraySrc.Utilities.hour
+StraySrc.Utilities.inst
+StraySrc.Utilities.Makefile
+StraySrc.Utilities.msgaof
+StraySrc.Utilities.o
+StraySrc.Utilities.pathutil
+StraySrc.Utilities.resgen
+StraySrc.Utilities.s
+StraySrc.Utilities.s.enumerate
+StraySrc.Utilities.s.hour
+StraySrc.Utilities.s.pathUtil
+StraySrc.Utilities.s.path_util
+StraySrc.Utilities.s.setSlot
+StraySrc.Utilities.s.test
+StraySrc.Utilities.setdate
+StraySrc.Utilities.setslot
+StraySrc.Utilities.sh
+StraySrc.Utilities.sh.pathUtil
+StraySrc.Utilities.ssrclean
+StraySrc.Utilities.submake
+StraySrc.Utilities.templaof
+StraySrc.Utilities.test
diff --git a/StraySrc/dist/makeDist,feb b/StraySrc/dist/makeDist,feb
new file mode 100644 (file)
index 0000000..feab2d6
--- /dev/null
@@ -0,0 +1,8 @@
+|
+| makeDist
+|
+| Build SSR distribution archives
+|
+
+dir <SSR$Dir>.^
+zip <SSR$Dir>.zip.%0 -@ < <SSR$Dir>.dist.%0
diff --git a/StraySrc/gplnote/Makefile,fe1 b/StraySrc/gplnote/Makefile,fe1
new file mode 100644 (file)
index 0000000..257c5a0
--- /dev/null
@@ -0,0 +1,99 @@
+#
+# Makefile
+#
+# © 1998 Straylight/Edgeware
+#
+
+#----- Licensing note -------------------------------------------------------
+#
+# This makefile is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This makefile is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this makefile.  If not, write to the Free Software Foundation,
+# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#----- Compilation flags ----------------------------------------------------
+
+# --- Uncomment to use the C4 tools ---
+
+# OLD = o-
+
+# --- C compilation ---
+
+CC = $(OLD)cc -c -o $@
+CFLAGS = -depend !Depend -throwback -ffah -Ilibs: -IC:
+COMPILE = $(CC) $(CFLAGS)
+
+# --- Assembling ---
+
+AS = $(OLD)objasm -quit -to $@
+ASFLAGS = -stamp -depend !Depend -throwback
+ASSEMBLE = $(AS) $(ASFLAGS) -from
+
+BAS = basasm
+
+# --- Linking ---
+
+LD = $(OLD)link -o $@
+LD_APP = $(LD) -aif
+LD_UTIL = $(LD) -bin -base 0
+LD_MOD = $(LD) -bin -base 0
+LD_BIN = $(LD) -bin -base 0
+LD_DLL = $(LD) -rmf
+LD_AOF = $(LD) -aof
+
+# --- Making libraries ---
+
+AR = $(OLD)libfile -o
+
+CDLL = cdll
+
+# --- Setting file types ---
+
+SET_APP = SetType $@ FF8
+SET_MOD = SetType $@ FFA
+SET_UTIL = SetType $@ FFC
+SET_DLL = SetType $@ FFD
+
+# --- Other maintenance things ---
+
+RM = ssrclean
+INSTALL = inst
+SETDATE = setdate
+SQUEEZE = squeeze $@
+DATE = %zdy %mo %ce%yr
+MODDATE = %dy %m3 %ce%yr
+CRIGHT = © %ce%yr Straylight
+FIXLINK = fixlink $@
+
+#----- Default rules --------------------------------------------------------
+
+.SUFFIXES: .o .c .s .bs
+.c.o:
+       $(COMPILE) $<
+.s.o:
+       $(ASSEMBLE) $<
+.bs.o:
+       $(BAS) $< $@
+
+#----- Object files ---------------------------------------------------------
+
+#----- Compiling things -----------------------------------------------------
+
+all:
+
+install:
+
+clean:
+
+#----- Dynamic dependencies -------------------------------------------------
+
+# Dynamic dependencies:
diff --git a/StraySrc/gplnote/asm b/StraySrc/gplnote/asm
new file mode 100644 (file)
index 0000000..06e27c2
--- /dev/null
@@ -0,0 +1,18 @@
+;----- Licensing note -------------------------------------------------------
+;
+; This file is part of Straylight's <...>
+;
+; <...> is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation; either version 2, or (at your option)
+; any later version.
+;
+; <...> is distributed in the hope that it will be useful,
+; but WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+; GNU General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with <...>.  If not, write to the Free Software Foundation,
+; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
diff --git a/StraySrc/gplnote/basic,ffb b/StraySrc/gplnote/basic,ffb
new file mode 100644 (file)
index 0000000..e3885d5
Binary files /dev/null and b/StraySrc/gplnote/basic,ffb differ
diff --git a/StraySrc/gplnote/c b/StraySrc/gplnote/c
new file mode 100644 (file)
index 0000000..0692006
--- /dev/null
@@ -0,0 +1,19 @@
+/*----- Licensing note ----------------------------------------------------*
+ *
+ * This file is part of Straylight's <...>
+ *
+ * <...> is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * <...> is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with <...>.  If not, write to the Free Software Foundation,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
diff --git a/StraySrc/ssr-init,feb b/StraySrc/ssr-init,feb
new file mode 100644 (file)
index 0000000..3234e87
--- /dev/null
@@ -0,0 +1,40 @@
+|
+| ssr_init
+|
+| Initialise paths for building SSR
+|
+| © 1998 Straylight
+|
+
+| --- Add my binaries to the run path ---
+
+Set SSR$Dir <Obey$Dir>
+/<SSR$Dir>.bin.hour -on
+/<SSR$Dir>.bin.pathutil -path Run$Path -add -dir <SSR$Dir>.bin.
+
+| --- Add my libraries to the path ---
+|
+| Indirect everything though `SSRLibs$Dir' to reduce the path length.
+
+Set SSRLibs$Dir <SSR$Dir>.Libraries
+Set Alias$_adlib pathutil -path Libs$Path -add -dir %%0. -create
+enumerate -noFiles -dir <SSRLibs$Dir> -cmd _adlib
+_adlib <SSRLibs$Dir>
+Unset Alias$_adlib
+
+Set Sapphire$Path libs:Sapphire.sh.
+
+| --- Development aliases ---
+
+Set Alias$basasm Set bas$Output "%%*1"|mIf "|<Prefix$Dir>" = "" Then Run %%0 Else Run |<Prefix$Dir>.%%0
+
+| --- Places to put things ---
+
+Set SSR$BinDir <SSR$Dir>.bin
+Set SSR$ModDir <SSR$Dir>.Modules
+Set SSR$LibDir <SSR$Dir>.Libraries
+Set SSR$DLLDir <SSR$Dir>.!DLLs
+
+| --- Done ---
+
+hour -off
diff --git a/StraySrc/ssr-order b/StraySrc/ssr-order
new file mode 100644 (file)
index 0000000..fa024dc
--- /dev/null
@@ -0,0 +1,85 @@
+From: mdw@excessus.ebi.ac.uk (Mark Wooding)
+Subject: Re: E is for Enlightenment
+Date: Fri, 19 Dec 1997 00:00:00 GMT
+Message-ID: <slrn69jenb.agt.mdw@excessus.ebi.ac.uk>
+References: <slrn69a3bm.eea.mdw@excessus.ebi.ac.uk>
+Organization: MRC Human Genome Mapping Project Resource Centre
+Reply-To: mdw@ebi.ac.uk
+Newsgroups: comp.sys.acorn.programmer
+
+
+
+[This isn't really a follow-up to anyone in particular, although it
+belongs in the same thread.]
+
+
+I'm extremely heartened by the interest people have shown.  I've even
+had people throwing themselves at me and trying to persuade me not to do
+this.  This puzzled me.  That's not really the point.  Thanks to
+everyone.
+
+I ought to try to explain in more detail how the Straylight Source
+Release (or SSR) is going to work.  There's nothing to see yet.
+Sources, when they appear, will be available by anonymous FTP from
+odie.barnet.ac.uk, in the directory /pub/Acorn/straylight.
+
+The SSR will appear one chunk at a time, hopefully in a sensible order
+(so that you don't need to wait for the next chunk before building this
+one).  Some chunks are big, and some are small.  Each one will be a Zip
+file, accompanied by a detached PGP signature.
+
+I don't have an exact timescale planned.  Some parts have to be delayed
+because they depend on earlier chunks.  Other chunks have licensing
+problems which I need to sort out.  In all, I reckon it'll take about
+three or four months for everything to appear.  Don't rush me.
+
+The order of things will probably be like this:
+
+  * Base -- a collection of little libraries, header files and tools which
+    you need to build everything else.
+
+  * BAS -- the Basic Assembler Supplement.  It's a macro library for
+    BASIC assembler users which generates AOF and does some other
+    stuff.
+
+  * Sculptrix -- Our 3D border module.  There's some lovely code in
+    here, I think.  (Sculptrix has a mutual dependency with Sapphire,
+    since the Setrix application is Sapphire-based, and Sapphire uses
+    Sculptrix for its borders.)
+
+  * SDLS -- the Straylight Dynamic Linking System.  You know what this
+    is, I hope.
+
+  * Sapphire -- Straylight's seriously neat library, written entirely in
+    assembler.  I don't imagine anyone actually using this, although I'm
+    sure some people will find it interesting.
+
+  * Dynamite -- the heap manager.  You know about this too.
+
+  * Toys -- some toys, some based on Sapphire.  Many of them are
+    designed to test Sapphire features.
+
+  * STEEL -- our old library.  This is C-oriented, and only really
+    released because Glass needs it.
+
+  * Glass -- the template editor.  Go fetch, use, enjoy.
+
+  * Toys -- more toys, mostly older ones, based on STEEL.
+
+On licensing: sources will be available under the GPL, except for
+Sapphire and STEEL, which will be available under the Library GPL.
+Software currently available as binaries under different conditions will
+continue to be available under those conditions, although this will only
+apply to the unmodified binaries, not anything you compile yourself from
+the supplied sources.
+
+I might as well point out that quite a lot of this isn't commercial-
+quality stuff.  There's hardly any documentation for anything, and
+there'll probably be lots of bugs.  I'm /not/ planning on doing much in
+the way of maintenance on any of this stuff.  If it breaks, you get to
+keep both pieces.
+-- 
+[mdw]
+
+`It can't rain all the time.'
+               -- Eric Draven
diff --git a/dist/README b/dist/README
new file mode 100644 (file)
index 0000000..0bfe1da
--- /dev/null
@@ -0,0 +1,104 @@
+STRAYLIGHT SOURCE RELEASE
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This directory contains the Straylight Source Release.  The various Zip
+files contain sources to distinct pieces of software.  Unfortunately, 
+the code was never written to be distributed, so there's a complex
+pattern of interdependency between some of the packages.
+
+`Phase 1' of the Release consists of the following parts:
+
+Core           Contains standard libraries and build tools required for
+               building everything else.
+
+Dynamite       Straylight's dynamic area management module.  Requires
+               Core.
+
+MiscToys       Some fairly silly utilities.  Requires Core.
+
+Sapphire       A large library for writing applications in ARM
+               assembler.  There's a `README' file providing a brief
+               overview, documented header files and a few examples.
+               Requires Core, SDLS, and Sculptrix
+
+Sculptrix      A module for drawing 3D buttons.  Requires Sapphire for
+               the configuration program.
+
+SDLS           Straylight's dynamic linking system.  Requires Sculptrix.
+
+Phase 2 will contain some more toys, the Steel C library, and the Glass
+template editor.  I'm not making any promises with regard to release
+times for phase 2.
+
+Building the SSR should be fairly straightforward.  First, unpack the
+sections you want.  They all share the same build root directory
+`StraySrc'.
+
+Now, make sure that the environment is set up properly.  I tested the
+Release using a minimal toolset consisting of:
+
+  * The following programs available in Run$Path:
+  
+    amu                Acorn's Make Utility version 5.02
+    cc         The Acorn C compiler version 5.06
+    ccrunch    A BASIC compactor written by Ragnar Hafstað
+    libfile    Acorn's library management tool version 5.00
+    link       Acorn's linker version 5.06
+    o-cc       An old Acorn C compiler version 4.00
+    o-libfile  An old Acorn library management tool version 4.00
+    o-link     An old Acorn linker version 4.00
+    o-objasm   An old Acorn assembler version 2.00
+    objasm     Acorn's ARM assembler version 3.06
+    sed                GNU sed version 2.03
+    squeeze    Acorn's AIF squeezer version 5.00
+    unzip      InfoZIP unarchiver version 5.13c BETA
+    zip                InfoZIP archiver version 2.0j
+
+  * The following libraries available in C$Path:
+
+    clib       Acorn's C library headers
+    risc_oslib Acorn's RISC OS library headers and object files
+
+You may be able to get away with different versions of tools.  In
+particular, the old versions of Acorn's tools are used to ensure
+that AOF2 is generated for compatibility with other people's old tools.
+
+SSR requires its own tools and libraries in addition to those listed
+above.  It will create `Libs$Path' pointing at its own libraries, and
+add its own tools to `Run$Path' when you run `ssr-init'.
+
+To build everything, run
+
+  amu
+  amu install
+
+in the `StraySrc' directory.  This will recursively build and install
+everything you've unpacked.  (The Makefiles work out which bits you've
+got and build them.)  If this doesn't work, make sure you've got all
+the tools you need, and all the paths are set up right.
+
+All the source code may be modified and redistributed under the terms of
+the GNU General Public License, which is included in the distribution
+archives as `StraySrc.COPYING'.  Special exceptions for distribution of
+binaries may be given; please ask me for permission.
+
+Public discussion of the Straylight Source Release, including reporting
+of bugs, and requesting new features, will take place on a mailing list. 
+To subscribe, send mail to `ssr-subscribe@excessus.demon.co.uk'.  You
+will be asked to send a confirmation message to prove that you can
+receive mail from the list.  To send a message to the list, mail
+`ssr@excessus.demon.co.uk'.
+
+I want to gather a small team of developers to continue maintenance of
+SSR.  If you think you could help to maintain and develop parts of SSR,
+or write documentation for it, then send me email.
+
+
+My personal email address is mdw@excessus.demon.co.uk.  Please try to
+report problems or requests to the list.  (On the other hand, problems
+/about/ the list probably ought to be sent to me!)
+
+I think that about wraps it up for me.
+
+                                               Mark Wooding
+                                               Fri 30th January 1998