--- /dev/null
+|
+| 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
--- /dev/null
+|
+| 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
--- /dev/null
+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.
--- /dev/null
+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
+
--- /dev/null
+ 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.
--- /dev/null
+#
+# 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:
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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\
+}
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+ LNK libs:s.fastMove
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+|
+| 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
--- /dev/null
+ ____
+ / ___ ___ ___
+ / ___ | /___\ (___ (___
+ \______/ |___ | | ____) ____)
+
+ © 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.
+___________________________________________________________
--- /dev/null
+|
+| 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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 -------------------------------------------------------
+
+;----------------------------------------------------------------------------
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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 */
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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,®);
+ }
+ 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));
+}
--- /dev/null
+/*
+ * 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,®);
+ }
+ 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,®);
+ }
+ 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,®);
+ }
+ }
+ }
+ }
+
+ /* --- 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));
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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,®);
+ 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,®);
+
+ /* --- 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;
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * _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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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:
--- /dev/null
+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
--- /dev/null
+#
+# 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
--- /dev/null
+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.)
+
+_____________________________________________________________________________
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+ LNK libs:s.fastMove
--- /dev/null
+;
+; 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
+
--- /dev/null
+;
+; 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
+
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+|
+| 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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+ LNK libs:sh.fastMove
--- /dev/null
+;
+; flex.sh
+;
+; Flexible memory handling
+;
+; © 1998 Straylight
+;
+
+ GBLL FLEX_STACK
+ LNK libs:sh.flex
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+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]
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+#
+# 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:
--- /dev/null
+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]
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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:
--- /dev/null
+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]
--- /dev/null
+/*
+ * 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
--- /dev/null
+ 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+/*
+ * _time.h
+ */
+
+extern char _time[];
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+;
+; 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
+
+
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+ GET libs:header
+ GET libs:swis
+
+ AREA |C$$Code|,CODE,READONLY
+ LNK libs:s.xswi
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+ GBLL xentry_swi
+ LNK s.xentry
--- /dev/null
+;
+; 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
--- /dev/null
+ GBLL xentry_small
+ LNK s.xentry
--- /dev/null
+ GBLL xentry_small
+ GBLL xentry_swi
+ LNK s.xentry
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+#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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+#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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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:
--- /dev/null
+#
+# 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
--- /dev/null
+ LNK libs:s.fastMove
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+\11
\ No newline at end of file
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+
+ /####\ ######\ ######\ #### ###\ ## ## /#/ ## ######
+ ##/ ## )# ## )# ## ##\#\ ## ## /#/ ## ##
+ \####\ ######/ ######/ ## ## \#\ ## ##<#< ## #####
+ \## ## ## \#\ ## ## \#\## ## \#\ ## ##
+ \####/ ## ## \#\ #### ## \### ## \#\ ###### ######
+
+ © 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').
+
+_____________________________________________________________________________
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+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\03À\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Âë\ 33À\99\1f_^\8bå]Ë\0U\8bì\8bN\ e
\ No newline at end of file
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
+}
--- /dev/null
+;
+; 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
+}
--- /dev/null
+;
+; 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
+}
--- /dev/null
+;
+; 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
+}
--- /dev/null
+;
+; 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
+}
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+ LNK libs:s.fastMove
--- /dev/null
+ GBLL OPT_SAPPHIRE
+ GBLL OPT_DYNAREA
+ GBLL OPT_STACK
+ LNK libs:s.flex
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+ GBLL OPT_SAPPHIRE
+ LNK libs:s.heap
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
+
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
+
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
+
+
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
+
+
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+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
--- /dev/null
+#
+# 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
--- /dev/null
+
+ 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
+
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
+
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; _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
--- /dev/null
+;
+; _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
--- /dev/null
+;
+; _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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; _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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+# /-------------------------------------------------------------------------\
+# | |
+# | 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.
+
+#============================================================================
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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."));
+}
--- /dev/null
+/************************************************************************/
+/* © 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, ®_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, ®_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, ®_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, ®_set)) != NULL)
+ return error;
+
+ return NULL;
+}
+
+#pragma check_stack
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/************************************
+
+ 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/************************************************************************/
+/* © 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
+
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/************************************************************************/
+/* © 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, ®_set);
+ reg_set.r [3] = at;
+ reg_set.r [4] = number;
+ return sprite__op (®_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, ®_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 (®_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, ®_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 (®_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, ®_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 (®_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, ®_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 (®_set);
+}
+
+#pragma check_stack
+
+/* end of c.sprite */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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));
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/* 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 */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+;
+; 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
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/****************************************************************************
+ * 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/****************************************************************************
+ * 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 */
+
+
--- /dev/null
+/*
+ * 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
--- /dev/null
+/****************************************************************************
+ * 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/************************************
+
+ 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/****************************************************************************
+ * 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/****************************************************************************
+ * 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
--- /dev/null
+/****************************************************************************
+ * 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 */
--- /dev/null
+/****************************************************************************
+ * 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 */
--- /dev/null
+/****************************************************************************
+ * 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 */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+ LNK libs:s.fastMove
--- /dev/null
+ GBLL OPT_APCS
+ GBLL OPT_DLL
+ GBLL OPT_DYNAREA
+ LNK libs:s.flex
--- /dev/null
+ GBLL OPT_APCS
+ GBLL OPT_DYNAREA
+ LNK libs:s.flex
--- /dev/null
+ GBLL OPT_APCS
+ GBLL OPT_DLL
+ LNK libs:s.heap
--- /dev/null
+ GBLL OPT_APCS
+ LNK libs:s.heap
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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:
--- /dev/null
+#
+# 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
--- /dev/null
+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]
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+ ___ _____
+ / __ __ | \ ___ __
+ | | | |__) |__) | | | |__)
+ \___ \__/ | \ | \ _|___/ _|_ | \
+
+ © 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.
+___________________________________________________________
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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:
--- /dev/null
+#
+# 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:
--- /dev/null
+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.)
--- /dev/null
+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.
--- /dev/null
+ ___ _ _
+ ! \ ! ! ! \ / ! ___ ___ ___ ___
+ ! \ ! ! ! \/ ! !__ !___) / __ !__
+ !____/ !____ !____ ! ! !___ ! \ \___/ !___
+
+ © 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
--- /dev/null
+|
+| 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
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; Template symbols [generated by templAOF]
+;
+
+ [ :LNOT::DEF:tpl__dfn
+ GBLL tpl__dfn
+
+ IMPORT tpl_merge
+ IMPORT tpl_progInfo
+
+ ]
+
+ END
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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>\
+}
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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:
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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]));
+}
--- /dev/null
+/*
+ * 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());
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+#
+# 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;
+ }
--- /dev/null
+;
+; 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
--- /dev/null
+|
+| 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
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; CApp messages
+;
+; © 1995 Straylight
+;
+
+caINF:Info...
+caQUIT:Quit
+caPUR:To prove it can be done!
--- /dev/null
+/*
+ * 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 -------------------------------------------------*/
--- /dev/null
+|
+| 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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:
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+|
+| 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
--- /dev/null
+ ____
+ | \ ___ ___ \ /
+ | \ | ___) | | ( ><
+ |_____/ | (___( |_|__) / \
+
+ © 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
+___________________________________________________________
--- /dev/null
+|
+| 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
--- /dev/null
+;
+; DrawX options
+;
+
+[DrawX]
+DefaultScale=100
+
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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.
--- /dev/null
+
+; 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
--- /dev/null
+ __ ___
+ (__ | | | | ' __ _|__
+ \ | | | | | | (__ |
+ ___/ \__|__/ _|_ |____ ( ___) (__
+
+
+ © 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.
+
+_____________________________________________________________________________
--- /dev/null
+|
+| 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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:
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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:
--- /dev/null
+RMEnsure Sculptrix 2.01 RMLoad <Obey$Dir>.Sculptrix
+Run <Obey$Dir>.LoadConfig <Obey$Dir>.SConfig
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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
--- /dev/null
+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.
+
+
--- /dev/null
+|
+| 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
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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.
--- /dev/null
+;
+; 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
--- /dev/null
+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.
--- /dev/null
+#
+# 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:
--- /dev/null
+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]
--- /dev/null
+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]
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+;
+; 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
--- /dev/null
+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]
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+;
+; 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>\
+}
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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 -------------------------------------------------*/
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 -------------------------------------------------*/
--- /dev/null
+/*
+ * 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 -------------------------------------------------*/
--- /dev/null
+/*
+ * 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 -------------------------------------------------*/
--- /dev/null
+/*
+ * 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 -------------------------------------------------*/
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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 -------------------------------------------------*/
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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 -------------------------------------------------*/
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+;
+; 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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+|
+| makeDist
+|
+| Build SSR distribution archives
+|
+
+dir <SSR$Dir>.^
+zip <SSR$Dir>.zip.%0 -@ < <SSR$Dir>.dist.%0
--- /dev/null
+#
+# 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:
--- /dev/null
+;----- 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.
+
--- /dev/null
+/*----- 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.
+ */
+
--- /dev/null
+|
+| 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
--- /dev/null
+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
--- /dev/null
+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